github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/tpl/transform/unmarshal_test.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package transform_test
    15  
    16  import (
    17  	"fmt"
    18  	"math/rand"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/gohugoio/hugo/hugolib"
    23  	"github.com/gohugoio/hugo/tpl/transform"
    24  
    25  	"github.com/gohugoio/hugo/common/hugio"
    26  	"github.com/gohugoio/hugo/resources/resource"
    27  
    28  	"github.com/gohugoio/hugo/media"
    29  
    30  	qt "github.com/frankban/quicktest"
    31  )
    32  
    33  const (
    34  	testJSON = `
    35  	
    36  {
    37      "ROOT_KEY": {
    38          "title": "example glossary",
    39  		"GlossDiv": {
    40              "title": "S",
    41  			"GlossList": {
    42                  "GlossEntry": {
    43                      "ID": "SGML",
    44  					"SortAs": "SGML",
    45  					"GlossTerm": "Standard Generalized Markup Language",
    46  					"Acronym": "SGML",
    47  					"Abbrev": "ISO 8879:1986",
    48  					"GlossDef": {
    49                          "para": "A meta-markup language, used to create markup languages such as DocBook.",
    50  						"GlossSeeAlso": ["GML", "XML"]
    51                      },
    52  					"GlossSee": "markup"
    53                  }
    54              }
    55          }
    56      }
    57  }
    58  
    59  	`
    60  )
    61  
    62  var _ resource.ReadSeekCloserResource = (*testContentResource)(nil)
    63  
    64  type testContentResource struct {
    65  	content string
    66  	mime    media.Type
    67  
    68  	key string
    69  }
    70  
    71  func (t testContentResource) ReadSeekCloser() (hugio.ReadSeekCloser, error) {
    72  	return hugio.NewReadSeekerNoOpCloserFromString(t.content), nil
    73  }
    74  
    75  func (t testContentResource) MediaType() media.Type {
    76  	return t.mime
    77  }
    78  
    79  func (t testContentResource) Key() string {
    80  	return t.key
    81  }
    82  
    83  func TestUnmarshal(t *testing.T) {
    84  	b := hugolib.NewIntegrationTestBuilder(
    85  		hugolib.IntegrationTestConfig{T: t},
    86  	).Build()
    87  
    88  	ns := transform.New(b.H.Deps)
    89  
    90  	assertSlogan := func(m map[string]interface{}) {
    91  		b.Assert(m["slogan"], qt.Equals, "Hugo Rocks!")
    92  	}
    93  
    94  	for _, test := range []struct {
    95  		data    interface{}
    96  		options interface{}
    97  		expect  interface{}
    98  	}{
    99  		{`{ "slogan": "Hugo Rocks!" }`, nil, func(m map[string]interface{}) {
   100  			assertSlogan(m)
   101  		}},
   102  		{`slogan: "Hugo Rocks!"`, nil, func(m map[string]interface{}) {
   103  			assertSlogan(m)
   104  		}},
   105  		{`slogan = "Hugo Rocks!"`, nil, func(m map[string]interface{}) {
   106  			assertSlogan(m)
   107  		}},
   108  		{testContentResource{key: "r1", content: `slogan: "Hugo Rocks!"`, mime: media.YAMLType}, nil, func(m map[string]interface{}) {
   109  			assertSlogan(m)
   110  		}},
   111  		{testContentResource{key: "r1", content: `{ "slogan": "Hugo Rocks!" }`, mime: media.JSONType}, nil, func(m map[string]interface{}) {
   112  			assertSlogan(m)
   113  		}},
   114  		{testContentResource{key: "r1", content: `slogan = "Hugo Rocks!"`, mime: media.TOMLType}, nil, func(m map[string]interface{}) {
   115  			assertSlogan(m)
   116  		}},
   117  		{testContentResource{key: "r1", content: `<root><slogan>Hugo Rocks!</slogan></root>"`, mime: media.XMLType}, nil, func(m map[string]interface{}) {
   118  			assertSlogan(m)
   119  		}},
   120  		{testContentResource{key: "r1", content: `1997,Ford,E350,"ac, abs, moon",3000.00
   121  1999,Chevy,"Venture ""Extended Edition""","",4900.00`, mime: media.CSVType}, nil, func(r [][]string) {
   122  			b.Assert(len(r), qt.Equals, 2)
   123  			first := r[0]
   124  			b.Assert(len(first), qt.Equals, 5)
   125  			b.Assert(first[1], qt.Equals, "Ford")
   126  		}},
   127  		{testContentResource{key: "r1", content: `a;b;c`, mime: media.CSVType}, map[string]interface{}{"delimiter": ";"}, func(r [][]string) {
   128  			b.Assert([][]string{{"a", "b", "c"}}, qt.DeepEquals, r)
   129  		}},
   130  		{"a,b,c", nil, func(r [][]string) {
   131  			b.Assert([][]string{{"a", "b", "c"}}, qt.DeepEquals, r)
   132  		}},
   133  		{"a;b;c", map[string]interface{}{"delimiter": ";"}, func(r [][]string) {
   134  			b.Assert([][]string{{"a", "b", "c"}}, qt.DeepEquals, r)
   135  		}},
   136  		{testContentResource{key: "r1", content: `
   137  % This is a comment
   138  a;b;c`, mime: media.CSVType}, map[string]interface{}{"DElimiter": ";", "Comment": "%"}, func(r [][]string) {
   139  			b.Assert([][]string{{"a", "b", "c"}}, qt.DeepEquals, r)
   140  		}},
   141  		// errors
   142  		{"thisisnotavaliddataformat", nil, false},
   143  		{testContentResource{key: "r1", content: `invalid&toml"`, mime: media.TOMLType}, nil, false},
   144  		{testContentResource{key: "r1", content: `unsupported: MIME"`, mime: media.CalendarType}, nil, false},
   145  		{"thisisnotavaliddataformat", nil, false},
   146  		{`{ notjson }`, nil, false},
   147  		{tstNoStringer{}, nil, false},
   148  	} {
   149  
   150  		ns.Reset()
   151  
   152  		var args []interface{}
   153  
   154  		if test.options != nil {
   155  			args = []interface{}{test.options, test.data}
   156  		} else {
   157  			args = []interface{}{test.data}
   158  		}
   159  
   160  		result, err := ns.Unmarshal(args...)
   161  
   162  		if bb, ok := test.expect.(bool); ok && !bb {
   163  			b.Assert(err, qt.Not(qt.IsNil))
   164  		} else if fn, ok := test.expect.(func(m map[string]interface{})); ok {
   165  			b.Assert(err, qt.IsNil)
   166  			m, ok := result.(map[string]interface{})
   167  			b.Assert(ok, qt.Equals, true)
   168  			fn(m)
   169  		} else if fn, ok := test.expect.(func(r [][]string)); ok {
   170  			b.Assert(err, qt.IsNil)
   171  			r, ok := result.([][]string)
   172  			b.Assert(ok, qt.Equals, true)
   173  			fn(r)
   174  		} else {
   175  			b.Assert(err, qt.IsNil)
   176  			b.Assert(result, qt.Equals, test.expect)
   177  		}
   178  
   179  	}
   180  }
   181  
   182  func BenchmarkUnmarshalString(b *testing.B) {
   183  	bb := hugolib.NewIntegrationTestBuilder(
   184  		hugolib.IntegrationTestConfig{T: b},
   185  	).Build()
   186  
   187  	ns := transform.New(bb.H.Deps)
   188  
   189  	const numJsons = 100
   190  
   191  	var jsons [numJsons]string
   192  	for i := 0; i < numJsons; i++ {
   193  		jsons[i] = strings.Replace(testJSON, "ROOT_KEY", fmt.Sprintf("root%d", i), 1)
   194  	}
   195  
   196  	b.ResetTimer()
   197  	for i := 0; i < b.N; i++ {
   198  		result, err := ns.Unmarshal(jsons[rand.Intn(numJsons)])
   199  		if err != nil {
   200  			b.Fatal(err)
   201  		}
   202  		if result == nil {
   203  			b.Fatal("no result")
   204  		}
   205  	}
   206  }
   207  
   208  func BenchmarkUnmarshalResource(b *testing.B) {
   209  	bb := hugolib.NewIntegrationTestBuilder(
   210  		hugolib.IntegrationTestConfig{T: b},
   211  	).Build()
   212  
   213  	ns := transform.New(bb.H.Deps)
   214  
   215  	const numJsons = 100
   216  
   217  	var jsons [numJsons]testContentResource
   218  	for i := 0; i < numJsons; i++ {
   219  		key := fmt.Sprintf("root%d", i)
   220  		jsons[i] = testContentResource{key: key, content: strings.Replace(testJSON, "ROOT_KEY", key, 1), mime: media.JSONType}
   221  	}
   222  
   223  	b.ResetTimer()
   224  	for i := 0; i < b.N; i++ {
   225  		result, err := ns.Unmarshal(jsons[rand.Intn(numJsons)])
   226  		if err != nil {
   227  			b.Fatal(err)
   228  		}
   229  		if result == nil {
   230  			b.Fatal("no result")
   231  		}
   232  	}
   233  }