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  }