github.com/hairyhenderson/templater@v3.5.0+incompatible/data/data_test.go (about) 1 package data 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/ugorji/go/codec" 8 9 "github.com/pkg/errors" 10 11 "github.com/stretchr/testify/assert" 12 13 "os" 14 15 "github.com/gotestyourself/gotestyourself/fs" 16 ) 17 18 func TestUnmarshalObj(t *testing.T) { 19 expected := map[string]interface{}{ 20 "foo": map[string]interface{}{"bar": "baz"}, 21 "one": 1.0, 22 "true": true, 23 } 24 25 test := func(actual map[string]interface{}, err error) { 26 assert.NoError(t, err) 27 assert.Equal(t, expected["foo"], actual["foo"]) 28 assert.Equal(t, expected["one"], actual["one"]) 29 assert.Equal(t, expected["true"], actual["true"]) 30 } 31 test(JSON(`{"foo":{"bar":"baz"},"one":1.0,"true":true}`)) 32 test(YAML(`foo: 33 bar: baz 34 one: 1.0 35 true: true 36 `)) 37 38 obj := make(map[string]interface{}) 39 _, err := unmarshalObj(obj, "SOMETHING", func(in []byte, out interface{}) error { 40 return errors.New("fail") 41 }) 42 assert.EqualError(t, err, "Unable to unmarshal object SOMETHING: fail") 43 } 44 45 func TestUnmarshalArray(t *testing.T) { 46 47 expected := []interface{}{"foo", "bar", 48 map[string]interface{}{ 49 "baz": map[string]interface{}{"qux": true}, 50 "quux": map[string]interface{}{"42": 18}, 51 "corge": map[string]interface{}{"false": "blah"}, 52 }} 53 54 test := func(actual []interface{}, err error) { 55 assert.NoError(t, err) 56 assert.EqualValues(t, expected, actual) 57 } 58 test(JSONArray(`["foo","bar",{"baz":{"qux": true},"quux":{"42":18},"corge":{"false":"blah"}}]`)) 59 test(YAMLArray(` 60 - foo 61 - bar 62 - baz: 63 qux: true 64 quux: 65 42: 18 66 corge: 67 false: blah 68 `)) 69 70 obj := make([]interface{}, 1) 71 _, err := unmarshalArray(obj, "SOMETHING", func(in []byte, out interface{}) error { 72 return errors.New("fail") 73 }) 74 assert.EqualError(t, err, "Unable to unmarshal array SOMETHING: fail") 75 } 76 77 func TestMarshalObj(t *testing.T) { 78 expected := "foo" 79 actual, err := marshalObj(nil, func(in interface{}) ([]byte, error) { 80 return []byte("foo"), nil 81 }) 82 assert.NoError(t, err) 83 assert.Equal(t, expected, actual) 84 _, err = marshalObj(nil, func(in interface{}) ([]byte, error) { 85 return nil, errors.New("fail") 86 }) 87 assert.Error(t, err) 88 } 89 90 func TestToJSONBytes(t *testing.T) { 91 expected := []byte("null") 92 actual, err := toJSONBytes(nil) 93 assert.NoError(t, err) 94 assert.Equal(t, expected, actual) 95 96 _, err = toJSONBytes(&badObject{}) 97 assert.Error(t, err) 98 } 99 100 type badObject struct { 101 } 102 103 func (b *badObject) CodecEncodeSelf(e *codec.Encoder) { 104 panic("boom") 105 } 106 107 func (b *badObject) CodecDecodeSelf(e *codec.Decoder) { 108 109 } 110 111 func TestToJSON(t *testing.T) { 112 expected := `{"down":{"the":{"rabbit":{"hole":true}}},"foo":"bar","one":1,"true":true}` 113 in := map[string]interface{}{ 114 "foo": "bar", 115 "one": 1, 116 "true": true, 117 "down": map[interface{}]interface{}{ 118 "the": map[interface{}]interface{}{ 119 "rabbit": map[interface{}]interface{}{ 120 "hole": true, 121 }, 122 }, 123 }, 124 } 125 out, err := ToJSON(in) 126 assert.NoError(t, err) 127 assert.Equal(t, expected, out) 128 129 _, err = ToJSON(&badObject{}) 130 assert.Error(t, err) 131 } 132 133 func TestToJSONPretty(t *testing.T) { 134 expected := `{ 135 "down": { 136 "the": { 137 "rabbit": { 138 "hole": true 139 } 140 } 141 }, 142 "foo": "bar", 143 "one": 1, 144 "true": true 145 }` 146 in := map[string]interface{}{ 147 "foo": "bar", 148 "one": 1, 149 "true": true, 150 "down": map[string]interface{}{ 151 "the": map[string]interface{}{ 152 "rabbit": map[string]interface{}{ 153 "hole": true, 154 }, 155 }, 156 }, 157 } 158 out, err := ToJSONPretty(" ", in) 159 assert.NoError(t, err) 160 assert.Equal(t, expected, out) 161 162 _, err = ToJSONPretty(" ", &badObject{}) 163 assert.Error(t, err) 164 } 165 166 func TestToYAML(t *testing.T) { 167 expected := `d: 2006-01-02T15:04:05.999999999-07:00 168 foo: bar 169 ? |- 170 multi 171 line 172 key 173 : hello: world 174 one: 1 175 "true": true 176 ` 177 mst, _ := time.LoadLocation("MST") 178 in := map[string]interface{}{ 179 "foo": "bar", 180 "one": 1, 181 "true": true, 182 `multi 183 line 184 key`: map[string]interface{}{ 185 "hello": "world", 186 }, 187 "d": time.Date(2006, time.January, 2, 15, 4, 5, 999999999, mst), 188 } 189 out, err := ToYAML(in) 190 assert.NoError(t, err) 191 assert.Equal(t, expected, out) 192 } 193 194 func TestCSV(t *testing.T) { 195 expected := [][]string{ 196 {"first", "second", "third"}, 197 {"1", "2", "3"}, 198 {"4", "5", "6"}, 199 } 200 testdata := []struct { 201 args []string 202 out [][]string 203 }{ 204 {[]string{"first,second,third\n1,2,3\n4,5,6"}, expected}, 205 {[]string{";", "first;second;third\r\n1;2;3\r\n4;5;6\r\n"}, expected}, 206 207 {[]string{""}, [][]string{nil}}, 208 {[]string{"\n"}, [][]string{nil}}, 209 {[]string{"foo"}, [][]string{{"foo"}}}, 210 } 211 for _, d := range testdata { 212 out, err := CSV(d.args...) 213 assert.NoError(t, err) 214 assert.Equal(t, d.out, out) 215 } 216 } 217 218 func TestCSVByRow(t *testing.T) { 219 in := "first,second,third\n1,2,3\n4,5,6" 220 expected := []map[string]string{ 221 { 222 "first": "1", 223 "second": "2", 224 "third": "3", 225 }, 226 { 227 "first": "4", 228 "second": "5", 229 "third": "6", 230 }, 231 } 232 testdata := []struct { 233 args []string 234 out []map[string]string 235 }{ 236 {[]string{in}, expected}, 237 {[]string{"first,second,third", "1,2,3\n4,5,6"}, expected}, 238 {[]string{";", "first;second;third", "1;2;3\n4;5;6"}, expected}, 239 {[]string{";", "first;second;third\r\n1;2;3\r\n4;5;6"}, expected}, 240 {[]string{"", "1,2,3\n4,5,6"}, []map[string]string{ 241 {"A": "1", "B": "2", "C": "3"}, 242 {"A": "4", "B": "5", "C": "6"}, 243 }}, 244 {[]string{"", "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"}, []map[string]string{ 245 {"A": "1", "B": "1", "C": "1", "D": "1", "E": "1", "F": "1", "G": "1", "H": "1", "I": "1", "J": "1", "K": "1", "L": "1", "M": "1", "N": "1", "O": "1", "P": "1", "Q": "1", "R": "1", "S": "1", "T": "1", "U": "1", "V": "1", "W": "1", "X": "1", "Y": "1", "Z": "1", "AA": "1", "BB": "1", "CC": "1", "DD": "1"}, 246 }}, 247 } 248 for _, d := range testdata { 249 out, err := CSVByRow(d.args...) 250 assert.NoError(t, err) 251 assert.Equal(t, d.out, out) 252 } 253 } 254 255 func TestCSVByColumn(t *testing.T) { 256 expected := map[string][]string{ 257 "first": {"1", "4"}, 258 "second": {"2", "5"}, 259 "third": {"3", "6"}, 260 } 261 262 testdata := []struct { 263 args []string 264 out map[string][]string 265 }{ 266 {[]string{"first,second,third\n1,2,3\n4,5,6"}, expected}, 267 {[]string{"first,second,third", "1,2,3\n4,5,6"}, expected}, 268 {[]string{";", "first;second;third", "1;2;3\n4;5;6"}, expected}, 269 {[]string{";", "first;second;third\r\n1;2;3\r\n4;5;6"}, expected}, 270 {[]string{"", "1,2,3\n4,5,6"}, map[string][]string{ 271 "A": {"1", "4"}, 272 "B": {"2", "5"}, 273 "C": {"3", "6"}, 274 }}, 275 } 276 for _, d := range testdata { 277 out, err := CSVByColumn(d.args...) 278 assert.NoError(t, err) 279 assert.Equal(t, d.out, out) 280 } 281 } 282 283 func TestAutoIndex(t *testing.T) { 284 assert.Equal(t, "A", autoIndex(0)) 285 assert.Equal(t, "B", autoIndex(1)) 286 assert.Equal(t, "Z", autoIndex(25)) 287 assert.Equal(t, "AA", autoIndex(26)) 288 assert.Equal(t, "ZZ", autoIndex(51)) 289 assert.Equal(t, "AAA", autoIndex(52)) 290 assert.Equal(t, "YYYYY", autoIndex(128)) 291 } 292 293 func TestToCSV(t *testing.T) { 294 in := [][]string{ 295 {"first", "second", "third"}, 296 {"1", "2", "3"}, 297 {"4", "5", "6"}, 298 } 299 expected := "first,second,third\r\n1,2,3\r\n4,5,6\r\n" 300 301 out, err := ToCSV(in) 302 assert.NoError(t, err) 303 assert.Equal(t, expected, out) 304 305 expected = "first;second;third\r\n1;2;3\r\n4;5;6\r\n" 306 307 out, err = ToCSV(";", in) 308 assert.NoError(t, err) 309 assert.Equal(t, expected, out) 310 311 _, err = ToCSV(42, [][]int{{1, 2}}) 312 assert.Error(t, err) 313 314 _, err = ToCSV([][]int{{1, 2}}) 315 assert.Error(t, err) 316 } 317 318 func TestTOML(t *testing.T) { 319 in := `# This is a TOML document. Boom. 320 321 title = "TOML Example" 322 323 [owner] 324 name = "Tom Preston-Werner" 325 organization = "GitHub" 326 bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 327 dob = 1979-05-27T07:32:00Z # First class dates? Why not? 328 329 [database] 330 server = "192.168.1.1" 331 ports = [ 8001, 8001, 8002 ] 332 connection_max = 5000 333 enabled = true 334 335 [servers] 336 337 # You can indent as you please. Tabs or spaces. TOML don't care. 338 [servers.alpha] 339 ip = "10.0.0.1" 340 dc = "eqdc10" 341 342 [servers.beta] 343 ip = "10.0.0.2" 344 dc = "eqdc10" 345 346 [clients] 347 data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 348 349 # Line breaks are OK when inside arrays 350 hosts = [ 351 "alpha", 352 "omega" 353 ] 354 ` 355 expected := map[string]interface{}{ 356 "title": "TOML Example", 357 "owner": map[string]interface{}{ 358 "name": "Tom Preston-Werner", 359 "organization": "GitHub", 360 "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", 361 "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), 362 }, 363 "database": map[string]interface{}{ 364 "server": "192.168.1.1", 365 "ports": []interface{}{int64(8001), int64(8001), int64(8002)}, 366 "connection_max": int64(5000), 367 "enabled": true, 368 }, 369 "servers": map[string]interface{}{ 370 "alpha": map[string]interface{}{ 371 "ip": "10.0.0.1", 372 "dc": "eqdc10", 373 }, 374 "beta": map[string]interface{}{ 375 "ip": "10.0.0.2", 376 "dc": "eqdc10", 377 }, 378 }, 379 "clients": map[string]interface{}{ 380 "data": []interface{}{ 381 []interface{}{"gamma", "delta"}, 382 []interface{}{int64(1), int64(2)}, 383 }, 384 "hosts": []interface{}{"alpha", "omega"}, 385 }, 386 } 387 388 out, err := TOML(in) 389 assert.NoError(t, err) 390 assert.Equal(t, expected, out) 391 } 392 393 func TestToTOML(t *testing.T) { 394 expected := `foo = "bar" 395 one = 1 396 true = true 397 398 [down] 399 [down.the] 400 [down.the.rabbit] 401 hole = true 402 ` 403 in := map[string]interface{}{ 404 "foo": "bar", 405 "one": 1, 406 "true": true, 407 "down": map[interface{}]interface{}{ 408 "the": map[interface{}]interface{}{ 409 "rabbit": map[interface{}]interface{}{ 410 "hole": true, 411 }, 412 }, 413 }, 414 } 415 out, err := ToTOML(in) 416 assert.NoError(t, err) 417 assert.Equal(t, expected, out) 418 } 419 420 func TestDecryptEJSON(t *testing.T) { 421 privateKey := "e282d979654f88267f7e6c2d8268f1f4314b8673579205ed0029b76de9c8223f" 422 publicKey := "6e05ec625bcdca34864181cc43e6fcc20a57732a453bc2f4a2e117ffdf1a6762" 423 expected := map[string]interface{}{ 424 "password": "supersecret", 425 "_unencrypted": "notsosecret", 426 } 427 in := `{ 428 "_public_key": "` + publicKey + `", 429 "password": "EJ[1:yJ7n4UorqxkJZMoKevIA1dJeDvaQhkbgENIVZW18jig=:0591iW+paVSh4APOytKBVW/ZcxHO/5wO:TssnpVtkiXmpDIxPlXSiYdgnWyd44stGcwG1]", 430 "_unencrypted": "notsosecret" 431 }` 432 433 os.Setenv("EJSON_KEY", privateKey) 434 defer os.Unsetenv("EJSON_KEY") 435 actual, err := decryptEJSON(in) 436 assert.NoError(t, err) 437 assert.EqualValues(t, expected, actual) 438 439 actual, err = JSON(in) 440 assert.NoError(t, err) 441 assert.EqualValues(t, expected, actual) 442 443 tmpDir := fs.NewDir(t, "gomplate-ejsontest", 444 fs.WithFile(publicKey, privateKey), 445 ) 446 defer tmpDir.Remove() 447 448 os.Unsetenv("EJSON_KEY") 449 os.Setenv("EJSON_KEY_FILE", tmpDir.Join(publicKey)) 450 defer os.Unsetenv("EJSON_KEY_FILE") 451 actual, err = decryptEJSON(in) 452 assert.NoError(t, err) 453 assert.EqualValues(t, expected, actual) 454 455 os.Unsetenv("EJSON_KEY") 456 os.Unsetenv("EJSON_KEY_FILE") 457 os.Setenv("EJSON_KEYDIR", tmpDir.Path()) 458 defer os.Unsetenv("EJSON_KEYDIR") 459 actual, err = decryptEJSON(in) 460 assert.NoError(t, err) 461 assert.EqualValues(t, expected, actual) 462 } 463 464 func TestDotEnv(t *testing.T) { 465 in := `FOO=a regular unquoted value 466 export BAR=another value, exports are ignored 467 468 # comments are totally ignored, as are blank lines 469 FOO.BAR = "values can be double-quoted, and shell\nescapes are supported" 470 471 BAZ = "variable expansion: ${FOO}" 472 QUX='single quotes ignore $variables' 473 ` 474 expected := map[string]interface{}{ 475 "FOO": "a regular unquoted value", 476 "BAR": "another value, exports are ignored", 477 "FOO.BAR": "values can be double-quoted, and shell\nescapes are supported", 478 "BAZ": "variable expansion: a regular unquoted value", 479 "QUX": "single quotes ignore $variables", 480 } 481 out, err := dotEnv(in) 482 assert.NoError(t, err) 483 assert.EqualValues(t, expected, out) 484 }