github.com/rajeev159/opa@v0.45.0/topdown/input_test.go (about) 1 // Copyright 2016 The OPA Authors. All rights reserved. 2 // Use of this source code is governed by an Apache2 3 // license that can be found in the LICENSE file. 4 5 package topdown 6 7 import ( 8 "testing" 9 10 "github.com/open-policy-agent/opa/ast" 11 ) 12 13 func TestMergeTermWithValues(t *testing.T) { 14 15 tests := []struct { 16 note string 17 exist string 18 input [][2]string 19 expected interface{} 20 }{ 21 { 22 note: "var", 23 input: [][2]string{{`input.hello`, `"world"`}}, 24 expected: `{"hello": "world"}`, 25 }, 26 { 27 note: "multiple vars", 28 input: [][2]string{{`input.a`, `"a"`}, {`input.b`, `"b"`}}, 29 expected: `{"a": "a", "b": "b"}`, 30 }, 31 { 32 note: "multiple overlapping vars", 33 input: [][2]string{{`input.a.b.c`, `"c"`}, {`input.a.b.d`, `"d"`}, {`input.x.y`, `[]`}}, 34 expected: `{"a": {"b": {"c": "c", "d": "d"}}, "x": {"y": []}}`, 35 }, 36 { 37 note: "ref value", 38 input: [][2]string{{"input.foo.bar", "data.com.example.widgets[i]"}}, 39 expected: `{"foo": {"bar": data.com.example.widgets[i]}}`, 40 }, 41 { 42 note: "non-object", 43 input: [][2]string{{"input", "[1,2,3]"}}, 44 expected: "[1,2,3]", 45 }, 46 { 47 note: "conflicting value", 48 input: [][2]string{{"input", "[1,2,3]"}, {"input.a", "true"}}, 49 expected: `{"a": true}`, 50 }, 51 { 52 note: "conflicting value, nested trailing terms", 53 input: [][2]string{{"input", "[1,2,3]"}, {"input.a.b", "true"}}, 54 expected: `{"a": {"b": true}}`, 55 }, 56 { 57 note: "conflicting merge", 58 input: [][2]string{{`input.a.b`, `"c"`}, {`input.a.b.d`, `"d"`}}, 59 expected: `{"a": {"b": {"d": "d"}}}`, 60 }, 61 { 62 note: "ordered roots", 63 input: [][2]string{{"input", `"a"`}, {"input", `"b"`}}, 64 expected: `"b"`, 65 }, 66 { 67 note: "bad import path", 68 input: [][2]string{{`input.a[1]`, `1`}}, 69 expected: errBadPath, 70 }, 71 { 72 note: "existing merge", 73 exist: `{"foo": {"bar": 1}}`, 74 input: [][2]string{{"input.foo.baz", "2"}}, 75 expected: `{"foo": {"bar": 1, "baz": 2}}`, 76 }, 77 { 78 note: "existing overwrite", 79 exist: `{"a": {"b": 1, "c": 2}}`, 80 input: [][2]string{{"input.a", `{"d": 3}`}}, 81 expected: `{"a": {"d": 3}}`, 82 }, 83 } 84 85 for i, tc := range tests { 86 87 t.Run(tc.note, func(t *testing.T) { 88 89 pairs := make([][2]*ast.Term, len(tc.input)) 90 91 for j := range tc.input { 92 k := ast.MustParseTerm(tc.input[j][0]) 93 v := ast.MustParseTerm(tc.input[j][1]) 94 pairs[j] = [...]*ast.Term{k, v} 95 } 96 97 var exist *ast.Term 98 99 if tc.exist != "" { 100 exist = ast.MustParseTerm(tc.exist) 101 } 102 103 input, err := mergeTermWithValues(exist, pairs) 104 105 switch e := tc.expected.(type) { 106 case error: 107 if err == nil { 108 t.Fatalf("%v (#%d): Expected error %v but got: %v", tc.note, i+1, e, input) 109 } 110 if err.Error() != e.Error() { 111 t.Fatalf("%v (#%d): Expected error %v but got: %v", tc.note, i+1, e, err) 112 } 113 case string: 114 if err != nil { 115 t.Fatalf("%v (#%d): Unexpected error: %v", tc.note, i+1, err) 116 } 117 expected := ast.MustParseTerm(e) 118 if expected.Value.Compare(input.Value) != 0 { 119 t.Fatalf("%v (#%d): Expected input to equal %v but got: %v", tc.note, i+1, expected, input) 120 } 121 } 122 }) 123 } 124 } 125 126 func TestMergeTermWithValuesInputsShouldBeImmutable(t *testing.T) { 127 128 initial := ast.MustParseTerm(`{"foo": 1}`) 129 expInitial := initial.Copy() 130 two := ast.MustParseTerm(`2`) 131 132 result, err := mergeTermWithValues(nil, [][2]*ast.Term{ 133 {ast.MustParseTerm("input"), initial}, 134 {ast.MustParseTerm("input.foo"), two}, 135 }) 136 137 if err != nil { 138 t.Fatal(err) 139 } 140 141 exp := ast.MustParseTerm(`{"foo": 2}`) 142 143 if !result.Equal(exp) { 144 t.Fatalf("expected %v but got %v", exp, result) 145 } 146 147 if !initial.Equal(expInitial) { 148 t.Fatalf("expected input value to be unchanged but got %v (expected: %v)", initial, expInitial) 149 } 150 }