where_test.go (26944B)
1 // Copyright 2017 The Hugo Authors. All rights reserved.
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 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package collections
15
16 import (
17 "fmt"
18 "html/template"
19 "reflect"
20 "strings"
21 "testing"
22 "time"
23
24 "github.com/gohugoio/hugo/common/maps"
25 "github.com/gohugoio/hugo/config"
26 "github.com/gohugoio/hugo/langs"
27
28 "github.com/gohugoio/hugo/deps"
29 )
30
31 func TestWhere(t *testing.T) {
32 t.Parallel()
33
34 ns := New(&deps.Deps{Language: langs.NewDefaultLanguage(config.New())})
35
36 type Mid struct {
37 Tst TstX
38 }
39
40 d1 := time.Now()
41 d2 := d1.Add(1 * time.Hour)
42 d3 := d2.Add(1 * time.Hour)
43 d4 := d3.Add(1 * time.Hour)
44 d5 := d4.Add(1 * time.Hour)
45 d6 := d5.Add(1 * time.Hour)
46
47 type testt struct {
48 seq any
49 key any
50 op string
51 match any
52 expect any
53 }
54
55 createTestVariants := func(test testt) []testt {
56 testVariants := []testt{test}
57 if islice := ToTstXIs(test.seq); islice != nil {
58 variant := test
59 variant.seq = islice
60 expect := ToTstXIs(test.expect)
61 if expect != nil {
62 variant.expect = expect
63 }
64 testVariants = append(testVariants, variant)
65 }
66
67 return testVariants
68 }
69
70 for i, test := range []testt{
71 {
72 seq: []map[int]string{
73 {1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
74 },
75 key: 2, match: "m",
76 expect: []map[int]string{
77 {1: "a", 2: "m"},
78 },
79 },
80 {
81 seq: []map[string]int{
82 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
83 },
84 key: "b", match: 4,
85 expect: []map[string]int{
86 {"a": 3, "b": 4},
87 },
88 },
89 {
90 seq: []map[string]float64{
91 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
92 },
93 key: "b", match: 4.0,
94 expect: []map[string]float64{{"a": 3, "b": 4}},
95 },
96 {
97 seq: []map[string]float64{
98 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
99 },
100 key: "b", match: 4.0, op: "!=",
101 expect: []map[string]float64{{"a": 1, "b": 2}, {"a": 5, "x": 4}},
102 },
103 {
104 seq: []map[string]float64{
105 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
106 },
107 key: "b", match: 4.0, op: "<",
108 expect: []map[string]float64{{"a": 1, "b": 2}},
109 },
110 {
111 seq: []map[string]float64{
112 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
113 },
114 key: "b", match: 4, op: "<",
115 expect: []map[string]float64{{"a": 1, "b": 2}},
116 },
117 {
118 seq: []map[string]int{
119 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
120 },
121 key: "b", match: 4.0, op: "<",
122 expect: []map[string]int{{"a": 1, "b": 2}},
123 },
124 {
125 seq: []map[string]int{
126 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
127 },
128 key: "b", match: 4.2, op: "<",
129 expect: []map[string]int{{"a": 1, "b": 2}, {"a": 3, "b": 4}},
130 },
131 {
132 seq: []map[string]float64{
133 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
134 },
135 key: "b", match: 4.0, op: "<=",
136 expect: []map[string]float64{{"a": 1, "b": 2}, {"a": 3, "b": 4}},
137 },
138 {
139 seq: []map[string]float64{
140 {"a": 1, "b": 2}, {"a": 3, "b": 3}, {"a": 5, "x": 4},
141 },
142 key: "b", match: 2.0, op: ">",
143 expect: []map[string]float64{{"a": 3, "b": 3}},
144 },
145 {
146 seq: []map[string]float64{
147 {"a": 1, "b": 2}, {"a": 3, "b": 3}, {"a": 5, "x": 4},
148 },
149 key: "b", match: 2.0, op: ">=",
150 expect: []map[string]float64{{"a": 1, "b": 2}, {"a": 3, "b": 3}},
151 },
152 // Issue #8353
153 // String type mismatch.
154 {
155 seq: []map[string]any{
156 {"a": "1", "b": "2"}, {"a": "3", "b": template.HTML("4")}, {"a": "5", "x": "4"},
157 },
158 key: "b", match: "4",
159 expect: []map[string]any{
160 {"a": "3", "b": template.HTML("4")},
161 },
162 },
163 {
164 seq: []TstX{
165 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
166 },
167 key: "B", match: "f",
168 expect: []TstX{
169 {A: "e", B: "f"},
170 },
171 },
172 {
173 seq: []*map[int]string{
174 {1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
175 },
176 key: 2, match: "m",
177 expect: []*map[int]string{
178 {1: "a", 2: "m"},
179 },
180 },
181 // Case insensitive maps.Params
182 // Slice of structs
183 {
184 seq: []TstParams{{params: maps.Params{"i": 0, "color": "indigo"}}, {params: maps.Params{"i": 1, "color": "blue"}}, {params: maps.Params{"i": 2, "color": "green"}}, {params: maps.Params{"i": 3, "color": "blue"}}},
185 key: ".Params.COLOR", match: "blue",
186 expect: []TstParams{{params: maps.Params{"i": 1, "color": "blue"}}, {params: maps.Params{"i": 3, "color": "blue"}}},
187 },
188 {
189 seq: []TstParams{{params: maps.Params{"nested": map[string]any{"color": "indigo"}}}, {params: maps.Params{"nested": map[string]any{"color": "blue"}}}},
190 key: ".Params.NEsTED.COLOR", match: "blue",
191 expect: []TstParams{{params: maps.Params{"nested": map[string]any{"color": "blue"}}}},
192 },
193 {
194 seq: []TstParams{{params: maps.Params{"i": 0, "color": "indigo"}}, {params: maps.Params{"i": 1, "color": "blue"}}, {params: maps.Params{"i": 2, "color": "green"}}, {params: maps.Params{"i": 3, "color": "blue"}}},
195 key: ".Params", match: "blue",
196 expect: []TstParams{},
197 },
198 // Slice of maps
199 {
200 seq: []maps.Params{
201 {"a": "a1", "b": "b1"}, {"a": "a2", "b": "b2"},
202 },
203 key: "B", match: "b2",
204 expect: []maps.Params{
205 {"a": "a2", "b": "b2"},
206 },
207 },
208 {
209 seq: []maps.Params{
210 {
211 "a": map[string]any{
212 "b": "b1",
213 },
214 },
215 {
216 "a": map[string]any{
217 "b": "b2",
218 },
219 },
220 },
221 key: "A.B", match: "b2",
222 expect: []maps.Params{
223 {
224 "a": map[string]any{
225 "b": "b2",
226 },
227 },
228 },
229 },
230 {
231 seq: []*TstX{
232 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
233 },
234 key: "B", match: "f",
235 expect: []*TstX{
236 {A: "e", B: "f"},
237 },
238 },
239 {
240 seq: []*TstX{
241 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "c"},
242 },
243 key: "TstRp", match: "rc",
244 expect: []*TstX{
245 {A: "c", B: "d"},
246 },
247 },
248 {
249 seq: []TstX{
250 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "c"},
251 },
252 key: "TstRv", match: "rc",
253 expect: []TstX{
254 {A: "e", B: "c"},
255 },
256 },
257 {
258 seq: []map[string]TstX{
259 {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
260 },
261 key: "foo.B", match: "d",
262 expect: []map[string]TstX{
263 {"foo": TstX{A: "c", B: "d"}},
264 },
265 },
266 {
267 seq: []map[string]TstX{
268 {"baz": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
269 },
270 key: "foo.B", match: "d",
271 expect: []map[string]TstX{
272 {"foo": TstX{A: "c", B: "d"}},
273 },
274 },
275 {
276 seq: []map[string]TstX{
277 {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
278 },
279 key: ".foo.B", match: "d",
280 expect: []map[string]TstX{
281 {"foo": TstX{A: "c", B: "d"}},
282 },
283 },
284 {
285 seq: []map[string]TstX{
286 {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
287 },
288 key: "foo.TstRv", match: "rd",
289 expect: []map[string]TstX{
290 {"foo": TstX{A: "c", B: "d"}},
291 },
292 },
293 {
294 seq: []map[string]*TstX{
295 {"foo": &TstX{A: "a", B: "b"}}, {"foo": &TstX{A: "c", B: "d"}}, {"foo": &TstX{A: "e", B: "f"}},
296 },
297 key: "foo.TstRp", match: "rc",
298 expect: []map[string]*TstX{
299 {"foo": &TstX{A: "c", B: "d"}},
300 },
301 },
302 {
303 seq: []TstXIHolder{
304 {&TstX{A: "a", B: "b"}}, {&TstX{A: "c", B: "d"}}, {&TstX{A: "e", B: "f"}},
305 },
306 key: "XI.TstRp", match: "rc",
307 expect: []TstXIHolder{
308 {&TstX{A: "c", B: "d"}},
309 },
310 },
311 {
312 seq: []TstXIHolder{
313 {&TstX{A: "a", B: "b"}}, {&TstX{A: "c", B: "d"}}, {&TstX{A: "e", B: "f"}},
314 },
315 key: "XI.A", match: "e",
316 expect: []TstXIHolder{
317 {&TstX{A: "e", B: "f"}},
318 },
319 },
320 {
321 seq: []map[string]Mid{
322 {"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
323 },
324 key: "foo.Tst.B", match: "d",
325 expect: []map[string]Mid{
326 {"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
327 },
328 },
329 {
330 seq: []map[string]Mid{
331 {"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
332 },
333 key: "foo.Tst.TstRv", match: "rd",
334 expect: []map[string]Mid{
335 {"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
336 },
337 },
338 {
339 seq: []map[string]*Mid{
340 {"foo": &Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": &Mid{Tst: TstX{A: "e", B: "f"}}},
341 },
342 key: "foo.Tst.TstRp", match: "rc",
343 expect: []map[string]*Mid{
344 {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}},
345 },
346 },
347 {
348 seq: []map[string]int{
349 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
350 },
351 key: "b", op: ">", match: 3,
352 expect: []map[string]int{
353 {"a": 3, "b": 4}, {"a": 5, "b": 6},
354 },
355 },
356 {
357 seq: []map[string]float64{
358 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
359 },
360 key: "b", op: ">", match: 3.0,
361 expect: []map[string]float64{
362 {"a": 3, "b": 4}, {"a": 5, "b": 6},
363 },
364 },
365 {
366 seq: []TstX{
367 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
368 },
369 key: "B", op: "!=", match: "f",
370 expect: []TstX{
371 {A: "a", B: "b"}, {A: "c", B: "d"},
372 },
373 },
374 {
375 seq: []map[string]int{
376 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
377 },
378 key: "b", op: "in", match: []int{3, 4, 5},
379 expect: []map[string]int{
380 {"a": 3, "b": 4},
381 },
382 },
383 {
384 seq: []map[string]float64{
385 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
386 },
387 key: "b", op: "in", match: []float64{3, 4, 5},
388 expect: []map[string]float64{
389 {"a": 3, "b": 4},
390 },
391 },
392 {
393 seq: []map[string][]string{
394 {"a": []string{"A", "B", "C"}, "b": []string{"D", "E", "F"}}, {"a": []string{"G", "H", "I"}, "b": []string{"J", "K", "L"}}, {"a": []string{"M", "N", "O"}, "b": []string{"P", "Q", "R"}},
395 },
396 key: "b", op: "intersect", match: []string{"D", "P", "Q"},
397 expect: []map[string][]string{
398 {"a": []string{"A", "B", "C"}, "b": []string{"D", "E", "F"}}, {"a": []string{"M", "N", "O"}, "b": []string{"P", "Q", "R"}},
399 },
400 },
401 {
402 seq: []map[string][]int{
403 {"a": []int{1, 2, 3}, "b": []int{4, 5, 6}}, {"a": []int{7, 8, 9}, "b": []int{10, 11, 12}}, {"a": []int{13, 14, 15}, "b": []int{16, 17, 18}},
404 },
405 key: "b", op: "intersect", match: []int{4, 10, 12},
406 expect: []map[string][]int{
407 {"a": []int{1, 2, 3}, "b": []int{4, 5, 6}}, {"a": []int{7, 8, 9}, "b": []int{10, 11, 12}},
408 },
409 },
410 {
411 seq: []map[string][]int8{
412 {"a": []int8{1, 2, 3}, "b": []int8{4, 5, 6}}, {"a": []int8{7, 8, 9}, "b": []int8{10, 11, 12}}, {"a": []int8{13, 14, 15}, "b": []int8{16, 17, 18}},
413 },
414 key: "b", op: "intersect", match: []int8{4, 10, 12},
415 expect: []map[string][]int8{
416 {"a": []int8{1, 2, 3}, "b": []int8{4, 5, 6}}, {"a": []int8{7, 8, 9}, "b": []int8{10, 11, 12}},
417 },
418 },
419 {
420 seq: []map[string][]int16{
421 {"a": []int16{1, 2, 3}, "b": []int16{4, 5, 6}}, {"a": []int16{7, 8, 9}, "b": []int16{10, 11, 12}}, {"a": []int16{13, 14, 15}, "b": []int16{16, 17, 18}},
422 },
423 key: "b", op: "intersect", match: []int16{4, 10, 12},
424 expect: []map[string][]int16{
425 {"a": []int16{1, 2, 3}, "b": []int16{4, 5, 6}}, {"a": []int16{7, 8, 9}, "b": []int16{10, 11, 12}},
426 },
427 },
428 {
429 seq: []map[string][]int32{
430 {"a": []int32{1, 2, 3}, "b": []int32{4, 5, 6}}, {"a": []int32{7, 8, 9}, "b": []int32{10, 11, 12}}, {"a": []int32{13, 14, 15}, "b": []int32{16, 17, 18}},
431 },
432 key: "b", op: "intersect", match: []int32{4, 10, 12},
433 expect: []map[string][]int32{
434 {"a": []int32{1, 2, 3}, "b": []int32{4, 5, 6}}, {"a": []int32{7, 8, 9}, "b": []int32{10, 11, 12}},
435 },
436 },
437 {
438 seq: []map[string][]int64{
439 {"a": []int64{1, 2, 3}, "b": []int64{4, 5, 6}}, {"a": []int64{7, 8, 9}, "b": []int64{10, 11, 12}}, {"a": []int64{13, 14, 15}, "b": []int64{16, 17, 18}},
440 },
441 key: "b", op: "intersect", match: []int64{4, 10, 12},
442 expect: []map[string][]int64{
443 {"a": []int64{1, 2, 3}, "b": []int64{4, 5, 6}}, {"a": []int64{7, 8, 9}, "b": []int64{10, 11, 12}},
444 },
445 },
446 {
447 seq: []map[string][]float32{
448 {"a": []float32{1.0, 2.0, 3.0}, "b": []float32{4.0, 5.0, 6.0}}, {"a": []float32{7.0, 8.0, 9.0}, "b": []float32{10.0, 11.0, 12.0}}, {"a": []float32{13.0, 14.0, 15.0}, "b": []float32{16.0, 17.0, 18.0}},
449 },
450 key: "b", op: "intersect", match: []float32{4, 10, 12},
451 expect: []map[string][]float32{
452 {"a": []float32{1.0, 2.0, 3.0}, "b": []float32{4.0, 5.0, 6.0}}, {"a": []float32{7.0, 8.0, 9.0}, "b": []float32{10.0, 11.0, 12.0}},
453 },
454 },
455 {
456 seq: []map[string][]float64{
457 {"a": []float64{1.0, 2.0, 3.0}, "b": []float64{4.0, 5.0, 6.0}}, {"a": []float64{7.0, 8.0, 9.0}, "b": []float64{10.0, 11.0, 12.0}}, {"a": []float64{13.0, 14.0, 15.0}, "b": []float64{16.0, 17.0, 18.0}},
458 },
459 key: "b", op: "intersect", match: []float64{4, 10, 12},
460 expect: []map[string][]float64{
461 {"a": []float64{1.0, 2.0, 3.0}, "b": []float64{4.0, 5.0, 6.0}}, {"a": []float64{7.0, 8.0, 9.0}, "b": []float64{10.0, 11.0, 12.0}},
462 },
463 },
464 {
465 seq: []map[string]int{
466 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
467 },
468 key: "b", op: "in", match: ns.Slice(3, 4, 5),
469 expect: []map[string]int{
470 {"a": 3, "b": 4},
471 },
472 },
473 {
474 seq: []map[string]float64{
475 {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
476 },
477 key: "b", op: "in", match: ns.Slice(3.0, 4.0, 5.0),
478 expect: []map[string]float64{
479 {"a": 3, "b": 4},
480 },
481 },
482 {
483 seq: []map[string]time.Time{
484 {"a": d1, "b": d2}, {"a": d3, "b": d4}, {"a": d5, "b": d6},
485 },
486 key: "b", op: "in", match: ns.Slice(d3, d4, d5),
487 expect: []map[string]time.Time{
488 {"a": d3, "b": d4},
489 },
490 },
491 {
492 seq: []TstX{
493 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
494 },
495 key: "B", op: "not in", match: []string{"c", "d", "e"},
496 expect: []TstX{
497 {A: "a", B: "b"}, {A: "e", B: "f"},
498 },
499 },
500 {
501 seq: []TstX{
502 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
503 },
504 key: "B", op: "not in", match: ns.Slice("c", t, "d", "e"),
505 expect: []TstX{
506 {A: "a", B: "b"}, {A: "e", B: "f"},
507 },
508 },
509 {
510 seq: []map[string]int{
511 {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6},
512 },
513 key: "b", op: "", match: nil,
514 expect: []map[string]int{
515 {"a": 3},
516 },
517 },
518 {
519 seq: []map[string]int{
520 {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6},
521 },
522 key: "b", op: "!=", match: nil,
523 expect: []map[string]int{
524 {"a": 1, "b": 2}, {"a": 5, "b": 6},
525 },
526 },
527 {
528 seq: []map[string]int{
529 {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6},
530 },
531 key: "b", op: ">", match: nil,
532 expect: []map[string]int{},
533 },
534 {
535 seq: []map[string]float64{
536 {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6},
537 },
538 key: "b", op: "", match: nil,
539 expect: []map[string]float64{
540 {"a": 3},
541 },
542 },
543 {
544 seq: []map[string]float64{
545 {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6},
546 },
547 key: "b", op: "!=", match: nil,
548 expect: []map[string]float64{
549 {"a": 1, "b": 2}, {"a": 5, "b": 6},
550 },
551 },
552 {
553 seq: []map[string]float64{
554 {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6},
555 },
556 key: "b", op: ">", match: nil,
557 expect: []map[string]float64{},
558 },
559 {
560 seq: []map[string]bool{
561 {"a": true, "b": false}, {"c": true, "b": true}, {"d": true, "b": false},
562 },
563 key: "b", op: "", match: true,
564 expect: []map[string]bool{
565 {"c": true, "b": true},
566 },
567 },
568 {
569 seq: []map[string]bool{
570 {"a": true, "b": false}, {"c": true, "b": true}, {"d": true, "b": false},
571 },
572 key: "b", op: "!=", match: true,
573 expect: []map[string]bool{
574 {"a": true, "b": false}, {"d": true, "b": false},
575 },
576 },
577 {
578 seq: []map[string]bool{
579 {"a": true, "b": false}, {"c": true, "b": true}, {"d": true, "b": false},
580 },
581 key: "b", op: ">", match: false,
582 expect: []map[string]bool{},
583 },
584 {
585 seq: []map[string]bool{
586 {"a": true, "b": false}, {"c": true, "b": true}, {"d": true, "b": false},
587 },
588 key: "b.z", match: false,
589 expect: []map[string]bool{},
590 },
591 {seq: (*[]TstX)(nil), key: "A", match: "a", expect: false},
592 {seq: TstX{A: "a", B: "b"}, key: "A", match: "a", expect: false},
593 {seq: []map[string]*TstX{{"foo": nil}}, key: "foo.B", match: "d", expect: []map[string]*TstX{}},
594 {seq: []map[string]*TstX{{"foo": nil}}, key: "foo.B.Z", match: "d", expect: []map[string]*TstX{}},
595 {
596 seq: []TstX{
597 {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
598 },
599 key: "B", op: "op", match: "f",
600 expect: false,
601 },
602 {
603 seq: map[string]any{
604 "foo": []any{map[any]any{"a": 1, "b": 2}},
605 "bar": []any{map[any]any{"a": 3, "b": 4}},
606 "zap": []any{map[any]any{"a": 5, "b": 6}},
607 },
608 key: "b", op: "in", match: ns.Slice(3, 4, 5),
609 expect: map[string]any{
610 "bar": []any{map[any]any{"a": 3, "b": 4}},
611 },
612 },
613 {
614 seq: map[string]any{
615 "foo": []any{map[any]any{"a": 1, "b": 2}},
616 "bar": []any{map[any]any{"a": 3, "b": 4}},
617 "zap": []any{map[any]any{"a": 5, "b": 6}},
618 },
619 key: "b", op: ">", match: 3,
620 expect: map[string]any{
621 "bar": []any{map[any]any{"a": 3, "b": 4}},
622 "zap": []any{map[any]any{"a": 5, "b": 6}},
623 },
624 },
625 {
626 seq: map[string]any{
627 "foo": []any{maps.Params{"a": 1, "b": 2}},
628 "bar": []any{maps.Params{"a": 3, "b": 4}},
629 "zap": []any{maps.Params{"a": 5, "b": 6}},
630 },
631 key: "B", op: ">", match: 3,
632 expect: map[string]any{
633 "bar": []any{maps.Params{"a": 3, "b": 4}},
634 "zap": []any{maps.Params{"a": 5, "b": 6}},
635 },
636 },
637 } {
638
639 testVariants := createTestVariants(test)
640 for j, test := range testVariants {
641 name := fmt.Sprintf("%d/%d %T %s %s", i, j, test.seq, test.op, test.key)
642 name = strings.ReplaceAll(name, "[]", "slice-of-")
643 t.Run(name, func(t *testing.T) {
644 var results any
645 var err error
646
647 if len(test.op) > 0 {
648 results, err = ns.Where(test.seq, test.key, test.op, test.match)
649 } else {
650 results, err = ns.Where(test.seq, test.key, test.match)
651 }
652 if b, ok := test.expect.(bool); ok && !b {
653 if err == nil {
654 t.Fatalf("[%d] Where didn't return an expected error", i)
655 }
656 } else {
657 if err != nil {
658 t.Fatalf("[%d] failed: %s", i, err)
659 }
660 if !reflect.DeepEqual(results, test.expect) {
661 t.Fatalf("Where clause matching %v with %v in seq %v (%T),\ngot\n%v (%T) but expected\n%v (%T)", test.key, test.match, test.seq, test.seq, results, results, test.expect, test.expect)
662 }
663 }
664 })
665 }
666 }
667
668 var err error
669 _, err = ns.Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1)
670 if err == nil {
671 t.Errorf("Where called with none string op value didn't return an expected error")
672 }
673
674 _, err = ns.Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1, 2)
675 if err == nil {
676 t.Errorf("Where called with more than two variable arguments didn't return an expected error")
677 }
678
679 _, err = ns.Where(map[string]int{"a": 1, "b": 2}, "a")
680 if err == nil {
681 t.Errorf("Where called with no variable arguments didn't return an expected error")
682 }
683 }
684
685 func TestCheckCondition(t *testing.T) {
686 t.Parallel()
687
688 ns := New(&deps.Deps{Language: langs.NewDefaultLanguage(config.New())})
689
690 type expect struct {
691 result bool
692 isError bool
693 }
694
695 for i, test := range []struct {
696 value reflect.Value
697 match reflect.Value
698 op string
699 expect
700 }{
701 {reflect.ValueOf(123), reflect.ValueOf(123), "", expect{true, false}},
702 {reflect.ValueOf("foo"), reflect.ValueOf("foo"), "", expect{true, false}},
703 {
704 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
705 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
706 "",
707 expect{true, false},
708 },
709 {reflect.ValueOf(true), reflect.ValueOf(true), "", expect{true, false}},
710 {reflect.ValueOf(nil), reflect.ValueOf(nil), "", expect{true, false}},
711 {reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}},
712 {reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}},
713 {
714 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
715 reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
716 "!=",
717 expect{true, false},
718 },
719 {reflect.ValueOf(true), reflect.ValueOf(false), "!=", expect{true, false}},
720 {reflect.ValueOf(123), reflect.ValueOf(nil), "!=", expect{true, false}},
721 {reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}},
722 {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}},
723 {
724 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
725 reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
726 ">=",
727 expect{true, false},
728 },
729 {reflect.ValueOf(456), reflect.ValueOf(123), ">", expect{true, false}},
730 {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">", expect{true, false}},
731 {
732 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
733 reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
734 ">",
735 expect{true, false},
736 },
737 {reflect.ValueOf(123), reflect.ValueOf(456), "<=", expect{true, false}},
738 {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<=", expect{true, false}},
739 {
740 reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
741 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
742 "<=",
743 expect{true, false},
744 },
745 {reflect.ValueOf(123), reflect.ValueOf(456), "<", expect{true, false}},
746 {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<", expect{true, false}},
747 {
748 reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
749 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
750 "<",
751 expect{true, false},
752 },
753 {reflect.ValueOf(123), reflect.ValueOf([]int{123, 45, 678}), "in", expect{true, false}},
754 {reflect.ValueOf("foo"), reflect.ValueOf([]string{"foo", "bar", "baz"}), "in", expect{true, false}},
755 {
756 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
757 reflect.ValueOf([]time.Time{
758 time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC),
759 time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC),
760 time.Date(2015, time.June, 26, 19, 18, 56, 12345, time.UTC),
761 }),
762 "in",
763 expect{true, false},
764 },
765 {reflect.ValueOf(123), reflect.ValueOf([]int{45, 678}), "not in", expect{true, false}},
766 {reflect.ValueOf("foo"), reflect.ValueOf([]string{"bar", "baz"}), "not in", expect{true, false}},
767 {
768 reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
769 reflect.ValueOf([]time.Time{
770 time.Date(2015, time.February, 26, 19, 18, 56, 12345, time.UTC),
771 time.Date(2015, time.March, 26, 19, 18, 56, 12345, time.UTC),
772 time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC),
773 }),
774 "not in",
775 expect{true, false},
776 },
777 {reflect.ValueOf("foo"), reflect.ValueOf("bar-foo-baz"), "in", expect{true, false}},
778 {reflect.ValueOf("foo"), reflect.ValueOf("bar--baz"), "not in", expect{true, false}},
779 {reflect.Value{}, reflect.ValueOf("foo"), "", expect{false, false}},
780 {reflect.ValueOf("foo"), reflect.Value{}, "", expect{false, false}},
781 {reflect.ValueOf((*TstX)(nil)), reflect.ValueOf("foo"), "", expect{false, false}},
782 {reflect.ValueOf("foo"), reflect.ValueOf((*TstX)(nil)), "", expect{false, false}},
783 {reflect.ValueOf(true), reflect.ValueOf("foo"), "", expect{false, false}},
784 {reflect.ValueOf("foo"), reflect.ValueOf(true), "", expect{false, false}},
785 {reflect.ValueOf("foo"), reflect.ValueOf(map[int]string{}), "", expect{false, false}},
786 {reflect.ValueOf("foo"), reflect.ValueOf([]int{1, 2}), "", expect{false, false}},
787 {reflect.ValueOf((*TstX)(nil)), reflect.ValueOf((*TstX)(nil)), ">", expect{false, false}},
788 {reflect.ValueOf(true), reflect.ValueOf(false), ">", expect{false, false}},
789 {reflect.ValueOf(123), reflect.ValueOf([]int{}), "in", expect{false, false}},
790 {reflect.ValueOf(123), reflect.ValueOf(123), "op", expect{false, true}},
791
792 // Issue #3718
793 {reflect.ValueOf([]any{"a"}), reflect.ValueOf([]string{"a", "b"}), "intersect", expect{true, false}},
794 {reflect.ValueOf([]string{"a"}), reflect.ValueOf([]any{"a", "b"}), "intersect", expect{true, false}},
795 {reflect.ValueOf([]any{1, 2}), reflect.ValueOf([]int{1}), "intersect", expect{true, false}},
796 {reflect.ValueOf([]int{1}), reflect.ValueOf([]any{1, 2}), "intersect", expect{true, false}},
797 } {
798 result, err := ns.checkCondition(test.value, test.match, test.op)
799 if test.expect.isError {
800 if err == nil {
801 t.Errorf("[%d] checkCondition didn't return an expected error", i)
802 }
803 } else {
804 if err != nil {
805 t.Errorf("[%d] failed: %s", i, err)
806 continue
807 }
808 if result != test.expect.result {
809 t.Errorf("[%d] check condition %v %s %v, got %v but expected %v", i, test.value, test.op, test.match, result, test.expect.result)
810 }
811 }
812 }
813 }
814
815 func TestEvaluateSubElem(t *testing.T) {
816 t.Parallel()
817 tstx := TstX{A: "foo", B: "bar"}
818 var inner struct {
819 S fmt.Stringer
820 }
821 inner.S = tstx
822 interfaceValue := reflect.ValueOf(&inner).Elem().Field(0)
823
824 for i, test := range []struct {
825 value reflect.Value
826 key string
827 expect any
828 }{
829 {reflect.ValueOf(tstx), "A", "foo"},
830 {reflect.ValueOf(&tstx), "TstRp", "rfoo"},
831 {reflect.ValueOf(tstx), "TstRv", "rbar"},
832 //{reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), 1, "foo"},
833 {reflect.ValueOf(map[string]string{"key1": "foo", "key2": "bar"}), "key1", "foo"},
834 {interfaceValue, "String", "A: foo, B: bar"},
835 {reflect.Value{}, "foo", false},
836 //{reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), 1.2, false},
837 {reflect.ValueOf(tstx), "unexported", false},
838 {reflect.ValueOf(tstx), "unexportedMethod", false},
839 {reflect.ValueOf(tstx), "MethodWithArg", false},
840 {reflect.ValueOf(tstx), "MethodReturnNothing", false},
841 {reflect.ValueOf(tstx), "MethodReturnErrorOnly", false},
842 {reflect.ValueOf(tstx), "MethodReturnTwoValues", false},
843 {reflect.ValueOf(tstx), "MethodReturnValueWithError", false},
844 {reflect.ValueOf((*TstX)(nil)), "A", false},
845 {reflect.ValueOf(tstx), "C", false},
846 {reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), "1", false},
847 {reflect.ValueOf([]string{"foo", "bar"}), "1", false},
848 } {
849 result, err := evaluateSubElem(test.value, test.key)
850 if b, ok := test.expect.(bool); ok && !b {
851 if err == nil {
852 t.Errorf("[%d] evaluateSubElem didn't return an expected error", i)
853 }
854 } else {
855 if err != nil {
856 t.Errorf("[%d] failed: %s", i, err)
857 continue
858 }
859 if result.Kind() != reflect.String || result.String() != test.expect {
860 t.Errorf("[%d] evaluateSubElem with %v got %v but expected %v", i, test.key, result, test.expect)
861 }
862 }
863 }
864 }