Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package strings_test |
| 6 | |
| 7 | import ( |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 8 | "bytes" |
| 9 | "fmt" |
| 10 | "log" |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 11 | . "strings" |
| 12 | "testing" |
| 13 | ) |
| 14 | |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 15 | var _ = log.Printf |
| 16 | |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 17 | type ReplacerTest struct { |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 18 | r *Replacer |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 19 | in string |
| 20 | out string |
| 21 | } |
| 22 | |
| 23 | var htmlEscaper = NewReplacer("&", "&", "<", "<", ">", ">", "\"", """) |
| 24 | |
| 25 | // The http package's old HTML escaping function. |
| 26 | func oldhtmlEscape(s string) string { |
| 27 | s = Replace(s, "&", "&", -1) |
| 28 | s = Replace(s, "<", "<", -1) |
| 29 | s = Replace(s, ">", ">", -1) |
| 30 | s = Replace(s, "\"", """, -1) |
| 31 | s = Replace(s, "'", "'", -1) |
| 32 | return s |
| 33 | } |
| 34 | |
| 35 | var replacer = NewReplacer("aaa", "3[aaa]", "aa", "2[aa]", "a", "1[a]", "i", "i", |
| 36 | "longerst", "most long", "longer", "medium", "long", "short", |
| 37 | "X", "Y", "Y", "Z") |
| 38 | |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 39 | var capitalLetters = NewReplacer("a", "A", "b", "B") |
| 40 | |
| 41 | var blankToXReplacer = NewReplacer("", "X", "o", "O") |
| 42 | |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 43 | var ReplacerTests = []ReplacerTest{ |
Brad Fitzpatrick | bba7396 | 2011-10-03 15:19:04 -0700 | [diff] [blame] | 44 | // byte->string |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 45 | {htmlEscaper, "No changes", "No changes"}, |
| 46 | {htmlEscaper, "I <3 escaping & stuff", "I <3 escaping & stuff"}, |
| 47 | {htmlEscaper, "&&&", "&&&"}, |
Brad Fitzpatrick | bba7396 | 2011-10-03 15:19:04 -0700 | [diff] [blame] | 48 | |
| 49 | // generic |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 50 | {replacer, "fooaaabar", "foo3[aaa]b1[a]r"}, |
| 51 | {replacer, "long, longerst, longer", "short, most long, medium"}, |
| 52 | {replacer, "XiX", "YiY"}, |
Brad Fitzpatrick | bba7396 | 2011-10-03 15:19:04 -0700 | [diff] [blame] | 53 | |
| 54 | // byte->byte |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 55 | {capitalLetters, "brad", "BrAd"}, |
| 56 | {capitalLetters, Repeat("a", (32<<10)+123), Repeat("A", (32<<10)+123)}, |
Brad Fitzpatrick | bba7396 | 2011-10-03 15:19:04 -0700 | [diff] [blame] | 57 | |
| 58 | // hitting "" special case |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 59 | {blankToXReplacer, "oo", "XOXOX"}, |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | func TestReplacer(t *testing.T) { |
| 63 | for i, tt := range ReplacerTests { |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 64 | if s := tt.r.Replace(tt.in); s != tt.out { |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 65 | t.Errorf("%d. Replace(%q) = %q, want %q", i, tt.in, s, tt.out) |
| 66 | } |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 67 | var buf bytes.Buffer |
| 68 | n, err := tt.r.WriteString(&buf, tt.in) |
| 69 | if err != nil { |
| 70 | t.Errorf("%d. WriteString: %v", i, err) |
| 71 | continue |
| 72 | } |
| 73 | got := buf.String() |
| 74 | if got != tt.out { |
| 75 | t.Errorf("%d. WriteString(%q) wrote %q, want %q", i, tt.in, got, tt.out) |
| 76 | continue |
| 77 | } |
| 78 | if n != len(tt.out) { |
| 79 | t.Errorf("%d. WriteString(%q) wrote correct string but reported %d bytes; want %d (%q)", |
| 80 | i, tt.in, n, len(tt.out), tt.out) |
| 81 | } |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 82 | } |
| 83 | } |
| 84 | |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 85 | // pickAlgorithmTest is a test that verifies that given input for a |
| 86 | // Replacer that we pick the correct algorithm. |
| 87 | type pickAlgorithmTest struct { |
| 88 | r *Replacer |
| 89 | want string // name of algorithm |
| 90 | } |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 91 | |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 92 | var pickAlgorithmTests = []pickAlgorithmTest{ |
| 93 | {capitalLetters, "*strings.byteReplacer"}, |
Brad Fitzpatrick | bba7396 | 2011-10-03 15:19:04 -0700 | [diff] [blame] | 94 | {NewReplacer("12", "123"), "*strings.genericReplacer"}, |
| 95 | {NewReplacer("1", "12"), "*strings.byteStringReplacer"}, |
| 96 | {htmlEscaper, "*strings.byteStringReplacer"}, |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | func TestPickAlgorithm(t *testing.T) { |
| 100 | for i, tt := range pickAlgorithmTests { |
| 101 | got := fmt.Sprintf("%T", tt.r.Replacer()) |
| 102 | if got != tt.want { |
| 103 | t.Errorf("%d. algorithm = %s, want %s", i, got, tt.want) |
| 104 | } |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 105 | } |
| 106 | } |
| 107 | |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 108 | func BenchmarkGenericMatch(b *testing.B) { |
| 109 | str := Repeat("A", 100) + Repeat("B", 100) |
| 110 | generic := NewReplacer("a", "A", "b", "B", "12", "123") // varying lengths forces generic |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 111 | for i := 0; i < b.N; i++ { |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 112 | generic.Replace(str) |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 116 | func BenchmarkByteByteNoMatch(b *testing.B) { |
| 117 | str := Repeat("A", 100) + Repeat("B", 100) |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 118 | for i := 0; i < b.N; i++ { |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 119 | capitalLetters.Replace(str) |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | func BenchmarkByteByteMatch(b *testing.B) { |
| 124 | str := Repeat("a", 100) + Repeat("b", 100) |
| 125 | for i := 0; i < b.N; i++ { |
| 126 | capitalLetters.Replace(str) |
| 127 | } |
| 128 | } |
| 129 | |
Brad Fitzpatrick | bba7396 | 2011-10-03 15:19:04 -0700 | [diff] [blame] | 130 | func BenchmarkByteStringMatch(b *testing.B) { |
| 131 | str := "<" + Repeat("a", 99) + Repeat("b", 99) + ">" |
| 132 | for i := 0; i < b.N; i++ { |
| 133 | htmlEscaper.Replace(str) |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | func BenchmarkHTMLEscapeNew(b *testing.B) { |
| 138 | str := "I <3 to escape HTML & other text too." |
| 139 | for i := 0; i < b.N; i++ { |
| 140 | htmlEscaper.Replace(str) |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | func BenchmarkHTMLEscapeOld(b *testing.B) { |
| 145 | str := "I <3 to escape HTML & other text too." |
| 146 | for i := 0; i < b.N; i++ { |
| 147 | oldhtmlEscape(str) |
| 148 | } |
| 149 | } |
| 150 | |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 151 | // BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces. |
| 152 | func BenchmarkByteByteReplaces(b *testing.B) { |
| 153 | str := Repeat("a", 100) + Repeat("b", 100) |
| 154 | for i := 0; i < b.N; i++ { |
| 155 | Replace(Replace(str, "a", "A", -1), "b", "B", -1) |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | // BenchmarkByteByteMap compares byteByteImpl against Map. |
| 160 | func BenchmarkByteByteMap(b *testing.B) { |
| 161 | str := Repeat("a", 100) + Repeat("b", 100) |
Russ Cox | 8f57181 | 2011-10-25 22:22:09 -0700 | [diff] [blame] | 162 | fn := func(r rune) rune { |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 163 | switch r { |
| 164 | case 'a': |
Russ Cox | 8f57181 | 2011-10-25 22:22:09 -0700 | [diff] [blame] | 165 | return 'A' |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 166 | case 'b': |
Russ Cox | 8f57181 | 2011-10-25 22:22:09 -0700 | [diff] [blame] | 167 | return 'B' |
Brad Fitzpatrick | f75ff01 | 2011-10-03 13:12:01 -0700 | [diff] [blame] | 168 | } |
| 169 | return r |
| 170 | } |
| 171 | for i := 0; i < b.N; i++ { |
| 172 | Map(fn, str) |
Brad Fitzpatrick | 7b0f3ca | 2011-09-28 09:34:26 -0700 | [diff] [blame] | 173 | } |
| 174 | } |