v2 / vlib / x / json2 / tests / encode_test.v
401 lines · 347 sloc · 8.49 KB · 07c796b670d9e498ccb25605af189617f61ec295
Raw
1import json2 as json
2import time
3import math.big
4
5type StrAlias = string
6type BoolAlias = bool
7type IntAlias = int
8type FloatAlias = f64
9
10enum TestEnum {
11 a
12 b @[json: 'BBB']
13 c = 10
14 d @[badattr: 'bad'; foobar]
15}
16
17type EnumAlias = TestEnum
18
19@[json_as_number]
20enum NumberedTestEnum {
21 a
22 b = 5
23}
24
25type Sum = int | string
26type SumAlias = Sum
27
28struct Basic {
29 a int
30 b string
31 c bool
32}
33
34struct NumberedEnumWrap {
35 a NumberedTestEnum
36}
37
38type BasicAlias = Basic
39
40struct Opt {
41 a ?int
42}
43
44type OptAlias = Opt
45
46struct OptRequiered {
47 a ?int @[required]
48}
49
50type OptRequieredAlias = OptRequiered
51
52struct CustomString {
53 data string
54}
55
56pub fn (cs CustomString) to_json() string {
57 return '"<<<' + cs.data + '>>>"'
58}
59
60type CustomStringAlias = CustomString
61
62type NullAlias = json.Null
63
64type TimeAlias = time.Time
65
66type BigAlias = big.Integer
67
68struct NamedFields {
69 a int @[json: 'id']
70 name string @[json: 'Name']
71}
72
73type NamedFieldsAlias = NamedFields
74
75struct SkipFields {
76 a int @[json: '-']
77 name string @[skip]
78}
79
80type SkipFieldsAlias = SkipFields
81
82struct SkipSomeFields {
83 a int @[json: '-']
84 name string @[skip]
85 hi bool = true
86}
87
88type SkipSomeFieldsAlias = SkipSomeFields
89
90struct PointerFields {
91 next &PointerFields = unsafe { nil }
92 data int
93}
94
95type PointerFieldsAlias = PointerFields
96
97struct F64ArrayRoundtripPayload {
98 arr []f64
99}
100
101struct OmitFields {
102 a ?bool @[omitempty]
103 b string @[omitempty]
104 c int @[omitempty]
105 d f64 @[omitempty]
106 e ?string = '' @[omitempty]
107 f ?int = 0 @[omitempty]
108 g ?f64 = 0.0 @[omitempty]
109}
110
111type OmitFieldsAlias = OmitFields
112
113struct OmitemptyRegressionNumber {
114 min int
115 max int
116}
117
118struct OmitemptyRegressionResp {
119 options []string @[omitempty]
120 metadata map[string]string @[omitempty]
121 number &OmitemptyRegressionNumber = unsafe { nil } @[omitempty]
122 config ?OmitemptyRegressionNumber @[omitempty]
123}
124
125fn test_primitives() {
126 assert json.encode('hello') == '"hello"'
127 assert json.encode(StrAlias('hello')) == '"hello"'
128 assert json.encode(true) == 'true'
129 assert json.encode(BoolAlias(false)) == 'false'
130 assert json.encode(-12345) == '-12345'
131 assert json.encode(IntAlias(-12345)) == '-12345'
132 assert json.encode(123.323) == '123.323'
133 assert json.encode(FloatAlias(123.323)) == '123.323'
134}
135
136fn test_encode_decode_struct_with_f64_array_roundtrips() ! {
137 original := F64ArrayRoundtripPayload{
138 arr: [0.9716157205240175, 0.9336099585062241]
139 }
140 encoded := json.encode(original)
141 assert encoded == '{"arr":[0.9716157205240175,0.9336099585062241]}'
142 assert json.decode[F64ArrayRoundtripPayload](encoded)! == original
143}
144
145fn test_arrays() {
146 assert json.encode([1, 2, 3, 4]) == '[1,2,3,4]'
147}
148
149fn test_maps() {
150 assert json.encode({
151 'hi': 0
152 'bye': 1
153 }) == '{"hi":0,"bye":1}'
154}
155
156fn test_enums() {
157 assert json.encode(TestEnum.c) == '"c"'
158 assert json.encode(EnumAlias(TestEnum.c)) == '"c"'
159 assert json.encode(TestEnum.c, enum_as_int: true) == '10'
160 assert json.encode(EnumAlias(TestEnum.c), enum_as_int: true) == '10'
161 assert json.encode(TestEnum.b) == '"BBB"'
162 assert json.encode(EnumAlias(TestEnum.b)) == '"BBB"'
163 // Ensure that only `json: ` attrs is applied
164 assert json.encode(TestEnum.d) == '"d"'
165 assert json.encode(EnumAlias(TestEnum.d)) == '"d"'
166}
167
168fn test_enum_json_as_number_attribute() {
169 assert json.encode(NumberedTestEnum.a) == '0'
170 assert json.encode(NumberedTestEnum.b) == '5'
171 assert json.encode(NumberedEnumWrap{
172 a: .a
173 }) == '{"a":0}'
174}
175
176fn test_sumtypes() {
177 assert json.encode(Sum(10)) == '10'
178 assert json.encode(Sum('hi')) == '"hi"'
179 assert json.encode(SumAlias(10)) == '10'
180 assert json.encode(SumAlias('hi')) == '"hi"'
181}
182
183fn test_basic_structs() {
184 assert json.encode(Basic{
185 a: 10
186 b: 'hi'
187 c: true
188 }) == '{"a":10,"b":"hi","c":true}'
189
190 assert json.encode(BasicAlias{
191 a: 10
192 b: 'hi'
193 c: true
194 }) == '{"a":10,"b":"hi","c":true}'
195}
196
197fn test_nested() {
198 assert json.encode([
199 {
200 'hi': Basic{ a: 1, b: 'a', c: false }
201 'bye': Basic{
202 a: 2
203 b: 'b'
204 c: true
205 }
206 },
207 {
208 'hi2': Basic{
209 a: 3
210 b: 'c'
211 c: false
212 }
213 'bye2': Basic{
214 a: 4
215 b: 'd'
216 c: true
217 }
218 },
219 ]) == '[{"hi":{"a":1,"b":"a","c":false},"bye":{"a":2,"b":"b","c":true}},{"hi2":{"a":3,"b":"c","c":false},"bye2":{"a":4,"b":"d","c":true}}]'
220 assert json.encode([
221 {
222 'hi': Basic{ a: 1, b: 'a', c: false }
223 'bye': Basic{
224 a: 2
225 b: 'b'
226 c: true
227 }
228 },
229 {
230 'hi2': Basic{
231 a: 3
232 b: 'c'
233 c: false
234 }
235 'bye2': Basic{
236 a: 4
237 b: 'd'
238 c: true
239 }
240 },
241 ],
242 prettify: true
243 ) == '[
244 {
245 "hi": {
246 "a": 1,
247 "b": "a",
248 "c": false
249 },
250 "bye": {
251 "a": 2,
252 "b": "b",
253 "c": true
254 }
255 },
256 {
257 "hi2": {
258 "a": 3,
259 "b": "c",
260 "c": false
261 },
262 "bye2": {
263 "a": 4,
264 "b": "d",
265 "c": true
266 }
267 }
268]'
269}
270
271fn test_string_escapes() {
272 assert json.encode('normal escapes: ", \\ special control escapes: \b, \n, \f, \t, \r, other control escapes: \0, \u001b') == r'"normal escapes: \", \\ special control escapes: \b, \n, \f, \t, \r, other control escapes: \u0000, \u001b"'
273 assert json.encode('ascii, é, 한, 😀, ascii') == r'"ascii, é, 한, 😀, ascii"'
274 assert json.encode('ascii, é, 한, 😀, ascii', escape_unicode: true) == r'"ascii, \u00e9, \ud55c, \uD83D\ude00, ascii"'
275}
276
277fn test_options() {
278 assert json.encode(Opt{none}) == '{}'
279 assert json.encode(Opt{99}) == '{"a":99}'
280 assert json.encode(OptAlias{none}) == '{}'
281 assert json.encode(OptAlias{99}) == '{"a":99}'
282
283 assert json.encode(OptRequiered{none}) == '{"a":null}'
284 assert json.encode(OptRequiered{99}) == '{"a":99}'
285 assert json.encode(OptRequieredAlias{none}) == '{"a":null}'
286 assert json.encode(OptRequieredAlias{99}) == '{"a":99}'
287}
288
289fn test_custom_encoders() {
290 assert json.encode(CustomString{'hi'}) == '"<<<hi>>>"'
291 assert json.encode(CustomStringAlias{'hi'}) == '"<<<hi>>>"'
292
293 assert json.encode(json.Null{}) == 'null'
294 assert json.encode(NullAlias{}) == 'null'
295
296 assert json.encode(time.Time{}) == '"0000-01-01T00:00:00.000Z"'
297 assert json.encode(TimeAlias{}) == '"0000-01-01T00:00:00.000Z"'
298
299 assert json.encode(big.integer_from_i64(1234567890)) == '1234567890'
300 assert json.encode(BigAlias(big.integer_from_i64(1234567890))) == '1234567890'
301}
302
303fn test_named_fields() {
304 assert json.encode(NamedFields{ a: 1, name: 'john' }) == '{"id":1,"Name":"john"}'
305 assert json.encode(NamedFieldsAlias{ a: 1, name: 'john' }) == '{"id":1,"Name":"john"}'
306}
307
308fn test_skip_fields() {
309 assert json.encode(SkipFields{ a: 1, name: 'john' }) == '{}'
310 assert json.encode(SkipFieldsAlias{ a: 1, name: 'john' }) == '{}'
311 assert json.encode(SkipFields{ a: 1, name: 'john' },
312 prettify: true
313 ) == '{}'
314
315 assert json.encode(SkipSomeFields{ a: 1, name: 'john' }) == '{"hi":true}'
316 assert json.encode(SkipSomeFieldsAlias{ a: 1, name: 'john' }) == '{"hi":true}'
317 assert json.encode(SkipSomeFields{ a: 1, name: 'john' },
318 prettify: true
319 ) == '{
320 "hi": true
321}'
322}
323
324fn test_omit_fields() {
325 assert json.encode(OmitFields{}) == '{}'
326 assert json.encode(OmitFieldsAlias{}) == '{}'
327
328 r1 := OmitemptyRegressionResp{
329 options: ['first', 'second']
330 }
331 r2 := OmitemptyRegressionResp{
332 number: &OmitemptyRegressionNumber{0, 0}
333 }
334 r3 := OmitemptyRegressionResp{
335 metadata: {
336 'kind': 'test'
337 }
338 }
339 assert json.encode(r1) == '{"options":["first","second"]}'
340 assert json.encode(r2) == '{"number":{"min":0,"max":0}}'
341 assert json.encode(r3) == '{"metadata":{"kind":"test"}}'
342 assert json.encode(OmitemptyRegressionResp{}) == '{}'
343 assert json.encode(OmitemptyRegressionResp{
344 config: OmitemptyRegressionNumber{
345 min: 1
346 max: 2
347 }
348 }) == '{"config":{"min":1,"max":2}}'
349}
350
351fn test_pointer_fields() {
352 assert json.encode(PointerFields{
353 next: &PointerFields{
354 next: &PointerFields{
355 next: &PointerFields{
356 data: 4
357 }
358 data: 3
359 }
360 data: 2
361 }
362 data: 1
363 }) == '{"next":{"next":{"next":{"data":4},"data":3},"data":2},"data":1}'
364 assert json.encode(PointerFieldsAlias{
365 next: &PointerFieldsAlias{
366 next: &PointerFieldsAlias{
367 next: &PointerFieldsAlias{
368 data: 4
369 }
370 data: 3
371 }
372 data: 2
373 }
374 data: 1
375 }) == '{"next":{"next":{"next":{"data":4},"data":3},"data":2},"data":1}'
376 assert json.encode(PointerFields{
377 next: &PointerFields{
378 next: &PointerFields{
379 next: &PointerFields{
380 data: 4
381 }
382 data: 3
383 }
384 data: 2
385 }
386 data: 1
387 },
388 prettify: true
389 ) == '{
390 "next": {
391 "next": {
392 "next": {
393 "data": 4
394 },
395 "data": 3
396 },
397 "data": 2
398 },
399 "data": 1
400}'
401}
402