| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package vdl |
| |
| import ( |
| "bytes" |
| "fmt" |
| "sort" |
| "strings" |
| "testing" |
| ) |
| |
| var ( |
| keyType = StructType([]Field{{"I", Int64Type}, {"S", StringType}}...) |
| |
| strA, strB, strC = StringValue("A"), StringValue("B"), StringValue("C") |
| int1, int2 = Int64Value(1), Int64Value(2) |
| key1, key2, key3 = makeKey(1, "A"), makeKey(2, "B"), makeKey(3, "C") |
| ) |
| |
| func makeKey(a int64, b string) *Value { |
| key := ZeroValue(keyType) |
| key.StructField(0).AssignInt(a) |
| key.StructField(1).AssignString(b) |
| return key |
| } |
| |
| func TestValueInvalid(t *testing.T) { |
| tests := []*Value{nil, new(Value)} |
| for ix, test := range tests { |
| if test.IsValid() { |
| t.Errorf(`%d IsValid()`, ix) |
| } |
| if got, want := test.String(), "INVALID"; got != want { |
| t.Errorf(`%d String() got %v, want %v`, ix, got, want) |
| } |
| } |
| } |
| |
| func TestValue(t *testing.T) { |
| tests := []struct { |
| k Kind |
| t *Type |
| s string |
| }{ |
| {Bool, BoolType, "false"}, |
| {Byte, ByteType, "byte(0)"}, |
| {Uint16, Uint16Type, "uint16(0)"}, |
| {Uint32, Uint32Type, "uint32(0)"}, |
| {Uint64, Uint64Type, "uint64(0)"}, |
| {Int8, Int8Type, "int8(0)"}, |
| {Int16, Int16Type, "int16(0)"}, |
| {Int32, Int32Type, "int32(0)"}, |
| {Int64, Int64Type, "int64(0)"}, |
| {Float32, Float32Type, "float32(0)"}, |
| {Float64, Float64Type, "float64(0)"}, |
| {Complex64, Complex64Type, "complex64(0+0i)"}, |
| {Complex128, Complex128Type, "complex128(0+0i)"}, |
| {String, StringType, `""`}, |
| {List, ListType(ByteType), `[]byte("")`}, |
| {Array, ArrayType(3, ByteType), `[3]byte("\x00\x00\x00")`}, |
| {Enum, EnumType("A", "B", "C"), "enum{A;B;C}(A)"}, |
| {TypeObject, TypeObjectType, "typeobject(any)"}, |
| {Array, ArrayType(2, StringType), `[2]string{"", ""}`}, |
| {List, ListType(StringType), "[]string{}"}, |
| {Set, SetType(StringType), "set[string]{}"}, |
| {Set, SetType(keyType), "set[struct{I int64;S string}]{}"}, |
| {Map, MapType(StringType, Int64Type), "map[string]int64{}"}, |
| {Map, MapType(keyType, Int64Type), "map[struct{I int64;S string}]int64{}"}, |
| {Struct, StructType([]Field{{"A", Int64Type}, {"B", StringType}, {"C", BoolType}}...), `struct{A int64;B string;C bool}{A: 0, B: "", C: false}`}, |
| {Union, UnionType([]Field{{"A", Int64Type}, {"B", StringType}, {"C", BoolType}}...), `union{A int64;B string;C bool}{A: 0}`}, |
| {Any, AnyType, "any(nil)"}, |
| } |
| for _, test := range tests { |
| x := ZeroValue(test.t) |
| if !x.IsValid() { |
| t.Errorf(`!ZeroValue(%s).IsValid`, test.k) |
| } |
| if !x.IsZero() { |
| t.Errorf(`ZeroValue(%s) isn't zero`, test.k) |
| } |
| if test.k == Any && !x.IsNil() { |
| t.Errorf(`ZeroValue(Any) isn't nil`) |
| } |
| if got, want := x.Kind(), test.k; got != want { |
| t.Errorf(`ZeroValue(%s) got kind %v, want %v`, test.k, got, want) |
| } |
| if got, want := x.Type(), test.t; got != want { |
| t.Errorf(`ZeroValue(%s) got type %v, want %v`, test.k, got, want) |
| } |
| if got, want := x.String(), test.s; got != want { |
| t.Errorf(`ZeroValue(%s) got string %q, want %q`, test.k, got, want) |
| } |
| y := CopyValue(x) |
| if !y.IsValid() { |
| t.Errorf(`!CopyValue(ZeroValue(%s)).IsValid`, test.k) |
| } |
| if !y.IsZero() { |
| t.Errorf(`ZeroValue(%s) of copy isn't zero, y: %v`, test.k, y) |
| } |
| if test.k == Any && !y.IsNil() { |
| t.Errorf(`ZeroValue(Any) of copy isn't nil`) |
| } |
| if !EqualValue(x, y) { |
| t.Errorf(`ZeroValue(%s) !Equal after copy, x: %v, y: %v`, test.k, x, y) |
| } |
| |
| // Invariant here: x == y == 0 |
| // The assign[KIND] functions assign a nonzero value. |
| assignBool(t, x) |
| assignUint(t, x) |
| assignInt(t, x) |
| assignFloat(t, x) |
| assignComplex(t, x) |
| assignString(t, x) |
| assignEnum(t, x) |
| assignTypeObject(t, x) |
| assignArray(t, x) |
| assignList(t, x) |
| assignSet(t, x) |
| assignMap(t, x) |
| assignStruct(t, x) |
| assignUnion(t, x) |
| assignAny(t, x) |
| |
| // Invariant here: x != 0 && y == 0 |
| if EqualValue(x, y) { |
| t.Errorf(`ZeroValue(%s) Equal after assign, x: %v, y: %v`, test.k, x, y) |
| } |
| z := CopyValue(x) // x == z && x != 0 && y == 0 |
| if !EqualValue(x, z) { |
| t.Errorf(`ZeroValue(%s) !Equal after copy, x: %v, z: %v`, test.k, x, z) |
| } |
| if EqualValue(y, z) { |
| t.Errorf(`ZeroValue(%s) Equal after copy, y: %v, z: %v`, test.k, y, z) |
| } |
| |
| z.Assign(nil) // x != 0 && y == z == 0 |
| if !z.IsValid() { |
| t.Errorf(`%s z after Assign(nil) isn't valid`, test.k) |
| } |
| if !z.IsZero() { |
| t.Errorf(`%s z after Assign(nil) isn't zero`, test.k) |
| } |
| if test.k == Any && !z.IsNil() { |
| t.Errorf(`Any z after Assign(nil) isn't nil`) |
| } |
| if EqualValue(x, z) { |
| t.Errorf(`%s Equal after Assign(nil), x: %v, z: %v`, test.k, x, z) |
| } |
| if !EqualValue(y, z) { |
| t.Errorf(`%s !Equal after Assign(nil), y: %v, z: %v`, test.k, y, z) |
| } |
| |
| y.Assign(x) // x == y && x != 0 && z == 0 |
| if !y.IsValid() { |
| t.Errorf(`%s y after Assign(x) isn't valid`, test.k) |
| } |
| if y.IsZero() { |
| t.Errorf(`%s y after Assign(x) is zero, y: %v`, test.k, y) |
| } |
| if y.IsNil() { |
| t.Errorf(`%s y after Assign(x) is nil, y: %v`, test.k, y) |
| } |
| if !EqualValue(x, y) { |
| t.Errorf(`%s Equal after Assign(x), x: %v, y: %v`, test.k, x, y) |
| } |
| if EqualValue(y, z) { |
| t.Errorf(`%s Equal after Assign(x), y: %v, z: %v`, test.k, y, z) |
| } |
| |
| // Test optional types |
| if !test.t.CanBeOptional() { |
| continue |
| } |
| ntype := OptionalType(test.t) |
| |
| // nx == nil |
| nx := ZeroValue(ntype) |
| if !nx.IsValid() { |
| t.Errorf(`!ZeroValue(?%s).IsValid`, test.k) |
| } |
| if !nx.IsZero() { |
| t.Errorf(`ZeroValue(?%s) isn't zero`, test.k) |
| } |
| if !nx.IsNil() { |
| t.Errorf(`ZeroValue(?%s) isn't nil`, test.k) |
| } |
| if got, want := nx.Kind(), Optional; got != want { |
| t.Errorf(`ZeroValue(?%s) got kind %v, want %v`, test.k, got, want) |
| } |
| if got, want := nx.Type(), ntype; got != want { |
| t.Errorf(`ZeroValue(?%s) got type %v, want %v`, test.k, got, want) |
| } |
| if got, want := nx.String(), ntype.String()+"(nil)"; got != want { |
| t.Errorf(`ZeroValue(?%s) got string %q, want %q`, test.k, got, want) |
| } |
| // ny != nil |
| ny := NonNilZeroValue(ntype) |
| if !ny.IsValid() { |
| t.Errorf(`!NonNilZeroValue(?%s).IsValid`, test.k) |
| } |
| if ny.IsZero() { |
| t.Errorf(`NonNilZeroValue(?%s) is zero`, test.k) |
| } |
| if ny.IsNil() { |
| t.Errorf(`NonNilZeroValue(?%s) is nil`, test.k) |
| } |
| if got, want := ny.Kind(), Optional; got != want { |
| t.Errorf(`NonNilZeroValue(?%s) got kind %v, want %v`, test.k, got, want) |
| } |
| if got, want := ny.Type(), ntype; got != want { |
| t.Errorf(`NonNilZeroValue(?%s) got type %v, want %v`, test.k, got, want) |
| } |
| } |
| } |
| |
| // Each of the below assign{KIND} functions assigns a nonzero value to x for |
| // matching kinds, otherwise it expects a mismatched-kind panic when trying the |
| // kind-specific methods. The point is to ensure we've tried all combinations |
| // of kinds and methods. |
| |
| func assignBool(t *testing.T, x *Value) { |
| newval, newstr := true, "true" |
| if x.Kind() == Bool { |
| if got, want := x.Bool(), false; got != want { |
| t.Errorf(`Bool zero value got %v, want %v`, got, want) |
| } |
| x.AssignBool(newval) |
| if got, want := x.Bool(), newval; got != want { |
| t.Errorf(`Bool assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), newstr; got != want { |
| t.Errorf(`Bool string got %v, want %v`, got, want) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.Bool() }) |
| ExpectMismatchedKind(t, func() { x.AssignBool(newval) }) |
| } |
| } |
| |
| func assignUint(t *testing.T, x *Value) { |
| newval := uint64(123) |
| switch x.Kind() { |
| case Byte, Uint16, Uint32, Uint64: |
| if got, want := x.Uint(), uint64(0); got != want { |
| t.Errorf(`Uint zero value got %v, want %v`, got, want) |
| } |
| x.AssignUint(newval) |
| if got, want := x.Uint(), newval; got != want { |
| t.Errorf(`Uint assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), x.Kind().String()+"(123)"; got != want { |
| t.Errorf(`Uint string got %v, want %v`, got, want) |
| } |
| default: |
| ExpectMismatchedKind(t, func() { x.Uint() }) |
| ExpectMismatchedKind(t, func() { x.AssignUint(newval) }) |
| } |
| } |
| |
| func assignInt(t *testing.T, x *Value) { |
| newval := int64(123) |
| switch x.Kind() { |
| case Int8, Int16, Int32, Int64: |
| if got, want := x.Int(), int64(0); got != want { |
| t.Errorf(`Int zero value got %v, want %v`, got, want) |
| } |
| x.AssignInt(newval) |
| if got, want := x.Int(), newval; got != want { |
| t.Errorf(`Int assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), x.Kind().String()+"(123)"; got != want { |
| t.Errorf(`Int string got %v, want %v`, got, want) |
| } |
| default: |
| ExpectMismatchedKind(t, func() { x.Int() }) |
| ExpectMismatchedKind(t, func() { x.AssignInt(newval) }) |
| } |
| } |
| |
| func assignFloat(t *testing.T, x *Value) { |
| newval := float64(1.23) |
| switch x.Kind() { |
| case Float32, Float64: |
| if got, want := x.Float(), float64(0); got != want { |
| t.Errorf(`Float zero value got %v, want %v`, got, want) |
| } |
| x.AssignFloat(newval) |
| if got, want := x.Float(), newval; got != want { |
| t.Errorf(`Float assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), x.Kind().String()+"(1.23)"; got != want { |
| t.Errorf(`Float string got %v, want %v`, got, want) |
| } |
| default: |
| ExpectMismatchedKind(t, func() { x.Float() }) |
| ExpectMismatchedKind(t, func() { x.AssignFloat(newval) }) |
| } |
| } |
| |
| func assignComplex(t *testing.T, x *Value) { |
| newval := complex128(1 + 2i) |
| switch x.Kind() { |
| case Complex64, Complex128: |
| if got, want := x.Complex(), complex128(0); got != want { |
| t.Errorf(`Complex zero value got %v, want %v`, got, want) |
| } |
| x.AssignComplex(newval) |
| if got, want := x.Complex(), newval; got != want { |
| t.Errorf(`Complex assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), x.Kind().String()+"(1+2i)"; got != want { |
| t.Errorf(`Complex string got %v, want %v`, got, want) |
| } |
| default: |
| ExpectMismatchedKind(t, func() { x.Complex() }) |
| ExpectMismatchedKind(t, func() { x.AssignComplex(newval) }) |
| } |
| } |
| |
| func assignString(t *testing.T, x *Value) { |
| zerostr, newval, newstr := `""`, "abc", `"abc"` |
| if x.Kind() == String { |
| if got, want := x.String(), zerostr; got != want { |
| t.Errorf(`String zero value got %v, want %v`, got, want) |
| } |
| x.AssignString(newval) |
| if got, want := x.RawString(), newval; got != want { |
| t.Errorf(`String assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), newstr; got != want { |
| t.Errorf(`String assign string rep got %v, want %v`, got, want) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.RawString() }) |
| ExpectMismatchedKind(t, func() { x.AssignString(newval) }) |
| } |
| } |
| |
| func assignEnum(t *testing.T, x *Value) { |
| if x.Kind() == Enum { |
| if gi, gl, wi, wl := x.EnumIndex(), x.EnumLabel(), 0, "A"; gi != wi || gl != wl { |
| t.Errorf(`Enum zero value got [%d]%v, want [%d]%v`, gi, gl, wi, wl) |
| } |
| x.AssignEnumIndex(1) |
| if gi, gl, wi, wl := x.EnumIndex(), x.EnumLabel(), 1, "B"; gi != wi || gl != wl { |
| t.Errorf(`Enum assign index value got [%d]%v, want [%d]%v`, gi, gl, wi, wl) |
| } |
| if got, want := x.String(), "enum{A;B;C}(B)"; got != want { |
| t.Errorf(`Enum string got %v, want %v`, got, want) |
| } |
| x.AssignEnumIndex(2) |
| if gi, gl, wi, wl := x.EnumIndex(), x.EnumLabel(), 2, "C"; gi != wi || gl != wl { |
| t.Errorf(`Enum assign label value got [%d]%v, want [%d]%v`, gi, gl, wi, wl) |
| } |
| if got, want := x.String(), "enum{A;B;C}(C)"; got != want { |
| t.Errorf(`Enum string got %v, want %v`, got, want) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.EnumIndex() }) |
| ExpectMismatchedKind(t, func() { x.EnumLabel() }) |
| ExpectMismatchedKind(t, func() { x.AssignEnumIndex(0) }) |
| ExpectMismatchedKind(t, func() { x.AssignEnumLabel("A") }) |
| } |
| } |
| |
| func assignTypeObject(t *testing.T, x *Value) { |
| newval, newstr := BoolType, "typeobject(bool)" |
| if x.Kind() == TypeObject { |
| if got, want := x.TypeObject(), zeroTypeObject; got != want { |
| t.Errorf(`TypeObject zero value got %v, want %v`, got, want) |
| } |
| x.AssignTypeObject(newval) |
| if got, want := x.TypeObject(), newval; got != want { |
| t.Errorf(`TypeObject assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), newstr; got != want { |
| t.Errorf(`TypeObject string got %v, want %v`, got, want) |
| } |
| x.AssignTypeObject(nil) // assigning nil sets the zero typeobject |
| if got, want := x.TypeObject(), zeroTypeObject; got != want { |
| t.Errorf(`TypeObject assign value got %v, want %v`, got, want) |
| } |
| x.AssignTypeObject(newval) |
| } else { |
| ExpectMismatchedKind(t, func() { x.TypeObject() }) |
| ExpectMismatchedKind(t, func() { x.AssignTypeObject(newval) }) |
| } |
| } |
| |
| func assignArray(t *testing.T, x *Value) { |
| if x.Kind() == Array { |
| if x.Type().IsBytes() { |
| assignBytes(t, x) |
| return |
| } |
| if got, want := x.Len(), 2; got != want { |
| t.Errorf(`Array zero len got %v, want %v`, got, want) |
| } |
| if g0, g1, w0, w1 := x.Index(0).String(), x.Index(1).String(), `""`, `""`; g0 != w0 || g1 != w1 { |
| t.Errorf(`Array assign values got %v %v, want %v %v`, g0, g1, w0, w1) |
| } |
| x.Index(0).AssignString("A") |
| x.Index(1).AssignString("B") |
| if g0, g1, w0, w1 := x.Index(0).String(), x.Index(1).String(), `"A"`, `"B"`; g0 != w0 || g1 != w1 { |
| t.Errorf(`Array assign values got %v %v, want %v %v`, g0, g1, w0, w1) |
| } |
| if got, want := x.String(), `[2]string{"A", "B"}`; got != want { |
| t.Errorf(`Array string got %v, want %v`, got, want) |
| } |
| } else { |
| if x.Kind() != List { |
| // Index is allowed for Array and List |
| ExpectMismatchedKind(t, func() { x.Index(0) }) |
| } |
| if x.Kind() != List && x.Kind() != Set && x.Kind() != Map { |
| // Len is allowed for Array, List, Set and Map |
| ExpectMismatchedKind(t, func() { x.Len() }) |
| } |
| } |
| } |
| |
| func assignList(t *testing.T, x *Value) { |
| if x.Kind() == List { |
| if x.Type().IsBytes() { |
| assignBytes(t, x) |
| return |
| } |
| if got, want := x.Len(), 0; got != want { |
| t.Errorf(`List zero len got %v, want %v`, got, want) |
| } |
| x.AssignLen(2) |
| if got, want := x.Len(), 2; got != want { |
| t.Errorf(`List assign len got %v, want %v`, got, want) |
| } |
| if g0, g1, w0, w1 := x.Index(0).String(), x.Index(1).String(), `""`, `""`; g0 != w0 || g1 != w1 { |
| t.Errorf(`List assign values got %v %v, want %v %v`, g0, g1, w0, w1) |
| } |
| if got, want := x.String(), `[]string{"", ""}`; got != want { |
| t.Errorf(`List string got %v, want %v`, got, want) |
| } |
| x.Index(0).AssignString("A") |
| x.Index(1).AssignString("B") |
| if g0, g1, w0, w1 := x.Index(0).String(), x.Index(1).String(), `"A"`, `"B"`; g0 != w0 || g1 != w1 { |
| t.Errorf(`List assign values got %v %v, want %v %v`, g0, g1, w0, w1) |
| } |
| if got, want := x.String(), `[]string{"A", "B"}`; got != want { |
| t.Errorf(`List string got %v, want %v`, got, want) |
| } |
| x.AssignLen(1) |
| if got, want := x.Len(), 1; got != want { |
| t.Errorf(`List assign len got %v, want %v`, got, want) |
| } |
| if g0, w0 := x.Index(0).String(), `"A"`; g0 != w0 { |
| t.Errorf(`List assign values got %v, want %v`, g0, w0) |
| } |
| if got, want := x.String(), `[]string{"A"}`; got != want { |
| t.Errorf(`List string got %v, want %v`, got, want) |
| } |
| x.AssignLen(3) |
| if got, want := x.Len(), 3; got != want { |
| t.Errorf(`List assign len got %v, want %v`, got, want) |
| } |
| if g0, g1, g2, w0, w1, w2 := x.Index(0).String(), x.Index(1).String(), x.Index(2).String(), `"A"`, `""`, `""`; g0 != w0 || g1 != w1 || g2 != w2 { |
| t.Errorf(`List assign values got %v %v %v, want %v %v %v`, g0, g1, g2, w0, w1, w2) |
| } |
| if got, want := x.String(), `[]string{"A", "", ""}`; got != want { |
| t.Errorf(`List string got %v, want %v`, got, want) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.AssignLen(0) }) |
| if x.Kind() != Array { |
| // Index is allowed for Array and List |
| ExpectMismatchedKind(t, func() { x.Index(0) }) |
| } |
| if x.Kind() != Array && x.Kind() != Set && x.Kind() != Map { |
| // Len is allowed for Array, List, Set and Map |
| ExpectMismatchedKind(t, func() { x.Len() }) |
| } |
| } |
| } |
| |
| func assignBytes(t *testing.T, x *Value) { |
| abval, abcval, abcdval := []byte("ab"), []byte("abc"), []byte("abcd") |
| efgval, efghval := []byte("efg"), []byte("efgh") |
| zeroval, typestr := []byte{}, "[]byte" |
| if x.Kind() == Array { |
| zeroval, typestr = []byte{0, 0, 0}, "[3]byte" |
| } |
| |
| if got, want := x.Bytes(), zeroval; !bytes.Equal(got, want) { |
| t.Errorf(`Bytes zero value got %v, want %v`, got, want) |
| } |
| // AssignBytes fills all bytes of the array if the array len is equal to the |
| // bytes len, and automatically assigns the len for lists. |
| x.AssignBytes(abcval) |
| if got, want := x.Bytes(), abcval; !bytes.Equal(got, want) { |
| t.Errorf(`Bytes CopyBytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("abc")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| abcval[1] = 'Z' // doesn't affect x |
| if got, want := x.Bytes(), []byte("abc"); !bytes.Equal(got, want) { |
| t.Errorf(`Bytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("abc")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| // AssignBytes panics for arrays if the array len is not equal to the bytes |
| // len, and automatically assigns the len for lists. |
| if x.Kind() == Array { |
| ExpectPanic(t, func() { x.AssignBytes(abval) }, "AssignBytes", "[3]byte AssignBytes(%v)", abval) |
| ExpectPanic(t, func() { x.AssignBytes(abcdval) }, "AssignBytes", "[3]byte AssignBytes(%v)", abcdval) |
| } else { |
| x.AssignBytes(abval) |
| if got, want := x.Bytes(), abval; !bytes.Equal(got, want) { |
| t.Errorf(`Bytes CopyBytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("ab")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| x.AssignBytes(abcdval) |
| if got, want := x.Bytes(), abcdval; !bytes.Equal(got, want) { |
| t.Errorf(`Bytes CopyBytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("abcd")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| x.AssignLen(3) |
| if got, want := x.Bytes(), []byte("abc"); !bytes.Equal(got, want) { |
| t.Errorf(`Bytes CopyBytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("abc")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| } |
| // CopyBytes ignores extra bytes, just like regular copy(). |
| x.CopyBytes(efghval) |
| if got, want := x.Bytes(), efgval; !bytes.Equal(got, want) { |
| t.Errorf(`Bytes CopyBytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("efg")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| // Bytes gives the underlying byteslice, which may be mutated. |
| x.Bytes()[1] = 'Z' |
| if got, want := x.Bytes(), []byte("eZg"); !bytes.Equal(got, want) { |
| t.Errorf(`Bytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("eZg")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| // Indexing also works, just like for any other list. |
| index := x.Index(1) |
| if got, want := index.Type(), ByteType; got != want { |
| t.Errorf(`Bytes index type got %v, want %v`, got, want) |
| } |
| if got, want := index.String(), fmt.Sprintf("byte(%d)", 'Z'); got != want { |
| t.Errorf(`Bytes index string got %v, want %v`, got, want) |
| } |
| if got, want := index.Uint(), uint64('Z'); got != want { |
| t.Errorf(`Bytes index Byte got %v, want %v`, got, want) |
| } |
| if got, want := index, ByteValue('Z'); !EqualValue(got, want) { |
| t.Errorf(`Bytes index value got %v, want %v`, got, want) |
| } |
| index.AssignUint(uint64('Y')) |
| if got, want := index.String(), fmt.Sprintf("byte(%d)", 'Y'); got != want { |
| t.Errorf(`Bytes index string got %v, want %v`, got, want) |
| } |
| if got, want := index.Uint(), uint64('Y'); got != want { |
| t.Errorf(`Bytes index Byte got %v, want %v`, got, want) |
| } |
| if got, want := index, ByteValue('Y'); !EqualValue(got, want) { |
| t.Errorf(`Bytes index value got %v, want %v`, got, want) |
| } |
| // Make sure the original bytes were mutated. |
| if got, want := x.Bytes(), []byte("eYg"); !bytes.Equal(got, want) { |
| t.Errorf(`Bytes got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), typestr+`("eYg")`; got != want { |
| t.Errorf(`Bytes string got %v, want %v`, got, want) |
| } |
| } |
| |
| func toStringSlice(a []*Value) []string { |
| ret := make([]string, len(a)) |
| for ix := 0; ix < len(a); ix++ { |
| ret[ix] = a[ix].String() |
| } |
| return ret |
| } |
| |
| // matchKeys returns true iff a and b hold the same values, in any order. |
| func matchKeys(a, b []*Value) bool { |
| ass := toStringSlice(a) |
| bss := toStringSlice(a) |
| sort.Strings(ass) |
| sort.Strings(bss) |
| return strings.Join(ass, "") == strings.Join(bss, "") |
| } |
| |
| // matchMapString returns true iff a and b are equivalent string representations |
| // of a map, dealing with entries in different orders. |
| func matchMapString(a, b string) bool { |
| atypeval := strings.SplitN(a, "{", 2) |
| btypeval := strings.SplitN(b, "{", 2) |
| if len(atypeval) != 2 || len(btypeval) != 2 || atypeval[0] != btypeval[0] { |
| return false |
| } |
| |
| a = atypeval[1] |
| b = btypeval[1] |
| |
| n := len(a) |
| if n != len(b) || n < 1 || a[n-1] != '}' || b[n-1] != '}' { |
| return false |
| } |
| asplit := strings.Split(a[:n-1], ", ") |
| bsplit := strings.Split(b[:n-1], ", ") |
| sort.Strings(asplit) |
| sort.Strings(bsplit) |
| return strings.Join(asplit, "") == strings.Join(bsplit, "") |
| } |
| |
| func assignSet(t *testing.T, x *Value) { |
| if x.Kind() == Set { |
| k1, k2, k3 := key1, key2, key3 |
| setstr1 := `set[struct{I int64;S string}]{{I: 1, S: "A"}, {I: 2, S: "B"}}` |
| setstr2 := `set[struct{I int64;S string}]{{I: 2, S: "B"}}` |
| if x.Type().Key() == StringType { |
| k1, k2, k3 = strA, strB, strC |
| setstr1, setstr2 = `set[string]{"A", "B"}`, `set[string]{"B"}` |
| } |
| |
| if got, want := x.Keys(), []*Value{}; !matchKeys(got, want) { |
| t.Errorf(`Set Keys got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k1), false; got != want { |
| t.Errorf(`Set ContainsKey k1 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k2), false; got != want { |
| t.Errorf(`Set ContainsKey k2 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k3), false; got != want { |
| t.Errorf(`Set ContainsKey k3 got %v, want %v`, got, want) |
| } |
| x.AssignSetKey(k1) |
| x.AssignSetKey(k2) |
| if got, want := x.Keys(), []*Value{k1, k2}; !matchKeys(got, want) { |
| t.Errorf(`Set Keys got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k1), true; got != want { |
| t.Errorf(`Set ContainsKey k1 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k2), true; got != want { |
| t.Errorf(`Set ContainsKey k2 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k3), false; got != want { |
| t.Errorf(`Set ContainsKey k3 got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), setstr1; !matchMapString(got, want) { |
| t.Errorf(`Set String got %v, want %v`, got, want) |
| } |
| x.DeleteSetKey(k1) |
| if got, want := x.Keys(), []*Value{k2}; !matchKeys(got, want) { |
| t.Errorf(`Set Keys got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k1), false; got != want { |
| t.Errorf(`Set ContainsKey k1 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k2), true; got != want { |
| t.Errorf(`Set ContainsKey k2 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k3), false; got != want { |
| t.Errorf(`Set ContainsKey k3 got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), setstr2; !matchMapString(got, want) { |
| t.Errorf(`Set String got %v, want %v`, got, want) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.AssignSetKey(nil) }) |
| ExpectMismatchedKind(t, func() { x.DeleteSetKey(nil) }) |
| if x.Kind() != Map { |
| // Keys and ContainsKey are allowed for Set and Map |
| ExpectMismatchedKind(t, func() { x.Keys() }) |
| ExpectMismatchedKind(t, func() { x.ContainsKey(nil) }) |
| } |
| if x.Kind() != Array && x.Kind() != List && x.Kind() != Map { |
| // Len is allowed for Array, List, Set and Map |
| ExpectMismatchedKind(t, func() { x.Len() }) |
| } |
| } |
| } |
| |
| func assignMap(t *testing.T, x *Value) { |
| if x.Kind() == Map { |
| k1, k2, k3 := key1, key2, key3 |
| v1, v2 := int1, int2 |
| mapstr1 := `map[struct{I int64;S string}]int64{{I: 1, S: "A"}: 1, {I: 2, S: "B"}: 2}` |
| mapstr2 := `map[struct{I int64;S string}]int64{{I: 2, S: "B"}: 2}` |
| if x.Type().Key() == StringType { |
| k1, k2, k3 = strA, strB, strC |
| mapstr1 = `map[string]int64{"A": 1, "B": 2}` |
| mapstr2 = `map[string]int64{"B": 2}` |
| } |
| |
| if got, want := x.Keys(), []*Value{}; !matchKeys(got, want) { |
| t.Errorf(`Map Keys got %v, want %v`, got, want) |
| } |
| if got := x.MapIndex(k1); got != nil { |
| t.Errorf(`Map MapIndex k1 got %v, want nil`, got) |
| } |
| if got := x.MapIndex(k2); got != nil { |
| t.Errorf(`Map MapIndex k2 got %v, want nil`, got) |
| } |
| if got := x.MapIndex(k3); got != nil { |
| t.Errorf(`Map MapIndex k3 got %v, want nil`, got) |
| } |
| if got, want := x.ContainsKey(k1), false; got != want { |
| t.Errorf(`Map ContainsKey k1 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k2), false; got != want { |
| t.Errorf(`Map ContainsKey k2 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k3), false; got != want { |
| t.Errorf(`Map ContainsKey k3 got %v, want %v`, got, want) |
| } |
| x.AssignMapIndex(k1, v1) |
| x.AssignMapIndex(k2, v2) |
| if got, want := x.Keys(), []*Value{k1, k2}; !matchKeys(got, want) { |
| t.Errorf(`Map Keys got %v, want %v`, got, want) |
| } |
| if got, want := x.MapIndex(k1), v1; !EqualValue(got, want) { |
| t.Errorf(`Map MapIndex k1 got %v, want %v`, got, want) |
| } |
| if got, want := x.MapIndex(k2), v2; !EqualValue(got, want) { |
| t.Errorf(`Map MapIndex k2 got %v, want %v`, got, want) |
| } |
| if got := x.MapIndex(k3); got != nil { |
| t.Errorf(`Map MapIndex k3 got %v, want nil`, got) |
| } |
| if got, want := x.ContainsKey(k1), true; got != want { |
| t.Errorf(`Map ContainsKey k1 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k2), true; got != want { |
| t.Errorf(`Map ContainsKey k2 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k3), false; got != want { |
| t.Errorf(`Map ContainsKey k3 got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), mapstr1; !matchMapString(got, want) { |
| t.Errorf(`Map string got %v, want %v`, got, want) |
| } |
| x.AssignMapIndex(k1, nil) |
| if got, want := x.Keys(), []*Value{k1, k2}; !matchKeys(got, want) { |
| t.Errorf(`Map Keys got %v, want %v`, got, want) |
| } |
| if got := x.MapIndex(k1); got != nil { |
| t.Errorf(`Map MapIndex k1 got %v, want nil`, got) |
| } |
| if got, want := x.MapIndex(k2), v2; !EqualValue(got, want) { |
| t.Errorf(`Map MapIndex k2 got %v, want %v`, got, want) |
| } |
| if got := x.MapIndex(k3); got != nil { |
| t.Errorf(`Map MapIndex k3 got %v, want nil`, got) |
| } |
| if got, want := x.ContainsKey(k1), false; got != want { |
| t.Errorf(`Map ContainsKey k1 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k2), true; got != want { |
| t.Errorf(`Map ContainsKey k2 got %v, want %v`, got, want) |
| } |
| if got, want := x.ContainsKey(k3), false; got != want { |
| t.Errorf(`Map ContainsKey k3 got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), mapstr2; !matchMapString(got, want) { |
| t.Errorf(`Map string got %v, want %v`, got, want) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.MapIndex(nil) }) |
| ExpectMismatchedKind(t, func() { x.AssignMapIndex(nil, nil) }) |
| if x.Kind() != Set { |
| // Keys and ContainsKey are allowed for Set and Map |
| ExpectMismatchedKind(t, func() { x.Keys() }) |
| ExpectMismatchedKind(t, func() { x.ContainsKey(nil) }) |
| } |
| if x.Kind() != Array && x.Kind() != List && x.Kind() != Set { |
| // Len is allowed for Array, List, Set and Map |
| ExpectMismatchedKind(t, func() { x.Len() }) |
| } |
| } |
| } |
| |
| func assignStruct(t *testing.T, x *Value) { |
| if x.Kind() == Struct { |
| x.StructField(0).AssignInt(1) |
| if x.IsZero() { |
| t.Errorf(`Struct assign index 0 is zero`) |
| } |
| if x.StructField(0) != x.StructFieldByName("A") { |
| t.Errorf(`struct{A int64;B string;C bool} does not have matching values at index 0 and field name A`) |
| } |
| if got, want := x.String(), `struct{A int64;B string;C bool}{A: 1, B: "", C: false}`; got != want { |
| t.Errorf(`Struct assign index 0 got %v, want %v`, got, want) |
| } |
| x.StructField(1).AssignString("a") |
| if x.IsZero() { |
| t.Errorf(`Struct assign index 1 is zero`) |
| } |
| if x.StructField(1) != x.StructFieldByName("B") { |
| t.Errorf(`struct{A int64;B string;C bool} does not have matching values at index 1 and field name B`) |
| } |
| if got, want := x.String(), `struct{A int64;B string;C bool}{A: 1, B: "a", C: false}`; got != want { |
| t.Errorf(`Struct assign index 1 got %v, want %v`, got, want) |
| } |
| if value := x.StructFieldByName("NotAStructField"); value != nil { |
| t.Errorf(`struct{A int64;B string;C bool} had value %v for field name NotAStructField`, value) |
| } |
| y := CopyValue(x) |
| y.StructField(2).AssignBool(false) |
| if !EqualValue(x, y) { |
| t.Errorf(`Struct !equal %v and %v`, x, y) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.StructField(0) }) |
| ExpectMismatchedKind(t, func() { x.StructFieldByName("A") }) |
| } |
| } |
| |
| func assignUnion(t *testing.T, x *Value) { |
| if x.Kind() == Union { |
| goti, gotv := x.UnionField() |
| if got, want := goti, 0; got != want { |
| t.Errorf(`Union zero value got index %v, want %v`, got, want) |
| } |
| if got, want := gotv, Int64Value(0); !EqualValue(got, want) { |
| t.Errorf(`Union zero value got value %v, want %v`, got, want) |
| } |
| x.AssignUnionField(1, strA) |
| goti, gotv = x.UnionField() |
| if got, want := goti, 1; got != want { |
| t.Errorf(`Union assign B value got index %v, want %v`, got, want) |
| } |
| if got, want := gotv, strA; !EqualValue(got, want) { |
| t.Errorf(`Union assign B value got value %v, want %v`, got, want) |
| } |
| if x.IsZero() { |
| t.Errorf(`Union assign B value is zero`) |
| } |
| if got, want := x.String(), `union{A int64;B string;C bool}{B: "A"}`; got != want { |
| t.Errorf(`Union assign B value got %v, want %v`, got, want) |
| } |
| } else { |
| ExpectMismatchedKind(t, func() { x.UnionField() }) |
| ExpectMismatchedKind(t, func() { x.AssignUnionField(0, nil) }) |
| } |
| } |
| |
| func assignAny(t *testing.T, x *Value) { |
| if x.Kind() == Any { |
| if got := x.Elem(); got != nil { |
| t.Errorf(`Any zero value got %v, want nil`, got) |
| } |
| x.Assign(int1) |
| if got, want := x.Elem(), int1; !EqualValue(got, want) { |
| t.Errorf(`Any assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), "any(int64(1))"; got != want { |
| t.Errorf(`Any assign string got %v, want %v`, got, want) |
| } |
| x.Assign(strA) |
| if got, want := x.Elem(), strA; !EqualValue(got, want) { |
| t.Errorf(`Any assign value got %v, want %v`, got, want) |
| } |
| if got, want := x.String(), `any("A")`; got != want { |
| t.Errorf(`Any assign string got %v, want %v`, got, want) |
| } |
| } else if x.Kind() != Optional { |
| ExpectMismatchedKind(t, func() { x.Elem() }) |
| } |
| } |