From 07a07929d48873eca3da971f979894812129e7e6 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Fri, 10 Apr 2020 19:17:17 -0400 Subject: [PATCH] Allow data.ToCSV to handle more general input types Signed-off-by: Dave Henderson --- data/data.go | 24 ++++++++++++++--- data/data_test.go | 18 +++++++++++++ tests/integration/docs_examples_test.go | 34 +++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 tests/integration/docs_examples_test.go diff --git a/data/data.go b/data/data.go index d0c136bc..beda7f03 100644 --- a/data/data.go +++ b/data/data.go @@ -15,6 +15,7 @@ import ( "github.com/Shopify/ejson" ejsonJson "github.com/Shopify/ejson/json" + "github.com/hairyhenderson/gomplate/v3/conv" "github.com/hairyhenderson/gomplate/v3/env" // XXX: replace once https://github.com/BurntSushi/toml/pull/179 is merged @@ -272,10 +273,25 @@ func ToCSV(args ...interface{}) (string, error) { args = args[1:] } if len(args) == 1 { - var ok bool - in, ok = args[0].([][]string) - if !ok { - return "", errors.Errorf("Can't parse ToCSV input - must be of type [][]string") + switch a := args[0].(type) { + case [][]string: + in = a + case [][]interface{}: + in = make([][]string, len(a)) + for i, v := range a { + in[i] = conv.ToStrings(v...) + } + case []interface{}: + in = make([][]string, len(a)) + for i, v := range a { + ar, ok := v.([]interface{}) + if !ok { + return "", errors.Errorf("Can't parse ToCSV input - must be a two-dimensional array (like [][]string or [][]interface{}) (was %T)", args[0]) + } + in[i] = conv.ToStrings(ar...) + } + default: + return "", errors.Errorf("Can't parse ToCSV input - must be a two-dimensional array (like [][]string or [][]interface{}) (was %T)", args[0]) } } b := &bytes.Buffer{} diff --git a/data/data_test.go b/data/data_test.go index 3ecf02c5..ae2c31c7 100644 --- a/data/data_test.go +++ b/data/data_test.go @@ -336,6 +336,24 @@ func TestToCSV(t *testing.T) { _, err = ToCSV([][]int{{1, 2}}) assert.Error(t, err) + + expected = "first,second,third\r\n1,2,3\r\n4,5,6\r\n" + out, err = ToCSV([][]interface{}{ + {"first", "second", "third"}, + {"1", "2", "3"}, + {"4", "5", "6"}, + }) + assert.NoError(t, err) + assert.Equal(t, expected, out) + + expected = "first|second|third\r\n1|2|3\r\n4|5|6\r\n" + out, err = ToCSV("|", []interface{}{ + []interface{}{"first", "second", "third"}, + []interface{}{1, "2", 3}, + []interface{}{"4", 5, "6"}, + }) + assert.NoError(t, err) + assert.Equal(t, expected, out) } func TestTOML(t *testing.T) { diff --git a/tests/integration/docs_examples_test.go b/tests/integration/docs_examples_test.go new file mode 100644 index 00000000..562beb07 --- /dev/null +++ b/tests/integration/docs_examples_test.go @@ -0,0 +1,34 @@ +//+build integration + +package integration + +import ( + . "gopkg.in/check.v1" + + "gotest.tools/v3/fs" + "gotest.tools/v3/icmd" +) + +// This suite contains integration tests to make sure that (some of) the examples +// in the gomplate docs work correctly +type DocExamplesSuite struct { + tmpDir *fs.Dir +} + +var _ = Suite(&DocExamplesSuite{}) + +func (s *DocExamplesSuite) SetUpSuite(c *C) { + s.tmpDir = fs.NewDir(c, "gomplate-inttests") +} + +func (s *DocExamplesSuite) TearDownSuite(c *C) { + s.tmpDir.Remove() +} + +func (s *DocExamplesSuite) TestDataExamples(c *C) { + result := icmd.RunCommand(GomplateBin, + "-i", "{{ $rows := (jsonArray `[[\"first\",\"second\"],[\"1\",\"2\"],[\"3\",\"4\"]]`) }}{{ data.ToCSV \";\" $rows }}", + ) + expected := "first;second\r\n1;2\r\n3;4\r\n" + result.Assert(c, icmd.Expected{ExitCode: 0, Out: expected}) +}