github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/tpl/collections/collections_test.go (about) 1 // Copyright 2019 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 "errors" 18 "fmt" 19 "html/template" 20 "math/rand" 21 "reflect" 22 "testing" 23 "time" 24 25 "github.com/gohugoio/hugo/common/maps" 26 27 qt "github.com/frankban/quicktest" 28 "github.com/gohugoio/hugo/common/loggers" 29 "github.com/gohugoio/hugo/config" 30 "github.com/gohugoio/hugo/deps" 31 "github.com/gohugoio/hugo/helpers" 32 "github.com/gohugoio/hugo/hugofs" 33 "github.com/gohugoio/hugo/langs" 34 "github.com/spf13/afero" 35 ) 36 37 type tstNoStringer struct{} 38 39 func TestAfter(t *testing.T) { 40 t.Parallel() 41 c := qt.New(t) 42 43 ns := New(&deps.Deps{}) 44 45 for i, test := range []struct { 46 index interface{} 47 seq interface{} 48 expect interface{} 49 }{ 50 {int(2), []string{"a", "b", "c", "d"}, []string{"c", "d"}}, 51 {int32(3), []string{"a", "b"}, []string{}}, 52 {int64(2), []int{100, 200, 300}, []int{300}}, 53 {100, []int{100, 200}, []int{}}, 54 {"1", []int{100, 200, 300}, []int{200, 300}}, 55 {0, []int{100, 200, 300, 400, 500}, []int{100, 200, 300, 400, 500}}, 56 {0, []string{"a", "b", "c", "d", "e"}, []string{"a", "b", "c", "d", "e"}}, 57 {int64(-1), []int{100, 200, 300}, false}, 58 {"noint", []int{100, 200, 300}, false}, 59 {2, []string{}, []string{}}, 60 {1, nil, false}, 61 {nil, []int{100}, false}, 62 {1, t, false}, 63 {1, (*string)(nil), false}, 64 } { 65 errMsg := qt.Commentf("[%d] %v", i, test) 66 67 result, err := ns.After(test.index, test.seq) 68 69 if b, ok := test.expect.(bool); ok && !b { 70 c.Assert(err, qt.Not(qt.IsNil), errMsg) 71 continue 72 } 73 74 c.Assert(err, qt.IsNil, errMsg) 75 c.Assert(result, qt.DeepEquals, test.expect, errMsg) 76 } 77 } 78 79 type tstGrouper struct { 80 } 81 82 type tstGroupers []*tstGrouper 83 84 func (g tstGrouper) Group(key interface{}, items interface{}) (interface{}, error) { 85 ilen := reflect.ValueOf(items).Len() 86 return fmt.Sprintf("%v(%d)", key, ilen), nil 87 } 88 89 type tstGrouper2 struct { 90 } 91 92 func (g *tstGrouper2) Group(key interface{}, items interface{}) (interface{}, error) { 93 ilen := reflect.ValueOf(items).Len() 94 return fmt.Sprintf("%v(%d)", key, ilen), nil 95 } 96 97 func TestGroup(t *testing.T) { 98 t.Parallel() 99 c := qt.New(t) 100 ns := New(&deps.Deps{}) 101 102 for i, test := range []struct { 103 key interface{} 104 items interface{} 105 expect interface{} 106 }{ 107 {"a", []*tstGrouper{{}, {}}, "a(2)"}, 108 {"b", tstGroupers{&tstGrouper{}, &tstGrouper{}}, "b(2)"}, 109 {"a", []tstGrouper{{}, {}}, "a(2)"}, 110 {"a", []*tstGrouper2{{}, {}}, "a(2)"}, 111 {"b", []tstGrouper2{{}, {}}, "b(2)"}, 112 {"a", []*tstGrouper{}, "a(0)"}, 113 {"a", []string{"a", "b"}, false}, 114 {"a", "asdf", false}, 115 {"a", nil, false}, 116 {nil, []*tstGrouper{{}, {}}, false}, 117 } { 118 errMsg := qt.Commentf("[%d] %v", i, test) 119 120 result, err := ns.Group(test.key, test.items) 121 122 if b, ok := test.expect.(bool); ok && !b { 123 c.Assert(err, qt.Not(qt.IsNil), errMsg) 124 continue 125 } 126 127 c.Assert(err, qt.IsNil, errMsg) 128 c.Assert(result, qt.Equals, test.expect, errMsg) 129 } 130 } 131 132 func TestDelimit(t *testing.T) { 133 t.Parallel() 134 c := qt.New(t) 135 136 ns := New(&deps.Deps{}) 137 138 for i, test := range []struct { 139 seq interface{} 140 delimiter interface{} 141 last interface{} 142 expect template.HTML 143 }{ 144 {[]string{"class1", "class2", "class3"}, " ", nil, "class1 class2 class3"}, 145 {[]int{1, 2, 3, 4, 5}, ",", nil, "1,2,3,4,5"}, 146 {[]int{1, 2, 3, 4, 5}, ", ", nil, "1, 2, 3, 4, 5"}, 147 {[]string{"class1", "class2", "class3"}, " ", " and ", "class1 class2 and class3"}, 148 {[]int{1, 2, 3, 4, 5}, ",", ",", "1,2,3,4,5"}, 149 {[]int{1, 2, 3, 4, 5}, ", ", ", and ", "1, 2, 3, 4, and 5"}, 150 // test maps with and without sorting required 151 {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", nil, "10--20--30--40--50"}, 152 {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", nil, "30--20--10--40--50"}, 153 {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", nil, "10--20--30--40--50"}, 154 {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", nil, "30--20--10--40--50"}, 155 {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", nil, "50--40--10--30--20"}, 156 {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", nil, "10--20--30--40--50"}, 157 {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", nil, "30--20--10--40--50"}, 158 {map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, "--", nil, "30--20--10--40--50"}, 159 // test maps with a last delimiter 160 {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", "--and--", "10--20--30--40--and--50"}, 161 {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", "--and--", "30--20--10--40--and--50"}, 162 {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", "--and--", "10--20--30--40--and--50"}, 163 {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", "--and--", "30--20--10--40--and--50"}, 164 {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", "--and--", "50--40--10--30--and--20"}, 165 {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", "--and--", "10--20--30--40--and--50"}, 166 {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", "--and--", "30--20--10--40--and--50"}, 167 {map[float64]string{3.5: "10", 2.5: "20", 1.5: "30", 4.5: "40", 5.5: "50"}, "--", "--and--", "30--20--10--40--and--50"}, 168 } { 169 errMsg := qt.Commentf("[%d] %v", i, test) 170 171 var result template.HTML 172 var err error 173 174 if test.last == nil { 175 result, err = ns.Delimit(test.seq, test.delimiter) 176 } else { 177 result, err = ns.Delimit(test.seq, test.delimiter, test.last) 178 } 179 180 c.Assert(err, qt.IsNil, errMsg) 181 c.Assert(result, qt.Equals, test.expect, errMsg) 182 } 183 } 184 185 func TestDictionary(t *testing.T) { 186 c := qt.New(t) 187 188 ns := New(&deps.Deps{}) 189 190 for i, test := range []struct { 191 values []interface{} 192 expect interface{} 193 }{ 194 {[]interface{}{"a", "b"}, map[string]interface{}{"a": "b"}}, 195 {[]interface{}{[]string{"a", "b"}, "c"}, map[string]interface{}{"a": map[string]interface{}{"b": "c"}}}, 196 { 197 []interface{}{[]string{"a", "b"}, "c", []string{"a", "b2"}, "c2", "b", "c"}, 198 map[string]interface{}{"a": map[string]interface{}{"b": "c", "b2": "c2"}, "b": "c"}, 199 }, 200 {[]interface{}{"a", 12, "b", []int{4}}, map[string]interface{}{"a": 12, "b": []int{4}}}, 201 // errors 202 {[]interface{}{5, "b"}, false}, 203 {[]interface{}{"a", "b", "c"}, false}, 204 } { 205 i := i 206 test := test 207 c.Run(fmt.Sprint(i), func(c *qt.C) { 208 c.Parallel() 209 errMsg := qt.Commentf("[%d] %v", i, test.values) 210 211 result, err := ns.Dictionary(test.values...) 212 213 if b, ok := test.expect.(bool); ok && !b { 214 c.Assert(err, qt.Not(qt.IsNil), errMsg) 215 return 216 } 217 218 c.Assert(err, qt.IsNil, errMsg) 219 c.Assert(result, qt.DeepEquals, test.expect, qt.Commentf(fmt.Sprint(result))) 220 }) 221 } 222 } 223 224 func TestReverse(t *testing.T) { 225 t.Parallel() 226 c := qt.New(t) 227 ns := New(&deps.Deps{}) 228 229 s := []string{"a", "b", "c"} 230 reversed, err := ns.Reverse(s) 231 c.Assert(err, qt.IsNil) 232 c.Assert(reversed, qt.DeepEquals, []string{"c", "b", "a"}, qt.Commentf(fmt.Sprint(reversed))) 233 c.Assert(s, qt.DeepEquals, []string{"a", "b", "c"}) 234 235 reversed, err = ns.Reverse(nil) 236 c.Assert(err, qt.IsNil) 237 c.Assert(reversed, qt.IsNil) 238 _, err = ns.Reverse(43) 239 c.Assert(err, qt.Not(qt.IsNil)) 240 } 241 242 func TestEchoParam(t *testing.T) { 243 t.Parallel() 244 c := qt.New(t) 245 246 ns := New(&deps.Deps{}) 247 248 for i, test := range []struct { 249 a interface{} 250 key interface{} 251 expect interface{} 252 }{ 253 {[]int{1, 2, 3}, 1, int64(2)}, 254 {[]uint{1, 2, 3}, 1, uint64(2)}, 255 {[]float64{1.1, 2.2, 3.3}, 1, float64(2.2)}, 256 {[]string{"foo", "bar", "baz"}, 1, "bar"}, 257 {[]TstX{{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"}}, 1, ""}, 258 {map[string]int{"foo": 1, "bar": 2, "baz": 3}, "bar", int64(2)}, 259 {map[string]uint{"foo": 1, "bar": 2, "baz": 3}, "bar", uint64(2)}, 260 {map[string]float64{"foo": 1.1, "bar": 2.2, "baz": 3.3}, "bar", float64(2.2)}, 261 {map[string]string{"foo": "FOO", "bar": "BAR", "baz": "BAZ"}, "bar", "BAR"}, 262 {map[string]TstX{"foo": {A: "a", B: "b"}, "bar": {A: "c", B: "d"}, "baz": {A: "e", B: "f"}}, "bar", ""}, 263 {map[string]interface{}{"foo": nil}, "foo", ""}, 264 {(*[]string)(nil), "bar", ""}, 265 } { 266 errMsg := qt.Commentf("[%d] %v", i, test) 267 268 result := ns.EchoParam(test.a, test.key) 269 270 c.Assert(result, qt.Equals, test.expect, errMsg) 271 } 272 } 273 274 func TestFirst(t *testing.T) { 275 t.Parallel() 276 c := qt.New(t) 277 278 ns := New(&deps.Deps{}) 279 280 for i, test := range []struct { 281 limit interface{} 282 seq interface{} 283 expect interface{} 284 }{ 285 {int(2), []string{"a", "b", "c"}, []string{"a", "b"}}, 286 {int32(3), []string{"a", "b"}, []string{"a", "b"}}, 287 {int64(2), []int{100, 200, 300}, []int{100, 200}}, 288 {100, []int{100, 200}, []int{100, 200}}, 289 {"1", []int{100, 200, 300}, []int{100}}, 290 {0, []string{"h", "u", "g", "o"}, []string{}}, 291 {int64(-1), []int{100, 200, 300}, false}, 292 {"noint", []int{100, 200, 300}, false}, 293 {1, nil, false}, 294 {nil, []int{100}, false}, 295 {1, t, false}, 296 {1, (*string)(nil), false}, 297 } { 298 errMsg := qt.Commentf("[%d] %v", i, test) 299 300 result, err := ns.First(test.limit, test.seq) 301 302 if b, ok := test.expect.(bool); ok && !b { 303 c.Assert(err, qt.Not(qt.IsNil), errMsg) 304 continue 305 } 306 307 c.Assert(err, qt.IsNil) 308 c.Assert(result, qt.DeepEquals, test.expect, errMsg) 309 } 310 } 311 312 func TestIn(t *testing.T) { 313 t.Parallel() 314 c := qt.New(t) 315 316 ns := New(&deps.Deps{}) 317 318 for i, test := range []struct { 319 l1 interface{} 320 l2 interface{} 321 expect bool 322 }{ 323 {[]string{"a", "b", "c"}, "b", true}, 324 {[]interface{}{"a", "b", "c"}, "b", true}, 325 {[]interface{}{"a", "b", "c"}, "d", false}, 326 {[]string{"a", "b", "c"}, "d", false}, 327 {[]string{"a", "12", "c"}, 12, false}, 328 {[]string{"a", "b", "c"}, nil, false}, 329 {[]int{1, 2, 4}, 2, true}, 330 {[]interface{}{1, 2, 4}, 2, true}, 331 {[]interface{}{1, 2, 4}, nil, false}, 332 {[]interface{}{nil}, nil, false}, 333 {[]int{1, 2, 4}, 3, false}, 334 {[]float64{1.23, 2.45, 4.67}, 1.23, true}, 335 {[]float64{1.234567, 2.45, 4.67}, 1.234568, false}, 336 {[]float64{1, 2, 3}, 1, true}, 337 {[]float32{1, 2, 3}, 1, true}, 338 {"this substring should be found", "substring", true}, 339 {"this substring should not be found", "subseastring", false}, 340 {nil, "foo", false}, 341 // Pointers 342 {pagesPtr{p1, p2, p3, p2}, p2, true}, 343 {pagesPtr{p1, p2, p3, p2}, p4, false}, 344 // Structs 345 {pagesVals{p3v, p2v, p3v, p2v}, p2v, true}, 346 {pagesVals{p3v, p2v, p3v, p2v}, p4v, false}, 347 // template.HTML 348 {template.HTML("this substring should be found"), "substring", true}, 349 {template.HTML("this substring should not be found"), "subseastring", false}, 350 // Uncomparable, use hashstructure 351 {[]string{"a", "b"}, []string{"a", "b"}, false}, 352 {[][]string{{"a", "b"}}, []string{"a", "b"}, true}, 353 } { 354 355 errMsg := qt.Commentf("[%d] %v", i, test) 356 357 result, err := ns.In(test.l1, test.l2) 358 c.Assert(err, qt.IsNil) 359 c.Assert(result, qt.Equals, test.expect, errMsg) 360 } 361 } 362 363 type testPage struct { 364 Title string 365 } 366 367 func (p testPage) String() string { 368 return "p-" + p.Title 369 } 370 371 type ( 372 pagesPtr []*testPage 373 pagesVals []testPage 374 ) 375 376 var ( 377 p1 = &testPage{"A"} 378 p2 = &testPage{"B"} 379 p3 = &testPage{"C"} 380 p4 = &testPage{"D"} 381 382 p1v = testPage{"A"} 383 p2v = testPage{"B"} 384 p3v = testPage{"C"} 385 p4v = testPage{"D"} 386 ) 387 388 func TestIntersect(t *testing.T) { 389 t.Parallel() 390 c := qt.New(t) 391 392 ns := New(&deps.Deps{}) 393 394 for i, test := range []struct { 395 l1, l2 interface{} 396 expect interface{} 397 }{ 398 {[]string{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []string{"a", "b"}}, 399 {[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b"}}, 400 {[]string{"a", "b", "c"}, []string{"d", "e"}, []string{}}, 401 {[]string{}, []string{}, []string{}}, 402 {[]string{"a", "b"}, nil, []interface{}{}}, 403 {nil, []string{"a", "b"}, []interface{}{}}, 404 {nil, nil, []interface{}{}}, 405 {[]string{"1", "2"}, []int{1, 2}, []string{}}, 406 {[]int{1, 2}, []string{"1", "2"}, []int{}}, 407 {[]int{1, 2, 4}, []int{2, 4}, []int{2, 4}}, 408 {[]int{2, 4}, []int{1, 2, 4}, []int{2, 4}}, 409 {[]int{1, 2, 4}, []int{3, 6}, []int{}}, 410 {[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4}}, 411 412 // []interface{} ∩ []interface{} 413 {[]interface{}{"a", "b", "c"}, []interface{}{"a", "b", "b"}, []interface{}{"a", "b"}}, 414 {[]interface{}{1, 2, 3}, []interface{}{1, 2, 2}, []interface{}{1, 2}}, 415 {[]interface{}{int8(1), int8(2), int8(3)}, []interface{}{int8(1), int8(2), int8(2)}, []interface{}{int8(1), int8(2)}}, 416 {[]interface{}{int16(1), int16(2), int16(3)}, []interface{}{int16(1), int16(2), int16(2)}, []interface{}{int16(1), int16(2)}}, 417 {[]interface{}{int32(1), int32(2), int32(3)}, []interface{}{int32(1), int32(2), int32(2)}, []interface{}{int32(1), int32(2)}}, 418 {[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(1), int64(2), int64(2)}, []interface{}{int64(1), int64(2)}}, 419 {[]interface{}{float32(1), float32(2), float32(3)}, []interface{}{float32(1), float32(2), float32(2)}, []interface{}{float32(1), float32(2)}}, 420 {[]interface{}{float64(1), float64(2), float64(3)}, []interface{}{float64(1), float64(2), float64(2)}, []interface{}{float64(1), float64(2)}}, 421 422 // []interface{} ∩ []T 423 {[]interface{}{"a", "b", "c"}, []string{"a", "b", "b"}, []interface{}{"a", "b"}}, 424 {[]interface{}{1, 2, 3}, []int{1, 2, 2}, []interface{}{1, 2}}, 425 {[]interface{}{int8(1), int8(2), int8(3)}, []int8{1, 2, 2}, []interface{}{int8(1), int8(2)}}, 426 {[]interface{}{int16(1), int16(2), int16(3)}, []int16{1, 2, 2}, []interface{}{int16(1), int16(2)}}, 427 {[]interface{}{int32(1), int32(2), int32(3)}, []int32{1, 2, 2}, []interface{}{int32(1), int32(2)}}, 428 {[]interface{}{int64(1), int64(2), int64(3)}, []int64{1, 2, 2}, []interface{}{int64(1), int64(2)}}, 429 {[]interface{}{uint(1), uint(2), uint(3)}, []uint{1, 2, 2}, []interface{}{uint(1), uint(2)}}, 430 {[]interface{}{float32(1), float32(2), float32(3)}, []float32{1, 2, 2}, []interface{}{float32(1), float32(2)}}, 431 {[]interface{}{float64(1), float64(2), float64(3)}, []float64{1, 2, 2}, []interface{}{float64(1), float64(2)}}, 432 433 // []T ∩ []interface{} 434 {[]string{"a", "b", "c"}, []interface{}{"a", "b", "b"}, []string{"a", "b"}}, 435 {[]int{1, 2, 3}, []interface{}{1, 2, 2}, []int{1, 2}}, 436 {[]int8{1, 2, 3}, []interface{}{int8(1), int8(2), int8(2)}, []int8{1, 2}}, 437 {[]int16{1, 2, 3}, []interface{}{int16(1), int16(2), int16(2)}, []int16{1, 2}}, 438 {[]int32{1, 2, 3}, []interface{}{int32(1), int32(2), int32(2)}, []int32{1, 2}}, 439 {[]int64{1, 2, 3}, []interface{}{int64(1), int64(2), int64(2)}, []int64{1, 2}}, 440 {[]float32{1, 2, 3}, []interface{}{float32(1), float32(2), float32(2)}, []float32{1, 2}}, 441 {[]float64{1, 2, 3}, []interface{}{float64(1), float64(2), float64(2)}, []float64{1, 2}}, 442 443 // Structs 444 {pagesPtr{p1, p4, p2, p3}, pagesPtr{p4, p2, p2}, pagesPtr{p4, p2}}, 445 {pagesVals{p1v, p4v, p2v, p3v}, pagesVals{p1v, p3v, p3v}, pagesVals{p1v, p3v}}, 446 {[]interface{}{p1, p4, p2, p3}, []interface{}{p4, p2, p2}, []interface{}{p4, p2}}, 447 {[]interface{}{p1v, p4v, p2v, p3v}, []interface{}{p1v, p3v, p3v}, []interface{}{p1v, p3v}}, 448 {pagesPtr{p1, p4, p2, p3}, pagesPtr{}, pagesPtr{}}, 449 {pagesVals{}, pagesVals{p1v, p3v, p3v}, pagesVals{}}, 450 {[]interface{}{p1, p4, p2, p3}, []interface{}{}, []interface{}{}}, 451 {[]interface{}{}, []interface{}{p1v, p3v, p3v}, []interface{}{}}, 452 453 // errors 454 {"not array or slice", []string{"a"}, false}, 455 {[]string{"a"}, "not array or slice", false}, 456 457 // uncomparable types - #3820 458 {[]map[int]int{{1: 1}, {2: 2}}, []map[int]int{{2: 2}, {3: 3}}, false}, 459 {[][]int{{1, 1}, {1, 2}}, [][]int{{1, 2}, {1, 2}, {1, 3}}, false}, 460 {[]int{1, 1}, [][]int{{1, 2}, {1, 2}, {1, 3}}, false}, 461 } { 462 463 errMsg := qt.Commentf("[%d] %v", i, test) 464 465 result, err := ns.Intersect(test.l1, test.l2) 466 467 if b, ok := test.expect.(bool); ok && !b { 468 c.Assert(err, qt.Not(qt.IsNil), errMsg) 469 continue 470 } 471 472 c.Assert(err, qt.IsNil, errMsg) 473 if !reflect.DeepEqual(result, test.expect) { 474 t.Fatalf("[%d] Got\n%v expected\n%v", i, result, test.expect) 475 } 476 } 477 } 478 479 func TestIsSet(t *testing.T) { 480 t.Parallel() 481 c := qt.New(t) 482 ns := newTestNs() 483 484 for i, test := range []struct { 485 a interface{} 486 key interface{} 487 expect bool 488 isErr bool 489 }{ 490 {[]interface{}{1, 2, 3, 5}, 2, true, false}, 491 {[]interface{}{1, 2, 3, 5}, "2", true, false}, 492 {[]interface{}{1, 2, 3, 5}, 2.0, true, false}, 493 494 {[]interface{}{1, 2, 3, 5}, 22, false, false}, 495 496 {map[string]interface{}{"a": 1, "b": 2}, "b", true, false}, 497 {map[string]interface{}{"a": 1, "b": 2}, "bc", false, false}, 498 499 {time.Now(), "Day", false, false}, 500 {nil, "nil", false, false}, 501 {[]interface{}{1, 2, 3, 5}, TstX{}, false, true}, 502 } { 503 errMsg := qt.Commentf("[%d] %v", i, test) 504 505 result, err := ns.IsSet(test.a, test.key) 506 if test.isErr { 507 continue 508 } 509 510 c.Assert(err, qt.IsNil, errMsg) 511 c.Assert(result, qt.Equals, test.expect, errMsg) 512 } 513 } 514 515 func TestLast(t *testing.T) { 516 t.Parallel() 517 c := qt.New(t) 518 519 ns := New(&deps.Deps{}) 520 521 for i, test := range []struct { 522 limit interface{} 523 seq interface{} 524 expect interface{} 525 }{ 526 {int(2), []string{"a", "b", "c"}, []string{"b", "c"}}, 527 {int32(3), []string{"a", "b"}, []string{"a", "b"}}, 528 {int64(2), []int{100, 200, 300}, []int{200, 300}}, 529 {100, []int{100, 200}, []int{100, 200}}, 530 {"1", []int{100, 200, 300}, []int{300}}, 531 {"0", []int{100, 200, 300}, []int{}}, 532 {"0", []string{"a", "b", "c"}, []string{}}, 533 // errors 534 {int64(-1), []int{100, 200, 300}, false}, 535 {"noint", []int{100, 200, 300}, false}, 536 {1, nil, false}, 537 {nil, []int{100}, false}, 538 {1, t, false}, 539 {1, (*string)(nil), false}, 540 } { 541 errMsg := qt.Commentf("[%d] %v", i, test) 542 543 result, err := ns.Last(test.limit, test.seq) 544 545 if b, ok := test.expect.(bool); ok && !b { 546 c.Assert(err, qt.Not(qt.IsNil), errMsg) 547 continue 548 } 549 550 c.Assert(err, qt.IsNil, errMsg) 551 c.Assert(result, qt.DeepEquals, test.expect, errMsg) 552 } 553 } 554 555 func TestQuerify(t *testing.T) { 556 t.Parallel() 557 c := qt.New(t) 558 ns := New(&deps.Deps{}) 559 560 for i, test := range []struct { 561 params []interface{} 562 expect interface{} 563 }{ 564 {[]interface{}{"a", "b"}, "a=b"}, 565 {[]interface{}{"a", "b", "c", "d", "f", " &"}, `a=b&c=d&f=+%26`}, 566 {[]interface{}{[]string{"a", "b"}}, "a=b"}, 567 {[]interface{}{[]string{"a", "b", "c", "d", "f", " &"}}, `a=b&c=d&f=+%26`}, 568 {[]interface{}{[]interface{}{"x", "y"}}, `x=y`}, 569 {[]interface{}{[]interface{}{"x", 5}}, `x=5`}, 570 // errors 571 {[]interface{}{5, "b"}, false}, 572 {[]interface{}{"a", "b", "c"}, false}, 573 {[]interface{}{[]string{"a", "b", "c"}}, false}, 574 {[]interface{}{[]string{"a", "b"}, "c"}, false}, 575 {[]interface{}{[]interface{}{"c", "d", "e"}}, false}, 576 } { 577 errMsg := qt.Commentf("[%d] %v", i, test.params) 578 579 result, err := ns.Querify(test.params...) 580 581 if b, ok := test.expect.(bool); ok && !b { 582 c.Assert(err, qt.Not(qt.IsNil), errMsg) 583 continue 584 } 585 586 c.Assert(err, qt.IsNil, errMsg) 587 c.Assert(result, qt.Equals, test.expect, errMsg) 588 } 589 } 590 591 func BenchmarkQuerify(b *testing.B) { 592 ns := New(&deps.Deps{}) 593 params := []interface{}{"a", "b", "c", "d", "f", " &"} 594 595 b.ResetTimer() 596 for i := 0; i < b.N; i++ { 597 _, err := ns.Querify(params...) 598 if err != nil { 599 b.Fatal(err) 600 } 601 } 602 } 603 604 func BenchmarkQuerifySlice(b *testing.B) { 605 ns := New(&deps.Deps{}) 606 params := []string{"a", "b", "c", "d", "f", " &"} 607 608 b.ResetTimer() 609 for i := 0; i < b.N; i++ { 610 _, err := ns.Querify(params) 611 if err != nil { 612 b.Fatal(err) 613 } 614 } 615 } 616 617 func TestSeq(t *testing.T) { 618 t.Parallel() 619 c := qt.New(t) 620 ns := New(&deps.Deps{}) 621 622 for i, test := range []struct { 623 args []interface{} 624 expect interface{} 625 }{ 626 {[]interface{}{-2, 5}, []int{-2, -1, 0, 1, 2, 3, 4, 5}}, 627 {[]interface{}{1, 2, 4}, []int{1, 3}}, 628 {[]interface{}{1}, []int{1}}, 629 {[]interface{}{3}, []int{1, 2, 3}}, 630 {[]interface{}{3.2}, []int{1, 2, 3}}, 631 {[]interface{}{0}, []int{}}, 632 {[]interface{}{-1}, []int{-1}}, 633 {[]interface{}{-3}, []int{-1, -2, -3}}, 634 {[]interface{}{3, -2}, []int{3, 2, 1, 0, -1, -2}}, 635 {[]interface{}{6, -2, 2}, []int{6, 4, 2}}, 636 // errors 637 {[]interface{}{1, 0, 2}, false}, 638 {[]interface{}{1, -1, 2}, false}, 639 {[]interface{}{2, 1, 1}, false}, 640 {[]interface{}{2, 1, 1, 1}, false}, 641 {[]interface{}{2001}, false}, 642 {[]interface{}{}, false}, 643 {[]interface{}{0, -1000000}, false}, 644 {[]interface{}{tstNoStringer{}}, false}, 645 {nil, false}, 646 } { 647 errMsg := qt.Commentf("[%d] %v", i, test) 648 649 result, err := ns.Seq(test.args...) 650 651 if b, ok := test.expect.(bool); ok && !b { 652 c.Assert(err, qt.Not(qt.IsNil), errMsg) 653 continue 654 } 655 656 c.Assert(err, qt.IsNil, errMsg) 657 c.Assert(result, qt.DeepEquals, test.expect, errMsg) 658 } 659 } 660 661 func TestShuffle(t *testing.T) { 662 t.Parallel() 663 c := qt.New(t) 664 ns := New(&deps.Deps{}) 665 666 for i, test := range []struct { 667 seq interface{} 668 success bool 669 }{ 670 {[]string{"a", "b", "c", "d"}, true}, 671 {[]int{100, 200, 300}, true}, 672 {[]int{100, 200, 300}, true}, 673 {[]int{100, 200}, true}, 674 {[]string{"a", "b"}, true}, 675 {[]int{100, 200, 300}, true}, 676 {[]int{100, 200, 300}, true}, 677 {[]int{100}, true}, 678 // errors 679 {nil, false}, 680 {t, false}, 681 {(*string)(nil), false}, 682 } { 683 errMsg := qt.Commentf("[%d] %v", i, test) 684 685 result, err := ns.Shuffle(test.seq) 686 687 if !test.success { 688 c.Assert(err, qt.Not(qt.IsNil), errMsg) 689 continue 690 } 691 692 c.Assert(err, qt.IsNil, errMsg) 693 694 resultv := reflect.ValueOf(result) 695 seqv := reflect.ValueOf(test.seq) 696 697 c.Assert(seqv.Len(), qt.Equals, resultv.Len(), errMsg) 698 } 699 } 700 701 func TestShuffleRandomising(t *testing.T) { 702 t.Parallel() 703 c := qt.New(t) 704 ns := New(&deps.Deps{}) 705 706 // Note that this test can fail with false negative result if the shuffle 707 // of the sequence happens to be the same as the original sequence. However 708 // the probability of the event is 10^-158 which is negligible. 709 seqLen := 100 710 rand.Seed(time.Now().UTC().UnixNano()) 711 712 for _, test := range []struct { 713 seq []int 714 }{ 715 {rand.Perm(seqLen)}, 716 } { 717 result, err := ns.Shuffle(test.seq) 718 resultv := reflect.ValueOf(result) 719 720 c.Assert(err, qt.IsNil) 721 722 allSame := true 723 for i, v := range test.seq { 724 allSame = allSame && (resultv.Index(i).Interface() == v) 725 } 726 727 c.Assert(allSame, qt.Equals, false) 728 } 729 } 730 731 // Also see tests in commons/collection. 732 func TestSlice(t *testing.T) { 733 t.Parallel() 734 c := qt.New(t) 735 ns := New(&deps.Deps{}) 736 737 for i, test := range []struct { 738 args []interface{} 739 expected interface{} 740 }{ 741 {[]interface{}{"a", "b"}, []string{"a", "b"}}, 742 {[]interface{}{}, []interface{}{}}, 743 {[]interface{}{nil}, []interface{}{nil}}, 744 {[]interface{}{5, "b"}, []interface{}{5, "b"}}, 745 {[]interface{}{tstNoStringer{}}, []tstNoStringer{{}}}, 746 } { 747 errMsg := qt.Commentf("[%d] %v", i, test.args) 748 749 result := ns.Slice(test.args...) 750 751 c.Assert(result, qt.DeepEquals, test.expected, errMsg) 752 } 753 } 754 755 func TestUnion(t *testing.T) { 756 t.Parallel() 757 c := qt.New(t) 758 759 ns := New(&deps.Deps{}) 760 761 for i, test := range []struct { 762 l1 interface{} 763 l2 interface{} 764 expect interface{} 765 isErr bool 766 }{ 767 {nil, nil, []interface{}{}, false}, 768 {nil, []string{"a", "b"}, []string{"a", "b"}, false}, 769 {[]string{"a", "b"}, nil, []string{"a", "b"}, false}, 770 771 // []A ∪ []B 772 {[]string{"1", "2"}, []int{3}, []string{}, false}, 773 {[]int{1, 2}, []string{"1", "2"}, []int{}, false}, 774 775 // []T ∪ []T 776 {[]string{"a", "b", "c", "c"}, []string{"a", "b", "b"}, []string{"a", "b", "c"}, false}, 777 {[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b", "c"}, false}, 778 {[]string{"a", "b", "c"}, []string{"d", "e"}, []string{"a", "b", "c", "d", "e"}, false}, 779 {[]string{}, []string{}, []string{}, false}, 780 {[]int{1, 2, 3}, []int{3, 4, 5}, []int{1, 2, 3, 4, 5}, false}, 781 {[]int{1, 2, 3}, []int{1, 2, 3}, []int{1, 2, 3}, false}, 782 {[]int{1, 2, 4}, []int{2, 4}, []int{1, 2, 4}, false}, 783 {[]int{2, 4}, []int{1, 2, 4}, []int{2, 4, 1}, false}, 784 {[]int{1, 2, 4}, []int{3, 6}, []int{1, 2, 4, 3, 6}, false}, 785 {[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false}, 786 {[]interface{}{"a", "b", "c", "c"}, []interface{}{"a", "b", "b"}, []interface{}{"a", "b", "c"}, false}, 787 788 // []T ∪ []interface{} 789 {[]string{"1", "2"}, []interface{}{"9"}, []string{"1", "2", "9"}, false}, 790 {[]int{2, 4}, []interface{}{1, 2, 4}, []int{2, 4, 1}, false}, 791 {[]int8{2, 4}, []interface{}{int8(1), int8(2), int8(4)}, []int8{2, 4, 1}, false}, 792 {[]int8{2, 4}, []interface{}{1, 2, 4}, []int8{2, 4, 1}, false}, 793 {[]int16{2, 4}, []interface{}{1, 2, 4}, []int16{2, 4, 1}, false}, 794 {[]int32{2, 4}, []interface{}{1, 2, 4}, []int32{2, 4, 1}, false}, 795 {[]int64{2, 4}, []interface{}{1, 2, 4}, []int64{2, 4, 1}, false}, 796 797 {[]float64{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float64{2.2, 4.4, 1.1}, false}, 798 {[]float32{2.2, 4.4}, []interface{}{1.1, 2.2, 4.4}, []float32{2.2, 4.4, 1.1}, false}, 799 800 // []interface{} ∪ []T 801 {[]interface{}{"a", "b", "c", "c"}, []string{"a", "b", "d"}, []interface{}{"a", "b", "c", "d"}, false}, 802 {[]interface{}{}, []string{}, []interface{}{}, false}, 803 {[]interface{}{1, 2}, []int{2, 3}, []interface{}{1, 2, 3}, false}, 804 {[]interface{}{1, 2}, []int8{2, 3}, []interface{}{1, 2, 3}, false}, // 28 805 {[]interface{}{uint(1), uint(2)}, []uint{2, 3}, []interface{}{uint(1), uint(2), uint(3)}, false}, 806 {[]interface{}{1.1, 2.2}, []float64{2.2, 3.3}, []interface{}{1.1, 2.2, 3.3}, false}, 807 808 // Structs 809 {pagesPtr{p1, p4}, pagesPtr{p4, p2, p2}, pagesPtr{p1, p4, p2}, false}, 810 {pagesVals{p1v}, pagesVals{p3v, p3v}, pagesVals{p1v, p3v}, false}, 811 {[]interface{}{p1, p4}, []interface{}{p4, p2, p2}, []interface{}{p1, p4, p2}, false}, 812 {[]interface{}{p1v}, []interface{}{p3v, p3v}, []interface{}{p1v, p3v}, false}, 813 // #3686 814 {[]interface{}{p1v}, []interface{}{}, []interface{}{p1v}, false}, 815 {[]interface{}{}, []interface{}{p1v}, []interface{}{p1v}, false}, 816 {pagesPtr{p1}, pagesPtr{}, pagesPtr{p1}, false}, 817 {pagesVals{p1v}, pagesVals{}, pagesVals{p1v}, false}, 818 {pagesPtr{}, pagesPtr{p1}, pagesPtr{p1}, false}, 819 {pagesVals{}, pagesVals{p1v}, pagesVals{p1v}, false}, 820 821 // errors 822 {"not array or slice", []string{"a"}, false, true}, 823 {[]string{"a"}, "not array or slice", false, true}, 824 825 // uncomparable types - #3820 826 {[]map[string]int{{"K1": 1}}, []map[string]int{{"K2": 2}, {"K2": 2}}, false, true}, 827 {[][]int{{1, 1}, {1, 2}}, [][]int{{2, 1}, {2, 2}}, false, true}, 828 } { 829 830 errMsg := qt.Commentf("[%d] %v", i, test) 831 832 result, err := ns.Union(test.l1, test.l2) 833 if test.isErr { 834 c.Assert(err, qt.Not(qt.IsNil), errMsg) 835 continue 836 } 837 838 c.Assert(err, qt.IsNil, errMsg) 839 if !reflect.DeepEqual(result, test.expect) { 840 t.Fatalf("[%d] Got\n%v expected\n%v", i, result, test.expect) 841 } 842 } 843 } 844 845 func TestUniq(t *testing.T) { 846 t.Parallel() 847 c := qt.New(t) 848 ns := New(&deps.Deps{}) 849 for i, test := range []struct { 850 l interface{} 851 expect interface{} 852 isErr bool 853 }{ 854 {[]string{"a", "b", "c"}, []string{"a", "b", "c"}, false}, 855 {[]string{"a", "b", "c", "c"}, []string{"a", "b", "c"}, false}, 856 {[]string{"a", "b", "b", "c"}, []string{"a", "b", "c"}, false}, 857 {[]string{"a", "b", "c", "b"}, []string{"a", "b", "c"}, false}, 858 {[]int{1, 2, 3}, []int{1, 2, 3}, false}, 859 {[]int{1, 2, 3, 3}, []int{1, 2, 3}, false}, 860 {[]int{1, 2, 2, 3}, []int{1, 2, 3}, false}, 861 {[]int{1, 2, 3, 2}, []int{1, 2, 3}, false}, 862 {[4]int{1, 2, 3, 2}, []int{1, 2, 3}, false}, 863 {nil, make([]interface{}, 0), false}, 864 // Pointers 865 {pagesPtr{p1, p2, p3, p2}, pagesPtr{p1, p2, p3}, false}, 866 {pagesPtr{}, pagesPtr{}, false}, 867 // Structs 868 {pagesVals{p3v, p2v, p3v, p2v}, pagesVals{p3v, p2v}, false}, 869 870 // not Comparable(), use hashstructure 871 {[]map[string]int{ 872 {"K1": 1}, {"K2": 2}, {"K1": 1}, {"K2": 1}, 873 }, []map[string]int{ 874 {"K1": 1}, {"K2": 2}, {"K2": 1}, 875 }, false}, 876 877 // should fail 878 {1, 1, true}, 879 {"foo", "fo", true}, 880 } { 881 errMsg := qt.Commentf("[%d] %v", i, test) 882 883 result, err := ns.Uniq(test.l) 884 if test.isErr { 885 c.Assert(err, qt.Not(qt.IsNil), errMsg) 886 continue 887 } 888 889 c.Assert(err, qt.IsNil, errMsg) 890 c.Assert(result, qt.DeepEquals, test.expect, errMsg) 891 } 892 } 893 894 func (x *TstX) TstRp() string { 895 return "r" + x.A 896 } 897 898 func (x TstX) TstRv() string { 899 return "r" + x.B 900 } 901 902 func (x TstX) TstRv2() string { 903 return "r" + x.B 904 } 905 906 func (x TstX) unexportedMethod() string { 907 return x.unexported 908 } 909 910 func (x TstX) MethodWithArg(s string) string { 911 return s 912 } 913 914 func (x TstX) MethodReturnNothing() {} 915 916 func (x TstX) MethodReturnErrorOnly() error { 917 return errors.New("some error occurred") 918 } 919 920 func (x TstX) MethodReturnTwoValues() (string, string) { 921 return "foo", "bar" 922 } 923 924 func (x TstX) MethodReturnValueWithError() (string, error) { 925 return "", errors.New("some error occurred") 926 } 927 928 func (x TstX) String() string { 929 return fmt.Sprintf("A: %s, B: %s", x.A, x.B) 930 } 931 932 type TstX struct { 933 A, B string 934 unexported string 935 } 936 937 type TstParams struct { 938 params maps.Params 939 } 940 941 func (x TstParams) Params() maps.Params { 942 return x.params 943 } 944 945 type TstXIHolder struct { 946 XI TstXI 947 } 948 949 // Partially implemented by the TstX struct. 950 type TstXI interface { 951 TstRv2() string 952 } 953 954 func ToTstXIs(slice interface{}) []TstXI { 955 s := reflect.ValueOf(slice) 956 if s.Kind() != reflect.Slice { 957 return nil 958 } 959 tis := make([]TstXI, s.Len()) 960 961 for i := 0; i < s.Len(); i++ { 962 tsti, ok := s.Index(i).Interface().(TstXI) 963 if !ok { 964 return nil 965 } 966 tis[i] = tsti 967 } 968 969 return tis 970 } 971 972 func newDeps(cfg config.Provider) *deps.Deps { 973 l := langs.NewLanguage("en", cfg) 974 l.Set("i18nDir", "i18n") 975 cs, err := helpers.NewContentSpec(l, loggers.NewErrorLogger(), afero.NewMemMapFs(), nil) 976 if err != nil { 977 panic(err) 978 } 979 return &deps.Deps{ 980 Cfg: cfg, 981 Fs: hugofs.NewMem(l), 982 ContentSpec: cs, 983 Log: loggers.NewErrorLogger(), 984 } 985 } 986 987 func newTestNs() *Namespace { 988 v := config.New() 989 v.Set("contentDir", "content") 990 return New(newDeps(v)) 991 }