package cty import ( "fmt" "reflect" "testing" ) func TestValueEquals(t *testing.T) { capsuleA := CapsuleVal(capsuleTestType1, &capsuleTestType1Native{"capsuleA"}) capsuleB := CapsuleVal(capsuleTestType1, &capsuleTestType1Native{"capsuleB"}) capsuleC := CapsuleVal(capsuleTestType2, &capsuleTestType2Native{"capsuleC"}) tests := []struct { LHS Value RHS Value Expected Value }{ // Booleans { BoolVal(true), BoolVal(true), BoolVal(true), }, { BoolVal(false), BoolVal(false), BoolVal(true), }, { BoolVal(true), BoolVal(false), BoolVal(false), }, // Numbers { NumberIntVal(1), NumberIntVal(2), BoolVal(false), }, { NumberIntVal(2), NumberIntVal(2), BoolVal(true), }, // Strings { StringVal(""), StringVal(""), BoolVal(true), }, { StringVal("hello"), StringVal("hello"), BoolVal(true), }, { StringVal("hello"), StringVal("world"), BoolVal(false), }, { StringVal("0"), StringVal(""), BoolVal(false), }, { StringVal("años"), StringVal("años"), BoolVal(true), }, { // Combining marks are normalized by StringVal StringVal("años"), // (precomposed tilde-n) StringVal("años"), // (combining tilde followed by bare n) BoolVal(true), }, { // tilde-n does not normalize with bare n StringVal("años"), StringVal("anos"), BoolVal(false), }, // Objects { ObjectVal(map[string]Value{}), ObjectVal(map[string]Value{}), BoolVal(true), }, { ObjectVal(map[string]Value{ "num": NumberIntVal(1), }), ObjectVal(map[string]Value{ "num": NumberIntVal(1), }), BoolVal(true), }, { ObjectVal(map[string]Value{ "num": NumberIntVal(1), }), ObjectVal(map[string]Value{}), BoolVal(false), }, { ObjectVal(map[string]Value{ "num": NumberIntVal(1), "flag": BoolVal(true), }), ObjectVal(map[string]Value{ "num": NumberIntVal(1), "flag": BoolVal(true), }), BoolVal(true), }, { ObjectVal(map[string]Value{ "num": NumberIntVal(1), }), ObjectVal(map[string]Value{ "num": NumberIntVal(2), }), BoolVal(false), }, { ObjectVal(map[string]Value{ "num": NumberIntVal(1), }), ObjectVal(map[string]Value{ "othernum": NumberIntVal(1), }), BoolVal(false), }, { ObjectVal(map[string]Value{ "num": NumberIntVal(1), "flag": BoolVal(true), }), ObjectVal(map[string]Value{ "num": NumberIntVal(1), }), BoolVal(false), }, { ObjectVal(map[string]Value{ "num": NumberIntVal(1), "flag": BoolVal(true), }), ObjectVal(map[string]Value{ "num": NumberIntVal(1), "flag": BoolVal(false), }), BoolVal(false), }, // Tuples { EmptyTupleVal, EmptyTupleVal, BoolVal(true), }, { TupleVal([]Value{NumberIntVal(1)}), TupleVal([]Value{NumberIntVal(1)}), BoolVal(true), }, { TupleVal([]Value{NumberIntVal(1)}), TupleVal([]Value{NumberIntVal(2)}), BoolVal(false), }, { TupleVal([]Value{StringVal("hi")}), TupleVal([]Value{NumberIntVal(1)}), BoolVal(false), }, { TupleVal([]Value{NumberIntVal(1)}), TupleVal([]Value{NumberIntVal(1), NumberIntVal(2)}), BoolVal(false), }, { TupleVal([]Value{NumberIntVal(1), NumberIntVal(2)}), TupleVal([]Value{NumberIntVal(1)}), BoolVal(false), }, { TupleVal([]Value{NumberIntVal(1), NumberIntVal(2)}), TupleVal([]Value{NumberIntVal(1), NumberIntVal(2)}), BoolVal(true), }, { TupleVal([]Value{UnknownVal(Number)}), TupleVal([]Value{NumberIntVal(1)}), UnknownVal(Bool), }, { TupleVal([]Value{UnknownVal(Number)}), TupleVal([]Value{UnknownVal(Number)}), UnknownVal(Bool), }, { TupleVal([]Value{NumberIntVal(1)}), TupleVal([]Value{UnknownVal(Number)}), UnknownVal(Bool), }, { TupleVal([]Value{NumberIntVal(1)}), TupleVal([]Value{DynamicVal}), UnknownVal(Bool), }, { TupleVal([]Value{DynamicVal}), TupleVal([]Value{NumberIntVal(1)}), UnknownVal(Bool), }, { TupleVal([]Value{NumberIntVal(1)}), UnknownVal(Tuple([]Type{Number})), UnknownVal(Bool), }, { UnknownVal(Tuple([]Type{Number})), TupleVal([]Value{NumberIntVal(1)}), UnknownVal(Bool), }, { DynamicVal, TupleVal([]Value{NumberIntVal(1)}), UnknownVal(Bool), }, { TupleVal([]Value{NumberIntVal(1)}), DynamicVal, UnknownVal(Bool), }, // Lists { ListValEmpty(Number), ListValEmpty(Number), BoolVal(true), }, { ListValEmpty(Number), ListValEmpty(Bool), BoolVal(false), }, { ListVal([]Value{ NumberIntVal(1), }), ListVal([]Value{ NumberIntVal(1), }), BoolVal(true), }, { ListVal([]Value{ NumberIntVal(1), }), ListValEmpty(String), BoolVal(false), }, { ListVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), ListVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), BoolVal(true), }, { ListVal([]Value{ NumberIntVal(1), }), ListVal([]Value{ NumberIntVal(2), }), BoolVal(false), }, { ListVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), ListVal([]Value{ NumberIntVal(1), }), BoolVal(false), }, { ListVal([]Value{ NumberIntVal(1), }), ListVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), BoolVal(false), }, // Maps { MapValEmpty(Number), MapValEmpty(Number), BoolVal(true), }, { MapValEmpty(Number), MapValEmpty(Bool), BoolVal(false), }, { MapVal(map[string]Value{ "num": NumberIntVal(1), }), MapVal(map[string]Value{ "num": NumberIntVal(1), }), BoolVal(true), }, { MapVal(map[string]Value{ "num": NumberIntVal(1), }), MapValEmpty(String), BoolVal(false), }, { MapVal(map[string]Value{ "num1": NumberIntVal(1), "num2": NumberIntVal(2), }), MapVal(map[string]Value{ "num1": NumberIntVal(1), "num2": NumberIntVal(2), }), BoolVal(true), }, { MapVal(map[string]Value{ "num": NumberIntVal(1), }), MapVal(map[string]Value{ "num": NumberIntVal(2), }), BoolVal(false), }, { MapVal(map[string]Value{ "num": NumberIntVal(1), }), MapVal(map[string]Value{ "othernum": NumberIntVal(1), }), BoolVal(false), }, { MapVal(map[string]Value{ "num1": NumberIntVal(1), "num2": NumberIntVal(2), }), MapVal(map[string]Value{ "num1": NumberIntVal(1), }), BoolVal(false), }, { MapVal(map[string]Value{ "num1": NumberIntVal(1), }), MapVal(map[string]Value{ "num1": NumberIntVal(1), "num2": NumberIntVal(2), }), BoolVal(false), }, { MapVal(map[string]Value{ "num1": NumberIntVal(1), "num2": NumberIntVal(2), }), MapVal(map[string]Value{ "num1": NumberIntVal(1), "num2": NumberIntVal(3), }), BoolVal(false), }, // Sets { SetValEmpty(Number), SetValEmpty(Number), BoolVal(true), }, { SetValEmpty(Number), SetValEmpty(Bool), BoolVal(false), }, { SetVal([]Value{ NumberIntVal(1), }), SetVal([]Value{ NumberIntVal(1), }), BoolVal(true), }, { SetVal([]Value{ NumberIntVal(1), }), SetValEmpty(String), BoolVal(false), }, { SetVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), SetVal([]Value{ NumberIntVal(2), NumberIntVal(1), }), BoolVal(true), }, { SetVal([]Value{ NumberIntVal(1), }), SetVal([]Value{ NumberIntVal(2), }), BoolVal(false), }, { SetVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), SetVal([]Value{ NumberIntVal(1), }), BoolVal(false), }, { SetVal([]Value{ NumberIntVal(1), }), SetVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), BoolVal(false), }, // Capsules { capsuleA, capsuleA, True, }, { capsuleA, capsuleB, False, }, { capsuleA, capsuleC, False, }, { capsuleA, UnknownVal(capsuleTestType1), // same type UnknownVal(Bool), }, { capsuleA, UnknownVal(capsuleTestType2), // different type False, }, // Unknowns and Dynamics { NumberIntVal(2), UnknownVal(Number), UnknownVal(Bool), }, { NumberIntVal(1), DynamicVal, UnknownVal(Bool), }, { DynamicVal, BoolVal(true), UnknownVal(Bool), }, { DynamicVal, DynamicVal, UnknownVal(Bool), }, { ListVal([]Value{ StringVal("hi"), DynamicVal, }), ListVal([]Value{ StringVal("hi"), DynamicVal, }), UnknownVal(Bool), }, { ListVal([]Value{ StringVal("hi"), UnknownVal(String), }), ListVal([]Value{ StringVal("hi"), UnknownVal(String), }), UnknownVal(Bool), }, { MapVal(map[string]Value{ "static": StringVal("hi"), "dynamic": DynamicVal, }), MapVal(map[string]Value{ "static": StringVal("hi"), "dynamic": DynamicVal, }), UnknownVal(Bool), }, { MapVal(map[string]Value{ "static": StringVal("hi"), "dynamic": UnknownVal(String), }), MapVal(map[string]Value{ "static": StringVal("hi"), "dynamic": UnknownVal(String), }), UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Equals(%#v)", test.LHS, test.RHS), func(t *testing.T) { got := test.LHS.Equals(test.RHS) if !got.RawEquals(test.Expected) { t.Fatalf("Equals returned %#v; want %#v", got, test.Expected) } }) } } func TestValueAdd(t *testing.T) { tests := []struct { LHS Value RHS Value Expected Value }{ { NumberIntVal(1), NumberIntVal(2), NumberIntVal(3), }, { NumberIntVal(1), NumberIntVal(-2), NumberIntVal(-1), }, { NumberIntVal(1), NumberFloatVal(0.5), NumberFloatVal(1.5), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Number), }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Number), }, { NumberIntVal(1), DynamicVal, UnknownVal(Number), }, { DynamicVal, DynamicVal, UnknownVal(Number), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Add(%#v)", test.LHS, test.RHS), func(t *testing.T) { got := test.LHS.Add(test.RHS) if !got.RawEquals(test.Expected) { t.Fatalf("Add returned %#v; want %#v", got, test.Expected) } }) } } func TestValueSubtract(t *testing.T) { tests := []struct { LHS Value RHS Value Expected Value }{ { NumberIntVal(1), NumberIntVal(2), NumberIntVal(-1), }, { NumberIntVal(1), NumberIntVal(-2), NumberIntVal(3), }, { NumberIntVal(1), NumberFloatVal(0.5), NumberFloatVal(0.5), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Number), }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Number), }, { NumberIntVal(1), DynamicVal, UnknownVal(Number), }, { DynamicVal, DynamicVal, UnknownVal(Number), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Subtract(%#v)", test.LHS, test.RHS), func(t *testing.T) { got := test.LHS.Subtract(test.RHS) if !got.RawEquals(test.Expected) { t.Fatalf("Subtract returned %#v; want %#v", got, test.Expected) } }) } } func TestValueNegate(t *testing.T) { tests := []struct { Receiver Value Expected Value }{ { NumberIntVal(1), NumberIntVal(-1), }, { NumberFloatVal(0.5), NumberFloatVal(-0.5), }, { UnknownVal(Number), UnknownVal(Number), }, { DynamicVal, UnknownVal(Number), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Negate()", test.Receiver), func(t *testing.T) { got := test.Receiver.Negate() if !got.RawEquals(test.Expected) { t.Fatalf("Negate returned %#v; want %#v", got, test.Expected) } }) } } func TestValueMultiply(t *testing.T) { tests := []struct { LHS Value RHS Value Expected Value }{ { NumberIntVal(4), NumberIntVal(2), NumberIntVal(8), }, { NumberIntVal(1), NumberIntVal(-2), NumberIntVal(-2), }, { NumberIntVal(5), NumberFloatVal(0.5), NumberFloatVal(2.5), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Number), }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Number), }, { NumberIntVal(1), DynamicVal, UnknownVal(Number), }, { DynamicVal, DynamicVal, UnknownVal(Number), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Multiply(%#v)", test.LHS, test.RHS), func(t *testing.T) { got := test.LHS.Multiply(test.RHS) if !got.RawEquals(test.Expected) { t.Fatalf("Multiply returned %#v; want %#v", got, test.Expected) } }) } } func TestValueDivide(t *testing.T) { tests := []struct { LHS Value RHS Value Expected Value }{ { NumberIntVal(10), NumberIntVal(2), NumberIntVal(5), }, { NumberIntVal(1), NumberIntVal(-2), NumberFloatVal(-0.5), }, { NumberIntVal(5), NumberFloatVal(0.5), NumberIntVal(10), }, { NumberIntVal(5), NumberIntVal(0), PositiveInfinity, }, { NumberIntVal(-5), NumberIntVal(0), NegativeInfinity, }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Number), }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Number), }, { NumberIntVal(1), DynamicVal, UnknownVal(Number), }, { DynamicVal, DynamicVal, UnknownVal(Number), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Divide(%#v)", test.LHS, test.RHS), func(t *testing.T) { got := test.LHS.Divide(test.RHS) if !got.RawEquals(test.Expected) { t.Fatalf("Divide returned %#v; want %#v", got, test.Expected) } }) } } func TestValueModulo(t *testing.T) { tests := []struct { LHS Value RHS Value Expected Value }{ { NumberIntVal(10), NumberIntVal(2), NumberIntVal(0), }, { NumberIntVal(-10), NumberIntVal(2), NumberIntVal(0), }, { NumberIntVal(11), NumberIntVal(2), NumberIntVal(1), }, { NumberIntVal(-11), NumberIntVal(2), NumberIntVal(-1), }, { NumberIntVal(1), NumberIntVal(-2), NumberFloatVal(1), }, { NumberIntVal(5), NumberFloatVal(0.5), NumberIntVal(0), }, { NumberIntVal(5), NumberFloatVal(1.5), NumberFloatVal(0.5), }, { NumberIntVal(5), NumberIntVal(0), NumberIntVal(5), }, { NumberIntVal(-5), NumberIntVal(0), NumberIntVal(-5), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Number), }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Number), }, { NumberIntVal(1), DynamicVal, UnknownVal(Number), }, { DynamicVal, DynamicVal, UnknownVal(Number), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Modulo(%#v)", test.LHS, test.RHS), func(t *testing.T) { got := test.LHS.Modulo(test.RHS) if !got.RawEquals(test.Expected) { t.Fatalf("Modulo returned %#v; want %#v", got, test.Expected) } }) } } func TestValueAbsolute(t *testing.T) { tests := []struct { Receiver Value Expected Value }{ { NumberIntVal(1), NumberIntVal(1), }, { NumberIntVal(-1), NumberIntVal(1), }, { NumberFloatVal(0.5), NumberFloatVal(0.5), }, { NumberFloatVal(-0.5), NumberFloatVal(0.5), }, { PositiveInfinity, PositiveInfinity, }, { NegativeInfinity, PositiveInfinity, }, { UnknownVal(Number), UnknownVal(Number), }, { DynamicVal, UnknownVal(Number), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Absolute()", test.Receiver), func(t *testing.T) { got := test.Receiver.Absolute() if !got.RawEquals(test.Expected) { t.Fatalf("Absolute returned %#v; want %#v", got, test.Expected) } }) } } func TestValueGetAttr(t *testing.T) { tests := []struct { Object Value AttrName string Expected Value }{ { ObjectVal(map[string]Value{ "greeting": StringVal("hello"), }), "greeting", StringVal("hello"), }, { UnknownVal(Object(map[string]Type{ "greeting": String, })), "greeting", UnknownVal(String), }, { DynamicVal, "hello", DynamicVal, }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.GetAttr(%q)", test.Object, test.AttrName), func(t *testing.T) { got := test.Object.GetAttr(test.AttrName) if !got.RawEquals(test.Expected) { t.Fatalf("GetAttr returned %#v; want %#v", got, test.Expected) } }) } } func TestValueIndex(t *testing.T) { tests := []struct { Collection Value Key Value Expected Value }{ { ListVal([]Value{StringVal("hello")}), NumberIntVal(0), StringVal("hello"), }, { ListVal([]Value{StringVal("hello"), StringVal("world")}), NumberIntVal(1), StringVal("world"), }, { ListVal([]Value{StringVal("hello")}), UnknownVal(Number), UnknownVal(String), }, { ListVal([]Value{StringVal("hello")}), DynamicVal, UnknownVal(String), }, { UnknownVal(List(String)), NumberIntVal(0), UnknownVal(String), }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), StringVal("greeting"), StringVal("hello"), }, { MapVal(map[string]Value{"greeting": True}), UnknownVal(String), UnknownVal(Bool), }, { MapVal(map[string]Value{"greeting": True}), DynamicVal, UnknownVal(Bool), }, { UnknownVal(Map(String)), StringVal("greeting"), UnknownVal(String), }, { DynamicVal, StringVal("hello"), DynamicVal, }, { DynamicVal, NumberIntVal(0), DynamicVal, }, { TupleVal([]Value{StringVal("hello")}), NumberIntVal(0), StringVal("hello"), }, { TupleVal([]Value{StringVal("hello"), NumberIntVal(5)}), NumberIntVal(0), StringVal("hello"), }, { TupleVal([]Value{StringVal("hello"), NumberIntVal(5)}), NumberIntVal(1), NumberIntVal(5), }, { TupleVal([]Value{StringVal("hello"), DynamicVal}), NumberIntVal(0), StringVal("hello"), }, { TupleVal([]Value{StringVal("hello"), DynamicVal}), NumberIntVal(1), DynamicVal, }, { TupleVal([]Value{StringVal("hello"), UnknownVal(Number)}), NumberIntVal(0), StringVal("hello"), }, { TupleVal([]Value{StringVal("hello"), UnknownVal(Number)}), NumberIntVal(1), UnknownVal(Number), }, { TupleVal([]Value{StringVal("hello"), UnknownVal(Number)}), UnknownVal(Number), DynamicVal, }, { UnknownVal(Tuple([]Type{String})), NumberIntVal(0), UnknownVal(String), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Index(%q)", test.Collection, test.Key), func(t *testing.T) { got := test.Collection.Index(test.Key) if !got.RawEquals(test.Expected) { t.Fatalf("Index returned %#v; want %#v", got, test.Expected) } }) } } func TestValueHasIndex(t *testing.T) { tests := []struct { Collection Value Key Value Expected Value }{ { ListVal([]Value{StringVal("hello")}), NumberIntVal(0), True, }, { ListVal([]Value{StringVal("hello"), StringVal("world")}), NumberIntVal(1), True, }, { ListVal([]Value{StringVal("hello"), StringVal("world")}), NumberIntVal(2), False, }, { ListVal([]Value{StringVal("hello"), StringVal("world")}), NumberIntVal(-1), False, }, { ListVal([]Value{StringVal("hello"), StringVal("world")}), NumberFloatVal(0.5), False, }, { ListVal([]Value{StringVal("hello"), StringVal("world")}), StringVal("greeting"), False, }, { ListVal([]Value{StringVal("hello"), StringVal("world")}), True, False, }, { ListVal([]Value{StringVal("hello")}), UnknownVal(Number), UnknownVal(Bool), }, { ListVal([]Value{StringVal("hello")}), DynamicVal, UnknownVal(Bool), }, { UnknownVal(List(String)), NumberIntVal(0), UnknownVal(Bool), }, { UnknownVal(List(String)), StringVal("hello"), False, }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), StringVal("greeting"), True, }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), StringVal("grouting"), False, }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), StringVal(""), False, }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), Zero, False, }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), True, False, }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), UnknownVal(String), UnknownVal(Bool), }, { MapVal(map[string]Value{"greeting": StringVal("hello")}), DynamicVal, UnknownVal(Bool), }, { UnknownVal(Map(String)), StringVal("hello"), UnknownVal(Bool), }, { UnknownVal(Map(String)), NumberIntVal(0), False, }, { TupleVal([]Value{StringVal("hello")}), NumberIntVal(0), True, }, { TupleVal([]Value{StringVal("hello"), StringVal("world")}), NumberIntVal(1), True, }, { TupleVal([]Value{StringVal("hello"), StringVal("world")}), NumberIntVal(2), False, }, { TupleVal([]Value{StringVal("hello"), StringVal("world")}), NumberIntVal(-1), False, }, { TupleVal([]Value{StringVal("hello"), StringVal("world")}), NumberFloatVal(0.5), False, }, { TupleVal([]Value{StringVal("hello"), StringVal("world")}), StringVal("greeting"), False, }, { TupleVal([]Value{StringVal("hello"), StringVal("world")}), True, False, }, { TupleVal([]Value{StringVal("hello")}), UnknownVal(Number), UnknownVal(Bool), }, { UnknownVal(Tuple([]Type{String})), NumberIntVal(0), True, }, { TupleVal([]Value{StringVal("hello")}), DynamicVal, UnknownVal(Bool), }, { DynamicVal, StringVal("hello"), UnknownVal(Bool), }, { DynamicVal, NumberIntVal(0), UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.HasIndex(%q)", test.Collection, test.Key), func(t *testing.T) { got := test.Collection.HasIndex(test.Key) if !got.RawEquals(test.Expected) { t.Fatalf("HasIndex returned %#v; want %#v", got, test.Expected) } }) } } func TestValueForEachElement(t *testing.T) { type call struct { Key Value Element Value } tests := []struct { Receiver Value Expected []call Stopped bool }{ { ListValEmpty(String), []call{}, false, }, { ListVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), []call{ {NumberIntVal(0), NumberIntVal(1)}, {NumberIntVal(1), NumberIntVal(2)}, }, false, }, { ListVal([]Value{ StringVal("hey"), StringVal("stop"), StringVal("hey"), }), []call{ {NumberIntVal(0), StringVal("hey")}, {NumberIntVal(1), StringVal("stop")}, }, true, }, { SetValEmpty(String), []call{}, false, }, { SetVal([]Value{ NumberIntVal(1), NumberIntVal(2), }), []call{ // Ordering is arbitrary but consistent, so future changes // to the set implementation may reorder these. {NumberIntVal(2), NumberIntVal(2)}, {NumberIntVal(1), NumberIntVal(1)}, }, false, }, { SetVal([]Value{ StringVal("hi"), StringVal("stop"), StringVal("hey"), }), []call{ // Ordering is arbitrary but consistent, so future changes // to the set implementation may reorder these. {StringVal("hi"), StringVal("hi")}, {StringVal("stop"), StringVal("stop")}, }, true, }, { MapVal(map[string]Value{ "second": NumberIntVal(2), "first": NumberIntVal(1), }), []call{ {StringVal("first"), NumberIntVal(1)}, {StringVal("second"), NumberIntVal(2)}, }, false, }, { MapVal(map[string]Value{ "item2": StringVal("value2"), "item1": StringVal("stop"), "item0": StringVal("value0"), }), []call{ {StringVal("item0"), StringVal("value0")}, {StringVal("item1"), StringVal("stop")}, }, true, }, { EmptyTupleVal, []call{}, false, }, { TupleVal([]Value{ StringVal("hello"), NumberIntVal(2), }), []call{ {NumberIntVal(0), StringVal("hello")}, {NumberIntVal(1), NumberIntVal(2)}, }, false, }, { TupleVal([]Value{ NumberIntVal(5), StringVal("stop"), True, }), []call{ {NumberIntVal(0), NumberIntVal(5)}, {NumberIntVal(1), StringVal("stop")}, }, true, }, { EmptyObjectVal, []call{}, false, }, { ObjectVal(map[string]Value{ "bool": True, "string": StringVal("hello"), }), []call{ {StringVal("bool"), True}, {StringVal("string"), StringVal("hello")}, }, false, }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.ForEachElement()", test.Receiver), func(t *testing.T) { calls := make([]call, 0) stopped := test.Receiver.ForEachElement( func(key Value, elem Value) (stop bool) { calls = append(calls, call{ Key: key, Element: elem, }) if elem.v == "stop" { stop = true } return }, ) if !reflect.DeepEqual(calls, test.Expected) { t.Errorf( "wrong calls from ForEachElement\ngot: %#v\nwant: %#v", calls, test.Expected, ) } if stopped != test.Stopped { t.Errorf( "ForEachElement returned %#v; want %#v", stopped, test.Stopped, ) } }) } } func TestValueNot(t *testing.T) { tests := []struct { Receiver Value Expected Value }{ { True, False, }, { False, True, }, { UnknownVal(Bool), UnknownVal(Bool), }, { DynamicVal, UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Not()", test.Receiver), func(t *testing.T) { got := test.Receiver.Not() if !got.RawEquals(test.Expected) { t.Fatalf("Not returned %#v; want %#v", got, test.Expected) } }) } } func TestValueAnd(t *testing.T) { tests := []struct { Receiver Value Other Value Expected Value }{ { False, False, False, }, { False, True, False, }, { True, False, False, }, { True, True, True, }, { UnknownVal(Bool), UnknownVal(Bool), UnknownVal(Bool), }, { True, UnknownVal(Bool), UnknownVal(Bool), }, { UnknownVal(Bool), True, UnknownVal(Bool), }, { DynamicVal, DynamicVal, UnknownVal(Bool), }, { True, DynamicVal, UnknownVal(Bool), }, { DynamicVal, True, UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.And(%#v)", test.Receiver, test.Other), func(t *testing.T) { got := test.Receiver.And(test.Other) if !got.RawEquals(test.Expected) { t.Fatalf("And returned %#v; want %#v", got, test.Expected) } }) } } func TestValueOr(t *testing.T) { tests := []struct { Receiver Value Other Value Expected Value }{ { False, False, False, }, { False, True, True, }, { True, False, True, }, { True, True, True, }, { UnknownVal(Bool), UnknownVal(Bool), UnknownVal(Bool), }, { True, UnknownVal(Bool), UnknownVal(Bool), }, { UnknownVal(Bool), True, UnknownVal(Bool), }, { DynamicVal, DynamicVal, UnknownVal(Bool), }, { True, DynamicVal, UnknownVal(Bool), }, { DynamicVal, True, UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.Or(%#v)", test.Receiver, test.Other), func(t *testing.T) { got := test.Receiver.Or(test.Other) if !got.RawEquals(test.Expected) { t.Fatalf("Or returned %#v; want %#v", got, test.Expected) } }) } } func TestLessThan(t *testing.T) { tests := []struct { Receiver Value Other Value Expected Value }{ { NumberIntVal(0), NumberIntVal(1), True, }, { NumberIntVal(1), NumberIntVal(0), False, }, { NumberIntVal(0), NumberIntVal(0), False, }, { NumberFloatVal(0.1), NumberFloatVal(0.2), True, }, { NumberFloatVal(0.2), NumberFloatVal(0.1), False, }, { NumberIntVal(0), NumberFloatVal(0.2), True, }, { NumberFloatVal(0.2), NumberIntVal(0), False, }, { NumberFloatVal(0.2), NumberFloatVal(0.2), False, }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Bool), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Bool), }, { UnknownVal(Number), NumberIntVal(1), UnknownVal(Bool), }, { DynamicVal, DynamicVal, UnknownVal(Bool), }, { NumberIntVal(1), DynamicVal, UnknownVal(Bool), }, { DynamicVal, NumberIntVal(1), UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.LessThan(%#v)", test.Receiver, test.Other), func(t *testing.T) { got := test.Receiver.LessThan(test.Other) if !got.RawEquals(test.Expected) { t.Fatalf("LessThan returned %#v; want %#v", got, test.Expected) } }) } } func TestGreaterThan(t *testing.T) { tests := []struct { Receiver Value Other Value Expected Value }{ { NumberIntVal(0), NumberIntVal(1), False, }, { NumberIntVal(1), NumberIntVal(0), True, }, { NumberIntVal(0), NumberIntVal(0), False, }, { NumberFloatVal(0.1), NumberFloatVal(0.2), False, }, { NumberFloatVal(0.2), NumberFloatVal(0.1), True, }, { NumberIntVal(0), NumberFloatVal(0.2), False, }, { NumberFloatVal(0.2), NumberIntVal(0), True, }, { NumberFloatVal(0.2), NumberFloatVal(0.2), False, }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Bool), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Bool), }, { UnknownVal(Number), NumberIntVal(1), UnknownVal(Bool), }, { DynamicVal, DynamicVal, UnknownVal(Bool), }, { NumberIntVal(1), DynamicVal, UnknownVal(Bool), }, { DynamicVal, NumberIntVal(1), UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.GreaterThan(%#v)", test.Receiver, test.Other), func(t *testing.T) { got := test.Receiver.GreaterThan(test.Other) if !got.RawEquals(test.Expected) { t.Fatalf("GreaterThan returned %#v; want %#v", got, test.Expected) } }) } } func TestLessThanOrEqualTo(t *testing.T) { tests := []struct { Receiver Value Other Value Expected Value }{ { NumberIntVal(0), NumberIntVal(1), True, }, { NumberIntVal(1), NumberIntVal(0), False, }, { NumberIntVal(0), NumberIntVal(0), True, }, { NumberFloatVal(0.1), NumberFloatVal(0.2), True, }, { NumberFloatVal(0.2), NumberFloatVal(0.1), False, }, { NumberIntVal(0), NumberFloatVal(0.2), True, }, { NumberFloatVal(0.2), NumberIntVal(0), False, }, { NumberFloatVal(0.2), NumberFloatVal(0.2), True, }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Bool), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Bool), }, { UnknownVal(Number), NumberIntVal(1), UnknownVal(Bool), }, { DynamicVal, DynamicVal, UnknownVal(Bool), }, { NumberIntVal(1), DynamicVal, UnknownVal(Bool), }, { DynamicVal, NumberIntVal(1), UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.LessThanOrEqualTo(%#v)", test.Receiver, test.Other), func(t *testing.T) { got := test.Receiver.LessThanOrEqualTo(test.Other) if !got.RawEquals(test.Expected) { t.Fatalf("LessThanOrEqualTo returned %#v; want %#v", got, test.Expected) } }) } } func TestGreaterThanOrEqualTo(t *testing.T) { tests := []struct { Receiver Value Other Value Expected Value }{ { NumberIntVal(0), NumberIntVal(1), False, }, { NumberIntVal(1), NumberIntVal(0), True, }, { NumberIntVal(0), NumberIntVal(0), True, }, { NumberFloatVal(0.1), NumberFloatVal(0.2), False, }, { NumberFloatVal(0.2), NumberFloatVal(0.1), True, }, { NumberIntVal(0), NumberFloatVal(0.2), False, }, { NumberFloatVal(0.2), NumberIntVal(0), True, }, { NumberFloatVal(0.2), NumberFloatVal(0.2), True, }, { UnknownVal(Number), UnknownVal(Number), UnknownVal(Bool), }, { NumberIntVal(1), UnknownVal(Number), UnknownVal(Bool), }, { UnknownVal(Number), NumberIntVal(1), UnknownVal(Bool), }, { DynamicVal, DynamicVal, UnknownVal(Bool), }, { NumberIntVal(1), DynamicVal, UnknownVal(Bool), }, { DynamicVal, NumberIntVal(1), UnknownVal(Bool), }, } for _, test := range tests { t.Run(fmt.Sprintf("%#v.GreaterThanOrEqualTo(%#v)", test.Receiver, test.Other), func(t *testing.T) { got := test.Receiver.GreaterThanOrEqualTo(test.Other) if !got.RawEquals(test.Expected) { t.Fatalf("GreaterThanOrEqualTo returned %#v; want %#v", got, test.Expected) } }) } }