-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfilter_benchmark_test.go
143 lines (121 loc) · 3.39 KB
/
filter_benchmark_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package twig
import (
"fmt"
"html"
"strings"
"testing"
)
// Benchmark HTML escape filter
func BenchmarkHtmlEscapeFilter(b *testing.B) {
ctx := NewRenderContext(nil, nil, nil)
defer ctx.Release()
// Create a string with all the special characters
testString := `This is a "test" with <tags> & special 'characters' that need escaping`
b.ResetTimer()
for i := 0; i < b.N; i++ {
result, _ := ctx.ApplyFilter("escape", testString)
_ = result
}
}
// Benchmark the original nested strings.Replace approach (for comparison)
func BenchmarkHtmlEscapeOriginal(b *testing.B) {
testString := `This is a "test" with <tags> & special 'characters' that need escaping`
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := strings.Replace(
strings.Replace(
strings.Replace(
strings.Replace(
strings.Replace(
testString,
"&", "&", -1),
"<", "<", -1),
">", ">", -1),
"\"", """, -1),
"'", "'", -1)
_ = result
}
}
// Benchmark the standard library's html.EscapeString (for comparison)
func BenchmarkHtmlEscapeStdLib(b *testing.B) {
testString := `This is a "test" with <tags> & special 'characters' that need escaping`
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := html.EscapeString(testString)
_ = result
}
}
// Helper for filter chain benchmarks - builds a deep filter chain
func createFilterChain(depth int) *FilterNode {
var node Node
// Create a literal base node
node = NewLiteralNode("test", 1)
// Add filters in sequence
for i := 0; i < depth; i++ {
// Use common filters
var filterName string
switch i % 4 {
case 0:
filterName = "upper"
case 1:
filterName = "lower"
case 2:
filterName = "capitalize"
case 3:
filterName = "escape"
}
node = NewFilterNode(node, filterName, nil, 1)
}
return node.(*FilterNode)
}
// Benchmark filter chain with different depths
func BenchmarkFilterChainDepth1(b *testing.B) {
benchmarkFilterChain(b, 1)
}
func BenchmarkFilterChainDepth5(b *testing.B) {
benchmarkFilterChain(b, 5)
}
func BenchmarkFilterChainDepth10(b *testing.B) {
benchmarkFilterChain(b, 10)
}
func benchmarkFilterChain(b *testing.B, depth int) {
// Create environment with test filters
env := &Environment{
filters: make(map[string]FilterFunc),
}
// Add filters directly to the map since Environment doesn't expose AddFilter
env.filters["upper"] = func(value interface{}, args ...interface{}) (interface{}, error) {
return strings.ToUpper(value.(string)), nil
}
env.filters["lower"] = func(value interface{}, args ...interface{}) (interface{}, error) {
return strings.ToLower(value.(string)), nil
}
env.filters["capitalize"] = func(value interface{}, args ...interface{}) (interface{}, error) {
s := value.(string)
if s == "" {
return s, nil
}
return strings.ToUpper(s[:1]) + s[1:], nil
}
env.filters["escape"] = func(value interface{}, args ...interface{}) (interface{}, error) {
return html.EscapeString(value.(string)), nil
}
ctx := NewRenderContext(env, nil, nil)
defer ctx.Release()
// Create a filter chain of the specified depth
filterNode := createFilterChain(depth)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = ctx.evaluateFilterNode(filterNode)
}
}
// Helper function specific to this benchmark
func benchmarkToString(value interface{}) string {
if value == nil {
return ""
}
if s, ok := value.(string); ok {
return s
}
return fmt.Sprintf("%v", value)
}