strings_test.go (16385B)
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 strings
15
16 import (
17 "html/template"
18 "testing"
19
20 "github.com/gohugoio/hugo/config"
21 "github.com/gohugoio/hugo/deps"
22
23 qt "github.com/frankban/quicktest"
24 "github.com/spf13/cast"
25 )
26
27 var ns = New(&deps.Deps{Cfg: config.New()})
28
29 type tstNoStringer struct{}
30
31 func TestChomp(t *testing.T) {
32 t.Parallel()
33 c := qt.New(t)
34
35 for _, test := range []struct {
36 s any
37 expect any
38 }{
39 {"\n a\n", "\n a"},
40 {"\n a\n\n", "\n a"},
41 {"\n a\r\n", "\n a"},
42 {"\n a\n\r\n", "\n a"},
43 {"\n a\r\r", "\n a"},
44 {"\n a\r", "\n a"},
45 // errors
46 {tstNoStringer{}, false},
47 } {
48
49 result, err := ns.Chomp(test.s)
50
51 if b, ok := test.expect.(bool); ok && !b {
52 c.Assert(err, qt.Not(qt.IsNil))
53 continue
54 }
55
56 c.Assert(err, qt.IsNil)
57 c.Assert(result, qt.Equals, test.expect)
58
59 // repeat the check with template.HTML input
60 result, err = ns.Chomp(template.HTML(cast.ToString(test.s)))
61 c.Assert(err, qt.IsNil)
62 c.Assert(result, qt.Equals, template.HTML(cast.ToString(test.expect)))
63 }
64 }
65
66 func TestContains(t *testing.T) {
67 t.Parallel()
68 c := qt.New(t)
69
70 for _, test := range []struct {
71 s any
72 substr any
73 expect bool
74 isErr bool
75 }{
76 {"", "", true, false},
77 {"123", "23", true, false},
78 {"123", "234", false, false},
79 {"123", "", true, false},
80 {"", "a", false, false},
81 {123, "23", true, false},
82 {123, "234", false, false},
83 {123, "", true, false},
84 {template.HTML("123"), []byte("23"), true, false},
85 {template.HTML("123"), []byte("234"), false, false},
86 {template.HTML("123"), []byte(""), true, false},
87 // errors
88 {"", tstNoStringer{}, false, true},
89 {tstNoStringer{}, "", false, true},
90 } {
91
92 result, err := ns.Contains(test.s, test.substr)
93
94 if test.isErr {
95 c.Assert(err, qt.Not(qt.IsNil))
96 continue
97 }
98
99 c.Assert(err, qt.IsNil)
100 c.Assert(result, qt.Equals, test.expect)
101 }
102 }
103
104 func TestContainsAny(t *testing.T) {
105 t.Parallel()
106 c := qt.New(t)
107
108 for _, test := range []struct {
109 s any
110 substr any
111 expect bool
112 isErr bool
113 }{
114 {"", "", false, false},
115 {"", "1", false, false},
116 {"", "123", false, false},
117 {"1", "", false, false},
118 {"1", "1", true, false},
119 {"111", "1", true, false},
120 {"123", "789", false, false},
121 {"123", "729", true, false},
122 {"a☺b☻c☹d", "uvw☻xyz", true, false},
123 {1, "", false, false},
124 {1, "1", true, false},
125 {111, "1", true, false},
126 {123, "789", false, false},
127 {123, "729", true, false},
128 {[]byte("123"), template.HTML("789"), false, false},
129 {[]byte("123"), template.HTML("729"), true, false},
130 {[]byte("a☺b☻c☹d"), template.HTML("uvw☻xyz"), true, false},
131 // errors
132 {"", tstNoStringer{}, false, true},
133 {tstNoStringer{}, "", false, true},
134 } {
135
136 result, err := ns.ContainsAny(test.s, test.substr)
137
138 if test.isErr {
139 c.Assert(err, qt.Not(qt.IsNil))
140 continue
141 }
142
143 c.Assert(err, qt.IsNil)
144 c.Assert(result, qt.Equals, test.expect)
145 }
146 }
147
148 func TestCountRunes(t *testing.T) {
149 t.Parallel()
150 c := qt.New(t)
151
152 for _, test := range []struct {
153 s any
154 expect any
155 }{
156 {"foo bar", 6},
157 {"旁边", 2},
158 {`<div class="test">旁边</div>`, 2},
159 // errors
160 {tstNoStringer{}, false},
161 } {
162
163 result, err := ns.CountRunes(test.s)
164
165 if b, ok := test.expect.(bool); ok && !b {
166 c.Assert(err, qt.Not(qt.IsNil))
167 continue
168 }
169
170 c.Assert(err, qt.IsNil)
171 c.Assert(result, qt.Equals, test.expect)
172 }
173 }
174
175 func TestRuneCount(t *testing.T) {
176 t.Parallel()
177 c := qt.New(t)
178
179 for _, test := range []struct {
180 s any
181 expect any
182 }{
183 {"foo bar", 7},
184 {"旁边", 2},
185 {`<div class="test">旁边</div>`, 26},
186 // errors
187 {tstNoStringer{}, false},
188 } {
189
190 result, err := ns.RuneCount(test.s)
191
192 if b, ok := test.expect.(bool); ok && !b {
193 c.Assert(err, qt.Not(qt.IsNil))
194 continue
195 }
196
197 c.Assert(err, qt.IsNil)
198 c.Assert(result, qt.Equals, test.expect)
199 }
200 }
201
202 func TestCountWords(t *testing.T) {
203 t.Parallel()
204 c := qt.New(t)
205
206 for _, test := range []struct {
207 s any
208 expect any
209 }{
210 {"Do Be Do Be Do", 5},
211 {"旁边", 2},
212 {`<div class="test">旁边</div>`, 2},
213 {"Here's to you...", 3},
214 {"Here’s to you...", 3},
215 {"Here’s to you…", 3},
216 // errors
217 {tstNoStringer{}, false},
218 } {
219
220 result, err := ns.CountWords(test.s)
221
222 if b, ok := test.expect.(bool); ok && !b {
223 c.Assert(err, qt.Not(qt.IsNil))
224 continue
225 }
226
227 c.Assert(err, qt.IsNil)
228 c.Assert(result, qt.Equals, test.expect)
229 }
230 }
231
232 func TestHasPrefix(t *testing.T) {
233 t.Parallel()
234 c := qt.New(t)
235
236 for _, test := range []struct {
237 s any
238 prefix any
239 expect any
240 isErr bool
241 }{
242 {"abcd", "ab", true, false},
243 {"abcd", "cd", false, false},
244 {template.HTML("abcd"), "ab", true, false},
245 {template.HTML("abcd"), "cd", false, false},
246 {template.HTML("1234"), 12, true, false},
247 {template.HTML("1234"), 34, false, false},
248 {[]byte("abcd"), "ab", true, false},
249 // errors
250 {"", tstNoStringer{}, false, true},
251 {tstNoStringer{}, "", false, true},
252 } {
253
254 result, err := ns.HasPrefix(test.s, test.prefix)
255
256 if test.isErr {
257 c.Assert(err, qt.Not(qt.IsNil))
258 continue
259 }
260
261 c.Assert(err, qt.IsNil)
262 c.Assert(result, qt.Equals, test.expect)
263 }
264 }
265
266 func TestHasSuffix(t *testing.T) {
267 t.Parallel()
268 c := qt.New(t)
269
270 for _, test := range []struct {
271 s any
272 suffix any
273 expect any
274 isErr bool
275 }{
276 {"abcd", "cd", true, false},
277 {"abcd", "ab", false, false},
278 {template.HTML("abcd"), "cd", true, false},
279 {template.HTML("abcd"), "ab", false, false},
280 {template.HTML("1234"), 34, true, false},
281 {template.HTML("1234"), 12, false, false},
282 {[]byte("abcd"), "cd", true, false},
283 // errors
284 {"", tstNoStringer{}, false, true},
285 {tstNoStringer{}, "", false, true},
286 } {
287
288 result, err := ns.HasSuffix(test.s, test.suffix)
289
290 if test.isErr {
291 c.Assert(err, qt.Not(qt.IsNil))
292 continue
293 }
294
295 c.Assert(err, qt.IsNil)
296 c.Assert(result, qt.Equals, test.expect)
297 }
298 }
299
300 func TestReplace(t *testing.T) {
301 t.Parallel()
302 c := qt.New(t)
303
304 for _, test := range []struct {
305 s any
306 old any
307 new any
308 limit any
309 expect any
310 }{
311 {"aab", "a", "b", nil, "bbb"},
312 {"11a11", 1, 2, nil, "22a22"},
313 {12345, 1, 2, nil, "22345"},
314 {"aab", "a", "b", 1, "bab"},
315 {"11a11", 1, 2, 2, "22a11"},
316 // errors
317 {tstNoStringer{}, "a", "b", nil, false},
318 {"a", tstNoStringer{}, "b", nil, false},
319 {"a", "b", tstNoStringer{}, nil, false},
320 } {
321
322 var (
323 result string
324 err error
325 )
326
327 if test.limit != nil {
328 result, err = ns.Replace(test.s, test.old, test.new, test.limit)
329 } else {
330 result, err = ns.Replace(test.s, test.old, test.new)
331 }
332
333 if b, ok := test.expect.(bool); ok && !b {
334 c.Assert(err, qt.Not(qt.IsNil))
335 continue
336 }
337
338 c.Assert(err, qt.IsNil)
339 c.Assert(result, qt.Equals, test.expect)
340 }
341 }
342
343 func TestSliceString(t *testing.T) {
344 t.Parallel()
345 c := qt.New(t)
346
347 var err error
348 for _, test := range []struct {
349 v1 any
350 v2 any
351 v3 any
352 expect any
353 }{
354 {"abc", 1, 2, "b"},
355 {"abc", 1, 3, "bc"},
356 {"abcdef", 1, int8(3), "bc"},
357 {"abcdef", 1, int16(3), "bc"},
358 {"abcdef", 1, int32(3), "bc"},
359 {"abcdef", 1, int64(3), "bc"},
360 {"abc", 0, 1, "a"},
361 {"abcdef", nil, nil, "abcdef"},
362 {"abcdef", 0, 6, "abcdef"},
363 {"abcdef", 0, 2, "ab"},
364 {"abcdef", 2, nil, "cdef"},
365 {"abcdef", int8(2), nil, "cdef"},
366 {"abcdef", int16(2), nil, "cdef"},
367 {"abcdef", int32(2), nil, "cdef"},
368 {"abcdef", int64(2), nil, "cdef"},
369 {123, 1, 3, "23"},
370 {"abcdef", 6, nil, false},
371 {"abcdef", 4, 7, false},
372 {"abcdef", -1, nil, false},
373 {"abcdef", -1, 7, false},
374 {"abcdef", 1, -1, false},
375 {tstNoStringer{}, 0, 1, false},
376 {"ĀĀĀ", 0, 1, "Ā"}, // issue #1333
377 {"a", t, nil, false},
378 {"a", 1, t, false},
379 } {
380
381 var result string
382 if test.v2 == nil {
383 result, err = ns.SliceString(test.v1)
384 } else if test.v3 == nil {
385 result, err = ns.SliceString(test.v1, test.v2)
386 } else {
387 result, err = ns.SliceString(test.v1, test.v2, test.v3)
388 }
389
390 if b, ok := test.expect.(bool); ok && !b {
391 c.Assert(err, qt.Not(qt.IsNil))
392 continue
393 }
394
395 c.Assert(err, qt.IsNil)
396 c.Assert(result, qt.Equals, test.expect)
397 }
398
399 // Too many arguments
400 _, err = ns.SliceString("a", 1, 2, 3)
401 if err == nil {
402 t.Errorf("Should have errored")
403 }
404 }
405
406 func TestSplit(t *testing.T) {
407 t.Parallel()
408 c := qt.New(t)
409
410 for _, test := range []struct {
411 v1 any
412 v2 string
413 expect any
414 }{
415 {"a, b", ", ", []string{"a", "b"}},
416 {"a & b & c", " & ", []string{"a", "b", "c"}},
417 {"http://example.com", "http://", []string{"", "example.com"}},
418 {123, "2", []string{"1", "3"}},
419 {tstNoStringer{}, ",", false},
420 } {
421
422 result, err := ns.Split(test.v1, test.v2)
423
424 if b, ok := test.expect.(bool); ok && !b {
425 c.Assert(err, qt.Not(qt.IsNil))
426 continue
427 }
428
429 c.Assert(err, qt.IsNil)
430 c.Assert(result, qt.DeepEquals, test.expect)
431 }
432 }
433
434 func TestSubstr(t *testing.T) {
435 t.Parallel()
436 c := qt.New(t)
437
438 var err error
439 for _, test := range []struct {
440 v1 any
441 v2 any
442 v3 any
443 expect any
444 }{
445 {"abc", 1, 2, "bc"},
446 {"abc", 0, 1, "a"},
447 {"abcdef", 0, 0, ""},
448 {"abcdef", 1, 0, ""},
449 {"abcdef", -1, 0, ""},
450 {"abcdef", -1, 2, "f"},
451 {"abcdef", -3, 3, "def"},
452 {"abcdef", -1, nil, "f"},
453 {"abcdef", -2, nil, "ef"},
454 {"abcdef", -3, 1, "d"},
455 {"abcdef", 0, -1, "abcde"},
456 {"abcdef", 2, -1, "cde"},
457 {"abcdef", 4, -4, ""},
458 {"abcdef", 7, 1, ""},
459 {"abcdef", 6, nil, ""},
460 {"abcdef", 1, 100, "bcdef"},
461 {"abcdef", -100, 3, "abc"},
462 {"abcdef", -3, -1, "de"},
463 {"abcdef", 2, nil, "cdef"},
464 {"abcdef", int8(2), nil, "cdef"},
465 {"abcdef", int16(2), nil, "cdef"},
466 {"abcdef", int32(2), nil, "cdef"},
467 {"abcdef", int64(2), nil, "cdef"},
468 {"abcdef", 2, int8(3), "cde"},
469 {"abcdef", 2, int16(3), "cde"},
470 {"abcdef", 2, int32(3), "cde"},
471 {"abcdef", 2, int64(3), "cde"},
472 {123, 1, 3, "23"},
473 {1.2e3, 0, 4, "1200"},
474 {tstNoStringer{}, 0, 1, false},
475 {"abcdef", 2.0, nil, "cdef"},
476 {"abcdef", 2.0, 2, "cd"},
477 {"abcdef", 2, 2.0, "cd"},
478 {"ĀĀĀ", 1, 2, "ĀĀ"}, // # issue 1333
479 {"abcdef", "doo", nil, false},
480 {"abcdef", "doo", "doo", false},
481 {"abcdef", 1, "doo", false},
482 {"", 0, nil, ""},
483 } {
484
485 var result string
486
487 if test.v3 == nil {
488 result, err = ns.Substr(test.v1, test.v2)
489 } else {
490 result, err = ns.Substr(test.v1, test.v2, test.v3)
491 }
492
493 if b, ok := test.expect.(bool); ok && !b {
494 c.Check(err, qt.Not(qt.IsNil), qt.Commentf("%v", test))
495 continue
496 }
497
498 c.Assert(err, qt.IsNil, qt.Commentf("%v", test))
499 c.Check(result, qt.Equals, test.expect, qt.Commentf("%v", test))
500 }
501
502 _, err = ns.Substr("abcdef")
503 c.Assert(err, qt.Not(qt.IsNil))
504
505 _, err = ns.Substr("abcdef", 1, 2, 3)
506 c.Assert(err, qt.Not(qt.IsNil))
507 }
508
509 func TestTitle(t *testing.T) {
510 t.Parallel()
511 c := qt.New(t)
512
513 for _, test := range []struct {
514 s any
515 expect any
516 }{
517 {"test", "Test"},
518 {template.HTML("hypertext"), "Hypertext"},
519 {[]byte("bytes"), "Bytes"},
520 // errors
521 {tstNoStringer{}, false},
522 } {
523
524 result, err := ns.Title(test.s)
525
526 if b, ok := test.expect.(bool); ok && !b {
527 c.Assert(err, qt.Not(qt.IsNil))
528 continue
529 }
530
531 c.Assert(err, qt.IsNil)
532 c.Assert(result, qt.Equals, test.expect)
533 }
534 }
535
536 func TestToLower(t *testing.T) {
537 t.Parallel()
538 c := qt.New(t)
539
540 for _, test := range []struct {
541 s any
542 expect any
543 }{
544 {"TEST", "test"},
545 {template.HTML("LoWeR"), "lower"},
546 {[]byte("BYTES"), "bytes"},
547 // errors
548 {tstNoStringer{}, false},
549 } {
550
551 result, err := ns.ToLower(test.s)
552
553 if b, ok := test.expect.(bool); ok && !b {
554 c.Assert(err, qt.Not(qt.IsNil))
555 continue
556 }
557
558 c.Assert(err, qt.IsNil)
559 c.Assert(result, qt.Equals, test.expect)
560 }
561 }
562
563 func TestToUpper(t *testing.T) {
564 t.Parallel()
565 c := qt.New(t)
566
567 for _, test := range []struct {
568 s any
569 expect any
570 }{
571 {"test", "TEST"},
572 {template.HTML("UpPeR"), "UPPER"},
573 {[]byte("bytes"), "BYTES"},
574 // errors
575 {tstNoStringer{}, false},
576 } {
577
578 result, err := ns.ToUpper(test.s)
579
580 if b, ok := test.expect.(bool); ok && !b {
581 c.Assert(err, qt.Not(qt.IsNil))
582 continue
583 }
584
585 c.Assert(err, qt.IsNil)
586 c.Assert(result, qt.Equals, test.expect)
587 }
588 }
589
590 func TestTrim(t *testing.T) {
591 t.Parallel()
592 c := qt.New(t)
593
594 for _, test := range []struct {
595 s any
596 cutset any
597 expect any
598 }{
599 {"abba", "a", "bb"},
600 {"abba", "ab", ""},
601 {"<tag>", "<>", "tag"},
602 {`"quote"`, `"`, "quote"},
603 {1221, "1", "22"},
604 {1221, "12", ""},
605 {template.HTML("<tag>"), "<>", "tag"},
606 {[]byte("<tag>"), "<>", "tag"},
607 // errors
608 {"", tstNoStringer{}, false},
609 {tstNoStringer{}, "", false},
610 } {
611
612 result, err := ns.Trim(test.s, test.cutset)
613
614 if b, ok := test.expect.(bool); ok && !b {
615 c.Assert(err, qt.Not(qt.IsNil))
616 continue
617 }
618
619 c.Assert(err, qt.IsNil)
620 c.Assert(result, qt.Equals, test.expect)
621 }
622 }
623
624 func TestTrimLeft(t *testing.T) {
625 t.Parallel()
626 c := qt.New(t)
627
628 for _, test := range []struct {
629 s any
630 cutset any
631 expect any
632 }{
633 {"abba", "a", "bba"},
634 {"abba", "ab", ""},
635 {"<tag>", "<>", "tag>"},
636 {`"quote"`, `"`, `quote"`},
637 {1221, "1", "221"},
638 {1221, "12", ""},
639 {"007", "0", "7"},
640 {template.HTML("<tag>"), "<>", "tag>"},
641 {[]byte("<tag>"), "<>", "tag>"},
642 // errors
643 {"", tstNoStringer{}, false},
644 {tstNoStringer{}, "", false},
645 } {
646
647 result, err := ns.TrimLeft(test.cutset, test.s)
648
649 if b, ok := test.expect.(bool); ok && !b {
650 c.Assert(err, qt.Not(qt.IsNil))
651 continue
652 }
653
654 c.Assert(err, qt.IsNil)
655 c.Assert(result, qt.Equals, test.expect)
656 }
657 }
658
659 func TestTrimPrefix(t *testing.T) {
660 t.Parallel()
661 c := qt.New(t)
662
663 for _, test := range []struct {
664 s any
665 prefix any
666 expect any
667 }{
668 {"aabbaa", "a", "abbaa"},
669 {"aabb", "b", "aabb"},
670 {1234, "12", "34"},
671 {1234, "34", "1234"},
672 // errors
673 {"", tstNoStringer{}, false},
674 {tstNoStringer{}, "", false},
675 } {
676
677 result, err := ns.TrimPrefix(test.prefix, test.s)
678
679 if b, ok := test.expect.(bool); ok && !b {
680 c.Assert(err, qt.Not(qt.IsNil))
681 continue
682 }
683
684 c.Assert(err, qt.IsNil)
685 c.Assert(result, qt.Equals, test.expect)
686 }
687 }
688
689 func TestTrimRight(t *testing.T) {
690 t.Parallel()
691 c := qt.New(t)
692
693 for _, test := range []struct {
694 s any
695 cutset any
696 expect any
697 }{
698 {"abba", "a", "abb"},
699 {"abba", "ab", ""},
700 {"<tag>", "<>", "<tag"},
701 {`"quote"`, `"`, `"quote`},
702 {1221, "1", "122"},
703 {1221, "12", ""},
704 {"007", "0", "007"},
705 {template.HTML("<tag>"), "<>", "<tag"},
706 {[]byte("<tag>"), "<>", "<tag"},
707 // errors
708 {"", tstNoStringer{}, false},
709 {tstNoStringer{}, "", false},
710 } {
711
712 result, err := ns.TrimRight(test.cutset, test.s)
713
714 if b, ok := test.expect.(bool); ok && !b {
715 c.Assert(err, qt.Not(qt.IsNil))
716 continue
717 }
718
719 c.Assert(err, qt.IsNil)
720 c.Assert(result, qt.Equals, test.expect)
721 }
722 }
723
724 func TestTrimSuffix(t *testing.T) {
725 t.Parallel()
726 c := qt.New(t)
727
728 for _, test := range []struct {
729 s any
730 suffix any
731 expect any
732 }{
733 {"aabbaa", "a", "aabba"},
734 {"aabb", "b", "aab"},
735 {1234, "12", "1234"},
736 {1234, "34", "12"},
737 // errors
738 {"", tstNoStringer{}, false},
739 {tstNoStringer{}, "", false},
740 } {
741
742 result, err := ns.TrimSuffix(test.suffix, test.s)
743
744 if b, ok := test.expect.(bool); ok && !b {
745 c.Assert(err, qt.Not(qt.IsNil))
746 continue
747 }
748
749 c.Assert(err, qt.IsNil)
750 c.Assert(result, qt.Equals, test.expect)
751 }
752 }
753
754 func TestRepeat(t *testing.T) {
755 t.Parallel()
756 c := qt.New(t)
757
758 for _, test := range []struct {
759 s any
760 n any
761 expect any
762 }{
763 {"yo", "2", "yoyo"},
764 {"~", "16", "~~~~~~~~~~~~~~~~"},
765 {"<tag>", "0", ""},
766 {"yay", "1", "yay"},
767 {1221, "1", "1221"},
768 {1221, 2, "12211221"},
769 {template.HTML("<tag>"), "2", "<tag><tag>"},
770 {[]byte("<tag>"), 2, "<tag><tag>"},
771 // errors
772 {"", tstNoStringer{}, false},
773 {tstNoStringer{}, "", false},
774 {"ab", -1, false},
775 } {
776
777 result, err := ns.Repeat(test.n, test.s)
778
779 if b, ok := test.expect.(bool); ok && !b {
780 c.Assert(err, qt.Not(qt.IsNil))
781 continue
782 }
783
784 c.Assert(err, qt.IsNil)
785 c.Assert(result, qt.Equals, test.expect)
786 }
787 }