1// Copyright 2019 Istio Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package constraint
16
17import (
18	"testing"
19
20	. "github.com/onsi/gomega"
21)
22
23func TestParse(t *testing.T) {
24	var cases = []struct {
25		Input    string
26		Expected *Constraints
27	}{
28		{
29			Input:    ``,
30			Expected: &Constraints{},
31		},
32		{
33			Input: `
34constraints:
35`,
36			Expected: &Constraints{},
37		},
38
39		{
40			Input: `
41constraints:
42  - collection: foo
43`,
44			Expected: &Constraints{
45				Constraints: []*Collection{
46					{
47						Name: "foo",
48					},
49				},
50			},
51		},
52
53		{
54			Input: `
55constraints:
56  - collection: foo
57    check:
58`,
59			Expected: &Constraints{
60				Constraints: []*Collection{
61					{
62						Name: "foo",
63					},
64				},
65			},
66		},
67
68		{
69			Input: `
70constraints:
71  - collection: foo
72    check:
73    - exactlyOne:
74`,
75			Expected: &Constraints{
76				Constraints: []*Collection{
77					{
78						Name: "foo",
79						Check: []Range{
80							&ExactlyOne{},
81						},
82					},
83				},
84			},
85		},
86
87		{
88			Input: `
89constraints:
90  - collection: foo
91    check:
92    - any:
93`,
94			Expected: &Constraints{
95				Constraints: []*Collection{
96					{
97						Name: "foo",
98						Check: []Range{
99							&Any{},
100						},
101					},
102				},
103			},
104		},
105
106		{
107			Input: `
108constraints:
109  - collection: foo
110    check:
111    - exactlyOne:
112      - select: foo
113        exists: true
114`,
115			Expected: &Constraints{
116				Constraints: []*Collection{
117					{
118						Name: "foo",
119						Check: []Range{
120							&ExactlyOne{
121								Constraints: []Check{
122									&Select{
123										Expression: "foo",
124										Op:         SelectExists,
125									},
126								},
127							},
128						},
129					},
130				},
131			},
132		},
133
134		{
135			Input: `
136constraints:
137  - collection: foo
138    check:
139    - exactlyOne:
140      - select: foo
141        exists: false
142`,
143			Expected: &Constraints{
144				Constraints: []*Collection{
145					{
146						Name: "foo",
147						Check: []Range{
148							&ExactlyOne{
149								Constraints: []Check{
150									&Select{
151										Expression: "foo",
152										Op:         SelectNotExists,
153									},
154								},
155							},
156						},
157					},
158				},
159			},
160		},
161
162		{
163			Input: `
164constraints:
165  - collection: foo
166    check:
167    - exactlyOne:
168      - select: foo
169        equals:
170          boo: bar
171`,
172			Expected: &Constraints{
173				Constraints: []*Collection{
174					{
175						Name: "foo",
176						Check: []Range{
177							&ExactlyOne{
178								Constraints: []Check{
179									&Select{
180										Expression: "foo",
181										Op:         SelectEquals,
182										Arg: map[string]interface{}{
183											"boo": "bar",
184										},
185									},
186								},
187							},
188						},
189					},
190				},
191			},
192		},
193
194		{
195			Input: `
196constraints:
197  - collection: foo
198    check:
199    - exactlyOne:
200      - select: foo
201        equals:
202          - boo: bar
203`,
204			Expected: &Constraints{
205				Constraints: []*Collection{
206					{
207						Name: "foo",
208						Check: []Range{
209							&ExactlyOne{
210								Constraints: []Check{
211									&Select{
212										Expression: "foo",
213										Op:         SelectEquals,
214										Arg: []interface{}{
215											map[string]interface{}{
216												"boo": "bar",
217											},
218										},
219									},
220								},
221							},
222						},
223					},
224				},
225			},
226		},
227
228		{
229			Input: `
230constraints:
231  - collection: foo
232    check:
233    - any:
234      - select: foo
235        then:
236        - select: bar
237          exists: true
238`,
239			Expected: &Constraints{
240				Constraints: []*Collection{
241					{
242						Name: "foo",
243						Check: []Range{
244							&Any{
245								Constraints: []Check{
246									&Select{
247										Expression: "foo",
248										Op:         SelectGroup,
249										Children: []*Select{
250											{
251												Expression: "bar",
252												Op:         SelectExists,
253											},
254										},
255									},
256								},
257							},
258						},
259					},
260				},
261			},
262		},
263	}
264
265	for _, c := range cases {
266		t.Run("", func(t *testing.T) {
267			g := NewGomegaWithT(t)
268			cons, err := Parse([]byte(c.Input))
269			g.Expect(err).To(BeNil())
270
271			// Clear parentage to simplify testing
272			for _, c := range cons.Constraints {
273				for _, d := range c.Check {
274					var constr []Check
275					switch v := d.(type) {
276					case *ExactlyOne:
277						constr = v.Constraints
278					case *Any:
279						constr = v.Constraints
280					}
281
282					for _, e := range constr {
283						s, ok := e.(*Select)
284						if ok {
285							s.Parent = nil
286						}
287
288						for _, c := range s.Children {
289							c.Parent = nil
290						}
291					}
292				}
293			}
294			g.Expect(cons).To(Equal(c.Expected))
295		})
296	}
297}
298