-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsafe_test.go
More file actions
124 lines (109 loc) · 3.2 KB
/
safe_test.go
File metadata and controls
124 lines (109 loc) · 3.2 KB
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
package template
import (
"errors"
"testing"
)
// SafeString is a string-compatible alias; constructing and converting
// to string is a direct cast.
func TestSafeString_StringCompatible(t *testing.T) {
t.Parallel()
s := SafeString("hello")
if string(s) != "hello" {
t.Errorf("string(SafeString) = %q, want %q", string(s), "hello")
}
}
// The safe filter is NOT registered globally. It only becomes available
// inside engines with FeatureLayout enabled.
func TestSafeFilter_NotRegisteredGlobally(t *testing.T) {
t.Parallel()
if _, ok := defaultRegistry.Filter("safe"); ok {
t.Error("safe filter should not be in the global registry")
}
}
// The safe filter is available in engines with FeatureLayout enabled.
func TestSafeFilter_AvailableInFeatureLayout(t *testing.T) {
t.Parallel()
engine := New(
WithLoader(NewMemoryLoader(map[string]string{
"a.txt": `{{ x | safe }}`,
})),
WithFormat(FormatText),
WithLayout(),
)
got, err := engine.Render("a.txt", Data{"x": "<b>"})
if err != nil {
t.Fatalf("err = %v", err)
}
if got != "<b>" {
t.Errorf("got %q", got)
}
}
// The built-in escape filter returns a plain string.
func TestEscapeFilter_GlobalReturnsString(t *testing.T) {
t.Parallel()
fn, ok := defaultRegistry.Filter("escape")
if !ok {
t.Fatal("escape filter missing from global registry")
}
result, err := fn("<b>")
if err != nil {
t.Fatalf("err = %v", err)
}
if _, ok := result.(string); !ok {
t.Errorf("escape returned %T, want string", result)
}
if _, ok := result.(SafeString); ok {
t.Error("escape should NOT return SafeString in global scope")
}
}
// Inside FormatHTML the escape filter is overridden with a SafeString-
// returning variant so the auto-escape pipeline does not double-escape.
func TestEscapeFilter_FormatHTMLReturnsSafeString(t *testing.T) {
t.Parallel()
engine := New(
WithLoader(NewMemoryLoader(map[string]string{
"a.html": `{{ x | escape }}`,
})),
WithFormat(FormatHTML),
)
got, err := engine.Render("a.html", Data{"x": "<b>"})
if err != nil {
t.Fatalf("err = %v", err)
}
// If escape returned a plain string, the auto-escape output path
// would double-escape and produce &lt;b&gt;. SafeString
// prevents that.
if got != "<b>" {
t.Errorf("got %q, want <b>", got)
}
}
// In FormatText, escape is overridden? No — only FormatHTML needs the safe
// variant. FormatText's escape uses the global (plain string) filter via
// parent fallback.
func TestEscapeFilter_FormatTextUsesGlobal(t *testing.T) {
t.Parallel()
engine := New(
WithLoader(NewMemoryLoader(map[string]string{
"a.txt": `{{ x | escape }}`,
})),
WithFormat(FormatText),
)
got, err := engine.Render("a.txt", Data{"x": "<b>"})
if err != nil {
t.Fatalf("err = %v", err)
}
// FormatText does not auto-escape, so escape's string return is
// written as-is.
if got != "<b>" {
t.Errorf("got %q", got)
}
}
// Built-in filter lookup for "safe" returns ErrFilterNotFound via a
// render that exercises the FilterNode path.
func TestCoreEngine_NoSafeFilter(t *testing.T) {
t.Parallel()
_, err := renderSourceTemplate(`{{ x | safe }}`, Data{"x": "<b>"})
if !errors.Is(err, ErrFilterNotFound) {
t.Errorf("err = %v, want ErrFilterNotFound", err)
}
}