Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
strings_test.go2234 linesDownload Raw Back to strings
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package strings_test6 7import (8	"bytes"9	"fmt"10	"internal/asan"11	"io"12	"iter"13	"math"14	"math/rand"15	"slices"16	"strconv"17	. "strings"18	"testing"19	"unicode"20	"unicode/utf8"21	"unsafe"22)23 24func collect(t *testing.T, seq iter.Seq[string]) []string {25	out := slices.Collect(seq)26	out1 := slices.Collect(seq)27	if !slices.Equal(out, out1) {28		t.Fatalf("inconsistent seq:\n%s\n%s", out, out1)29	}30	return out31}32 33type LinesTest struct {34	a string35	b []string36}37 38var linesTests = []LinesTest{39	{a: "abc\nabc\n", b: []string{"abc\n", "abc\n"}},40	{a: "abc\r\nabc", b: []string{"abc\r\n", "abc"}},41	{a: "abc\r\n", b: []string{"abc\r\n"}},42	{a: "\nabc", b: []string{"\n", "abc"}},43	{a: "\nabc\n\n", b: []string{"\n", "abc\n", "\n"}},44}45 46func TestLines(t *testing.T) {47	for _, s := range linesTests {48		result := slices.Collect(Lines(s.a))49		if !slices.Equal(result, s.b) {50			t.Errorf(`slices.Collect(Lines(%q)) = %q; want %q`, s.a, result, s.b)51		}52	}53}54 55var abcd = "abcd"56var faces = "☺☻☹"57var commas = "1,2,3,4"58var dots = "1....2....3....4"59 60type IndexTest struct {61	s   string62	sep string63	out int64}65 66var indexTests = []IndexTest{67	{"", "", 0},68	{"", "a", -1},69	{"", "foo", -1},70	{"fo", "foo", -1},71	{"foo", "foo", 0},72	{"oofofoofooo", "f", 2},73	{"oofofoofooo", "foo", 4},74	{"barfoobarfoo", "foo", 3},75	{"foo", "", 0},76	{"foo", "o", 1},77	{"abcABCabc", "A", 3},78	{"jrzm6jjhorimglljrea4w3rlgosts0w2gia17hno2td4qd1jz", "jz", 47},79	{"ekkuk5oft4eq0ocpacknhwouic1uua46unx12l37nioq9wbpnocqks6", "ks6", 52},80	{"999f2xmimunbuyew5vrkla9cpwhmxan8o98ec", "98ec", 33},81	{"9lpt9r98i04k8bz6c6dsrthb96bhi", "96bhi", 24},82	{"55u558eqfaod2r2gu42xxsu631xf0zobs5840vl", "5840vl", 33},83	// cases with one byte strings - test special case in Index()84	{"", "a", -1},85	{"x", "a", -1},86	{"x", "x", 0},87	{"abc", "a", 0},88	{"abc", "b", 1},89	{"abc", "c", 2},90	{"abc", "x", -1},91	// test special cases in Index() for short strings92	{"", "ab", -1},93	{"bc", "ab", -1},94	{"ab", "ab", 0},95	{"xab", "ab", 1},96	{"xab"[:2], "ab", -1},97	{"", "abc", -1},98	{"xbc", "abc", -1},99	{"abc", "abc", 0},100	{"xabc", "abc", 1},101	{"xabc"[:3], "abc", -1},102	{"xabxc", "abc", -1},103	{"", "abcd", -1},104	{"xbcd", "abcd", -1},105	{"abcd", "abcd", 0},106	{"xabcd", "abcd", 1},107	{"xyabcd"[:5], "abcd", -1},108	{"xbcqq", "abcqq", -1},109	{"abcqq", "abcqq", 0},110	{"xabcqq", "abcqq", 1},111	{"xyabcqq"[:6], "abcqq", -1},112	{"xabxcqq", "abcqq", -1},113	{"xabcqxq", "abcqq", -1},114	{"", "01234567", -1},115	{"32145678", "01234567", -1},116	{"01234567", "01234567", 0},117	{"x01234567", "01234567", 1},118	{"x0123456x01234567", "01234567", 9},119	{"xx01234567"[:9], "01234567", -1},120	{"", "0123456789", -1},121	{"3214567844", "0123456789", -1},122	{"0123456789", "0123456789", 0},123	{"x0123456789", "0123456789", 1},124	{"x012345678x0123456789", "0123456789", 11},125	{"xyz0123456789"[:12], "0123456789", -1},126	{"x01234567x89", "0123456789", -1},127	{"", "0123456789012345", -1},128	{"3214567889012345", "0123456789012345", -1},129	{"0123456789012345", "0123456789012345", 0},130	{"x0123456789012345", "0123456789012345", 1},131	{"x012345678901234x0123456789012345", "0123456789012345", 17},132	{"", "01234567890123456789", -1},133	{"32145678890123456789", "01234567890123456789", -1},134	{"01234567890123456789", "01234567890123456789", 0},135	{"x01234567890123456789", "01234567890123456789", 1},136	{"x0123456789012345678x01234567890123456789", "01234567890123456789", 21},137	{"xyz01234567890123456789"[:22], "01234567890123456789", -1},138	{"", "0123456789012345678901234567890", -1},139	{"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1},140	{"0123456789012345678901234567890", "0123456789012345678901234567890", 0},141	{"x0123456789012345678901234567890", "0123456789012345678901234567890", 1},142	{"x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32},143	{"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1},144	{"", "01234567890123456789012345678901", -1},145	{"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1},146	{"01234567890123456789012345678901", "01234567890123456789012345678901", 0},147	{"x01234567890123456789012345678901", "01234567890123456789012345678901", 1},148	{"x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33},149	{"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1},150	{"xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6},151	{"", "0123456789012345678901234567890123456789", -1},152	{"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2},153	{"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1},154	{"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1},155	{"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65},156	// test fallback to Rabin-Karp.157	{"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22},158	{"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1},159	// test fallback to IndexRune160	{"oxoxoxoxoxoxoxoxoxoxox☺", "☺", 22},161	// invalid UTF-8 byte sequence (must be longer than bytealg.MaxBruteForce to162	// test that we don't use IndexRune)163	{"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx\xed\x9f\xc0", "\xed\x9f\xc0", 105},164}165 166var lastIndexTests = []IndexTest{167	{"", "", 0},168	{"", "a", -1},169	{"", "foo", -1},170	{"fo", "foo", -1},171	{"foo", "foo", 0},172	{"foo", "f", 0},173	{"oofofoofooo", "f", 7},174	{"oofofoofooo", "foo", 7},175	{"barfoobarfoo", "foo", 9},176	{"foo", "", 3},177	{"foo", "o", 2},178	{"abcABCabc", "A", 3},179	{"abcABCabc", "a", 6},180}181 182var indexAnyTests = []IndexTest{183	{"", "", -1},184	{"", "a", -1},185	{"", "abc", -1},186	{"a", "", -1},187	{"a", "a", 0},188	{"\x80", "\xffb", 0},189	{"aaa", "a", 0},190	{"abc", "xyz", -1},191	{"abc", "xcz", 2},192	{"ab☺c", "x☺yz", 2},193	{"a☺b☻c☹d", "cx", len("a☺b☻")},194	{"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},195	{"aRegExp*", ".(|)*+?^$[]", 7},196	{dots + dots + dots, " ", -1},197	{"012abcba210", "\xffb", 4},198	{"012\x80bcb\x80210", "\xffb", 3},199	{"0123456\xcf\x80abc", "\xcfb\x80", 10},200}201 202var lastIndexAnyTests = []IndexTest{203	{"", "", -1},204	{"", "a", -1},205	{"", "abc", -1},206	{"a", "", -1},207	{"a", "a", 0},208	{"\x80", "\xffb", 0},209	{"aaa", "a", 2},210	{"abc", "xyz", -1},211	{"abc", "ab", 1},212	{"ab☺c", "x☺yz", 2},213	{"a☺b☻c☹d", "cx", len("a☺b☻")},214	{"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},215	{"a.RegExp*", ".(|)*+?^$[]", 8},216	{dots + dots + dots, " ", -1},217	{"012abcba210", "\xffb", 6},218	{"012\x80bcb\x80210", "\xffb", 7},219	{"0123456\xcf\x80abc", "\xcfb\x80", 10},220}221 222// Execute f on each test case.  funcName should be the name of f; it's used223// in failure reports.224func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) {225	for _, test := range testCases {226		actual := f(test.s, test.sep)227		if actual != test.out {228			t.Errorf("%s(%q,%q) = %v; want %v", funcName, test.s, test.sep, actual, test.out)229		}230	}231}232 233func TestIndex(t *testing.T)     { runIndexTests(t, Index, "Index", indexTests) }234func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }235func TestIndexAny(t *testing.T)  { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }236func TestLastIndexAny(t *testing.T) {237	runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests)238}239 240func TestIndexByte(t *testing.T) {241	for _, tt := range indexTests {242		if len(tt.sep) != 1 {243			continue244		}245		pos := IndexByte(tt.s, tt.sep[0])246		if pos != tt.out {247			t.Errorf(`IndexByte(%q, %q) = %v; want %v`, tt.s, tt.sep[0], pos, tt.out)248		}249	}250}251 252func TestLastIndexByte(t *testing.T) {253	testCases := []IndexTest{254		{"", "q", -1},255		{"abcdef", "q", -1},256		{"abcdefabcdef", "a", len("abcdef")},      // something in the middle257		{"abcdefabcdef", "f", len("abcdefabcde")}, // last byte258		{"zabcdefabcdef", "z", 0},                 // first byte259		{"a☺b☻c☹d", "b", len("a☺")},               // non-ascii260	}261	for _, test := range testCases {262		actual := LastIndexByte(test.s, test.sep[0])263		if actual != test.out {264			t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.s, test.sep[0], actual, test.out)265		}266	}267}268 269func simpleIndex(s, sep string) int {270	n := len(sep)271	for i := n; i <= len(s); i++ {272		if s[i-n:i] == sep {273			return i - n274		}275	}276	return -1277}278 279func TestIndexRandom(t *testing.T) {280	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"281	for times := 0; times < 10; times++ {282		for strLen := 5 + rand.Intn(5); strLen < 140; strLen += 10 { // Arbitrary283			s1 := make([]byte, strLen)284			for i := range s1 {285				s1[i] = chars[rand.Intn(len(chars))]286			}287			s := string(s1)288			for i := 0; i < 50; i++ {289				begin := rand.Intn(len(s) + 1)290				end := begin + rand.Intn(len(s)+1-begin)291				sep := s[begin:end]292				if i%4 == 0 {293					pos := rand.Intn(len(sep) + 1)294					sep = sep[:pos] + "A" + sep[pos:]295				}296				want := simpleIndex(s, sep)297				res := Index(s, sep)298				if res != want {299					t.Errorf("Index(%s,%s) = %d; want %d", s, sep, res, want)300				}301			}302		}303	}304}305 306func TestIndexRune(t *testing.T) {307	tests := []struct {308		in   string309		rune rune310		want int311	}{312		{"", 'a', -1},313		{"", '☺', -1},314		{"foo", '☹', -1},315		{"foo", 'o', 1},316		{"foo☺bar", '☺', 3},317		{"foo☺☻☹bar", '☹', 9},318		{"a A x", 'A', 2},319		{"some_text=some_value", '=', 9},320		{"☺a", 'a', 3},321		{"a☻☺b", '☺', 4},322 323		// RuneError should match any invalid UTF-8 byte sequence.324		{"�", '�', 0},325		{"\xff", '�', 0},326		{"☻x�", '�', len("☻x")},327		{"☻x\xe2\x98", '�', len("☻x")},328		{"☻x\xe2\x98�", '�', len("☻x")},329		{"☻x\xe2\x98x", '�', len("☻x")},330 331		// Invalid rune values should never match.332		{"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1},333		{"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair334		{"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1},335 336		// 2 bytes337		{"ӆ", 'ӆ', 0},338		{"a", 'ӆ', -1},339		{"  ӆ", 'ӆ', 2},340		{"  a", 'ӆ', -1},341		{Repeat("ц", 64) + "ӆ", 'ӆ', 128}, // test cutover342		{Repeat("Ꙁ", 64) + "Ꚁ", '䚀', -1},  // 'Ꚁ' and '䚀' share the same last two bytes343 344		// 3 bytes345		{"Ꚁ", 'Ꚁ', 0},346		{"a", 'Ꚁ', -1},347		{"  Ꚁ", 'Ꚁ', 2},348		{"  a", 'Ꚁ', -1},349		{Repeat("Ꙁ", 64) + "Ꚁ", 'Ꚁ', 192}, // test cutover350		{Repeat("𡋀", 64) + "𡌀", '𣌀', -1},  // '𡌀' and '𣌀' share the same last two bytes351 352		// 4 bytes353		{"𡌀", '𡌀', 0},354		{"a", '𡌀', -1},355		{"  𡌀", '𡌀', 2},356		{"  a", '𡌀', -1},357		{Repeat("𡋀", 64) + "𡌀", '𡌀', 256}, // test cutover358		{Repeat("𡋀", 64), '𡌀', -1},359 360		// Test the cutover to bytealg.IndexString when it is triggered in361		// the middle of rune that contains consecutive runs of equal bytes.362		{"aaaaaKKKK\U000bc104", '\U000bc104', 17}, // cutover: (n + 16) / 8363		{"aaaaaKKKK鄄", '鄄', 17},364		{"aaKKKKKa\U000bc104", '\U000bc104', 18}, // cutover: 4 + n>>4365		{"aaKKKKKa鄄", '鄄', 18},366	}367	for _, tt := range tests {368		if got := IndexRune(tt.in, tt.rune); got != tt.want {369			t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want)370		}371	}372 373	// Make sure we trigger the cutover and string(rune) conversion.374	haystack := "test" + Repeat("𡋀", 32) + "𡌀"375	allocs := testing.AllocsPerRun(1000, func() {376		if i := IndexRune(haystack, 's'); i != 2 {377			t.Fatalf("'s' at %d; want 2", i)378		}379		if i := IndexRune(haystack, '𡌀'); i != 132 {380			t.Fatalf("'𡌀' at %d; want 4", i)381		}382	})383	if allocs != 0 && testing.CoverMode() == "" {384		t.Errorf("expected no allocations, got %f", allocs)385	}386}387 388const benchmarkString = "some_text=some☺value"389 390func BenchmarkIndexRune(b *testing.B) {391	if got := IndexRune(benchmarkString, '☺'); got != 14 {392		b.Fatalf("wrong index: expected 14, got=%d", got)393	}394	for i := 0; i < b.N; i++ {395		IndexRune(benchmarkString, '☺')396	}397}398 399var benchmarkLongString = Repeat(" ", 100) + benchmarkString400 401func BenchmarkIndexRuneLongString(b *testing.B) {402	if got := IndexRune(benchmarkLongString, '☺'); got != 114 {403		b.Fatalf("wrong index: expected 114, got=%d", got)404	}405	for i := 0; i < b.N; i++ {406		IndexRune(benchmarkLongString, '☺')407	}408}409 410func BenchmarkIndexRuneFastPath(b *testing.B) {411	if got := IndexRune(benchmarkString, 'v'); got != 17 {412		b.Fatalf("wrong index: expected 17, got=%d", got)413	}414	for i := 0; i < b.N; i++ {415		IndexRune(benchmarkString, 'v')416	}417}418 419func BenchmarkIndex(b *testing.B) {420	if got := Index(benchmarkString, "v"); got != 17 {421		b.Fatalf("wrong index: expected 17, got=%d", got)422	}423	for i := 0; i < b.N; i++ {424		Index(benchmarkString, "v")425	}426}427 428func BenchmarkLastIndex(b *testing.B) {429	if got := Index(benchmarkString, "v"); got != 17 {430		b.Fatalf("wrong index: expected 17, got=%d", got)431	}432	for i := 0; i < b.N; i++ {433		LastIndex(benchmarkString, "v")434	}435}436 437func BenchmarkIndexByte(b *testing.B) {438	if got := IndexByte(benchmarkString, 'v'); got != 17 {439		b.Fatalf("wrong index: expected 17, got=%d", got)440	}441	for i := 0; i < b.N; i++ {442		IndexByte(benchmarkString, 'v')443	}444}445 446type SplitTest struct {447	s   string448	sep string449	n   int450	a   []string451}452 453var splittests = []SplitTest{454	{"", "", -1, []string{}},455	{abcd, "", 2, []string{"a", "bcd"}},456	{abcd, "", 4, []string{"a", "b", "c", "d"}},457	{abcd, "", -1, []string{"a", "b", "c", "d"}},458	{faces, "", -1, []string{"☺", "☻", "☹"}},459	{faces, "", 3, []string{"☺", "☻", "☹"}},460	{faces, "", 17, []string{"☺", "☻", "☹"}},461	{"☺�☹", "", -1, []string{"☺", "�", "☹"}},462	{abcd, "a", 0, nil},463	{abcd, "a", -1, []string{"", "bcd"}},464	{abcd, "z", -1, []string{"abcd"}},465	{commas, ",", -1, []string{"1", "2", "3", "4"}},466	{dots, "...", -1, []string{"1", ".2", ".3", ".4"}},467	{faces, "☹", -1, []string{"☺☻", ""}},468	{faces, "~", -1, []string{faces}},469	{"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},470	{"1 2", " ", 3, []string{"1", "2"}},471	{"", "T", math.MaxInt / 4, []string{""}},472	{"\xff-\xff", "", -1, []string{"\xff", "-", "\xff"}},473	{"\xff-\xff", "-", -1, []string{"\xff", "\xff"}},474}475 476func TestSplit(t *testing.T) {477	for _, tt := range splittests {478		a := SplitN(tt.s, tt.sep, tt.n)479		if !slices.Equal(a, tt.a) {480			t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a)481			continue482		}483		if tt.n < 0 {484			a2 := slices.Collect(SplitSeq(tt.s, tt.sep))485			if !slices.Equal(a2, tt.a) {486				t.Errorf(`collect(SplitSeq(%q, %q)) = %v; want %v`, tt.s, tt.sep, a2, tt.a)487			}488		}489		if tt.n == 0 {490			continue491		}492		s := Join(a, tt.sep)493		if s != tt.s {494			t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s)495		}496		if tt.n < 0 {497			b := Split(tt.s, tt.sep)498			if !slices.Equal(a, b) {499				t.Errorf("Split disagrees with SplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)500			}501		}502	}503}504 505var splitaftertests = []SplitTest{506	{abcd, "a", -1, []string{"a", "bcd"}},507	{abcd, "z", -1, []string{"abcd"}},508	{abcd, "", -1, []string{"a", "b", "c", "d"}},509	{commas, ",", -1, []string{"1,", "2,", "3,", "4"}},510	{dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},511	{faces, "☹", -1, []string{"☺☻☹", ""}},512	{faces, "~", -1, []string{faces}},513	{faces, "", -1, []string{"☺", "☻", "☹"}},514	{"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},515	{"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},516	{"1 2", " ", 3, []string{"1 ", "2"}},517	{"123", "", 2, []string{"1", "23"}},518	{"123", "", 17, []string{"1", "2", "3"}},519}520 521func TestSplitAfter(t *testing.T) {522	for _, tt := range splitaftertests {523		a := SplitAfterN(tt.s, tt.sep, tt.n)524		if !slices.Equal(a, tt.a) {525			t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a)526			continue527		}528		if tt.n < 0 {529			a2 := slices.Collect(SplitAfterSeq(tt.s, tt.sep))530			if !slices.Equal(a2, tt.a) {531				t.Errorf(`collect(SplitAfterSeq(%q, %q)) = %v; want %v`, tt.s, tt.sep, a2, tt.a)532			}533		}534		s := Join(a, "")535		if s != tt.s {536			t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)537		}538		if tt.n < 0 {539			b := SplitAfter(tt.s, tt.sep)540			if !slices.Equal(a, b) {541				t.Errorf("SplitAfter disagrees with SplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)542			}543		}544	}545}546 547type FieldsTest struct {548	s string549	a []string550}551 552var fieldstests = []FieldsTest{553	{"", []string{}},554	{" ", []string{}},555	{" \t ", []string{}},556	{"\u2000", []string{}},557	{"  abc  ", []string{"abc"}},558	{"1 2 3 4", []string{"1", "2", "3", "4"}},559	{"1  2  3  4", []string{"1", "2", "3", "4"}},560	{"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},561	{"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},562	{"\u2000\u2001\u2002", []string{}},563	{"\n™\t™\n", []string{"™", "™"}},564	{"\n\u20001™2\u2000 \u2001 ™", []string{"1™2", "™"}},565	{"\n1\uFFFD \uFFFD2\u20003\uFFFD4", []string{"1\uFFFD", "\uFFFD2", "3\uFFFD4"}},566	{"1\xFF\u2000\xFF2\xFF \xFF", []string{"1\xFF", "\xFF2\xFF", "\xFF"}},567	{faces, []string{faces}},568}569 570func TestFields(t *testing.T) {571	for _, tt := range fieldstests {572		a := Fields(tt.s)573		if !slices.Equal(a, tt.a) {574			t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)575			continue576		}577		a2 := collect(t, FieldsSeq(tt.s))578		if !slices.Equal(a2, tt.a) {579			t.Errorf(`collect(FieldsSeq(%q)) = %v; want %v`, tt.s, a2, tt.a)580		}581	}582}583 584var FieldsFuncTests = []FieldsTest{585	{"", []string{}},586	{"XX", []string{}},587	{"XXhiXXX", []string{"hi"}},588	{"aXXbXXXcX", []string{"a", "b", "c"}},589}590 591func TestFieldsFunc(t *testing.T) {592	for _, tt := range fieldstests {593		a := FieldsFunc(tt.s, unicode.IsSpace)594		if !slices.Equal(a, tt.a) {595			t.Errorf("FieldsFunc(%q, unicode.IsSpace) = %v; want %v", tt.s, a, tt.a)596			continue597		}598	}599	pred := func(c rune) bool { return c == 'X' }600	for _, tt := range FieldsFuncTests {601		a := FieldsFunc(tt.s, pred)602		if !slices.Equal(a, tt.a) {603			t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)604		}605		a2 := collect(t, FieldsFuncSeq(tt.s, pred))606		if !slices.Equal(a2, tt.a) {607			t.Errorf(`collect(FieldsFuncSeq(%q)) = %v; want %v`, tt.s, a2, tt.a)608		}609	}610}611 612// Test case for any function which accepts and returns a single string.613type StringTest struct {614	in, out string615}616 617// Execute f on each test case.  funcName should be the name of f; it's used618// in failure reports.619func runStringTests(t *testing.T, f func(string) string, funcName string, testCases []StringTest) {620	for _, tc := range testCases {621		actual := f(tc.in)622		if actual != tc.out {623			t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)624		}625	}626}627 628var upperTests = []StringTest{629	{"", ""},630	{"ONLYUPPER", "ONLYUPPER"},631	{"abc", "ABC"},632	{"AbC123", "ABC123"},633	{"azAZ09_", "AZAZ09_"},634	{"longStrinGwitHmixofsmaLLandcAps", "LONGSTRINGWITHMIXOFSMALLANDCAPS"},635	{"RENAN BASTOS 93 AOSDAJDJAIDJAIDAJIaidsjjaidijadsjiadjiOOKKO", "RENAN BASTOS 93 AOSDAJDJAIDJAIDAJIAIDSJJAIDIJADSJIADJIOOKKO"},636	{"long\u0250string\u0250with\u0250nonascii\u2C6Fchars", "LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS"},637	{"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char638	{"a\u0080\U0010FFFF", "A\u0080\U0010FFFF"},                           // test utf8.RuneSelf and utf8.MaxRune639}640 641var lowerTests = []StringTest{642	{"", ""},643	{"abc", "abc"},644	{"AbC123", "abc123"},645	{"azAZ09_", "azaz09_"},646	{"longStrinGwitHmixofsmaLLandcAps", "longstringwithmixofsmallandcaps"},647	{"renan bastos 93 AOSDAJDJAIDJAIDAJIaidsjjaidijadsjiadjiOOKKO", "renan bastos 93 aosdajdjaidjaidajiaidsjjaidijadsjiadjiookko"},648	{"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", "long\u0250string\u0250with\u0250nonascii\u0250chars"},649	{"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char650	{"A\u0080\U0010FFFF", "a\u0080\U0010FFFF"},                           // test utf8.RuneSelf and utf8.MaxRune651}652 653const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"654 655var trimSpaceTests = []StringTest{656	{"", ""},657	{"abc", "abc"},658	{space + "abc" + space, "abc"},659	{" ", ""},660	{" \t\r\n \t\t\r\r\n\n ", ""},661	{" \t\r\n x\t\t\r\r\n\n ", "x"},662	{" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},663	{"1 \t\r\n2", "1 \t\r\n2"},664	{" x\x80", "x\x80"},665	{" x\xc0", "x\xc0"},666	{"x \xc0\xc0 ", "x \xc0\xc0"},667	{"x \xc0", "x \xc0"},668	{"x \xc0 ", "x \xc0"},669	{"x \xc0\xc0 ", "x \xc0\xc0"},670	{"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},671	{"x ☺ ", "x ☺"},672}673 674func tenRunes(ch rune) string {675	r := make([]rune, 10)676	for i := range r {677		r[i] = ch678	}679	return string(r)680}681 682// User-defined self-inverse mapping function683func rot13(r rune) rune {684	step := rune(13)685	if r >= 'a' && r <= 'z' {686		return ((r - 'a' + step) % 26) + 'a'687	}688	if r >= 'A' && r <= 'Z' {689		return ((r - 'A' + step) % 26) + 'A'690	}691	return r692}693 694func TestMap(t *testing.T) {695	// Run a couple of awful growth/shrinkage tests696	a := tenRunes('a')697	// 1. Grow. This triggers two reallocations in Map.698	maxRune := func(rune) rune { return unicode.MaxRune }699	m := Map(maxRune, a)700	expect := tenRunes(unicode.MaxRune)701	if m != expect {702		t.Errorf("growing: expected %q got %q", expect, m)703	}704 705	// 2. Shrink706	minRune := func(rune) rune { return 'a' }707	m = Map(minRune, tenRunes(unicode.MaxRune))708	expect = a709	if m != expect {710		t.Errorf("shrinking: expected %q got %q", expect, m)711	}712 713	// 3. Rot13714	m = Map(rot13, "a to zed")715	expect = "n gb mrq"716	if m != expect {717		t.Errorf("rot13: expected %q got %q", expect, m)718	}719 720	// 4. Rot13^2721	m = Map(rot13, Map(rot13, "a to zed"))722	expect = "a to zed"723	if m != expect {724		t.Errorf("rot13: expected %q got %q", expect, m)725	}726 727	// 5. Drop728	dropNotLatin := func(r rune) rune {729		if unicode.Is(unicode.Latin, r) {730			return r731		}732		return -1733	}734	m = Map(dropNotLatin, "Hello, 세계")735	expect = "Hello"736	if m != expect {737		t.Errorf("drop: expected %q got %q", expect, m)738	}739 740	// 6. Identity741	identity := func(r rune) rune {742		return r743	}744	orig := "Input string that we expect not to be copied."745	m = Map(identity, orig)746	if unsafe.StringData(orig) != unsafe.StringData(m) {747		t.Error("unexpected copy during identity map")748	}749 750	// 7. Handle invalid UTF-8 sequence751	replaceNotLatin := func(r rune) rune {752		if unicode.Is(unicode.Latin, r) {753			return r754		}755		return utf8.RuneError756	}757	m = Map(replaceNotLatin, "Hello\255World")758	expect = "Hello\uFFFDWorld"759	if m != expect {760		t.Errorf("replace invalid sequence: expected %q got %q", expect, m)761	}762 763	// 8. Check utf8.RuneSelf and utf8.MaxRune encoding764	encode := func(r rune) rune {765		switch r {766		case utf8.RuneSelf:767			return unicode.MaxRune768		case unicode.MaxRune:769			return utf8.RuneSelf770		}771		return r772	}773	s := string(rune(utf8.RuneSelf)) + string(utf8.MaxRune)774	r := string(utf8.MaxRune) + string(rune(utf8.RuneSelf)) // reverse of s775	m = Map(encode, s)776	if m != r {777		t.Errorf("encoding not handled correctly: expected %q got %q", r, m)778	}779	m = Map(encode, r)780	if m != s {781		t.Errorf("encoding not handled correctly: expected %q got %q", s, m)782	}783 784	// 9. Check mapping occurs in the front, middle and back785	trimSpaces := func(r rune) rune {786		if unicode.IsSpace(r) {787			return -1788		}789		return r790	}791	m = Map(trimSpaces, "   abc    123   ")792	expect = "abc123"793	if m != expect {794		t.Errorf("trimSpaces: expected %q got %q", expect, m)795	}796}797 798func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }799 800func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }801 802var toValidUTF8Tests = []struct {803	in   string804	repl string805	out  string806}{807	{"", "\uFFFD", ""},808	{"abc", "\uFFFD", "abc"},809	{"\uFDDD", "\uFFFD", "\uFDDD"},810	{"a\xffb", "\uFFFD", "a\uFFFDb"},811	{"a\xffb\uFFFD", "X", "aXb\uFFFD"},812	{"a☺\xffb☺\xC0\xAFc☺\xff", "", "a☺b☺c☺"},813	{"a☺\xffb☺\xC0\xAFc☺\xff", "日本語", "a☺日本語b☺日本語c☺日本語"},814	{"\xC0\xAF", "\uFFFD", "\uFFFD"},815	{"\xE0\x80\xAF", "\uFFFD", "\uFFFD"},816	{"\xed\xa0\x80", "abc", "abc"},817	{"\xed\xbf\xbf", "\uFFFD", "\uFFFD"},818	{"\xF0\x80\x80\xaf", "☺", "☺"},819	{"\xF8\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"},820	{"\xFC\x80\x80\x80\x80\xAF", "\uFFFD", "\uFFFD"},821}822 823func TestToValidUTF8(t *testing.T) {824	for _, tc := range toValidUTF8Tests {825		got := ToValidUTF8(tc.in, tc.repl)826		if got != tc.out {827			t.Errorf("ToValidUTF8(%q, %q) = %q; want %q", tc.in, tc.repl, got, tc.out)828		}829	}830}831 832func BenchmarkToUpper(b *testing.B) {833	for _, tc := range upperTests {834		b.Run(tc.in, func(b *testing.B) {835			for i := 0; i < b.N; i++ {836				actual := ToUpper(tc.in)837				if actual != tc.out {838					b.Errorf("ToUpper(%q) = %q; want %q", tc.in, actual, tc.out)839				}840			}841		})842	}843}844 845func BenchmarkToLower(b *testing.B) {846	for _, tc := range lowerTests {847		b.Run(tc.in, func(b *testing.B) {848			for i := 0; i < b.N; i++ {849				actual := ToLower(tc.in)850				if actual != tc.out {851					b.Errorf("ToLower(%q) = %q; want %q", tc.in, actual, tc.out)852				}853			}854		})855	}856}857 858func BenchmarkMapNoChanges(b *testing.B) {859	identity := func(r rune) rune {860		return r861	}862	for i := 0; i < b.N; i++ {863		Map(identity, "Some string that won't be modified.")864	}865}866 867func TestSpecialCase(t *testing.T) {868	lower := "abcçdefgğhıijklmnoöprsştuüvyz"869	upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"870	u := ToUpperSpecial(unicode.TurkishCase, upper)871	if u != upper {872		t.Errorf("Upper(upper) is %s not %s", u, upper)873	}874	u = ToUpperSpecial(unicode.TurkishCase, lower)875	if u != upper {876		t.Errorf("Upper(lower) is %s not %s", u, upper)877	}878	l := ToLowerSpecial(unicode.TurkishCase, lower)879	if l != lower {880		t.Errorf("Lower(lower) is %s not %s", l, lower)881	}882	l = ToLowerSpecial(unicode.TurkishCase, upper)883	if l != lower {884		t.Errorf("Lower(upper) is %s not %s", l, lower)885	}886}887 888func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }889 890var trimTests = []struct {891	f            string892	in, arg, out string893}{894	{"Trim", "abba", "a", "bb"},895	{"Trim", "abba", "ab", ""},896	{"TrimLeft", "abba", "ab", ""},897	{"TrimRight", "abba", "ab", ""},898	{"TrimLeft", "abba", "a", "bba"},899	{"TrimLeft", "abba", "b", "abba"},900	{"TrimRight", "abba", "a", "abb"},901	{"TrimRight", "abba", "b", "abba"},902	{"Trim", "<tag>", "<>", "tag"},903	{"Trim", "* listitem", " *", "listitem"},904	{"Trim", `"quote"`, `"`, "quote"},905	{"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},906	{"Trim", "\x80test\xff", "\xff", "test"},907	{"Trim", " Ġ ", " ", "Ġ"},908	{"Trim", " Ġİ0", "0 ", "Ġİ"},909	//empty string tests910	{"Trim", "abba", "", "abba"},911	{"Trim", "", "123", ""},912	{"Trim", "", "", ""},913	{"TrimLeft", "abba", "", "abba"},914	{"TrimLeft", "", "123", ""},915	{"TrimLeft", "", "", ""},916	{"TrimRight", "abba", "", "abba"},917	{"TrimRight", "", "123", ""},918	{"TrimRight", "", "", ""},919	{"TrimRight", "☺\xc0", "☺", "☺\xc0"},920	{"TrimPrefix", "aabb", "a", "abb"},921	{"TrimPrefix", "aabb", "b", "aabb"},922	{"TrimSuffix", "aabb", "a", "aabb"},923	{"TrimSuffix", "aabb", "b", "aab"},924}925 926func TestTrim(t *testing.T) {927	for _, tc := range trimTests {928		name := tc.f929		var f func(string, string) string930		switch name {931		case "Trim":932			f = Trim933		case "TrimLeft":934			f = TrimLeft935		case "TrimRight":936			f = TrimRight937		case "TrimPrefix":938			f = TrimPrefix939		case "TrimSuffix":940			f = TrimSuffix941		default:942			t.Errorf("Undefined trim function %s", name)943		}944		actual := f(tc.in, tc.arg)945		if actual != tc.out {946			t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)947		}948	}949}950 951func BenchmarkTrim(b *testing.B) {952	b.ReportAllocs()953 954	for i := 0; i < b.N; i++ {955		for _, tc := range trimTests {956			name := tc.f957			var f func(string, string) string958			switch name {959			case "Trim":960				f = Trim961			case "TrimLeft":962				f = TrimLeft963			case "TrimRight":964				f = TrimRight965			case "TrimPrefix":966				f = TrimPrefix967			case "TrimSuffix":968				f = TrimSuffix969			default:970				b.Errorf("Undefined trim function %s", name)971			}972			actual := f(tc.in, tc.arg)973			if actual != tc.out {974				b.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)975			}976		}977	}978}979 980func BenchmarkToValidUTF8(b *testing.B) {981	tests := []struct {982		name  string983		input string984	}{985		{"Valid", "typical"},986		{"InvalidASCII", "foo\xffbar"},987		{"InvalidNonASCII", "日本語\xff日本語"},988	}989	replacement := "\uFFFD"990	b.ResetTimer()991	for _, test := range tests {992		b.Run(test.name, func(b *testing.B) {993			for i := 0; i < b.N; i++ {994				ToValidUTF8(test.input, replacement)995			}996		})997	}998}999 1000type predicate struct {1001	f    func(rune) bool1002	name string1003}1004 1005var isSpace = predicate{unicode.IsSpace, "IsSpace"}1006var isDigit = predicate{unicode.IsDigit, "IsDigit"}1007var isUpper = predicate{unicode.IsUpper, "IsUpper"}1008var isValidRune = predicate{1009	func(r rune) bool {1010		return r != utf8.RuneError1011	},1012	"IsValidRune",1013}1014 1015func not(p predicate) predicate {1016	return predicate{1017		func(r rune) bool {1018			return !p.f(r)1019		},1020		"not " + p.name,1021	}1022}1023 1024var trimFuncTests = []struct {1025	f        predicate1026	in       string1027	trimOut  string1028	leftOut  string1029	rightOut string1030}{1031	{isSpace, space + " hello " + space,1032		"hello",1033		"hello " + space,1034		space + " hello"},1035	{isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51",1036		"hello",1037		"hello34\u0e50\u0e51",1038		"\u0e50\u0e5212hello"},1039	{isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F",1040		"hello",1041		"helloEF\u2C6F\u2C6FGH\u2C6F\u2C6F",1042		"\u2C6F\u2C6F\u2C6F\u2C6FABCDhello"},1043	{not(isSpace), "hello" + space + "hello",1044		space,1045		space + "hello",1046		"hello" + space},1047	{not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo",1048		"\u0e50\u0e521234\u0e50\u0e51",1049		"\u0e50\u0e521234\u0e50\u0e51helo",1050		"hello\u0e50\u0e521234\u0e50\u0e51"},1051	{isValidRune, "ab\xc0a\xc0cd",1052		"\xc0a\xc0",1053		"\xc0a\xc0cd",1054		"ab\xc0a\xc0"},1055	{not(isValidRune), "\xc0a\xc0",1056		"a",1057		"a\xc0",1058		"\xc0a"},1059	{isSpace, "",1060		"",1061		"",1062		""},1063	{isSpace, " ",1064		"",1065		"",1066		""},1067}1068 1069func TestTrimFunc(t *testing.T) {1070	for _, tc := range trimFuncTests {1071		trimmers := []struct {1072			name string1073			trim func(s string, f func(r rune) bool) string1074			out  string1075		}{1076			{"TrimFunc", TrimFunc, tc.trimOut},1077			{"TrimLeftFunc", TrimLeftFunc, tc.leftOut},1078			{"TrimRightFunc", TrimRightFunc, tc.rightOut},1079		}1080		for _, trimmer := range trimmers {1081			actual := trimmer.trim(tc.in, tc.f.f)1082			if actual != trimmer.out {1083				t.Errorf("%s(%q, %q) = %q; want %q", trimmer.name, tc.in, tc.f.name, actual, trimmer.out)1084			}1085		}1086	}1087}1088 1089var indexFuncTests = []struct {1090	in          string1091	f           predicate1092	first, last int1093}{1094	{"", isValidRune, -1, -1},1095	{"abc", isDigit, -1, -1},1096	{"0123", isDigit, 0, 3},1097	{"a1b", isDigit, 1, 1},1098	{space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes1099	{"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},1100	{"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},1101	{"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},1102 1103	// tests of invalid UTF-81104	{"\x801", isDigit, 1, 1},1105	{"\x80abc", isDigit, -1, -1},1106	{"\xc0a\xc0", isValidRune, 1, 1},1107	{"\xc0a\xc0", not(isValidRune), 0, 2},1108	{"\xc0☺\xc0", not(isValidRune), 0, 4},1109	{"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},1110	{"ab\xc0a\xc0cd", not(isValidRune), 2, 4},1111	{"a\xe0\x80cd", not(isValidRune), 1, 2},1112	{"\x80\x80\x80\x80", not(isValidRune), 0, 3},1113}1114 1115func TestIndexFunc(t *testing.T) {1116	for _, tc := range indexFuncTests {1117		first := IndexFunc(tc.in, tc.f.f)1118		if first != tc.first {1119			t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)1120		}1121		last := LastIndexFunc(tc.in, tc.f.f)1122		if last != tc.last {1123			t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)1124		}1125	}1126}1127 1128func equal(m string, s1, s2 string, t *testing.T) bool {1129	if s1 == s2 {1130		return true1131	}1132	e1 := Split(s1, "")1133	e2 := Split(s2, "")1134	for i, c1 := range e1 {1135		if i >= len(e2) {1136			break1137		}1138		r1, _ := utf8.DecodeRuneInString(c1)1139		r2, _ := utf8.DecodeRuneInString(e2[i])1140		if r1 != r2 {1141			t.Errorf("%s diff at %d: U+%04X U+%04X", m, i, r1, r2)1142		}1143	}1144	return false1145}1146 1147func TestCaseConsistency(t *testing.T) {1148	// Make a string of all the runes.1149	numRunes := int(unicode.MaxRune + 1)1150	if testing.Short() {1151		numRunes = 10001152	}1153	a := make([]rune, numRunes)1154	for i := range a {1155		a[i] = rune(i)1156	}1157	s := string(a)1158	// convert the cases.1159	upper := ToUpper(s)1160	lower := ToLower(s)1161 1162	// Consistency checks1163	if n := utf8.RuneCountInString(upper); n != numRunes {1164		t.Error("rune count wrong in upper:", n)1165	}1166	if n := utf8.RuneCountInString(lower); n != numRunes {1167		t.Error("rune count wrong in lower:", n)1168	}1169	if !equal("ToUpper(upper)", ToUpper(upper), upper, t) {1170		t.Error("ToUpper(upper) consistency fail")1171	}1172	if !equal("ToLower(lower)", ToLower(lower), lower, t) {1173		t.Error("ToLower(lower) consistency fail")1174	}1175	/*1176		  These fail because of non-one-to-oneness of the data, such as multiple1177		  upper case 'I' mapping to 'i'.  We comment them out but keep them for1178		  interest.1179		  For instance: CAPITAL LETTER I WITH DOT ABOVE:1180			unicode.ToUpper(unicode.ToLower('\u0130')) != '\u0130'1181 1182		if !equal("ToUpper(lower)", ToUpper(lower), upper, t) {1183			t.Error("ToUpper(lower) consistency fail");1184		}1185		if !equal("ToLower(upper)", ToLower(upper), lower, t) {1186			t.Error("ToLower(upper) consistency fail");1187		}1188	*/1189}1190 1191var longString = "a" + string(make([]byte, 1<<16)) + "z"1192var longSpaces = func() string {1193	b := make([]byte, 200)1194	for i := range b {1195		b[i] = ' '1196	}1197	return string(b)1198}()1199 1200var RepeatTests = []struct {

Showing the first 1,200 of 2234 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai