1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 func eq(a
, b
[]string) bool {
19 for i
:= 0; i
< len(a
); i
++ {
29 var commas
= "1,2,3,4"
30 var dots
= "1....2....3....4"
32 type IndexTest
struct {
38 var indexTests
= []IndexTest
{
44 {"oofofoofooo", "f", 2},
45 {"oofofoofooo", "foo", 4},
46 {"barfoobarfoo", "foo", 3},
49 {"abcABCabc", "A", 3},
50 // cases with one byte strings - test special case in Index()
60 var lastIndexTests
= []IndexTest
{
67 {"oofofoofooo", "f", 7},
68 {"oofofoofooo", "foo", 7},
69 {"barfoobarfoo", "foo", 9},
72 {"abcABCabc", "A", 3},
73 {"abcABCabc", "a", 6},
76 var indexAnyTests
= []IndexTest
{
85 {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
86 {"aRegExp*", ".(|)*+?^$[]", 7},
87 {dots
+ dots
+ dots
, " ", -1},
90 // Execute f on each test case. funcName should be the name of f; it's used
91 // in failure reports.
92 func runIndexTests(t
*testing
.T
, f
func(s
, sep
string) int, funcName
string, testCases
[]IndexTest
) {
93 for _
, test
:= range testCases
{
94 actual
:= f(test
.s
, test
.sep
)
95 if actual
!= test
.out
{
96 t
.Errorf("%s(%q,%q) = %v; want %v", funcName
, test
.s
, test
.sep
, actual
, test
.out
)
101 func TestIndex(t
*testing
.T
) { runIndexTests(t
, Index
, "Index", indexTests
) }
102 func TestLastIndex(t
*testing
.T
) { runIndexTests(t
, LastIndex
, "LastIndex", lastIndexTests
) }
103 func TestIndexAny(t
*testing
.T
) { runIndexTests(t
, IndexAny
, "IndexAny", indexAnyTests
) }
105 type ExplodeTest
struct {
111 var explodetests
= []ExplodeTest
{
112 {"", -1, []string{}},
113 {abcd
, 4, []string{"a", "b", "c", "d"}},
114 {faces
, 3, []string{"☺", "☻", "☹"}},
115 {abcd
, 2, []string{"a", "bcd"}},
118 func TestExplode(t
*testing
.T
) {
119 for _
, tt
:= range explodetests
{
120 a
:= Split(tt
.s
, "", tt
.n
)
122 t
.Errorf("explode(%q, %d) = %v; want %v", tt
.s
, tt
.n
, a
, tt
.a
)
127 t
.Errorf(`Join(explode(%q, %d), "") = %q`, tt
.s
, tt
.n
, s
)
132 type SplitTest
struct {
139 var splittests
= []SplitTest
{
141 {abcd
, "a", -1, []string{"", "bcd"}},
142 {abcd
, "z", -1, []string{"abcd"}},
143 {abcd
, "", -1, []string{"a", "b", "c", "d"}},
144 {commas
, ",", -1, []string{"1", "2", "3", "4"}},
145 {dots
, "...", -1, []string{"1", ".2", ".3", ".4"}},
146 {faces
, "☹", -1, []string{"☺☻", ""}},
147 {faces
, "~", -1, []string{faces
}},
148 {faces
, "", -1, []string{"☺", "☻", "☹"}},
149 {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
150 {"1 2", " ", 3, []string{"1", "2"}},
151 {"123", "", 2, []string{"1", "23"}},
152 {"123", "", 17, []string{"1", "2", "3"}},
155 func TestSplit(t
*testing
.T
) {
156 for _
, tt
:= range splittests
{
157 a
:= Split(tt
.s
, tt
.sep
, tt
.n
)
159 t
.Errorf("Split(%q, %q, %d) = %v; want %v", tt
.s
, tt
.sep
, tt
.n
, a
, tt
.a
)
167 t
.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt
.s
, tt
.sep
, tt
.n
, tt
.sep
, s
)
172 var splitaftertests
= []SplitTest
{
173 {abcd
, "a", -1, []string{"a", "bcd"}},
174 {abcd
, "z", -1, []string{"abcd"}},
175 {abcd
, "", -1, []string{"a", "b", "c", "d"}},
176 {commas
, ",", -1, []string{"1,", "2,", "3,", "4"}},
177 {dots
, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
178 {faces
, "☹", -1, []string{"☺☻☹", ""}},
179 {faces
, "~", -1, []string{faces
}},
180 {faces
, "", -1, []string{"☺", "☻", "☹"}},
181 {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
182 {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
183 {"1 2", " ", 3, []string{"1 ", "2"}},
184 {"123", "", 2, []string{"1", "23"}},
185 {"123", "", 17, []string{"1", "2", "3"}},
188 func TestSplitAfter(t
*testing
.T
) {
189 for _
, tt
:= range splitaftertests
{
190 a
:= SplitAfter(tt
.s
, tt
.sep
, tt
.n
)
192 t
.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt
.s
, tt
.sep
, tt
.n
, a
, tt
.a
)
197 t
.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt
.s
, tt
.sep
, tt
.n
, tt
.sep
, s
)
202 type FieldsTest
struct {
207 var fieldstests
= []FieldsTest
{
210 {" \t ", []string{}},
211 {" abc ", []string{"abc"}},
212 {"1 2 3 4", []string{"1", "2", "3", "4"}},
213 {"1 2 3 4", []string{"1", "2", "3", "4"}},
214 {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
215 {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
216 {"\u2000\u2001\u2002", []string{}},
217 {"\n™\t™\n", []string{"™", "™"}},
218 {faces
, []string{faces
}},
221 func TestFields(t
*testing
.T
) {
222 for _
, tt
:= range fieldstests
{
225 t
.Errorf("Fields(%q) = %v; want %v", tt
.s
, a
, tt
.a
)
231 func TestFieldsFunc(t
*testing
.T
) {
232 pred
:= func(c
int) bool { return c
== 'X' }
233 var fieldsFuncTests
= []FieldsTest
{
236 {"XXhiXXX", []string{"hi"}},
237 {"aXXbXXXcX", []string{"a", "b", "c"}},
239 for _
, tt
:= range fieldsFuncTests
{
240 a
:= FieldsFunc(tt
.s
, pred
)
242 t
.Errorf("FieldsFunc(%q) = %v, want %v", tt
.s
, a
, tt
.a
)
248 // Test case for any function which accepts and returns a single string.
249 type StringTest
struct {
253 // Execute f on each test case. funcName should be the name of f; it's used
254 // in failure reports.
255 func runStringTests(t
*testing
.T
, f
func(string) string, funcName
string, testCases
[]StringTest
) {
256 for _
, tc
:= range testCases
{
258 if actual
!= tc
.out
{
259 t
.Errorf("%s(%q) = %q; want %q", funcName
, tc
.in
, actual
, tc
.out
)
264 var upperTests
= []StringTest
{
267 {"AbC123", "ABC123"},
268 {"azAZ09_", "AZAZ09_"},
269 {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
272 var lowerTests
= []StringTest
{
275 {"AbC123", "abc123"},
276 {"azAZ09_", "azaz09_"},
277 {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
280 const space
= "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
282 var trimSpaceTests
= []StringTest
{
285 {space
+ "abc" + space
, "abc"},
287 {" \t\r\n \t\t\r\r\n\n ", ""},
288 {" \t\r\n x\t\t\r\r\n\n ", "x"},
289 {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
290 {"1 \t\r\n2", "1 \t\r\n2"},
293 {"x \xc0\xc0 ", "x \xc0\xc0"},
294 {"x \xc0", "x \xc0"},
295 {"x \xc0 ", "x \xc0"},
296 {"x \xc0\xc0 ", "x \xc0\xc0"},
297 {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
301 func tenRunes(rune
int) string {
309 // User-defined self-inverse mapping function
310 func rot13(rune
int) int {
312 if rune
>= 'a' && rune
<= 'z' {
313 return ((rune
- 'a' + step
) % 26) + 'a'
315 if rune
>= 'A' && rune
<= 'Z' {
316 return ((rune
- 'A' + step
) % 26) + 'A'
321 func TestMap(t
*testing
.T
) {
322 // Run a couple of awful growth/shrinkage tests
324 // 1. Grow. This triggers two reallocations in Map.
325 maxRune
:= func(rune
int) int { return unicode
.MaxRune
}
327 expect
:= tenRunes(unicode
.MaxRune
)
329 t
.Errorf("growing: expected %q got %q", expect
, m
)
333 minRune
:= func(rune
int) int { return 'a' }
334 m
= Map(minRune
, tenRunes(unicode
.MaxRune
))
337 t
.Errorf("shrinking: expected %q got %q", expect
, m
)
341 m
= Map(rot13
, "a to zed")
344 t
.Errorf("rot13: expected %q got %q", expect
, m
)
348 m
= Map(rot13
, Map(rot13
, "a to zed"))
351 t
.Errorf("rot13: expected %q got %q", expect
, m
)
355 dropNotLatin
:= func(rune
int) int {
356 if unicode
.Is(unicode
.Latin
, rune
) {
361 m
= Map(dropNotLatin
, "Hello, 세계")
364 t
.Errorf("drop: expected %q got %q", expect
, m
)
368 func TestToUpper(t
*testing
.T
) { runStringTests(t
, ToUpper
, "ToUpper", upperTests
) }
370 func TestToLower(t
*testing
.T
) { runStringTests(t
, ToLower
, "ToLower", lowerTests
) }
372 func TestSpecialCase(t
*testing
.T
) {
373 lower
:= "abcçdefgğhıijklmnoöprsştuüvyz"
374 upper
:= "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"
375 u
:= ToUpperSpecial(unicode
.TurkishCase
, upper
)
377 t
.Errorf("Upper(upper) is %s not %s", u
, upper
)
379 u
= ToUpperSpecial(unicode
.TurkishCase
, lower
)
381 t
.Errorf("Upper(lower) is %s not %s", u
, upper
)
383 l
:= ToLowerSpecial(unicode
.TurkishCase
, lower
)
385 t
.Errorf("Lower(lower) is %s not %s", l
, lower
)
387 l
= ToLowerSpecial(unicode
.TurkishCase
, upper
)
389 t
.Errorf("Lower(upper) is %s not %s", l
, lower
)
393 func TestTrimSpace(t
*testing
.T
) { runStringTests(t
, TrimSpace
, "TrimSpace", trimSpaceTests
) }
395 type TrimTest
struct {
396 f
func(string, string) string
397 in
, cutset
, out
string
400 var trimTests
= []TrimTest
{
401 {Trim
, "abba", "a", "bb"},
402 {Trim
, "abba", "ab", ""},
403 {TrimLeft
, "abba", "ab", ""},
404 {TrimRight
, "abba", "ab", ""},
405 {TrimLeft
, "abba", "a", "bba"},
406 {TrimRight
, "abba", "a", "abb"},
407 {Trim
, "<tag>", "<>", "tag"},
408 {Trim
, "* listitem", " *", "listitem"},
409 {Trim
, `"quote"`, `"`, "quote"},
410 {Trim
, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
412 {Trim
, "abba", "", "abba"},
413 {Trim
, "", "123", ""},
415 {TrimLeft
, "abba", "", "abba"},
416 {TrimLeft
, "", "123", ""},
417 {TrimLeft
, "", "", ""},
418 {TrimRight
, "abba", "", "abba"},
419 {TrimRight
, "", "123", ""},
420 {TrimRight
, "", "", ""},
421 {TrimRight
, "☺\xc0", "☺", "☺\xc0"},
424 func TestTrim(t
*testing
.T
) {
425 for _
, tc
:= range trimTests
{
426 actual
:= tc
.f(tc
.in
, tc
.cutset
)
436 t
.Error("Undefined trim function")
438 if actual
!= tc
.out
{
439 t
.Errorf("%s(%q, %q) = %q; want %q", name
, tc
.in
, tc
.cutset
, actual
, tc
.out
)
444 type predicate
struct {
449 var isSpace
= predicate
{unicode
.IsSpace
, "IsSpace"}
450 var isDigit
= predicate
{unicode
.IsDigit
, "IsDigit"}
451 var isUpper
= predicate
{unicode
.IsUpper
, "IsUpper"}
452 var isValidRune
= predicate
{
454 return r
!= utf8
.RuneError
459 type TrimFuncTest
struct {
464 func not(p predicate
) predicate
{
473 var trimFuncTests
= []TrimFuncTest
{
474 {isSpace
, space
+ " hello " + space
, "hello"},
475 {isDigit
, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
476 {isUpper
, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
477 {not(isSpace
), "hello" + space
+ "hello", space
},
478 {not(isDigit
), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
479 {isValidRune
, "ab\xc0a\xc0cd", "\xc0a\xc0"},
480 {not(isValidRune
), "\xc0a\xc0", "a"},
483 func TestTrimFunc(t
*testing
.T
) {
484 for _
, tc
:= range trimFuncTests
{
485 actual
:= TrimFunc(tc
.in
, tc
.f
.f
)
486 if actual
!= tc
.out
{
487 t
.Errorf("TrimFunc(%q, %q) = %q; want %q", tc
.in
, tc
.f
.name
, actual
, tc
.out
)
492 type IndexFuncTest
struct {
498 var indexFuncTests
= []IndexFuncTest
{
499 {"", isValidRune
, -1, -1},
500 {"abc", isDigit
, -1, -1},
501 {"0123", isDigit
, 0, 3},
502 {"a1b", isDigit
, 1, 1},
503 {space
, isSpace
, 0, len(space
) - 3}, // last rune in space is 3 bytes
504 {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit
, 0, 18},
505 {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper
, 0, 34},
506 {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit
), 8, 12},
508 // tests of invalid UTF-8
509 {"\x801", isDigit
, 1, 1},
510 {"\x80abc", isDigit
, -1, -1},
511 {"\xc0a\xc0", isValidRune
, 1, 1},
512 {"\xc0a\xc0", not(isValidRune
), 0, 2},
513 {"\xc0☺\xc0", not(isValidRune
), 0, 4},
514 {"\xc0☺\xc0\xc0", not(isValidRune
), 0, 5},
515 {"ab\xc0a\xc0cd", not(isValidRune
), 2, 4},
516 {"a\xe0\x80cd", not(isValidRune
), 1, 2},
517 {"\x80\x80\x80\x80", not(isValidRune
), 0, 3},
520 func TestIndexFunc(t
*testing
.T
) {
521 for _
, tc
:= range indexFuncTests
{
522 first
:= IndexFunc(tc
.in
, tc
.f
.f
)
523 if first
!= tc
.first
{
524 t
.Errorf("IndexFunc(%q, %s) = %d; want %d", tc
.in
, tc
.f
.name
, first
, tc
.first
)
526 last
:= LastIndexFunc(tc
.in
, tc
.f
.f
)
528 t
.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc
.in
, tc
.f
.name
, last
, tc
.last
)
533 func equal(m
string, s1
, s2
string, t
*testing
.T
) bool {
537 e1
:= Split(s1
, "", -1)
538 e2
:= Split(s2
, "", -1)
539 for i
, c1
:= range e1
{
543 r1
, _
:= utf8
.DecodeRuneInString(c1
)
544 r2
, _
:= utf8
.DecodeRuneInString(e2
[i
])
546 t
.Errorf("%s diff at %d: U+%04X U+%04X", m
, i
, r1
, r2
)
552 func TestCaseConsistency(t
*testing
.T
) {
553 // Make a string of all the runes.
554 a
:= make([]int, unicode
.MaxRune
+1)
559 // convert the cases.
563 // Consistency checks
564 if n
:= utf8
.RuneCountInString(upper
); n
!= unicode
.MaxRune
+1 {
565 t
.Error("rune count wrong in upper:", n
)
567 if n
:= utf8
.RuneCountInString(lower
); n
!= unicode
.MaxRune
+1 {
568 t
.Error("rune count wrong in lower:", n
)
570 if !equal("ToUpper(upper)", ToUpper(upper
), upper
, t
) {
571 t
.Error("ToUpper(upper) consistency fail")
573 if !equal("ToLower(lower)", ToLower(lower
), lower
, t
) {
574 t
.Error("ToLower(lower) consistency fail")
577 These fail because of non-one-to-oneness of the data, such as multiple
578 upper case 'I' mapping to 'i'. We comment them out but keep them for
580 For instance: CAPITAL LETTER I WITH DOT ABOVE:
581 unicode.ToUpper(unicode.ToLower('\u0130')) != '\u0130'
583 if !equal("ToUpper(lower)", ToUpper(lower), upper, t) {
584 t.Error("ToUpper(lower) consistency fail");
586 if !equal("ToLower(upper)", ToLower(upper), lower, t) {
587 t.Error("ToLower(upper) consistency fail");
592 type RepeatTest
struct {
597 var RepeatTests
= []RepeatTest
{
603 {"-", "----------", 10},
604 {"abc ", "abc abc abc ", 3},
607 func TestRepeat(t
*testing
.T
) {
608 for _
, tt
:= range RepeatTests
{
609 a
:= Repeat(tt
.in
, tt
.count
)
610 if !equal("Repeat(s)", a
, tt
.out
, t
) {
611 t
.Errorf("Repeat(%v, %d) = %v; want %v", tt
.in
, tt
.count
, a
, tt
.out
)
617 func runesEqual(a
, b
[]int) bool {
618 if len(a
) != len(b
) {
621 for i
, r
:= range a
{
629 type RunesTest
struct {
635 var RunesTests
= []RunesTest
{
636 {"", []int{}, false},
637 {" ", []int{32}, false},
638 {"ABC", []int{65, 66, 67}, false},
639 {"abc", []int{97, 98, 99}, false},
640 {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
641 {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
642 {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
645 func TestRunes(t
*testing
.T
) {
646 for _
, tt
:= range RunesTests
{
648 if !runesEqual(a
, tt
.out
) {
649 t
.Errorf("[]int(%q) = %v; want %v", tt
.in
, a
, tt
.out
)
653 // can only test reassembly if we didn't lose information
656 t
.Errorf("string([]int(%q)) = %x; want %x", tt
.in
, s
, tt
.in
)
662 func TestReadRune(t
*testing
.T
) {
663 testStrings
:= []string{"", abcd
, faces
, commas
}
664 for _
, s
:= range testStrings
{
665 reader
:= NewReader(s
)
668 r
, _
, e
:= reader
.ReadRune()
673 t
.Errorf("Reading %q: %s", s
, e
)
679 t
.Errorf("Reader(%q).ReadRune() produced %q", s
, res
)
684 type ReplaceTest
struct {
691 var ReplaceTests
= []ReplaceTest
{
692 {"hello", "l", "L", 0, "hello"},
693 {"hello", "l", "L", -1, "heLLo"},
694 {"hello", "x", "X", -1, "hello"},
695 {"", "x", "X", -1, ""},
696 {"radar", "r", "<r>", -1, "<r>ada<r>"},
697 {"", "", "<>", -1, "<>"},
698 {"banana", "a", "<>", -1, "b<>n<>n<>"},
699 {"banana", "a", "<>", 1, "b<>nana"},
700 {"banana", "a", "<>", 1000, "b<>n<>n<>"},
701 {"banana", "an", "<>", -1, "b<><>a"},
702 {"banana", "ana", "<>", -1, "b<>na"},
703 {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
704 {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
705 {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
706 {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
707 {"banana", "", "<>", 1, "<>banana"},
708 {"banana", "a", "a", -1, "banana"},
709 {"banana", "a", "a", 1, "banana"},
710 {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
713 func TestReplace(t
*testing
.T
) {
714 for _
, tt
:= range ReplaceTests
{
715 if s
:= Replace(tt
.in
, tt
.old
, tt
.new, tt
.n
); s
!= tt
.out
{
716 t
.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt
.in
, tt
.old
, tt
.new, tt
.n
, s
, tt
.out
)
721 type TitleTest
struct {
725 var TitleTests
= []TitleTest
{
728 {" aaa aaa aaa ", " Aaa Aaa Aaa "},
729 {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
730 {"123a456", "123a456"},
731 {"double-blind", "Double-Blind"},
735 func TestTitle(t
*testing
.T
) {
736 for _
, tt
:= range TitleTests
{
737 if s
:= Title(tt
.in
); s
!= tt
.out
{
738 t
.Errorf("Title(%q) = %q, want %q", tt
.in
, s
, tt
.out
)
743 type ContainsTest
struct {
748 var ContainsTests
= []ContainsTest
{
750 {"abc", "bcd", false},
755 func TestContains(t
*testing
.T
) {
756 for _
, ct
:= range ContainsTests
{
757 if Contains(ct
.str
, ct
.substr
) != ct
.expected
{
758 t
.Errorf("Contains(%s, %s) = %v, want %v",
759 ct
.str
, ct
.substr
, !ct
.expected
, ct
.expected
)