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