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 }