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