Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(384)

Side by Side Diff: src/pkg/strings/replace_test.go

Issue 6492076: code review 6492076: strings: implement a faster generic Replacer (Closed)
Patch Set: diff -r c99aad44d76c https://code.google.com/p/go Created 11 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pkg/strings/replace.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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" 10 "log"
11 . "strings" 11 . "strings"
12 "testing" 12 "testing"
13 ) 13 )
14 14
15 var _ = log.Printf 15 var _ = log.Printf
16 16
17 type ReplacerTest struct { 17 type ReplacerTest struct {
18 r *Replacer 18 r *Replacer
19 in string 19 in string
20 out string 20 out string
21 } 21 }
22 22
23 var htmlEscaper = NewReplacer("&", "&amp;", "<", "&lt;", ">", "&gt;", "\"", "&qu ot;") 23 var htmlEscaper = NewReplacer("&", "&amp;", "<", "&lt;", ">", "&gt;", "\"", "&qu ot;", "'", "&apos;")
24 var htmlUnescaper = NewReplacer("&amp;", "&", "&lt;", "<", "&gt;", ">", "&quot;" , `"`, "&apos;", "'")
24 25
25 // The http package's old HTML escaping function. 26 // The http package's old HTML escaping function.
26 func oldhtmlEscape(s string) string { 27 func oldhtmlEscape(s string) string {
27 s = Replace(s, "&", "&amp;", -1) 28 s = Replace(s, "&", "&amp;", -1)
28 s = Replace(s, "<", "&lt;", -1) 29 s = Replace(s, "<", "&lt;", -1)
29 s = Replace(s, ">", "&gt;", -1) 30 s = Replace(s, ">", "&gt;", -1)
30 s = Replace(s, "\"", "&quot;", -1) 31 s = Replace(s, "\"", "&quot;", -1)
31 s = Replace(s, "'", "&apos;", -1) 32 s = Replace(s, "'", "&apos;", -1)
32 return s 33 return s
33 } 34 }
34 35
35 var replacer = NewReplacer("aaa", "3[aaa]", "aa", "2[aa]", "a", "1[a]", "i", "i" , 36 var replacer = NewReplacer("aaa", "3[aaa]", "aa", "2[aa]", "a", "1[a]", "i", "i" ,
36 "longerst", "most long", "longer", "medium", "long", "short", 37 "longerst", "most long", "longer", "medium", "long", "short",
37 "X", "Y", "Y", "Z") 38 "X", "Y", "Y", "Z")
38 39
40 var genReplacer = NewReplacer(
41 "abracadabra", "poof",
42 "abracadabrakazam", "splat", // Should never trigger.
43 "abraham", "lincoln",
44 "abrasion", "scrape",
45 "abraham", "isaac", // Should never trigger.
46 )
47
39 var capitalLetters = NewReplacer("a", "A", "b", "B") 48 var capitalLetters = NewReplacer("a", "A", "b", "B")
40 49
41 var blankToXReplacer = NewReplacer("", "X", "o", "O") 50 var blankToXReplacer = NewReplacer("", "X", "o", "O", "", "less important")
42 51
43 var ReplacerTests = []ReplacerTest{ 52 var ReplacerTests = []ReplacerTest{
44 // byte->string 53 // byte->string
45 {htmlEscaper, "No changes", "No changes"}, 54 {htmlEscaper, "No changes", "No changes"},
46 {htmlEscaper, "I <3 escaping & stuff", "I &lt;3 escaping &amp; stuff"}, 55 {htmlEscaper, "I <3 escaping & stuff", "I &lt;3 escaping &amp; stuff"},
47 {htmlEscaper, "&&&", "&amp;&amp;&amp;"}, 56 {htmlEscaper, "&&&", "&amp;&amp;&amp;"},
48 57
49 // generic 58 // generic
50 » {replacer, "fooaaabar", "foo3[aaa]b1[a]r"}, 59 » {htmlUnescaper, "&amp;amp;", "&amp;"},
60 » {htmlUnescaper, "&lt;b&gt;HTML&apos;s neat&lt;/b&gt;", "<b>HTML's neat</ b>"},
61
62 » {replacer, "fooaaabarbaaz", "foo3[aaa]b1[a]rb2[aa]z"},
51 {replacer, "long, longerst, longer", "short, most long, medium"}, 63 {replacer, "long, longerst, longer", "short, most long, medium"},
52 {replacer, "XiX", "YiY"}, 64 {replacer, "XiX", "YiY"},
53 65
66 {genReplacer, "abracadabrakazam abraham", "poofkazam lincoln"},
67 {genReplacer, "abrasion abracad", "scrape abracad"},
68 {genReplacer, "abba abram abrasive", "abba abram abrasive"},
69
54 // byte->byte 70 // byte->byte
55 {capitalLetters, "brad", "BrAd"}, 71 {capitalLetters, "brad", "BrAd"},
56 {capitalLetters, Repeat("a", (32<<10)+123), Repeat("A", (32<<10)+123)}, 72 {capitalLetters, Repeat("a", (32<<10)+123), Repeat("A", (32<<10)+123)},
57 73
58 // hitting "" special case 74 // hitting "" special case
75 {blankToXReplacer, "", "X"},
59 {blankToXReplacer, "oo", "XOXOX"}, 76 {blankToXReplacer, "oo", "XOXOX"},
77 {blankToXReplacer, "iioi", "XiXiXOXiX"},
78 {NewReplacer("", "", "", "X"), "a", "a"},
79 {NewReplacer("a", "A", "", "X"), "abba", "AXbXbAX"},
60 } 80 }
61 81
62 func TestReplacer(t *testing.T) { 82 func TestReplacer(t *testing.T) {
83 // Added here for initialization.
nigeltao 2012/09/11 03:14:41 You might as well move all the ReplacerTests into
84 var allBytes []byte
85 for i := 0; i < 256; i++ {
86 allBytes = append(allBytes, byte(i))
87 }
88 allString := string(allBytes)
89 bigReplacer := NewReplacer(allString, "[all]",
90 "\xff", "[allbits]", "\x00", "[nobits]")
91
92 ReplacerTests = append(ReplacerTests,
93 ReplacerTest{bigReplacer, allString, "[all]"},
94 ReplacerTest{bigReplacer, "a\xff" + allString + "\x00", "a[allbi ts][all][nobits]"},
95 )
96
63 for i, tt := range ReplacerTests { 97 for i, tt := range ReplacerTests {
64 if s := tt.r.Replace(tt.in); s != tt.out { 98 if s := tt.r.Replace(tt.in); s != tt.out {
65 t.Errorf("%d. Replace(%q) = %q, want %q", i, tt.in, s, t t.out) 99 t.Errorf("%d. Replace(%q) = %q, want %q", i, tt.in, s, t t.out)
66 } 100 }
67 var buf bytes.Buffer 101 var buf bytes.Buffer
68 n, err := tt.r.WriteString(&buf, tt.in) 102 n, err := tt.r.WriteString(&buf, tt.in)
69 if err != nil { 103 if err != nil {
70 t.Errorf("%d. WriteString: %v", i, err) 104 t.Errorf("%d. WriteString: %v", i, err)
71 continue 105 continue
72 } 106 }
(...skipping 25 matching lines...) Expand all
98 132
99 func TestPickAlgorithm(t *testing.T) { 133 func TestPickAlgorithm(t *testing.T) {
100 for i, tt := range pickAlgorithmTests { 134 for i, tt := range pickAlgorithmTests {
101 got := fmt.Sprintf("%T", tt.r.Replacer()) 135 got := fmt.Sprintf("%T", tt.r.Replacer())
102 if got != tt.want { 136 if got != tt.want {
103 t.Errorf("%d. algorithm = %s, want %s", i, got, tt.want) 137 t.Errorf("%d. algorithm = %s, want %s", i, got, tt.want)
104 } 138 }
105 } 139 }
106 } 140 }
107 141
108 func BenchmarkGenericMatch(b *testing.B) { 142 func BenchmarkGenericNoMatch(b *testing.B) {
109 str := Repeat("A", 100) + Repeat("B", 100) 143 str := Repeat("A", 100) + Repeat("B", 100)
110 generic := NewReplacer("a", "A", "b", "B", "12", "123") // varying lengt hs forces generic 144 generic := NewReplacer("a", "A", "b", "B", "12", "123") // varying lengt hs forces generic
145 b.SetBytes(int64(len(str)))
111 for i := 0; i < b.N; i++ { 146 for i := 0; i < b.N; i++ {
112 generic.Replace(str) 147 generic.Replace(str)
113 } 148 }
114 } 149 }
115 150
151 func BenchmarkGenericMatch(b *testing.B) {
152 html := Repeat("It&apos;s &lt;b&gt;HTML&lt;/b&gt;!", 10)
153 b.SetBytes(int64(len(html)))
154 for i := 0; i < b.N; i++ {
155 htmlUnescaper.Replace(html)
156 }
157 }
158
116 func BenchmarkByteByteNoMatch(b *testing.B) { 159 func BenchmarkByteByteNoMatch(b *testing.B) {
117 str := Repeat("A", 100) + Repeat("B", 100) 160 str := Repeat("A", 100) + Repeat("B", 100)
161 b.SetBytes(int64(len(str)))
118 for i := 0; i < b.N; i++ { 162 for i := 0; i < b.N; i++ {
119 capitalLetters.Replace(str) 163 capitalLetters.Replace(str)
120 } 164 }
121 } 165 }
122 166
123 func BenchmarkByteByteMatch(b *testing.B) { 167 func BenchmarkByteByteMatch(b *testing.B) {
124 str := Repeat("a", 100) + Repeat("b", 100) 168 str := Repeat("a", 100) + Repeat("b", 100)
169 b.SetBytes(int64(len(str)))
125 for i := 0; i < b.N; i++ { 170 for i := 0; i < b.N; i++ {
126 capitalLetters.Replace(str) 171 capitalLetters.Replace(str)
127 } 172 }
128 } 173 }
129 174
130 func BenchmarkByteStringMatch(b *testing.B) { 175 func BenchmarkByteStringMatch(b *testing.B) {
131 str := "<" + Repeat("a", 99) + Repeat("b", 99) + ">" 176 str := "<" + Repeat("a", 99) + Repeat("b", 99) + ">"
177 b.SetBytes(int64(len(str)))
132 for i := 0; i < b.N; i++ { 178 for i := 0; i < b.N; i++ {
133 htmlEscaper.Replace(str) 179 htmlEscaper.Replace(str)
134 } 180 }
135 } 181 }
136 182
137 func BenchmarkHTMLEscapeNew(b *testing.B) { 183 func BenchmarkHTMLEscapeNew(b *testing.B) {
138 str := "I <3 to escape HTML & other text too." 184 str := "I <3 to escape HTML & other text too."
185 b.SetBytes(int64(len(str)))
139 for i := 0; i < b.N; i++ { 186 for i := 0; i < b.N; i++ {
140 htmlEscaper.Replace(str) 187 htmlEscaper.Replace(str)
141 } 188 }
142 } 189 }
143 190
144 func BenchmarkHTMLEscapeOld(b *testing.B) { 191 func BenchmarkHTMLEscapeOld(b *testing.B) {
145 str := "I <3 to escape HTML & other text too." 192 str := "I <3 to escape HTML & other text too."
193 b.SetBytes(int64(len(str)))
146 for i := 0; i < b.N; i++ { 194 for i := 0; i < b.N; i++ {
147 oldhtmlEscape(str) 195 oldhtmlEscape(str)
148 } 196 }
149 } 197 }
150 198
151 // BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces. 199 // BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces.
152 func BenchmarkByteByteReplaces(b *testing.B) { 200 func BenchmarkByteByteReplaces(b *testing.B) {
153 str := Repeat("a", 100) + Repeat("b", 100) 201 str := Repeat("a", 100) + Repeat("b", 100)
202 b.SetBytes(int64(len(str)))
154 for i := 0; i < b.N; i++ { 203 for i := 0; i < b.N; i++ {
155 Replace(Replace(str, "a", "A", -1), "b", "B", -1) 204 Replace(Replace(str, "a", "A", -1), "b", "B", -1)
156 } 205 }
157 } 206 }
158 207
159 // BenchmarkByteByteMap compares byteByteImpl against Map. 208 // BenchmarkByteByteMap compares byteByteImpl against Map.
160 func BenchmarkByteByteMap(b *testing.B) { 209 func BenchmarkByteByteMap(b *testing.B) {
161 str := Repeat("a", 100) + Repeat("b", 100) 210 str := Repeat("a", 100) + Repeat("b", 100)
162 fn := func(r rune) rune { 211 fn := func(r rune) rune {
163 switch r { 212 switch r {
164 case 'a': 213 case 'a':
165 return 'A' 214 return 'A'
166 case 'b': 215 case 'b':
167 return 'B' 216 return 'B'
168 } 217 }
169 return r 218 return r
170 } 219 }
220 b.SetBytes(int64(len(str)))
171 for i := 0; i < b.N; i++ { 221 for i := 0; i < b.N; i++ {
172 Map(fn, str) 222 Map(fn, str)
173 } 223 }
174 } 224 }
OLDNEW
« no previous file with comments | « src/pkg/strings/replace.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b