featurebase/idk/interfaces_test.go
2022-09-02 13:23:39 -07:00

437 lines
8.8 KiB
Go

package idk
import (
"fmt"
"strings"
"testing"
"time"
)
func TestDecimalFieldPilosafy(t *testing.T) {
f := DecimalField{NameVal: "a", Scale: 3}
if ret, err := f.PilosafyVal(float32(0.9)); err != nil || ret != int64(900) {
t.Errorf("got: %v of %[1]T, err: %v", ret, err)
}
}
func TestPilosafyVal(t *testing.T) {
tests := []struct {
field Field
vals []interface{}
exps []interface{}
expErrs []string
}{
{
field: StringArrayField{},
vals: []interface{}{
"a,b,c",
"[a,b,c]",
""},
exps: []interface{}{
[]string{"a", "b", "c"},
[]string{"a", "b", "c"},
[]string(nil)},
},
{
field: IDArrayField{},
vals: []interface{}{
"1,2,3",
"[1,2,3]",
""},
exps: []interface{}{
[]uint64{1, 2, 3},
[]uint64{1, 2, 3},
[]uint64(nil)},
},
{
field: IntField{},
vals: []interface{}{
1,
"1",
"",
nil,
},
exps: []interface{}{
int64(1),
int64(1),
nil,
nil,
},
},
{
field: DecimalField{Scale: 2},
vals: []interface{}{
1,
"1",
"",
nil,
},
exps: []interface{}{
int64(100),
int64(100),
nil,
nil,
},
},
{
field: IDField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
{
field: BoolField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
{
field: StringField{},
vals: []interface{}{""},
exps: []interface{}{""},
expErrs: []string(nil),
},
{
field: IntField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
{
field: DecimalField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
{
field: StringArrayField{},
vals: []interface{}{""},
exps: []interface{}{[]string(nil)},
expErrs: []string(nil),
},
{
field: IDArrayField{},
vals: []interface{}{""},
exps: []interface{}{[]uint64(nil)},
expErrs: []string(nil),
},
{
field: DateIntField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
{
field: RecordTimeField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
{
field: TimestampField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
{
field: SignedIntBoolKeyField{},
vals: []interface{}{"", int64(-2), int(2), uint64(3)},
exps: []interface{}{nil, int64(-2), int64(2), int64(3)},
expErrs: []string(nil),
},
{
field: IgnoreField{},
vals: []interface{}{""},
exps: []interface{}{nil},
expErrs: []string(nil),
},
}
for i, test := range tests {
if len(test.exps) > 0 && len(test.vals) != len(test.exps) {
panic(fmt.Sprintf("invalid test at %d", i))
}
if len(test.expErrs) > 0 && len(test.vals) != len(test.expErrs) {
panic(fmt.Sprintf("invalid test at %d", i))
}
for j, val := range test.vals {
t.Run(fmt.Sprintf("test%dval%d", i, j), func(t *testing.T) {
pval, err := test.field.PilosafyVal(val)
if len(test.exps) > 0 {
errorIfNotEqual(t, test.exps[j], pval)
}
if len(test.expErrs) > 0 {
errorIfNotErrMatch(t, test.expErrs[j], err)
}
})
}
}
}
func TestTTLOf(t *testing.T) {
tests := []struct {
name string
field Field
expectedTTL time.Duration
expectedErr string
}{
{
name: "ttl StringField",
field: StringField{NameVal: "a", Mutex: false, Quantum: "YMD", TTL: "1s"},
expectedTTL: time.Second,
expectedErr: "",
},
{
name: "ttl IDField",
field: IDField{NameVal: "a", Mutex: false, Quantum: "YMD", TTL: "60s"},
expectedTTL: time.Second * 60,
expectedErr: "",
},
{
name: "ttl StringArrayField",
field: StringArrayField{NameVal: "a", Quantum: "YMD", TTL: "1h"},
expectedTTL: time.Hour,
expectedErr: "",
},
{
name: "ttl IDArrayField",
field: StringArrayField{NameVal: "a", Quantum: "YMD", TTL: "1h"},
expectedTTL: time.Hour,
expectedErr: "",
},
{
name: "ttl bad format",
field: StringField{NameVal: "a", Mutex: false, Quantum: "YMD", TTL: "0ssss"},
expectedTTL: 0,
expectedErr: "unable to parse TTL",
},
{
name: "ttl empty",
field: StringField{NameVal: "a", Mutex: false, Quantum: "YMD", TTL: ""},
expectedTTL: 0,
expectedErr: "",
},
{
name: "no ttl",
field: StringField{NameVal: "a", Mutex: false, Quantum: "YMD"},
expectedTTL: 0,
expectedErr: "",
},
{
name: "ttl IntField",
field: IntField{NameVal: "a"},
expectedTTL: 0,
expectedErr: "",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ttl, err := TTLOf(test.field)
if ttl != test.expectedTTL {
t.Errorf("expected TTL: '%v', got: '%v'", test.expectedTTL, ttl)
}
if err != nil && !strings.Contains(err.Error(), test.expectedErr) {
t.Errorf("expected error: '%s', got: '%s'", test.expectedErr, err.Error())
}
})
}
}
func TestTimestampFieldValidateDuration(t *testing.T) {
errTimeOutsideEpoch := "value + epoch is too far from Unix epoch"
type args struct {
dur int64
offset int64
unit Unit
}
tests := []struct {
name string
args args
wantErr bool
errStr string
}{
{
name: "max-max",
args: args{
dur: 0,
offset: TimestampToVal(Unit("s"), MaxTimestamp),
unit: Unit("s"),
},
wantErr: false,
},
{
name: "oor-max",
args: args{
dur: 1,
offset: TimestampToVal(Unit("s"), MaxTimestamp),
unit: Unit("s"),
},
wantErr: true,
errStr: errTimeOutsideEpoch,
},
{
name: "max-oor",
args: args{
dur: 0,
offset: TimestampToVal(Unit("s"), MaxTimestamp.Add(1*time.Second)),
unit: Unit("s"),
},
wantErr: true,
errStr: errTimeOutsideEpoch,
},
{
name: "min-min",
args: args{
dur: 0,
offset: TimestampToVal(Unit("s"), MinTimestamp),
unit: Unit("s"),
},
wantErr: false,
},
{
name: "oor-min",
args: args{
dur: -1,
offset: TimestampToVal(Unit("s"), MinTimestamp),
unit: Unit("s"),
},
wantErr: true,
errStr: errTimeOutsideEpoch,
},
{
name: "min-oor",
args: args{
dur: 0,
offset: TimestampToVal(Unit("s"), MinTimestamp.Add(-1*time.Second)),
unit: Unit("s"),
},
wantErr: true,
errStr: errTimeOutsideEpoch,
},
{
name: "max-max",
args: args{
dur: 0,
offset: TimestampToVal(Unit("ns"), MaxTimestampNano),
unit: Unit("ns"),
},
wantErr: false,
},
{
name: "oor-max",
args: args{
dur: 1,
offset: TimestampToVal(Unit("ns"), MaxTimestampNano),
unit: Unit("ns"),
},
wantErr: true,
errStr: errTimeOutsideEpoch,
},
{
name: "max-oor",
args: args{
dur: 0,
offset: TimestampToVal(Unit("ns"), MaxTimestampNano.Add(1*time.Nanosecond)),
unit: Unit("ns"),
},
wantErr: true,
errStr: errTimeOutsideEpoch,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validateDuration(tt.args.dur, tt.args.offset, tt.args.unit); (err != nil) != tt.wantErr {
if !strings.Contains(err.Error(), tt.errStr) {
t.Errorf("TimestampField.validateDuration() error = %v, wantErr %v", err, tt.wantErr)
}
}
})
}
}
func TestValidateTimestamp(t *testing.T) {
type args struct {
unit Unit
ts time.Time
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "nano-max",
args: args{
unit: Unit("ns"),
ts: MaxTimestampNano,
},
wantErr: false,
},
{
name: "nano-min",
args: args{
unit: Unit("ns"),
ts: MinTimestampNano,
},
wantErr: false,
},
{
name: "nano-max-oor",
args: args{
unit: Unit("ns"),
ts: MaxTimestampNano.Add(1 * time.Nanosecond),
},
wantErr: true,
},
{
name: "nano-min-oor",
args: args{
unit: Unit("ns"),
ts: MinTimestampNano.Add(-1 * time.Nanosecond),
},
wantErr: true,
},
{
name: "ms-max",
args: args{
unit: Unit("ms"),
ts: MaxTimestamp,
},
wantErr: false,
},
{
name: "ms-min",
args: args{
unit: Unit("ms"),
ts: MinTimestamp,
},
wantErr: false,
},
{
name: "ms-max-oor",
args: args{
unit: Unit("ms"),
ts: MaxTimestamp.Add(1 * time.Millisecond),
},
wantErr: true,
},
{
name: "ms-min-oor",
args: args{
unit: Unit("ms"),
ts: MinTimestamp.Add(-1 * time.Millisecond),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validateTimestamp(tt.args.unit, tt.args.ts); (err != nil) != tt.wantErr {
t.Errorf("validateTimestamp() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}