diff options
author | Ben Cheng <bccheng@google.com> | 2012-10-01 10:30:31 -0700 |
---|---|---|
committer | Ben Cheng <bccheng@google.com> | 2012-10-01 10:30:31 -0700 |
commit | 82bcbebce43f0227f506d75a5b764b6847041bae (patch) | |
tree | fe9f8597b48a430c4daeb5123e3e8eb28e6f9da9 /gcc-4.7/libgo/go/strings | |
parent | 3c052de3bb16ac53b6b6ed659ec7557eb84c7590 (diff) | |
download | toolchain_gcc-82bcbebce43f0227f506d75a5b764b6847041bae.tar.gz toolchain_gcc-82bcbebce43f0227f506d75a5b764b6847041bae.tar.bz2 toolchain_gcc-82bcbebce43f0227f506d75a5b764b6847041bae.zip |
Initial check-in of gcc 4.7.2.
Change-Id: I4a2f5a921c21741a0e18bda986d77e5f1bef0365
Diffstat (limited to 'gcc-4.7/libgo/go/strings')
-rw-r--r-- | gcc-4.7/libgo/go/strings/example_test.go | 181 | ||||
-rw-r--r-- | gcc-4.7/libgo/go/strings/export_test.go | 9 | ||||
-rw-r--r-- | gcc-4.7/libgo/go/strings/reader.go | 125 | ||||
-rw-r--r-- | gcc-4.7/libgo/go/strings/reader_test.go | 88 | ||||
-rw-r--r-- | gcc-4.7/libgo/go/strings/replace.go | 312 | ||||
-rw-r--r-- | gcc-4.7/libgo/go/strings/replace_test.go | 174 | ||||
-rw-r--r-- | gcc-4.7/libgo/go/strings/strings.go | 651 | ||||
-rw-r--r-- | gcc-4.7/libgo/go/strings/strings_test.go | 986 |
8 files changed, 2526 insertions, 0 deletions
diff --git a/gcc-4.7/libgo/go/strings/example_test.go b/gcc-4.7/libgo/go/strings/example_test.go new file mode 100644 index 000000000..733caf5f2 --- /dev/null +++ b/gcc-4.7/libgo/go/strings/example_test.go @@ -0,0 +1,181 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings_test + +import ( + "fmt" + "strings" +) + +func ExampleFields() { + fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) + // Output: Fields are: ["foo" "bar" "baz"] +} + +func ExampleContains() { + fmt.Println(strings.Contains("seafood", "foo")) + fmt.Println(strings.Contains("seafood", "bar")) + fmt.Println(strings.Contains("seafood", "")) + fmt.Println(strings.Contains("", "")) + // Output: + // true + // false + // true + // true +} + +func ExampleContainsAny() { + fmt.Println(strings.ContainsAny("team", "i")) + fmt.Println(strings.ContainsAny("failure", "u & i")) + fmt.Println(strings.ContainsAny("foo", "")) + fmt.Println(strings.ContainsAny("", "")) + // Output: + // false + // true + // false + // false +} + +func ExampleCount() { + fmt.Println(strings.Count("cheese", "e")) + fmt.Println(strings.Count("five", "")) // before & after each rune + // Output: + // 3 + // 5 +} + +func ExampleEqualFold() { + fmt.Println(strings.EqualFold("Go", "go")) + // Output: true +} + +func ExampleIndex() { + fmt.Println(strings.Index("chicken", "ken")) + fmt.Println(strings.Index("chicken", "dmr")) + // Output: + // 4 + // -1 +} + +func ExampleIndexRune() { + fmt.Println(strings.IndexRune("chicken", 'k')) + fmt.Println(strings.IndexRune("chicken", 'd')) + // Output: + // 4 + // -1 +} + +func ExampleLastIndex() { + fmt.Println(strings.Index("go gopher", "go")) + fmt.Println(strings.LastIndex("go gopher", "go")) + fmt.Println(strings.LastIndex("go gopher", "rodent")) + // Output: + // 0 + // 3 + // -1 +} + +func ExampleJoin() { + s := []string{"foo", "bar", "baz"} + fmt.Println(strings.Join(s, ", ")) + // Output: foo, bar, baz +} + +func ExampleRepeat() { + fmt.Println("ba" + strings.Repeat("na", 2)) + // Output: banana +} + +func ExampleReplace() { + fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2)) + fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1)) + // Output: + // oinky oinky oink + // moo moo moo +} + +func ExampleSplit() { + fmt.Printf("%q\n", strings.Split("a,b,c", ",")) + fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a ")) + fmt.Printf("%q\n", strings.Split(" xyz ", "")) + fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins")) + // Output: + // ["a" "b" "c"] + // ["" "man " "plan " "canal panama"] + // [" " "x" "y" "z" " "] + // [""] +} + +func ExampleSplitN() { + fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2)) + z := strings.SplitN("a,b,c", ",", 0) + fmt.Printf("%q (nil = %v)\n", z, z == nil) + // Output: + // ["a" "b,c"] + // [] (nil = true) +} + +func ExampleSplitAfter() { + fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ",")) + // Output: ["a," "b," "c"] +} + +func ExampleSplitAfterN() { + fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2)) + // Output: ["a," "b,c"] +} + +func ExampleTitle() { + fmt.Println(strings.Title("her royal highness")) + // Output: Her Royal Highness +} + +func ExampleToTitle() { + fmt.Println(strings.ToTitle("loud noises")) + fmt.Println(strings.ToTitle("хлеб")) + // Output: + // LOUD NOISES + // ХЛЕБ +} + +func ExampleTrim() { + fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! ")) + // Output: ["Achtung"] +} + +func ExampleMap() { + rot13 := func(r rune) rune { + switch { + case r >= 'A' && r <= 'Z': + return 'A' + (r-'A'+13)%26 + case r >= 'a' && r <= 'z': + return 'a' + (r-'a'+13)%26 + } + return r + } + fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher...")) + // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure... +} + +func ExampleTrimSpace() { + fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n")) + // Output: a lone gopher +} + +func ExampleNewReplacer() { + r := strings.NewReplacer("<", "<", ">", ">") + fmt.Println(r.Replace("This is <b>HTML</b>!")) + // Output: This is <b>HTML</b>! +} + +func ExampleToUpper() { + fmt.Println(strings.ToUpper("Gopher")) + // Output: GOPHER +} + +func ExampleToLower() { + fmt.Println(strings.ToLower("Gopher")) + // Output: gopher +} diff --git a/gcc-4.7/libgo/go/strings/export_test.go b/gcc-4.7/libgo/go/strings/export_test.go new file mode 100644 index 000000000..dcfec513c --- /dev/null +++ b/gcc-4.7/libgo/go/strings/export_test.go @@ -0,0 +1,9 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +func (r *Replacer) Replacer() interface{} { + return r.r +} diff --git a/gcc-4.7/libgo/go/strings/reader.go b/gcc-4.7/libgo/go/strings/reader.go new file mode 100644 index 000000000..856980555 --- /dev/null +++ b/gcc-4.7/libgo/go/strings/reader.go @@ -0,0 +1,125 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import ( + "errors" + "io" + "unicode/utf8" +) + +// A Reader implements the io.Reader, io.ReaderAt, io.Seeker, +// io.ByteScanner, and io.RuneScanner interfaces by reading +// from a string. +type Reader struct { + s string + i int // current reading index + prevRune int // index of previous rune; or < 0 +} + +// Len returns the number of bytes of the unread portion of the +// string. +func (r *Reader) Len() int { + if r.i >= len(r.s) { + return 0 + } + return len(r.s) - r.i +} + +func (r *Reader) Read(b []byte) (n int, err error) { + if len(b) == 0 { + return 0, nil + } + if r.i >= len(r.s) { + return 0, io.EOF + } + n = copy(b, r.s[r.i:]) + r.i += n + r.prevRune = -1 + return +} + +func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { + if off < 0 { + return 0, errors.New("strings: invalid offset") + } + if off >= int64(len(r.s)) { + return 0, io.EOF + } + n = copy(b, r.s[int(off):]) + if n < len(b) { + err = io.EOF + } + return +} + +func (r *Reader) ReadByte() (b byte, err error) { + if r.i >= len(r.s) { + return 0, io.EOF + } + b = r.s[r.i] + r.i++ + r.prevRune = -1 + return +} + +func (r *Reader) UnreadByte() error { + if r.i <= 0 { + return errors.New("strings.Reader: at beginning of string") + } + r.i-- + r.prevRune = -1 + return nil +} + +func (r *Reader) ReadRune() (ch rune, size int, err error) { + if r.i >= len(r.s) { + return 0, 0, io.EOF + } + r.prevRune = r.i + if c := r.s[r.i]; c < utf8.RuneSelf { + r.i++ + return rune(c), 1, nil + } + ch, size = utf8.DecodeRuneInString(r.s[r.i:]) + r.i += size + return +} + +func (r *Reader) UnreadRune() error { + if r.prevRune < 0 { + return errors.New("strings.Reader: previous operation was not ReadRune") + } + r.i = r.prevRune + r.prevRune = -1 + return nil +} + +// Seek implements the io.Seeker interface. +func (r *Reader) Seek(offset int64, whence int) (int64, error) { + var abs int64 + switch whence { + case 0: + abs = offset + case 1: + abs = int64(r.i) + offset + case 2: + abs = int64(len(r.s)) + offset + default: + return 0, errors.New("strings: invalid whence") + } + if abs < 0 { + return 0, errors.New("strings: negative position") + } + if abs >= 1<<31 { + return 0, errors.New("strings: position out of range") + } + r.i = int(abs) + return abs, nil +} + +// NewReader returns a new Reader reading from s. +// It is similar to bytes.NewBufferString but more efficient and read-only. +func NewReader(s string) *Reader { return &Reader{s, 0, -1} } diff --git a/gcc-4.7/libgo/go/strings/reader_test.go b/gcc-4.7/libgo/go/strings/reader_test.go new file mode 100644 index 000000000..a99ae2a0e --- /dev/null +++ b/gcc-4.7/libgo/go/strings/reader_test.go @@ -0,0 +1,88 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings_test + +import ( + "fmt" + "io" + "os" + "strings" + "testing" +) + +func TestReader(t *testing.T) { + r := strings.NewReader("0123456789") + tests := []struct { + off int64 + seek int + n int + want string + wantpos int64 + seekerr string + }{ + {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"}, + {seek: os.SEEK_SET, off: 1, n: 1, want: "1"}, + {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"}, + {seek: os.SEEK_SET, off: -1, seekerr: "strings: negative position"}, + {seek: os.SEEK_SET, off: 1<<31 - 1}, + {seek: os.SEEK_CUR, off: 1, seekerr: "strings: position out of range"}, + {seek: os.SEEK_SET, n: 5, want: "01234"}, + {seek: os.SEEK_CUR, n: 5, want: "56789"}, + {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"}, + } + + for i, tt := range tests { + pos, err := r.Seek(tt.off, tt.seek) + if err == nil && tt.seekerr != "" { + t.Errorf("%d. want seek error %q", i, tt.seekerr) + continue + } + if err != nil && err.Error() != tt.seekerr { + t.Errorf("%d. seek error = %q; want %q", i, err.Error(), tt.seekerr) + continue + } + if tt.wantpos != 0 && tt.wantpos != pos { + t.Errorf("%d. pos = %d, want %d", i, pos, tt.wantpos) + } + buf := make([]byte, tt.n) + n, err := r.Read(buf) + if err != nil { + t.Errorf("%d. read = %v", i, err) + continue + } + got := string(buf[:n]) + if got != tt.want { + t.Errorf("%d. got %q; want %q", i, got, tt.want) + } + } +} + +func TestReaderAt(t *testing.T) { + r := strings.NewReader("0123456789") + tests := []struct { + off int64 + n int + want string + wanterr interface{} + }{ + {0, 10, "0123456789", nil}, + {1, 10, "123456789", io.EOF}, + {1, 9, "123456789", nil}, + {11, 10, "", io.EOF}, + {0, 0, "", nil}, + {-1, 0, "", "strings: invalid offset"}, + } + for i, tt := range tests { + b := make([]byte, tt.n) + rn, err := r.ReadAt(b, tt.off) + got := string(b[:rn]) + if got != tt.want { + t.Errorf("%d. got %q; want %q", i, got, tt.want) + } + if fmt.Sprintf("%v", err) != fmt.Sprintf("%v", tt.wanterr) { + t.Errorf("%d. got error = %v; want %v", i, err, tt.wanterr) + } + } +} diff --git a/gcc-4.7/libgo/go/strings/replace.go b/gcc-4.7/libgo/go/strings/replace.go new file mode 100644 index 000000000..f53a96ee0 --- /dev/null +++ b/gcc-4.7/libgo/go/strings/replace.go @@ -0,0 +1,312 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import "io" + +// A Replacer replaces a list of strings with replacements. +type Replacer struct { + r replacer +} + +// replacer is the interface that a replacement algorithm needs to implement. +type replacer interface { + Replace(s string) string + WriteString(w io.Writer, s string) (n int, err error) +} + +// byteBitmap represents bytes which are sought for replacement. +// byteBitmap is 256 bits wide, with a bit set for each old byte to be +// replaced. +type byteBitmap [256 / 32]uint32 + +func (m *byteBitmap) set(b byte) { + m[b>>5] |= uint32(1 << (b & 31)) +} + +// NewReplacer returns a new Replacer from a list of old, new string pairs. +// Replacements are performed in order, without overlapping matches. +func NewReplacer(oldnew ...string) *Replacer { + if len(oldnew)%2 == 1 { + panic("strings.NewReplacer: odd argument count") + } + + // Possible implementations. + var ( + bb byteReplacer + bs byteStringReplacer + gen genericReplacer + ) + + allOldBytes, allNewBytes := true, true + for len(oldnew) > 0 { + old, new := oldnew[0], oldnew[1] + oldnew = oldnew[2:] + if len(old) != 1 { + allOldBytes = false + } + if len(new) != 1 { + allNewBytes = false + } + + // generic + gen.p = append(gen.p, pair{old, new}) + + // byte -> string + if allOldBytes { + bs.old.set(old[0]) + bs.new[old[0]] = []byte(new) + } + + // byte -> byte + if allOldBytes && allNewBytes { + bb.old.set(old[0]) + bb.new[old[0]] = new[0] + } + } + + if allOldBytes && allNewBytes { + return &Replacer{r: &bb} + } + if allOldBytes { + return &Replacer{r: &bs} + } + return &Replacer{r: &gen} +} + +// Replace returns a copy of s with all replacements performed. +func (r *Replacer) Replace(s string) string { + return r.r.Replace(s) +} + +// WriteString writes s to w with all replacements performed. +func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error) { + return r.r.WriteString(w, s) +} + +// genericReplacer is the fully generic (and least optimized) algorithm. +// It's used as a fallback when nothing faster can be used. +type genericReplacer struct { + p []pair +} + +type pair struct{ old, new string } + +type appendSliceWriter struct { + b []byte +} + +func (w *appendSliceWriter) Write(p []byte) (int, error) { + w.b = append(w.b, p...) + return len(p), nil +} + +func (r *genericReplacer) Replace(s string) string { + // TODO(bradfitz): optimized version + n, _ := r.WriteString(discard, s) + w := appendSliceWriter{make([]byte, 0, n)} + r.WriteString(&w, s) + return string(w.b) +} + +func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) { + lastEmpty := false // the last replacement was of the empty string +Input: + // TODO(bradfitz): optimized version + for i := 0; i < len(s); { + for _, p := range r.p { + if p.old == "" && lastEmpty { + // Don't let old match twice in a row. + // (it doesn't advance the input and + // would otherwise loop forever) + continue + } + if HasPrefix(s[i:], p.old) { + if p.new != "" { + wn, err := w.Write([]byte(p.new)) + n += wn + if err != nil { + return n, err + } + } + i += len(p.old) + lastEmpty = p.old == "" + continue Input + } + } + wn, err := w.Write([]byte{s[i]}) + n += wn + if err != nil { + return n, err + } + i++ + } + + // Final empty match at end. + for _, p := range r.p { + if p.old == "" { + if p.new != "" { + wn, err := w.Write([]byte(p.new)) + n += wn + if err != nil { + return n, err + } + } + break + } + } + + return n, nil +} + +// byteReplacer is the implementation that's used when all the "old" +// and "new" values are single ASCII bytes. +type byteReplacer struct { + // old has a bit set for each old byte that should be replaced. + old byteBitmap + + // replacement byte, indexed by old byte. only valid if + // corresponding old bit is set. + new [256]byte +} + +func (r *byteReplacer) Replace(s string) string { + var buf []byte // lazily allocated + for i := 0; i < len(s); i++ { + b := s[i] + if r.old[b>>5]&uint32(1<<(b&31)) != 0 { + if buf == nil { + buf = []byte(s) + } + buf[i] = r.new[b] + } + } + if buf == nil { + return s + } + return string(buf) +} + +func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) { + // TODO(bradfitz): use io.WriteString with slices of s, avoiding allocation. + bufsize := 32 << 10 + if len(s) < bufsize { + bufsize = len(s) + } + buf := make([]byte, bufsize) + + for len(s) > 0 { + ncopy := copy(buf, s[:]) + s = s[ncopy:] + for i, b := range buf[:ncopy] { + if r.old[b>>5]&uint32(1<<(b&31)) != 0 { + buf[i] = r.new[b] + } + } + wn, err := w.Write(buf[:ncopy]) + n += wn + if err != nil { + return n, err + } + } + return n, nil +} + +// byteStringReplacer is the implementation that's used when all the +// "old" values are single ASCII bytes but the "new" values vary in +// size. +type byteStringReplacer struct { + // old has a bit set for each old byte that should be replaced. + old byteBitmap + + // replacement string, indexed by old byte. only valid if + // corresponding old bit is set. + new [256][]byte +} + +func (r *byteStringReplacer) Replace(s string) string { + newSize := 0 + anyChanges := false + for i := 0; i < len(s); i++ { + b := s[i] + if r.old[b>>5]&uint32(1<<(b&31)) != 0 { + anyChanges = true + newSize += len(r.new[b]) + } else { + newSize++ + } + } + if !anyChanges { + return s + } + buf := make([]byte, newSize) + bi := buf + for i := 0; i < len(s); i++ { + b := s[i] + if r.old[b>>5]&uint32(1<<(b&31)) != 0 { + n := copy(bi[:], r.new[b]) + bi = bi[n:] + } else { + bi[0] = b + bi = bi[1:] + } + } + return string(buf) +} + +// WriteString maintains one buffer that's at most 32KB. The bytes in +// s are enumerated and the buffer is filled. If it reaches its +// capacity or a byte has a replacement, the buffer is flushed to w. +func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err error) { + // TODO(bradfitz): use io.WriteString with slices of s instead. + bufsize := 32 << 10 + if len(s) < bufsize { + bufsize = len(s) + } + buf := make([]byte, bufsize) + bi := buf[:0] + + for i := 0; i < len(s); i++ { + b := s[i] + var new []byte + if r.old[b>>5]&uint32(1<<(b&31)) != 0 { + new = r.new[b] + } else { + bi = append(bi, b) + } + if len(bi) == cap(bi) || (len(bi) > 0 && len(new) > 0) { + nw, err := w.Write(bi) + n += nw + if err != nil { + return n, err + } + bi = buf[:0] + } + if len(new) > 0 { + nw, err := w.Write(new) + n += nw + if err != nil { + return n, err + } + } + } + if len(bi) > 0 { + nw, err := w.Write(bi) + n += nw + if err != nil { + return n, err + } + } + return n, nil +} + +// strings is too low-level to import io/ioutil +var discard io.Writer = devNull(0) + +type devNull int + +func (devNull) Write(p []byte) (int, error) { + return len(p), nil +} diff --git a/gcc-4.7/libgo/go/strings/replace_test.go b/gcc-4.7/libgo/go/strings/replace_test.go new file mode 100644 index 000000000..23c7e2e53 --- /dev/null +++ b/gcc-4.7/libgo/go/strings/replace_test.go @@ -0,0 +1,174 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings_test + +import ( + "bytes" + "fmt" + "log" + . "strings" + "testing" +) + +var _ = log.Printf + +type ReplacerTest struct { + r *Replacer + in string + out string +} + +var htmlEscaper = NewReplacer("&", "&", "<", "<", ">", ">", "\"", """) + +// The http package's old HTML escaping function. +func oldhtmlEscape(s string) string { + s = Replace(s, "&", "&", -1) + s = Replace(s, "<", "<", -1) + s = Replace(s, ">", ">", -1) + s = Replace(s, "\"", """, -1) + s = Replace(s, "'", "'", -1) + return s +} + +var replacer = NewReplacer("aaa", "3[aaa]", "aa", "2[aa]", "a", "1[a]", "i", "i", + "longerst", "most long", "longer", "medium", "long", "short", + "X", "Y", "Y", "Z") + +var capitalLetters = NewReplacer("a", "A", "b", "B") + +var blankToXReplacer = NewReplacer("", "X", "o", "O") + +var ReplacerTests = []ReplacerTest{ + // byte->string + {htmlEscaper, "No changes", "No changes"}, + {htmlEscaper, "I <3 escaping & stuff", "I <3 escaping & stuff"}, + {htmlEscaper, "&&&", "&&&"}, + + // generic + {replacer, "fooaaabar", "foo3[aaa]b1[a]r"}, + {replacer, "long, longerst, longer", "short, most long, medium"}, + {replacer, "XiX", "YiY"}, + + // byte->byte + {capitalLetters, "brad", "BrAd"}, + {capitalLetters, Repeat("a", (32<<10)+123), Repeat("A", (32<<10)+123)}, + + // hitting "" special case + {blankToXReplacer, "oo", "XOXOX"}, +} + +func TestReplacer(t *testing.T) { + for i, tt := range ReplacerTests { + if s := tt.r.Replace(tt.in); s != tt.out { + t.Errorf("%d. Replace(%q) = %q, want %q", i, tt.in, s, tt.out) + } + var buf bytes.Buffer + n, err := tt.r.WriteString(&buf, tt.in) + if err != nil { + t.Errorf("%d. WriteString: %v", i, err) + continue + } + got := buf.String() + if got != tt.out { + t.Errorf("%d. WriteString(%q) wrote %q, want %q", i, tt.in, got, tt.out) + continue + } + if n != len(tt.out) { + t.Errorf("%d. WriteString(%q) wrote correct string but reported %d bytes; want %d (%q)", + i, tt.in, n, len(tt.out), tt.out) + } + } +} + +// pickAlgorithmTest is a test that verifies that given input for a +// Replacer that we pick the correct algorithm. +type pickAlgorithmTest struct { + r *Replacer + want string // name of algorithm +} + +var pickAlgorithmTests = []pickAlgorithmTest{ + {capitalLetters, "*strings.byteReplacer"}, + {NewReplacer("12", "123"), "*strings.genericReplacer"}, + {NewReplacer("1", "12"), "*strings.byteStringReplacer"}, + {htmlEscaper, "*strings.byteStringReplacer"}, +} + +func TestPickAlgorithm(t *testing.T) { + for i, tt := range pickAlgorithmTests { + got := fmt.Sprintf("%T", tt.r.Replacer()) + if got != tt.want { + t.Errorf("%d. algorithm = %s, want %s", i, got, tt.want) + } + } +} + +func BenchmarkGenericMatch(b *testing.B) { + str := Repeat("A", 100) + Repeat("B", 100) + generic := NewReplacer("a", "A", "b", "B", "12", "123") // varying lengths forces generic + for i := 0; i < b.N; i++ { + generic.Replace(str) + } +} + +func BenchmarkByteByteNoMatch(b *testing.B) { + str := Repeat("A", 100) + Repeat("B", 100) + for i := 0; i < b.N; i++ { + capitalLetters.Replace(str) + } +} + +func BenchmarkByteByteMatch(b *testing.B) { + str := Repeat("a", 100) + Repeat("b", 100) + for i := 0; i < b.N; i++ { + capitalLetters.Replace(str) + } +} + +func BenchmarkByteStringMatch(b *testing.B) { + str := "<" + Repeat("a", 99) + Repeat("b", 99) + ">" + for i := 0; i < b.N; i++ { + htmlEscaper.Replace(str) + } +} + +func BenchmarkHTMLEscapeNew(b *testing.B) { + str := "I <3 to escape HTML & other text too." + for i := 0; i < b.N; i++ { + htmlEscaper.Replace(str) + } +} + +func BenchmarkHTMLEscapeOld(b *testing.B) { + str := "I <3 to escape HTML & other text too." + for i := 0; i < b.N; i++ { + oldhtmlEscape(str) + } +} + +// BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces. +func BenchmarkByteByteReplaces(b *testing.B) { + str := Repeat("a", 100) + Repeat("b", 100) + for i := 0; i < b.N; i++ { + Replace(Replace(str, "a", "A", -1), "b", "B", -1) + } +} + +// BenchmarkByteByteMap compares byteByteImpl against Map. +func BenchmarkByteByteMap(b *testing.B) { + str := Repeat("a", 100) + Repeat("b", 100) + fn := func(r rune) rune { + switch r { + case 'a': + return 'A' + case 'b': + return 'B' + } + return r + } + for i := 0; i < b.N; i++ { + Map(fn, str) + } +} diff --git a/gcc-4.7/libgo/go/strings/strings.go b/gcc-4.7/libgo/go/strings/strings.go new file mode 100644 index 000000000..b411ba5d8 --- /dev/null +++ b/gcc-4.7/libgo/go/strings/strings.go @@ -0,0 +1,651 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package strings implements simple functions to manipulate strings. +package strings + +import ( + "unicode" + "unicode/utf8" +) + +// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit). +// Invalid UTF-8 sequences become correct encodings of U+FFF8. +func explode(s string, n int) []string { + if n == 0 { + return nil + } + l := utf8.RuneCountInString(s) + if n <= 0 || n > l { + n = l + } + a := make([]string, n) + var size int + var ch rune + i, cur := 0, 0 + for ; i+1 < n; i++ { + ch, size = utf8.DecodeRuneInString(s[cur:]) + a[i] = string(ch) + cur += size + } + // add the rest, if there is any + if cur < len(s) { + a[i] = s[cur:] + } + return a +} + +// Count counts the number of non-overlapping instances of sep in s. +func Count(s, sep string) int { + if sep == "" { + return utf8.RuneCountInString(s) + 1 + } + c := sep[0] + l := len(sep) + n := 0 + if l == 1 { + // special case worth making fast + for i := 0; i < len(s); i++ { + if s[i] == c { + n++ + } + } + return n + } + for i := 0; i+l <= len(s); i++ { + if s[i] == c && s[i:i+l] == sep { + n++ + i += l - 1 + } + } + return n +} + +// Contains returns true if substr is within s. +func Contains(s, substr string) bool { + return Index(s, substr) >= 0 +} + +// ContainsAny returns true if any Unicode code points in chars are within s. +func ContainsAny(s, chars string) bool { + return IndexAny(s, chars) >= 0 +} + +// ContainsRune returns true if the Unicode code point r is within s. +func ContainsRune(s string, r rune) bool { + return IndexRune(s, r) >= 0 +} + +// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s. +func Index(s, sep string) int { + n := len(sep) + if n == 0 { + return 0 + } + c := sep[0] + if n == 1 { + // special case worth making fast + for i := 0; i < len(s); i++ { + if s[i] == c { + return i + } + } + return -1 + } + // n > 1 + for i := 0; i+n <= len(s); i++ { + if s[i] == c && s[i:i+n] == sep { + return i + } + } + return -1 +} + +// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s. +func LastIndex(s, sep string) int { + n := len(sep) + if n == 0 { + return len(s) + } + c := sep[0] + if n == 1 { + // special case worth making fast + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 + } + // n > 1 + for i := len(s) - n; i >= 0; i-- { + if s[i] == c && s[i:i+n] == sep { + return i + } + } + return -1 +} + +// IndexRune returns the index of the first instance of the Unicode code point +// r, or -1 if rune is not present in s. +func IndexRune(s string, r rune) int { + switch { + case r < 0x80: + b := byte(r) + for i := 0; i < len(s); i++ { + if s[i] == b { + return i + } + } + default: + for i, c := range s { + if c == r { + return i + } + } + } + return -1 +} + +// IndexAny returns the index of the first instance of any Unicode code point +// from chars in s, or -1 if no Unicode code point from chars is present in s. +func IndexAny(s, chars string) int { + if len(chars) > 0 { + for i, c := range s { + for _, m := range chars { + if c == m { + return i + } + } + } + } + return -1 +} + +// LastIndexAny returns the index of the last instance of any Unicode code +// point from chars in s, or -1 if no Unicode code point from chars is +// present in s. +func LastIndexAny(s, chars string) int { + if len(chars) > 0 { + for i := len(s); i > 0; { + rune, size := utf8.DecodeLastRuneInString(s[0:i]) + i -= size + for _, m := range chars { + if rune == m { + return i + } + } + } + } + return -1 +} + +// Generic split: splits after each instance of sep, +// including sepSave bytes of sep in the subarrays. +func genSplit(s, sep string, sepSave, n int) []string { + if n == 0 { + return nil + } + if sep == "" { + return explode(s, n) + } + if n < 0 { + n = Count(s, sep) + 1 + } + c := sep[0] + start := 0 + a := make([]string, n) + na := 0 + for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ { + if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) { + a[na] = s[start : i+sepSave] + na++ + start = i + len(sep) + i += len(sep) - 1 + } + } + a[na] = s[start:] + return a[0 : na+1] +} + +// SplitN slices s into substrings separated by sep and returns a slice of +// the substrings between those separators. +// If sep is empty, SplitN splits after each UTF-8 sequence. +// The count determines the number of substrings to return: +// n > 0: at most n substrings; the last substring will be the unsplit remainder. +// n == 0: the result is nil (zero substrings) +// n < 0: all substrings +func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) } + +// SplitAfterN slices s into substrings after each instance of sep and +// returns a slice of those substrings. +// If sep is empty, SplitAfterN splits after each UTF-8 sequence. +// The count determines the number of substrings to return: +// n > 0: at most n substrings; the last substring will be the unsplit remainder. +// n == 0: the result is nil (zero substrings) +// n < 0: all substrings +func SplitAfterN(s, sep string, n int) []string { + return genSplit(s, sep, len(sep), n) +} + +// Split slices s into all substrings separated by sep and returns a slice of +// the substrings between those separators. +// If sep is empty, Split splits after each UTF-8 sequence. +// It is equivalent to SplitN with a count of -1. +func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) } + +// SplitAfter slices s into all substrings after each instance of sep and +// returns a slice of those substrings. +// If sep is empty, SplitAfter splits after each UTF-8 sequence. +// It is equivalent to SplitAfterN with a count of -1. +func SplitAfter(s, sep string) []string { + return genSplit(s, sep, len(sep), -1) +} + +// Fields splits the string s around each instance of one or more consecutive white space +// characters, returning an array of substrings of s or an empty list if s contains only white space. +func Fields(s string) []string { + return FieldsFunc(s, unicode.IsSpace) +} + +// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c) +// and returns an array of slices of s. If all code points in s satisfy f(c) or the +// string is empty, an empty slice is returned. +func FieldsFunc(s string, f func(rune) bool) []string { + // First count the fields. + n := 0 + inField := false + for _, rune := range s { + wasInField := inField + inField = !f(rune) + if inField && !wasInField { + n++ + } + } + + // Now create them. + a := make([]string, n) + na := 0 + fieldStart := -1 // Set to -1 when looking for start of field. + for i, rune := range s { + if f(rune) { + if fieldStart >= 0 { + a[na] = s[fieldStart:i] + na++ + fieldStart = -1 + } + } else if fieldStart == -1 { + fieldStart = i + } + } + if fieldStart >= 0 { // Last field might end at EOF. + a[na] = s[fieldStart:] + } + return a +} + +// Join concatenates the elements of a to create a single string. The separator string +// sep is placed between elements in the resulting string. +func Join(a []string, sep string) string { + if len(a) == 0 { + return "" + } + if len(a) == 1 { + return a[0] + } + n := len(sep) * (len(a) - 1) + for i := 0; i < len(a); i++ { + n += len(a[i]) + } + + b := make([]byte, n) + bp := copy(b, a[0]) + for _, s := range a[1:] { + bp += copy(b[bp:], sep) + bp += copy(b[bp:], s) + } + return string(b) +} + +// HasPrefix tests whether the string s begins with prefix. +func HasPrefix(s, prefix string) bool { + return len(s) >= len(prefix) && s[0:len(prefix)] == prefix +} + +// HasSuffix tests whether the string s ends with suffix. +func HasSuffix(s, suffix string) bool { + return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix +} + +// Map returns a copy of the string s with all its characters modified +// according to the mapping function. If mapping returns a negative value, the character is +// dropped from the string with no replacement. +func Map(mapping func(rune) rune, s string) string { + // In the worst case, the string can grow when mapped, making + // things unpleasant. But it's so rare we barge in assuming it's + // fine. It could also shrink but that falls out naturally. + maxbytes := len(s) // length of b + nbytes := 0 // number of bytes encoded in b + // The output buffer b is initialized on demand, the first + // time a character differs. + var b []byte + + for i, c := range s { + r := mapping(c) + if b == nil { + if r == c { + continue + } + b = make([]byte, maxbytes) + nbytes = copy(b, s[:i]) + } + if r >= 0 { + wid := 1 + if r >= utf8.RuneSelf { + wid = utf8.RuneLen(r) + } + if nbytes+wid > maxbytes { + // Grow the buffer. + maxbytes = maxbytes*2 + utf8.UTFMax + nb := make([]byte, maxbytes) + copy(nb, b[0:nbytes]) + b = nb + } + nbytes += utf8.EncodeRune(b[nbytes:maxbytes], r) + } + } + if b == nil { + return s + } + return string(b[0:nbytes]) +} + +// Repeat returns a new string consisting of count copies of the string s. +func Repeat(s string, count int) string { + b := make([]byte, len(s)*count) + bp := 0 + for i := 0; i < count; i++ { + for j := 0; j < len(s); j++ { + b[bp] = s[j] + bp++ + } + } + return string(b) +} + +// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case. +func ToUpper(s string) string { return Map(unicode.ToUpper, s) } + +// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case. +func ToLower(s string) string { return Map(unicode.ToLower, s) } + +// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case. +func ToTitle(s string) string { return Map(unicode.ToTitle, s) } + +// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their +// upper case, giving priority to the special casing rules. +func ToUpperSpecial(_case unicode.SpecialCase, s string) string { + return Map(func(r rune) rune { return _case.ToUpper(r) }, s) +} + +// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their +// lower case, giving priority to the special casing rules. +func ToLowerSpecial(_case unicode.SpecialCase, s string) string { + return Map(func(r rune) rune { return _case.ToLower(r) }, s) +} + +// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their +// title case, giving priority to the special casing rules. +func ToTitleSpecial(_case unicode.SpecialCase, s string) string { + return Map(func(r rune) rune { return _case.ToTitle(r) }, s) +} + +// isSeparator reports whether the rune could mark a word boundary. +// TODO: update when package unicode captures more of the properties. +func isSeparator(r rune) bool { + // ASCII alphanumerics and underscore are not separators + if r <= 0x7F { + switch { + case '0' <= r && r <= '9': + return false + case 'a' <= r && r <= 'z': + return false + case 'A' <= r && r <= 'Z': + return false + case r == '_': + return false + } + return true + } + // Letters and digits are not separators + if unicode.IsLetter(r) || unicode.IsDigit(r) { + return false + } + // Otherwise, all we can do for now is treat spaces as separators. + return unicode.IsSpace(r) +} + +// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly. + +// Title returns a copy of the string s with all Unicode letters that begin words +// mapped to their title case. +func Title(s string) string { + // Use a closure here to remember state. + // Hackish but effective. Depends on Map scanning in order and calling + // the closure once per rune. + prev := ' ' + return Map( + func(r rune) rune { + if isSeparator(prev) { + prev = r + return unicode.ToTitle(r) + } + prev = r + return r + }, + s) +} + +// TrimLeftFunc returns a slice of the string s with all leading +// Unicode code points c satisfying f(c) removed. +func TrimLeftFunc(s string, f func(rune) bool) string { + i := indexFunc(s, f, false) + if i == -1 { + return "" + } + return s[i:] +} + +// TrimRightFunc returns a slice of the string s with all trailing +// Unicode code points c satisfying f(c) removed. +func TrimRightFunc(s string, f func(rune) bool) string { + i := lastIndexFunc(s, f, false) + if i >= 0 && s[i] >= utf8.RuneSelf { + _, wid := utf8.DecodeRuneInString(s[i:]) + i += wid + } else { + i++ + } + return s[0:i] +} + +// TrimFunc returns a slice of the string s with all leading +// and trailing Unicode code points c satisfying f(c) removed. +func TrimFunc(s string, f func(rune) bool) string { + return TrimRightFunc(TrimLeftFunc(s, f), f) +} + +// IndexFunc returns the index into s of the first Unicode +// code point satisfying f(c), or -1 if none do. +func IndexFunc(s string, f func(rune) bool) int { + return indexFunc(s, f, true) +} + +// LastIndexFunc returns the index into s of the last +// Unicode code point satisfying f(c), or -1 if none do. +func LastIndexFunc(s string, f func(rune) bool) int { + return lastIndexFunc(s, f, true) +} + +// indexFunc is the same as IndexFunc except that if +// truth==false, the sense of the predicate function is +// inverted. +func indexFunc(s string, f func(rune) bool, truth bool) int { + start := 0 + for start < len(s) { + wid := 1 + r := rune(s[start]) + if r >= utf8.RuneSelf { + r, wid = utf8.DecodeRuneInString(s[start:]) + } + if f(r) == truth { + return start + } + start += wid + } + return -1 +} + +// lastIndexFunc is the same as LastIndexFunc except that if +// truth==false, the sense of the predicate function is +// inverted. +func lastIndexFunc(s string, f func(rune) bool, truth bool) int { + for i := len(s); i > 0; { + r, size := utf8.DecodeLastRuneInString(s[0:i]) + i -= size + if f(r) == truth { + return i + } + } + return -1 +} + +func makeCutsetFunc(cutset string) func(rune) bool { + return func(r rune) bool { return IndexRune(cutset, r) >= 0 } +} + +// Trim returns a slice of the string s with all leading and +// trailing Unicode code points contained in cutset removed. +func Trim(s string, cutset string) string { + if s == "" || cutset == "" { + return s + } + return TrimFunc(s, makeCutsetFunc(cutset)) +} + +// TrimLeft returns a slice of the string s with all leading +// Unicode code points contained in cutset removed. +func TrimLeft(s string, cutset string) string { + if s == "" || cutset == "" { + return s + } + return TrimLeftFunc(s, makeCutsetFunc(cutset)) +} + +// TrimRight returns a slice of the string s, with all trailing +// Unicode code points contained in cutset removed. +func TrimRight(s string, cutset string) string { + if s == "" || cutset == "" { + return s + } + return TrimRightFunc(s, makeCutsetFunc(cutset)) +} + +// TrimSpace returns a slice of the string s, with all leading +// and trailing white space removed, as defined by Unicode. +func TrimSpace(s string) string { + return TrimFunc(s, unicode.IsSpace) +} + +// Replace returns a copy of the string s with the first n +// non-overlapping instances of old replaced by new. +// If n < 0, there is no limit on the number of replacements. +func Replace(s, old, new string, n int) string { + if old == new || n == 0 { + return s // avoid allocation + } + + // Compute number of replacements. + if m := Count(s, old); m == 0 { + return s // avoid allocation + } else if n < 0 || m < n { + n = m + } + + // Apply replacements to buffer. + t := make([]byte, len(s)+n*(len(new)-len(old))) + w := 0 + start := 0 + for i := 0; i < n; i++ { + j := start + if len(old) == 0 { + if i > 0 { + _, wid := utf8.DecodeRuneInString(s[start:]) + j += wid + } + } else { + j += Index(s[start:], old) + } + w += copy(t[w:], s[start:j]) + w += copy(t[w:], new) + start = j + len(old) + } + w += copy(t[w:], s[start:]) + return string(t[0:w]) +} + +// EqualFold reports whether s and t, interpreted as UTF-8 strings, +// are equal under Unicode case-folding. +func EqualFold(s, t string) bool { + for s != "" && t != "" { + // Extract first rune from each string. + var sr, tr rune + if s[0] < utf8.RuneSelf { + sr, s = rune(s[0]), s[1:] + } else { + r, size := utf8.DecodeRuneInString(s) + sr, s = r, s[size:] + } + if t[0] < utf8.RuneSelf { + tr, t = rune(t[0]), t[1:] + } else { + r, size := utf8.DecodeRuneInString(t) + tr, t = r, t[size:] + } + + // If they match, keep going; if not, return false. + + // Easy case. + if tr == sr { + continue + } + + // Make sr < tr to simplify what follows. + if tr < sr { + tr, sr = sr, tr + } + // Fast check for ASCII. + if tr < utf8.RuneSelf && 'A' <= sr && sr <= 'Z' { + // ASCII, and sr is upper case. tr must be lower case. + if tr == sr+'a'-'A' { + continue + } + return false + } + + // General case. SimpleFold(x) returns the next equivalent rune > x + // or wraps around to smaller values. + r := unicode.SimpleFold(sr) + for r != sr && r < tr { + r = unicode.SimpleFold(r) + } + if r == tr { + continue + } + return false + } + + // One string is empty. Are both? + return s == t +} diff --git a/gcc-4.7/libgo/go/strings/strings_test.go b/gcc-4.7/libgo/go/strings/strings_test.go new file mode 100644 index 000000000..54046d68a --- /dev/null +++ b/gcc-4.7/libgo/go/strings/strings_test.go @@ -0,0 +1,986 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings_test + +import ( + "bytes" + "io" + "reflect" + . "strings" + "testing" + "unicode" + "unicode/utf8" + "unsafe" +) + +func eq(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +var abcd = "abcd" +var faces = "☺☻☹" +var commas = "1,2,3,4" +var dots = "1....2....3....4" + +type IndexTest struct { + s string + sep string + out int +} + +var indexTests = []IndexTest{ + {"", "", 0}, + {"", "a", -1}, + {"", "foo", -1}, + {"fo", "foo", -1}, + {"foo", "foo", 0}, + {"oofofoofooo", "f", 2}, + {"oofofoofooo", "foo", 4}, + {"barfoobarfoo", "foo", 3}, + {"foo", "", 0}, + {"foo", "o", 1}, + {"abcABCabc", "A", 3}, + // cases with one byte strings - test special case in Index() + {"", "a", -1}, + {"x", "a", -1}, + {"x", "x", 0}, + {"abc", "a", 0}, + {"abc", "b", 1}, + {"abc", "c", 2}, + {"abc", "x", -1}, +} + +var lastIndexTests = []IndexTest{ + {"", "", 0}, + {"", "a", -1}, + {"", "foo", -1}, + {"fo", "foo", -1}, + {"foo", "foo", 0}, + {"foo", "f", 0}, + {"oofofoofooo", "f", 7}, + {"oofofoofooo", "foo", 7}, + {"barfoobarfoo", "foo", 9}, + {"foo", "", 3}, + {"foo", "o", 2}, + {"abcABCabc", "A", 3}, + {"abcABCabc", "a", 6}, +} + +var indexAnyTests = []IndexTest{ + {"", "", -1}, + {"", "a", -1}, + {"", "abc", -1}, + {"a", "", -1}, + {"a", "a", 0}, + {"aaa", "a", 0}, + {"abc", "xyz", -1}, + {"abc", "xcz", 2}, + {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")}, + {"aRegExp*", ".(|)*+?^$[]", 7}, + {dots + dots + dots, " ", -1}, +} +var lastIndexAnyTests = []IndexTest{ + {"", "", -1}, + {"", "a", -1}, + {"", "abc", -1}, + {"a", "", -1}, + {"a", "a", 0}, + {"aaa", "a", 2}, + {"abc", "xyz", -1}, + {"abc", "ab", 1}, + {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")}, + {"a.RegExp*", ".(|)*+?^$[]", 8}, + {dots + dots + dots, " ", -1}, +} + +// Execute f on each test case. funcName should be the name of f; it's used +// in failure reports. +func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) { + for _, test := range testCases { + actual := f(test.s, test.sep) + if actual != test.out { + t.Errorf("%s(%q,%q) = %v; want %v", funcName, test.s, test.sep, actual, test.out) + } + } +} + +func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) } +func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) } +func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) } +func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) } + +var indexRuneTests = []struct { + s string + rune rune + out int +}{ + {"a A x", 'A', 2}, + {"some_text=some_value", '=', 9}, + {"☺a", 'a', 3}, + {"a☻☺b", '☺', 4}, +} + +func TestIndexRune(t *testing.T) { + for _, test := range indexRuneTests { + if actual := IndexRune(test.s, test.rune); actual != test.out { + t.Errorf("IndexRune(%q,%d)= %v; want %v", test.s, test.rune, actual, test.out) + } + } +} + +const benchmarkString = "some_text=some☺value" + +func BenchmarkIndexRune(b *testing.B) { + if got := IndexRune(benchmarkString, '☺'); got != 14 { + b.Fatalf("wrong index: expected 14, got=%d", got) + } + for i := 0; i < b.N; i++ { + IndexRune(benchmarkString, '☺') + } +} + +func BenchmarkIndexRuneFastPath(b *testing.B) { + if got := IndexRune(benchmarkString, 'v'); got != 17 { + b.Fatalf("wrong index: expected 17, got=%d", got) + } + for i := 0; i < b.N; i++ { + IndexRune(benchmarkString, 'v') + } +} + +func BenchmarkIndex(b *testing.B) { + if got := Index(benchmarkString, "v"); got != 17 { + b.Fatalf("wrong index: expected 17, got=%d", got) + } + for i := 0; i < b.N; i++ { + Index(benchmarkString, "v") + } +} + +var explodetests = []struct { + s string + n int + a []string +}{ + {"", -1, []string{}}, + {abcd, 4, []string{"a", "b", "c", "d"}}, + {faces, 3, []string{"☺", "☻", "☹"}}, + {abcd, 2, []string{"a", "bcd"}}, +} + +func TestExplode(t *testing.T) { + for _, tt := range explodetests { + a := SplitN(tt.s, "", tt.n) + if !eq(a, tt.a) { + t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a) + continue + } + s := Join(a, "") + if s != tt.s { + t.Errorf(`Join(explode(%q, %d), "") = %q`, tt.s, tt.n, s) + } + } +} + +type SplitTest struct { + s string + sep string + n int + a []string +} + +var splittests = []SplitTest{ + {abcd, "a", 0, nil}, + {abcd, "a", -1, []string{"", "bcd"}}, + {abcd, "z", -1, []string{"abcd"}}, + {abcd, "", -1, []string{"a", "b", "c", "d"}}, + {commas, ",", -1, []string{"1", "2", "3", "4"}}, + {dots, "...", -1, []string{"1", ".2", ".3", ".4"}}, + {faces, "☹", -1, []string{"☺☻", ""}}, + {faces, "~", -1, []string{faces}}, + {faces, "", -1, []string{"☺", "☻", "☹"}}, + {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}}, + {"1 2", " ", 3, []string{"1", "2"}}, + {"123", "", 2, []string{"1", "23"}}, + {"123", "", 17, []string{"1", "2", "3"}}, +} + +func TestSplit(t *testing.T) { + for _, tt := range splittests { + a := SplitN(tt.s, tt.sep, tt.n) + if !eq(a, tt.a) { + t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a) + continue + } + if tt.n == 0 { + continue + } + s := Join(a, tt.sep) + if s != tt.s { + t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s) + } + if tt.n < 0 { + b := Split(tt.s, tt.sep) + if !reflect.DeepEqual(a, b) { + t.Errorf("Split disagrees with SplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) + } + } + } +} + +var splitaftertests = []SplitTest{ + {abcd, "a", -1, []string{"a", "bcd"}}, + {abcd, "z", -1, []string{"abcd"}}, + {abcd, "", -1, []string{"a", "b", "c", "d"}}, + {commas, ",", -1, []string{"1,", "2,", "3,", "4"}}, + {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}}, + {faces, "☹", -1, []string{"☺☻☹", ""}}, + {faces, "~", -1, []string{faces}}, + {faces, "", -1, []string{"☺", "☻", "☹"}}, + {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}}, + {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}}, + {"1 2", " ", 3, []string{"1 ", "2"}}, + {"123", "", 2, []string{"1", "23"}}, + {"123", "", 17, []string{"1", "2", "3"}}, +} + +func TestSplitAfter(t *testing.T) { + for _, tt := range splitaftertests { + a := SplitAfterN(tt.s, tt.sep, tt.n) + if !eq(a, tt.a) { + t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a) + continue + } + s := Join(a, "") + if s != tt.s { + t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) + } + if tt.n < 0 { + b := SplitAfter(tt.s, tt.sep) + if !reflect.DeepEqual(a, b) { + t.Errorf("SplitAfter disagrees with SplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) + } + } + } +} + +type FieldsTest struct { + s string + a []string +} + +var fieldstests = []FieldsTest{ + {"", []string{}}, + {" ", []string{}}, + {" \t ", []string{}}, + {" abc ", []string{"abc"}}, + {"1 2 3 4", []string{"1", "2", "3", "4"}}, + {"1 2 3 4", []string{"1", "2", "3", "4"}}, + {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}}, + {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}}, + {"\u2000\u2001\u2002", []string{}}, + {"\n™\t™\n", []string{"™", "™"}}, + {faces, []string{faces}}, +} + +func TestFields(t *testing.T) { + for _, tt := range fieldstests { + a := Fields(tt.s) + if !eq(a, tt.a) { + t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a) + continue + } + } +} + +var FieldsFuncTests = []FieldsTest{ + {"", []string{}}, + {"XX", []string{}}, + {"XXhiXXX", []string{"hi"}}, + {"aXXbXXXcX", []string{"a", "b", "c"}}, +} + +func TestFieldsFunc(t *testing.T) { + pred := func(c rune) bool { return c == 'X' } + for _, tt := range FieldsFuncTests { + a := FieldsFunc(tt.s, pred) + if !eq(a, tt.a) { + t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a) + } + } +} + +// Test case for any function which accepts and returns a single string. +type StringTest struct { + in, out string +} + +// Execute f on each test case. funcName should be the name of f; it's used +// in failure reports. +func runStringTests(t *testing.T, f func(string) string, funcName string, testCases []StringTest) { + for _, tc := range testCases { + actual := f(tc.in) + if actual != tc.out { + t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out) + } + } +} + +var upperTests = []StringTest{ + {"", ""}, + {"abc", "ABC"}, + {"AbC123", "ABC123"}, + {"azAZ09_", "AZAZ09_"}, + {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char +} + +var lowerTests = []StringTest{ + {"", ""}, + {"abc", "abc"}, + {"AbC123", "abc123"}, + {"azAZ09_", "azaz09_"}, + {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char +} + +const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000" + +var trimSpaceTests = []StringTest{ + {"", ""}, + {"abc", "abc"}, + {space + "abc" + space, "abc"}, + {" ", ""}, + {" \t\r\n \t\t\r\r\n\n ", ""}, + {" \t\r\n x\t\t\r\r\n\n ", "x"}, + {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"}, + {"1 \t\r\n2", "1 \t\r\n2"}, + {" x\x80", "x\x80"}, + {" x\xc0", "x\xc0"}, + {"x \xc0\xc0 ", "x \xc0\xc0"}, + {"x \xc0", "x \xc0"}, + {"x \xc0 ", "x \xc0"}, + {"x \xc0\xc0 ", "x \xc0\xc0"}, + {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"}, + {"x ☺ ", "x ☺"}, +} + +func tenRunes(ch rune) string { + r := make([]rune, 10) + for i := range r { + r[i] = ch + } + return string(r) +} + +// User-defined self-inverse mapping function +func rot13(r rune) rune { + step := rune(13) + if r >= 'a' && r <= 'z' { + return ((r - 'a' + step) % 26) + 'a' + } + if r >= 'A' && r <= 'Z' { + return ((r - 'A' + step) % 26) + 'A' + } + return r +} + +func TestMap(t *testing.T) { + // Run a couple of awful growth/shrinkage tests + a := tenRunes('a') + // 1. Grow. This triggers two reallocations in Map. + maxRune := func(rune) rune { return unicode.MaxRune } + m := Map(maxRune, a) + expect := tenRunes(unicode.MaxRune) + if m != expect { + t.Errorf("growing: expected %q got %q", expect, m) + } + + // 2. Shrink + minRune := func(rune) rune { return 'a' } + m = Map(minRune, tenRunes(unicode.MaxRune)) + expect = a + if m != expect { + t.Errorf("shrinking: expected %q got %q", expect, m) + } + + // 3. Rot13 + m = Map(rot13, "a to zed") + expect = "n gb mrq" + if m != expect { + t.Errorf("rot13: expected %q got %q", expect, m) + } + + // 4. Rot13^2 + m = Map(rot13, Map(rot13, "a to zed")) + expect = "a to zed" + if m != expect { + t.Errorf("rot13: expected %q got %q", expect, m) + } + + // 5. Drop + dropNotLatin := func(r rune) rune { + if unicode.Is(unicode.Latin, r) { + return r + } + return -1 + } + m = Map(dropNotLatin, "Hello, 세계") + expect = "Hello" + if m != expect { + t.Errorf("drop: expected %q got %q", expect, m) + } + + // 6. Identity + identity := func(r rune) rune { + return r + } + orig := "Input string that we expect not to be copied." + m = Map(identity, orig) + if (*reflect.StringHeader)(unsafe.Pointer(&orig)).Data != + (*reflect.StringHeader)(unsafe.Pointer(&m)).Data { + t.Error("unexpected copy during identity map") + } +} + +func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) } + +func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } + +func BenchmarkMapNoChanges(b *testing.B) { + identity := func(r rune) rune { + return r + } + for i := 0; i < b.N; i++ { + Map(identity, "Some string that won't be modified.") + } +} + +func TestSpecialCase(t *testing.T) { + lower := "abcçdefgğhıijklmnoöprsştuüvyz" + upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ" + u := ToUpperSpecial(unicode.TurkishCase, upper) + if u != upper { + t.Errorf("Upper(upper) is %s not %s", u, upper) + } + u = ToUpperSpecial(unicode.TurkishCase, lower) + if u != upper { + t.Errorf("Upper(lower) is %s not %s", u, upper) + } + l := ToLowerSpecial(unicode.TurkishCase, lower) + if l != lower { + t.Errorf("Lower(lower) is %s not %s", l, lower) + } + l = ToLowerSpecial(unicode.TurkishCase, upper) + if l != lower { + t.Errorf("Lower(upper) is %s not %s", l, lower) + } +} + +func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) } + +var trimTests = []struct { + f string + in, cutset, out string +}{ + {"Trim", "abba", "a", "bb"}, + {"Trim", "abba", "ab", ""}, + {"TrimLeft", "abba", "ab", ""}, + {"TrimRight", "abba", "ab", ""}, + {"TrimLeft", "abba", "a", "bba"}, + {"TrimRight", "abba", "a", "abb"}, + {"Trim", "<tag>", "<>", "tag"}, + {"Trim", "* listitem", " *", "listitem"}, + {"Trim", `"quote"`, `"`, "quote"}, + {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"}, + //empty string tests + {"Trim", "abba", "", "abba"}, + {"Trim", "", "123", ""}, + {"Trim", "", "", ""}, + {"TrimLeft", "abba", "", "abba"}, + {"TrimLeft", "", "123", ""}, + {"TrimLeft", "", "", ""}, + {"TrimRight", "abba", "", "abba"}, + {"TrimRight", "", "123", ""}, + {"TrimRight", "", "", ""}, + {"TrimRight", "☺\xc0", "☺", "☺\xc0"}, +} + +func TestTrim(t *testing.T) { + for _, tc := range trimTests { + name := tc.f + var f func(string, string) string + switch name { + case "Trim": + f = Trim + case "TrimLeft": + f = TrimLeft + case "TrimRight": + f = TrimRight + default: + t.Errorf("Undefined trim function %s", name) + } + actual := f(tc.in, tc.cutset) + if actual != tc.out { + t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out) + } + } +} + +type predicate struct { + f func(rune) bool + name string +} + +var isSpace = predicate{unicode.IsSpace, "IsSpace"} +var isDigit = predicate{unicode.IsDigit, "IsDigit"} +var isUpper = predicate{unicode.IsUpper, "IsUpper"} +var isValidRune = predicate{ + func(r rune) bool { + return r != utf8.RuneError + }, + "IsValidRune", +} + +func not(p predicate) predicate { + return predicate{ + func(r rune) bool { + return !p.f(r) + }, + "not " + p.name, + } +} + +var trimFuncTests = []struct { + f predicate + in, out string +}{ + {isSpace, space + " hello " + space, "hello"}, + {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"}, + {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"}, + {not(isSpace), "hello" + space + "hello", space}, + {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"}, + {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"}, + {not(isValidRune), "\xc0a\xc0", "a"}, +} + +func TestTrimFunc(t *testing.T) { + for _, tc := range trimFuncTests { + actual := TrimFunc(tc.in, tc.f.f) + if actual != tc.out { + t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out) + } + } +} + +var indexFuncTests = []struct { + in string + f predicate + first, last int +}{ + {"", isValidRune, -1, -1}, + {"abc", isDigit, -1, -1}, + {"0123", isDigit, 0, 3}, + {"a1b", isDigit, 1, 1}, + {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes + {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18}, + {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34}, + {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12}, + + // tests of invalid UTF-8 + {"\x801", isDigit, 1, 1}, + {"\x80abc", isDigit, -1, -1}, + {"\xc0a\xc0", isValidRune, 1, 1}, + {"\xc0a\xc0", not(isValidRune), 0, 2}, + {"\xc0☺\xc0", not(isValidRune), 0, 4}, + {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5}, + {"ab\xc0a\xc0cd", not(isValidRune), 2, 4}, + {"a\xe0\x80cd", not(isValidRune), 1, 2}, + {"\x80\x80\x80\x80", not(isValidRune), 0, 3}, +} + +func TestIndexFunc(t *testing.T) { + for _, tc := range indexFuncTests { + first := IndexFunc(tc.in, tc.f.f) + if first != tc.first { + t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first) + } + last := LastIndexFunc(tc.in, tc.f.f) + if last != tc.last { + t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last) + } + } +} + +func equal(m string, s1, s2 string, t *testing.T) bool { + if s1 == s2 { + return true + } + e1 := Split(s1, "") + e2 := Split(s2, "") + for i, c1 := range e1 { + if i > len(e2) { + break + } + r1, _ := utf8.DecodeRuneInString(c1) + r2, _ := utf8.DecodeRuneInString(e2[i]) + if r1 != r2 { + t.Errorf("%s diff at %d: U+%04X U+%04X", m, i, r1, r2) + } + } + return false +} + +func TestCaseConsistency(t *testing.T) { + // Make a string of all the runes. + numRunes := int(unicode.MaxRune + 1) + if testing.Short() { + numRunes = 1000 + } + a := make([]rune, numRunes) + for i := range a { + a[i] = rune(i) + } + s := string(a) + // convert the cases. + upper := ToUpper(s) + lower := ToLower(s) + + // Consistency checks + if n := utf8.RuneCountInString(upper); n != numRunes { + t.Error("rune count wrong in upper:", n) + } + if n := utf8.RuneCountInString(lower); n != numRunes { + t.Error("rune count wrong in lower:", n) + } + if !equal("ToUpper(upper)", ToUpper(upper), upper, t) { + t.Error("ToUpper(upper) consistency fail") + } + if !equal("ToLower(lower)", ToLower(lower), lower, t) { + t.Error("ToLower(lower) consistency fail") + } + /* + These fail because of non-one-to-oneness of the data, such as multiple + upper case 'I' mapping to 'i'. We comment them out but keep them for + interest. + For instance: CAPITAL LETTER I WITH DOT ABOVE: + unicode.ToUpper(unicode.ToLower('\u0130')) != '\u0130' + + if !equal("ToUpper(lower)", ToUpper(lower), upper, t) { + t.Error("ToUpper(lower) consistency fail"); + } + if !equal("ToLower(upper)", ToLower(upper), lower, t) { + t.Error("ToLower(upper) consistency fail"); + } + */ +} + +var RepeatTests = []struct { + in, out string + count int +}{ + {"", "", 0}, + {"", "", 1}, + {"", "", 2}, + {"-", "", 0}, + {"-", "-", 1}, + {"-", "----------", 10}, + {"abc ", "abc abc abc ", 3}, +} + +func TestRepeat(t *testing.T) { + for _, tt := range RepeatTests { + a := Repeat(tt.in, tt.count) + if !equal("Repeat(s)", a, tt.out, t) { + t.Errorf("Repeat(%v, %d) = %v; want %v", tt.in, tt.count, a, tt.out) + continue + } + } +} + +func runesEqual(a, b []rune) bool { + if len(a) != len(b) { + return false + } + for i, r := range a { + if r != b[i] { + return false + } + } + return true +} + +var RunesTests = []struct { + in string + out []rune + lossy bool +}{ + {"", []rune{}, false}, + {" ", []rune{32}, false}, + {"ABC", []rune{65, 66, 67}, false}, + {"abc", []rune{97, 98, 99}, false}, + {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false}, + {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true}, + {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true}, +} + +func TestRunes(t *testing.T) { + for _, tt := range RunesTests { + a := []rune(tt.in) + if !runesEqual(a, tt.out) { + t.Errorf("[]rune(%q) = %v; want %v", tt.in, a, tt.out) + continue + } + if !tt.lossy { + // can only test reassembly if we didn't lose information + s := string(a) + if s != tt.in { + t.Errorf("string([]rune(%q)) = %x; want %x", tt.in, s, tt.in) + } + } + } +} + +func TestReadByte(t *testing.T) { + testStrings := []string{"", abcd, faces, commas} + for _, s := range testStrings { + reader := NewReader(s) + if e := reader.UnreadByte(); e == nil { + t.Errorf("Unreading %q at beginning: expected error", s) + } + var res bytes.Buffer + for { + b, e := reader.ReadByte() + if e == io.EOF { + break + } + if e != nil { + t.Errorf("Reading %q: %s", s, e) + break + } + res.WriteByte(b) + // unread and read again + e = reader.UnreadByte() + if e != nil { + t.Errorf("Unreading %q: %s", s, e) + break + } + b1, e := reader.ReadByte() + if e != nil { + t.Errorf("Reading %q after unreading: %s", s, e) + break + } + if b1 != b { + t.Errorf("Reading %q after unreading: want byte %q, got %q", s, b, b1) + break + } + } + if res.String() != s { + t.Errorf("Reader(%q).ReadByte() produced %q", s, res.String()) + } + } +} + +func TestReadRune(t *testing.T) { + testStrings := []string{"", abcd, faces, commas} + for _, s := range testStrings { + reader := NewReader(s) + if e := reader.UnreadRune(); e == nil { + t.Errorf("Unreading %q at beginning: expected error", s) + } + res := "" + for { + r, z, e := reader.ReadRune() + if e == io.EOF { + break + } + if e != nil { + t.Errorf("Reading %q: %s", s, e) + break + } + res += string(r) + // unread and read again + e = reader.UnreadRune() + if e != nil { + t.Errorf("Unreading %q: %s", s, e) + break + } + r1, z1, e := reader.ReadRune() + if e != nil { + t.Errorf("Reading %q after unreading: %s", s, e) + break + } + if r1 != r { + t.Errorf("Reading %q after unreading: want rune %q, got %q", s, r, r1) + break + } + if z1 != z { + t.Errorf("Reading %q after unreading: want size %d, got %d", s, z, z1) + break + } + } + if res != s { + t.Errorf("Reader(%q).ReadRune() produced %q", s, res) + } + } +} + +var ReplaceTests = []struct { + in string + old, new string + n int + out string +}{ + {"hello", "l", "L", 0, "hello"}, + {"hello", "l", "L", -1, "heLLo"}, + {"hello", "x", "X", -1, "hello"}, + {"", "x", "X", -1, ""}, + {"radar", "r", "<r>", -1, "<r>ada<r>"}, + {"", "", "<>", -1, "<>"}, + {"banana", "a", "<>", -1, "b<>n<>n<>"}, + {"banana", "a", "<>", 1, "b<>nana"}, + {"banana", "a", "<>", 1000, "b<>n<>n<>"}, + {"banana", "an", "<>", -1, "b<><>a"}, + {"banana", "ana", "<>", -1, "b<>na"}, + {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"}, + {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"}, + {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"}, + {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"}, + {"banana", "", "<>", 1, "<>banana"}, + {"banana", "a", "a", -1, "banana"}, + {"banana", "a", "a", 1, "banana"}, + {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"}, +} + +func TestReplace(t *testing.T) { + for _, tt := range ReplaceTests { + if s := Replace(tt.in, tt.old, tt.new, tt.n); s != tt.out { + t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out) + } + } +} + +var TitleTests = []struct { + in, out string +}{ + {"", ""}, + {"a", "A"}, + {" aaa aaa aaa ", " Aaa Aaa Aaa "}, + {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "}, + {"123a456", "123a456"}, + {"double-blind", "Double-Blind"}, + {"ÿøû", "Ÿøû"}, +} + +func TestTitle(t *testing.T) { + for _, tt := range TitleTests { + if s := Title(tt.in); s != tt.out { + t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out) + } + } +} + +var ContainsTests = []struct { + str, substr string + expected bool +}{ + {"abc", "bc", true}, + {"abc", "bcd", false}, + {"abc", "", true}, + {"", "a", false}, +} + +func TestContains(t *testing.T) { + for _, ct := range ContainsTests { + if Contains(ct.str, ct.substr) != ct.expected { + t.Errorf("Contains(%s, %s) = %v, want %v", + ct.str, ct.substr, !ct.expected, ct.expected) + } + } +} + +var ContainsAnyTests = []struct { + str, substr string + expected bool +}{ + {"", "", false}, + {"", "a", false}, + {"", "abc", false}, + {"a", "", false}, + {"a", "a", true}, + {"aaa", "a", true}, + {"abc", "xyz", false}, + {"abc", "xcz", true}, + {"a☺b☻c☹d", "uvw☻xyz", true}, + {"aRegExp*", ".(|)*+?^$[]", true}, + {dots + dots + dots, " ", false}, +} + +func TestContainsAny(t *testing.T) { + for _, ct := range ContainsAnyTests { + if ContainsAny(ct.str, ct.substr) != ct.expected { + t.Errorf("ContainsAny(%s, %s) = %v, want %v", + ct.str, ct.substr, !ct.expected, ct.expected) + } + } +} + +var ContainsRuneTests = []struct { + str string + r rune + expected bool +}{ + {"", 'a', false}, + {"a", 'a', true}, + {"aaa", 'a', true}, + {"abc", 'y', false}, + {"abc", 'c', true}, + {"a☺b☻c☹d", 'x', false}, + {"a☺b☻c☹d", '☻', true}, + {"aRegExp*", '*', true}, +} + +func TestContainsRune(t *testing.T) { + for _, ct := range ContainsRuneTests { + if ContainsRune(ct.str, ct.r) != ct.expected { + t.Errorf("ContainsRune(%s, %s) = %v, want %v", + ct.str, ct.r, !ct.expected, ct.expected) + } + } +} + +var EqualFoldTests = []struct { + s, t string + out bool +}{ + {"abc", "abc", true}, + {"ABcd", "ABcd", true}, + {"123abc", "123ABC", true}, + {"αβδ", "ΑΒΔ", true}, + {"abc", "xyz", false}, + {"abc", "XYZ", false}, + {"abcdefghijk", "abcdefghijX", false}, + {"abcdefghijk", "abcdefghij\u212A", true}, + {"abcdefghijK", "abcdefghij\u212A", true}, + {"abcdefghijkz", "abcdefghij\u212Ay", false}, + {"abcdefghijKz", "abcdefghij\u212Ay", false}, +} + +func TestEqualFold(t *testing.T) { + for _, tt := range EqualFoldTests { + if out := EqualFold(tt.s, tt.t); out != tt.out { + t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out) + } + if out := EqualFold(tt.t, tt.s); out != tt.out { + t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out) + } + } +} |