hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

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 }