unmarshal_test.go (6379B)
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]any) {
91 b.Assert(m["slogan"], qt.Equals, "Hugo Rocks!")
92 }
93
94 for _, test := range []struct {
95 data any
96 options any
97 expect any
98 }{
99 {`{ "slogan": "Hugo Rocks!" }`, nil, func(m map[string]any) {
100 assertSlogan(m)
101 }},
102 {`slogan: "Hugo Rocks!"`, nil, func(m map[string]any) {
103 assertSlogan(m)
104 }},
105 {`slogan = "Hugo Rocks!"`, nil, func(m map[string]any) {
106 assertSlogan(m)
107 }},
108 {testContentResource{key: "r1", content: `slogan: "Hugo Rocks!"`, mime: media.YAMLType}, nil, func(m map[string]any) {
109 assertSlogan(m)
110 }},
111 {testContentResource{key: "r1", content: `{ "slogan": "Hugo Rocks!" }`, mime: media.JSONType}, nil, func(m map[string]any) {
112 assertSlogan(m)
113 }},
114 {testContentResource{key: "r1", content: `slogan = "Hugo Rocks!"`, mime: media.TOMLType}, nil, func(m map[string]any) {
115 assertSlogan(m)
116 }},
117 {testContentResource{key: "r1", content: `<root><slogan>Hugo Rocks!</slogan></root>"`, mime: media.XMLType}, nil, func(m map[string]any) {
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]any{"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]any{"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]any{"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 []any
153
154 if test.options != nil {
155 args = []any{test.options, test.data}
156 } else {
157 args = []any{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]any)); ok {
165 b.Assert(err, qt.IsNil)
166 m, ok := result.(map[string]any)
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 }