github.com/hashicorp/vault/sdk@v0.13.0/helper/template/template_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package template 5 6 import ( 7 "fmt" 8 "strings" 9 "testing" 10 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestGenerate(t *testing.T) { 15 type testCase struct { 16 template string 17 additionalOpts []Opt 18 data interface{} 19 20 expected string 21 expectErr bool 22 } 23 24 tests := map[string]testCase{ 25 "template without arguments": { 26 template: "this is a template", 27 data: nil, 28 expected: "this is a template", 29 expectErr: false, 30 }, 31 "template with arguments but no data": { 32 template: "this is a {{.String}}", 33 data: nil, 34 expected: "this is a <no value>", 35 expectErr: false, 36 }, 37 "template with arguments": { 38 template: "this is a {{.String}}", 39 data: struct { 40 String string 41 }{ 42 String: "foobar", 43 }, 44 expected: "this is a foobar", 45 expectErr: false, 46 }, 47 "template with builtin functions": { 48 template: `{{.String | truncate 10}} 49 {{.String | uppercase}} 50 {{.String | lowercase}} 51 {{.String | replace " " "."}} 52 {{.String | sha256}} 53 {{.String | base64}} 54 {{.String | truncate_sha256 20}}`, 55 data: struct { 56 String string 57 }{ 58 String: "Some string with Multiple Capitals LETTERS", 59 }, 60 expected: `Some strin 61 SOME STRING WITH MULTIPLE CAPITALS LETTERS 62 some string with multiple capitals letters 63 Some.string.with.Multiple.Capitals.LETTERS 64 da9872dd96609c72897defa11fe81017a62c3f44339d9d3b43fe37540ede3601 65 U29tZSBzdHJpbmcgd2l0aCBNdWx0aXBsZSBDYXBpdGFscyBMRVRURVJT 66 Some string 6841cf80`, 67 expectErr: false, 68 }, 69 "custom function": { 70 template: "{{foo}}", 71 additionalOpts: []Opt{ 72 Function("foo", func() string { 73 return "custom-foo" 74 }), 75 }, 76 expected: "custom-foo", 77 expectErr: false, 78 }, 79 } 80 81 for name, test := range tests { 82 t.Run(name, func(t *testing.T) { 83 opts := append(test.additionalOpts, Template(test.template)) 84 st, err := NewTemplate(opts...) 85 require.NoError(t, err) 86 87 actual, err := st.Generate(test.data) 88 if test.expectErr && err == nil { 89 t.Fatalf("err expected, got nil") 90 } 91 if !test.expectErr && err != nil { 92 t.Fatalf("no error expected, got: %s", err) 93 } 94 95 require.Equal(t, test.expected, actual) 96 }) 97 } 98 99 t.Run("random", func(t *testing.T) { 100 for i := 1; i < 100; i++ { 101 st, err := NewTemplate( 102 Template(fmt.Sprintf("{{random %d}}", i)), 103 ) 104 require.NoError(t, err) 105 106 actual, err := st.Generate(nil) 107 require.NoError(t, err) 108 109 require.Regexp(t, fmt.Sprintf("^[a-zA-Z0-9]{%d}$", i), actual) 110 } 111 }) 112 113 t.Run("unix_time", func(t *testing.T) { 114 for i := 0; i < 100; i++ { 115 st, err := NewTemplate( 116 Template("{{unix_time}}"), 117 ) 118 require.NoError(t, err) 119 120 actual, err := st.Generate(nil) 121 require.NoError(t, err) 122 123 require.Regexp(t, "^[0-9]+$", actual) 124 } 125 }) 126 127 t.Run("unix_time_millis", func(t *testing.T) { 128 for i := 0; i < 100; i++ { 129 st, err := NewTemplate( 130 Template("{{unix_time_millis}}"), 131 ) 132 require.NoError(t, err) 133 134 actual, err := st.Generate(nil) 135 require.NoError(t, err) 136 137 require.Regexp(t, "^[0-9]+$", actual) 138 } 139 }) 140 141 t.Run("timestamp", func(t *testing.T) { 142 for i := 0; i < 100; i++ { 143 st, err := NewTemplate( 144 Template(`{{timestamp "2006-01-02T15:04:05.000Z"}}`), 145 ) 146 require.NoError(t, err) 147 148 actual, err := st.Generate(nil) 149 require.NoError(t, err) 150 151 require.Regexp(t, `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$`, actual) 152 } 153 }) 154 155 t.Run("too-large-overflow", func(t *testing.T) { 156 data := "{{" + strings.Repeat("(", 1000000) 157 _, err := NewTemplate( 158 Template(data), 159 ) 160 // We expect an error due it being too large, 161 // this test should not fail with an overflow 162 require.Error(t, err) 163 }) 164 } 165 166 func TestBadConstructorArguments(t *testing.T) { 167 type testCase struct { 168 opts []Opt 169 } 170 171 tests := map[string]testCase{ 172 "missing template": { 173 opts: nil, 174 }, 175 "missing custom function name": { 176 opts: []Opt{ 177 Template("foo bar"), 178 Function("", func() string { 179 return "foo" 180 }), 181 }, 182 }, 183 "missing custom function": { 184 opts: []Opt{ 185 Template("foo bar"), 186 Function("foo", nil), 187 }, 188 }, 189 "bad template": { 190 opts: []Opt{ 191 Template("{{.String"), 192 }, 193 }, 194 } 195 196 for name, test := range tests { 197 t.Run(name, func(t *testing.T) { 198 st, err := NewTemplate(test.opts...) 199 require.Error(t, err) 200 201 str, err := st.Generate(nil) 202 require.Error(t, err) 203 require.Equal(t, "", str) 204 }) 205 } 206 207 t.Run("erroring custom function", func(t *testing.T) { 208 st, err := NewTemplate( 209 Template("{{foo}}"), 210 Function("foo", func() (string, error) { 211 return "", fmt.Errorf("an error!") 212 }), 213 ) 214 require.NoError(t, err) 215 216 str, err := st.Generate(nil) 217 require.Error(t, err) 218 require.Equal(t, "", str) 219 }) 220 }