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 }