LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package strings_test | 5 package strings_test |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "fmt" | 9 "fmt" |
10 "log" | |
11 . "strings" | 10 . "strings" |
12 "testing" | 11 "testing" |
13 ) | 12 ) |
14 | 13 |
15 var _ = log.Printf | 14 var htmlEscaper = NewReplacer( |
16 | 15 » "&", "&", |
17 type ReplacerTest struct { | 16 » "<", "<", |
18 » r *Replacer | 17 » ">", ">", |
19 » in string | 18 » `"`, """, |
20 » out string | 19 » "'", "'", |
21 } | 20 ) |
22 | 21 |
23 var htmlEscaper = NewReplacer("&", "&", "<", "<", ">", ">", "\"", "&qu
ot;", "'", "'") | 22 var htmlUnescaper = NewReplacer( |
24 var htmlUnescaper = NewReplacer("&", "&", "<", "<", ">", ">", """
, `"`, "'", "'") | 23 » "&", "&", |
| 24 » "<", "<", |
| 25 » ">", ">", |
| 26 » """, `"`, |
| 27 » "'", "'", |
| 28 ) |
25 | 29 |
26 // The http package's old HTML escaping function. | 30 // The http package's old HTML escaping function. |
27 func oldhtmlEscape(s string) string { | 31 func oldHTMLEscape(s string) string { |
28 s = Replace(s, "&", "&", -1) | 32 s = Replace(s, "&", "&", -1) |
29 s = Replace(s, "<", "<", -1) | 33 s = Replace(s, "<", "<", -1) |
30 s = Replace(s, ">", ">", -1) | 34 s = Replace(s, ">", ">", -1) |
31 » s = Replace(s, "\"", """, -1) | 35 » s = Replace(s, `"`, """, -1) |
32 s = Replace(s, "'", "'", -1) | 36 s = Replace(s, "'", "'", -1) |
33 return s | 37 return s |
34 } | 38 } |
35 | 39 |
36 var replacer = NewReplacer("aaa", "3[aaa]", "aa", "2[aa]", "a", "1[a]", "i", "i"
, | |
37 "longerst", "most long", "longer", "medium", "long", "short", | |
38 "X", "Y", "Y", "Z") | |
39 | |
40 var capitalLetters = NewReplacer("a", "A", "b", "B") | 40 var capitalLetters = NewReplacer("a", "A", "b", "B") |
41 | 41 |
42 var blankToXReplacer = NewReplacer("", "X", "o", "O", "", "less important") | 42 // TestReplacer tests the replacer implementations. |
43 | |
44 var ReplacerTests = []ReplacerTest{ | |
45 » // byte->string | |
46 » {htmlEscaper, "No changes", "No changes"}, | |
47 » {htmlEscaper, "I <3 escaping & stuff", "I <3 escaping & stuff"}, | |
48 » {htmlEscaper, "&&&", "&&&"}, | |
49 | |
50 » // generic | |
51 » {replacer, "fooaaabar", "foo3[aaa]b1[a]r"}, | |
52 » {replacer, "long, longerst, longer", "short, most long, medium"}, | |
53 » {replacer, "XiX", "YiY"}, | |
54 | |
55 » // byte->byte | |
56 » {capitalLetters, "brad", "BrAd"}, | |
57 » {capitalLetters, Repeat("a", (32<<10)+123), Repeat("A", (32<<10)+123)}, | |
58 | |
59 » // hitting "" special case | |
60 » {blankToXReplacer, "oo", "XOXOX"}, | |
61 » {blankToXReplacer, "iioi", "XiXiXOXiX"}, | |
62 } | |
63 | |
64 func TestReplacer(t *testing.T) { | 43 func TestReplacer(t *testing.T) { |
65 » for i, tt := range ReplacerTests { | 44 » type testCase struct { |
66 » » if s := tt.r.Replace(tt.in); s != tt.out { | 45 » » r *Replacer |
67 » » » t.Errorf("%d. Replace(%q) = %q, want %q", i, tt.in, s, t
t.out) | 46 » » in, out string |
| 47 » } |
| 48 » var testCases []testCase |
| 49 |
| 50 » // str converts 0xff to "\xff". This isn't just string(b) since that con
verts to UTF-8. |
| 51 » str := func(b byte) string { |
| 52 » » return string([]byte{b}) |
| 53 » } |
| 54 » var s []string |
| 55 |
| 56 » // inc maps "\x00"->"\x01", ..., "a"->"b", "b"->"c", ..., "\xff"->"\x00"
. |
| 57 » s = nil |
| 58 » for i := 0; i < 256; i++ { |
| 59 » » s = append(s, str(byte(i)), str(byte(i+1))) |
| 60 » } |
| 61 » inc := NewReplacer(s...) |
| 62 |
| 63 » // Test cases with 1-byte old strings, 1-byte new strings. |
| 64 » testCases = append(testCases, |
| 65 » » testCase{capitalLetters, "brad", "BrAd"}, |
| 66 » » testCase{capitalLetters, Repeat("a", (32<<10)+123), Repeat("A",
(32<<10)+123)}, |
| 67 » » testCase{capitalLetters, "", ""}, |
| 68 |
| 69 » » testCase{inc, "brad", "csbe"}, |
| 70 » » testCase{inc, "\x00\xff", "\x01\x00"}, |
| 71 » » testCase{inc, "", ""}, |
| 72 |
| 73 » » testCase{NewReplacer("a", "1", "a", "2"), "brad", "br1d"}, |
| 74 » ) |
| 75 |
| 76 » // repeat maps "a"->"a", "b"->"bb", "c"->"ccc", ... |
| 77 » s = nil |
| 78 » for i := 0; i < 256; i++ { |
| 79 » » n := i + 1 - 'a' |
| 80 » » if n < 1 { |
| 81 » » » n = 1 |
| 82 » » } |
| 83 » » s = append(s, str(byte(i)), Repeat(str(byte(i)), n)) |
| 84 » } |
| 85 » repeat := NewReplacer(s...) |
| 86 |
| 87 » // Test cases with 1-byte old strings, variable length new strings. |
| 88 » testCases = append(testCases, |
| 89 » » testCase{htmlEscaper, "No changes", "No changes"}, |
| 90 » » testCase{htmlEscaper, "I <3 escaping & stuff", "I <3 escaping
& stuff"}, |
| 91 » » testCase{htmlEscaper, "&&&", "&&&"}, |
| 92 » » testCase{htmlEscaper, "", ""}, |
| 93 |
| 94 » » testCase{repeat, "brad", "bbrrrrrrrrrrrrrrrrrradddd"}, |
| 95 » » testCase{repeat, "abba", "abbbba"}, |
| 96 » » testCase{repeat, "", ""}, |
| 97 |
| 98 » » testCase{NewReplacer("a", "11", "a", "22"), "brad", "br11d"}, |
| 99 » ) |
| 100 |
| 101 » // The remaining test cases have variable length old strings. |
| 102 |
| 103 » testCases = append(testCases, |
| 104 » » testCase{htmlUnescaper, "&amp;", "&"}, |
| 105 » » testCase{htmlUnescaper, "<b>HTML's neat</b>", "
<b>HTML's neat</b>"}, |
| 106 » » testCase{htmlUnescaper, "", ""}, |
| 107 |
| 108 » » testCase{NewReplacer("a", "1", "a", "2", "xxx", "xxx"), "brad",
"br1d"}, |
| 109 |
| 110 » » testCase{NewReplacer("a", "1", "aa", "2", "aaa", "3"), "aaaa", "
1111"}, |
| 111 |
| 112 » » testCase{NewReplacer("aaa", "3", "aa", "2", "a", "1"), "aaaa", "
31"}, |
| 113 » ) |
| 114 |
| 115 » // gen1 has multiple old strings of variable length. There is no |
| 116 » // overall non-empty common prefix, but some pairwise common prefixes. |
| 117 » gen1 := NewReplacer( |
| 118 » » "aaa", "3[aaa]", |
| 119 » » "aa", "2[aa]", |
| 120 » » "a", "1[a]", |
| 121 » » "i", "i", |
| 122 » » "longerst", "most long", |
| 123 » » "longer", "medium", |
| 124 » » "long", "short", |
| 125 » » "xx", "xx", |
| 126 » » "x", "X", |
| 127 » » "X", "Y", |
| 128 » » "Y", "Z", |
| 129 » ) |
| 130 » testCases = append(testCases, |
| 131 » » testCase{gen1, "fooaaabar", "foo3[aaa]b1[a]r"}, |
| 132 » » testCase{gen1, "long, longerst, longer", "short, most long, medi
um"}, |
| 133 » » testCase{gen1, "xxxxx", "xxxxX"}, |
| 134 » » testCase{gen1, "XiX", "YiY"}, |
| 135 » » testCase{gen1, "", ""}, |
| 136 » ) |
| 137 |
| 138 » // gen2 has multiple old strings with no pairwise common prefix. |
| 139 » gen2 := NewReplacer( |
| 140 » » "roses", "red", |
| 141 » » "violets", "blue", |
| 142 » » "sugar", "sweet", |
| 143 » ) |
| 144 » testCases = append(testCases, |
| 145 » » testCase{gen2, "roses are red, violets are blue...", "red are re
d, blue are blue..."}, |
| 146 » » testCase{gen2, "", ""}, |
| 147 » ) |
| 148 |
| 149 » // gen3 has multiple old strings with an overall common prefix. |
| 150 » gen3 := NewReplacer( |
| 151 » » "abracadabra", "poof", |
| 152 » » "abracadabrakazam", "splat", |
| 153 » » "abraham", "lincoln", |
| 154 » » "abrasion", "scrape", |
| 155 » » "abraham", "isaac", |
| 156 » ) |
| 157 » testCases = append(testCases, |
| 158 » » testCase{gen3, "abracadabrakazam abraham", "poofkazam lincoln"}, |
| 159 » » testCase{gen3, "abrasion abracad", "scrape abracad"}, |
| 160 » » testCase{gen3, "abba abram abrasive", "abba abram abrasive"}, |
| 161 » » testCase{gen3, "", ""}, |
| 162 » ) |
| 163 |
| 164 » // foo{1,2,3,4} have multiple old strings with an overall common prefix |
| 165 » // and 1- or 2- byte extensions from the common prefix. |
| 166 » foo1 := NewReplacer( |
| 167 » » "foo1", "A", |
| 168 » » "foo2", "B", |
| 169 » » "foo3", "C", |
| 170 » ) |
| 171 » foo2 := NewReplacer( |
| 172 » » "foo1", "A", |
| 173 » » "foo2", "B", |
| 174 » » "foo31", "C", |
| 175 » » "foo32", "D", |
| 176 » ) |
| 177 » foo3 := NewReplacer( |
| 178 » » "foo11", "A", |
| 179 » » "foo12", "B", |
| 180 » » "foo31", "C", |
| 181 » » "foo32", "D", |
| 182 » ) |
| 183 » foo4 := NewReplacer( |
| 184 » » "foo12", "B", |
| 185 » » "foo32", "D", |
| 186 » ) |
| 187 » testCases = append(testCases, |
| 188 » » testCase{foo1, "fofoofoo12foo32oo", "fofooA2C2oo"}, |
| 189 » » testCase{foo1, "", ""}, |
| 190 |
| 191 » » testCase{foo2, "fofoofoo12foo32oo", "fofooA2Doo"}, |
| 192 » » testCase{foo2, "", ""}, |
| 193 |
| 194 » » testCase{foo3, "fofoofoo12foo32oo", "fofooBDoo"}, |
| 195 » » testCase{foo3, "", ""}, |
| 196 |
| 197 » » testCase{foo4, "fofoofoo12foo32oo", "fofooBDoo"}, |
| 198 » » testCase{foo4, "", ""}, |
| 199 » ) |
| 200 |
| 201 » // genAll maps "\x00\x01\x02...\xfe\xff" to "[all]", amongst other thing
s. |
| 202 » allBytes := make([]byte, 256) |
| 203 » for i := range allBytes { |
| 204 » » allBytes[i] = byte(i) |
| 205 » } |
| 206 » allString := string(allBytes) |
| 207 » genAll := NewReplacer( |
| 208 » » allString, "[all]", |
| 209 » » "\xff", "[ff]", |
| 210 » » "\x00", "[00]", |
| 211 » ) |
| 212 » testCases = append(testCases, |
| 213 » » testCase{genAll, allString, "[all]"}, |
| 214 » » testCase{genAll, "a\xff" + allString + "\x00", "a[ff][all][00]"}
, |
| 215 » » testCase{genAll, "", ""}, |
| 216 » ) |
| 217 |
| 218 » // Test cases with empty old strings. |
| 219 |
| 220 » blankToX1 := NewReplacer("", "X") |
| 221 » blankToX2 := NewReplacer("", "X", "", "") |
| 222 » blankHighPriority := NewReplacer("", "X", "o", "O") |
| 223 » blankLowPriority := NewReplacer("o", "O", "", "X") |
| 224 » blankNoOp1 := NewReplacer("", "") |
| 225 » blankNoOp2 := NewReplacer("", "", "", "A") |
| 226 » blankFoo := NewReplacer("", "X", "foobar", "R", "foobaz", "Z") |
| 227 » testCases = append(testCases, |
| 228 » » testCase{blankToX1, "foo", "XfXoXoX"}, |
| 229 » » testCase{blankToX1, "", "X"}, |
| 230 |
| 231 » » testCase{blankToX2, "foo", "XfXoXoX"}, |
| 232 » » testCase{blankToX2, "", "X"}, |
| 233 |
| 234 » » testCase{blankHighPriority, "oo", "XOXOX"}, |
| 235 » » testCase{blankHighPriority, "ii", "XiXiX"}, |
| 236 » » testCase{blankHighPriority, "iooi", "XiXOXOXiX"}, |
| 237 » » testCase{blankHighPriority, "", "X"}, |
| 238 |
| 239 » » testCase{blankLowPriority, "oo", "OOX"}, |
| 240 » » testCase{blankLowPriority, "ii", "XiXiX"}, |
| 241 » » testCase{blankLowPriority, "iooi", "XiOOXiX"}, |
| 242 » » testCase{blankLowPriority, "", "X"}, |
| 243 |
| 244 » » testCase{blankNoOp1, "foo", "foo"}, |
| 245 » » testCase{blankNoOp1, "", ""}, |
| 246 |
| 247 » » testCase{blankNoOp2, "foo", "foo"}, |
| 248 » » testCase{blankNoOp2, "", ""}, |
| 249 |
| 250 » » testCase{blankFoo, "foobarfoobaz", "XRXZX"}, |
| 251 » » testCase{blankFoo, "foobar-foobaz", "XRX-XZX"}, |
| 252 » » testCase{blankFoo, "", "X"}, |
| 253 » ) |
| 254 |
| 255 » // No-arg test cases. |
| 256 |
| 257 » nop := NewReplacer() |
| 258 » testCases = append(testCases, |
| 259 » » testCase{nop, "abc", "abc"}, |
| 260 » » testCase{nop, "", ""}, |
| 261 » ) |
| 262 |
| 263 » // Run the test cases. |
| 264 |
| 265 » for i, tc := range testCases { |
| 266 » » if s := tc.r.Replace(tc.in); s != tc.out { |
| 267 » » » t.Errorf("%d. Replace(%q) = %q, want %q", i, tc.in, s, t
c.out) |
68 } | 268 } |
69 var buf bytes.Buffer | 269 var buf bytes.Buffer |
70 » » n, err := tt.r.WriteString(&buf, tt.in) | 270 » » n, err := tc.r.WriteString(&buf, tc.in) |
71 if err != nil { | 271 if err != nil { |
72 t.Errorf("%d. WriteString: %v", i, err) | 272 t.Errorf("%d. WriteString: %v", i, err) |
73 continue | 273 continue |
74 } | 274 } |
75 got := buf.String() | 275 got := buf.String() |
76 » » if got != tt.out { | 276 » » if got != tc.out { |
77 » » » t.Errorf("%d. WriteString(%q) wrote %q, want %q", i, tt.
in, got, tt.out) | 277 » » » t.Errorf("%d. WriteString(%q) wrote %q, want %q", i, tc.
in, got, tc.out) |
78 continue | 278 continue |
79 } | 279 } |
80 » » if n != len(tt.out) { | 280 » » if n != len(tc.out) { |
81 t.Errorf("%d. WriteString(%q) wrote correct string but r
eported %d bytes; want %d (%q)", | 281 t.Errorf("%d. WriteString(%q) wrote correct string but r
eported %d bytes; want %d (%q)", |
82 » » » » i, tt.in, n, len(tt.out), tt.out) | 282 » » » » i, tc.in, n, len(tc.out), tc.out) |
83 » » } | 283 » » } |
84 » } | 284 » } |
85 } | 285 } |
86 | 286 |
87 // pickAlgorithmTest is a test that verifies that given input for a | 287 // TestPickAlgorithm tests that NewReplacer picks the correct algorithm. |
88 // Replacer that we pick the correct algorithm. | |
89 type pickAlgorithmTest struct { | |
90 » r *Replacer | |
91 » want string // name of algorithm | |
92 } | |
93 | |
94 var pickAlgorithmTests = []pickAlgorithmTest{ | |
95 » {capitalLetters, "*strings.byteReplacer"}, | |
96 » {NewReplacer("12", "123"), "*strings.genericReplacer"}, | |
97 » {NewReplacer("1", "12"), "*strings.byteStringReplacer"}, | |
98 » {htmlEscaper, "*strings.byteStringReplacer"}, | |
99 } | |
100 | |
101 func TestPickAlgorithm(t *testing.T) { | 288 func TestPickAlgorithm(t *testing.T) { |
102 » for i, tt := range pickAlgorithmTests { | 289 » testCases := []struct { |
103 » » got := fmt.Sprintf("%T", tt.r.Replacer()) | 290 » » r *Replacer |
104 » » if got != tt.want { | 291 » » want string |
105 » » » t.Errorf("%d. algorithm = %s, want %s", i, got, tt.want) | 292 » }{ |
| 293 » » {capitalLetters, "*strings.byteReplacer"}, |
| 294 » » {htmlEscaper, "*strings.byteStringReplacer"}, |
| 295 » » {NewReplacer("12", "123"), "*strings.genericReplacer"}, |
| 296 » » {NewReplacer("1", "12"), "*strings.byteStringReplacer"}, |
| 297 » » {NewReplacer("a", "1", "b", "12", "cde", "123"), "*strings.gener
icReplacer"}, |
| 298 » } |
| 299 » for i, tc := range testCases { |
| 300 » » got := fmt.Sprintf("%T", tc.r.Replacer()) |
| 301 » » if got != tc.want { |
| 302 » » » t.Errorf("%d. algorithm = %s, want %s", i, got, tc.want) |
| 303 » » } |
| 304 » } |
| 305 } |
| 306 |
| 307 // TestGenericTrieBuilding verifies the structure of the generated trie. There |
| 308 // is one node per line, and the key ending with the current line is in the |
| 309 // trie if it ends with a "+". |
| 310 func TestGenericTrieBuilding(t *testing.T) { |
| 311 » testCases := []struct{ in, out string }{ |
| 312 » » {"abc;abdef;abdefgh;xx;xy;z", `- |
| 313 » » » a- |
| 314 » » » .b- |
| 315 » » » ..c+ |
| 316 » » » ..d- |
| 317 » » » ...ef+ |
| 318 » » » .....gh+ |
| 319 » » » x- |
| 320 » » » .x+ |
| 321 » » » .y+ |
| 322 » » » z+ |
| 323 » » » `}, |
| 324 » » {"abracadabra;abracadabrakazam;abraham;abrasion", `- |
| 325 » » » a- |
| 326 » » » .bra- |
| 327 » » » ....c- |
| 328 » » » .....adabra+ |
| 329 » » » ...........kazam+ |
| 330 » » » ....h- |
| 331 » » » .....am+ |
| 332 » » » ....s- |
| 333 » » » .....ion+ |
| 334 » » » `}, |
| 335 » » {"aaa;aa;a;i;longerst;longer;long;xx;x;X;Y", `- |
| 336 » » » X+ |
| 337 » » » Y+ |
| 338 » » » a+ |
| 339 » » » .a+ |
| 340 » » » ..a+ |
| 341 » » » i+ |
| 342 » » » l- |
| 343 » » » .ong+ |
| 344 » » » ....er+ |
| 345 » » » ......st+ |
| 346 » » » x+ |
| 347 » » » .x+ |
| 348 » » » `}, |
| 349 » » {"foo;;foo;foo1", `+ |
| 350 » » » f- |
| 351 » » » .oo+ |
| 352 » » » ...1+ |
| 353 » » » `}, |
| 354 » } |
| 355 |
| 356 » for _, tc := range testCases { |
| 357 » » keys := Split(tc.in, ";") |
| 358 » » args := make([]string, len(keys)*2) |
| 359 » » for i, key := range keys { |
| 360 » » » args[i*2] = key |
| 361 » » } |
| 362 |
| 363 » » got := NewReplacer(args...).PrintTrie() |
| 364 » » // Remove tabs from tc.out |
| 365 » » wantbuf := make([]byte, 0, len(tc.out)) |
| 366 » » for i := 0; i < len(tc.out); i++ { |
| 367 » » » if tc.out[i] != '\t' { |
| 368 » » » » wantbuf = append(wantbuf, tc.out[i]) |
| 369 » » » } |
| 370 » » } |
| 371 » » want := string(wantbuf) |
| 372 |
| 373 » » if got != want { |
| 374 » » » t.Errorf("PrintTrie(%q)\ngot\n%swant\n%s", tc.in, got, w
ant) |
106 } | 375 } |
107 } | 376 } |
108 } | 377 } |
109 | 378 |
110 func BenchmarkGenericNoMatch(b *testing.B) { | 379 func BenchmarkGenericNoMatch(b *testing.B) { |
111 str := Repeat("A", 100) + Repeat("B", 100) | 380 str := Repeat("A", 100) + Repeat("B", 100) |
112 generic := NewReplacer("a", "A", "b", "B", "12", "123") // varying lengt
hs forces generic | 381 generic := NewReplacer("a", "A", "b", "B", "12", "123") // varying lengt
hs forces generic |
113 for i := 0; i < b.N; i++ { | 382 for i := 0; i < b.N; i++ { |
114 generic.Replace(str) | 383 generic.Replace(str) |
115 } | 384 } |
116 } | 385 } |
117 | 386 |
118 func BenchmarkGenericMatch(b *testing.B) { | 387 func BenchmarkGenericMatch1(b *testing.B) { |
119 » html := Repeat("It's <b>HTML</b>!", 10) | 388 » str := Repeat("a", 100) + Repeat("b", 100) |
120 » for i := 0; i < b.N; i++ { | 389 » generic := NewReplacer("a", "A", "b", "B", "12", "123") |
121 » » htmlUnescaper.Replace(html) | 390 » for i := 0; i < b.N; i++ { |
| 391 » » generic.Replace(str) |
| 392 » } |
| 393 } |
| 394 |
| 395 func BenchmarkGenericMatch2(b *testing.B) { |
| 396 » str := Repeat("It's <b>HTML</b>!", 100) |
| 397 » for i := 0; i < b.N; i++ { |
| 398 » » htmlUnescaper.Replace(str) |
122 } | 399 } |
123 } | 400 } |
124 | 401 |
125 func BenchmarkByteByteNoMatch(b *testing.B) { | 402 func BenchmarkByteByteNoMatch(b *testing.B) { |
126 str := Repeat("A", 100) + Repeat("B", 100) | 403 str := Repeat("A", 100) + Repeat("B", 100) |
127 for i := 0; i < b.N; i++ { | 404 for i := 0; i < b.N; i++ { |
128 capitalLetters.Replace(str) | 405 capitalLetters.Replace(str) |
129 } | 406 } |
130 } | 407 } |
131 | 408 |
(...skipping 14 matching lines...) Expand all Loading... |
146 func BenchmarkHTMLEscapeNew(b *testing.B) { | 423 func BenchmarkHTMLEscapeNew(b *testing.B) { |
147 str := "I <3 to escape HTML & other text too." | 424 str := "I <3 to escape HTML & other text too." |
148 for i := 0; i < b.N; i++ { | 425 for i := 0; i < b.N; i++ { |
149 htmlEscaper.Replace(str) | 426 htmlEscaper.Replace(str) |
150 } | 427 } |
151 } | 428 } |
152 | 429 |
153 func BenchmarkHTMLEscapeOld(b *testing.B) { | 430 func BenchmarkHTMLEscapeOld(b *testing.B) { |
154 str := "I <3 to escape HTML & other text too." | 431 str := "I <3 to escape HTML & other text too." |
155 for i := 0; i < b.N; i++ { | 432 for i := 0; i < b.N; i++ { |
156 » » oldhtmlEscape(str) | 433 » » oldHTMLEscape(str) |
157 } | 434 } |
158 } | 435 } |
159 | 436 |
160 // BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces. | 437 // BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces. |
161 func BenchmarkByteByteReplaces(b *testing.B) { | 438 func BenchmarkByteByteReplaces(b *testing.B) { |
162 str := Repeat("a", 100) + Repeat("b", 100) | 439 str := Repeat("a", 100) + Repeat("b", 100) |
163 for i := 0; i < b.N; i++ { | 440 for i := 0; i < b.N; i++ { |
164 Replace(Replace(str, "a", "A", -1), "b", "B", -1) | 441 Replace(Replace(str, "a", "A", -1), "b", "B", -1) |
165 } | 442 } |
166 } | 443 } |
167 | 444 |
168 // BenchmarkByteByteMap compares byteByteImpl against Map. | 445 // BenchmarkByteByteMap compares byteByteImpl against Map. |
169 func BenchmarkByteByteMap(b *testing.B) { | 446 func BenchmarkByteByteMap(b *testing.B) { |
170 str := Repeat("a", 100) + Repeat("b", 100) | 447 str := Repeat("a", 100) + Repeat("b", 100) |
171 fn := func(r rune) rune { | 448 fn := func(r rune) rune { |
172 switch r { | 449 switch r { |
173 case 'a': | 450 case 'a': |
174 return 'A' | 451 return 'A' |
175 case 'b': | 452 case 'b': |
176 return 'B' | 453 return 'B' |
177 } | 454 } |
178 return r | 455 return r |
179 } | 456 } |
180 for i := 0; i < b.N; i++ { | 457 for i := 0; i < b.N; i++ { |
181 Map(fn, str) | 458 Map(fn, str) |
182 } | 459 } |
183 } | 460 } |
LEFT | RIGHT |