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 }