v / vlib / json
Raw file | 533 loc (463 sloc) | 11.45 KB | Latest commit hash ef5be22f8
1import json
2import time
3
4enum JobTitle {
5 manager
6 executive
7 worker
8}
9
10struct Employee {
11 name string
12 age int
13 salary f32
14 title JobTitle
15}
16
17fn test_simple() {
18 x := Employee{'Peter', 28, 95000.5, .worker}
19 s := json.encode(x)
20 // eprintln('Employee x: $s')
21 assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":"worker"}'
22 y := json.decode(Employee, s)!
23 // eprintln('Employee y: $y')
24 assert y.name == 'Peter'
25 assert y.age == 28
26 assert y.salary == 95000.5
27 assert y.title == .worker
28}
29
30const currency_id = 'cconst'
31
32struct Price {
33 net f64
34 currency_id string [json: currencyId] = currency_id
35}
36
37fn test_field_with_default_expr() {
38 data := '[{"net":1},{"net":2,"currencyId":"cjson"}]'
39 prices := json.decode([]Price, data)!
40 assert prices == [Price{
41 net: 1
42 currency_id: 'cconst'
43 }, Price{
44 net: 2
45 currency_id: 'cjson'
46 }]
47}
48
49fn test_decode_top_level_array() {
50 s := '[{"name":"Peter", "age": 29}, {"name":"Bob", "age":31}]'
51 x := json.decode([]Employee, s) or { panic(err) }
52 assert x.len == 2
53 assert x[0].name == 'Peter'
54 assert x[0].age == 29
55 assert x[1].name == 'Bob'
56 assert x[1].age == 31
57}
58
59struct Human {
60 name string
61}
62
63struct Item {
64 tag string
65}
66
67enum Animal {
68 dog // Will be encoded as `0`
69 cat
70}
71
72type Entity = Animal | Human | Item | string | time.Time
73
74struct SomeGame {
75 title string
76 player Entity
77 other []Entity
78}
79
80fn test_encode_decode_sumtype() {
81 t := time.now()
82 game := SomeGame{
83 title: 'Super Mega Game'
84 player: Human{'Monke'}
85 other: [
86 Entity(Item{'Pen'}),
87 Item{'Cookie'},
88 Animal.cat,
89 'Stool',
90 t,
91 ]
92 }
93 // eprintln('Game: $game')
94
95 enc := json.encode(game)
96 // eprintln('Encoded Game: $enc')
97
98 assert enc == '{"title":"Super Mega Game","player":{"name":"Monke","_type":"Human"},"other":[{"tag":"Pen","_type":"Item"},{"tag":"Cookie","_type":"Item"},"cat","Stool",{"_type":"Time","value":${t.unix_time()}}]}'
99
100 dec := json.decode(SomeGame, enc)!
101 // eprintln('Decoded Game: $dec')
102
103 assert game.title == dec.title
104 assert game.player == dec.player
105 assert (game.other[2] as Animal) == .cat
106 assert dec.other[2] == Entity('cat')
107 assert (game.other[4] as time.Time).unix_time() == (dec.other[4] as time.Time).unix_time()
108}
109
110fn bar[T](payload string) !Bar { // ?T doesn't work currently
111 result := json.decode(T, payload)!
112 return result
113}
114
115struct Bar {
116 x string
117}
118
119fn test_generic() {
120 result := bar[Bar]('{"x":"test"}') or { Bar{} }
121 assert result.x == 'test'
122}
123
124struct User2 {
125 age int
126 nums []int
127 reg_date time.Time
128}
129
130struct User {
131 age int
132 nums []int
133 last_name string [json: lastName]
134 is_registered bool [json: IsRegistered]
135 typ int [json: 'type']
136 pets string [json: 'pet_animals'; raw]
137}
138
139fn test_parse_user() {
140 s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}'
141 u2 := json.decode(User2, s)!
142 // println(u2)
143 u := json.decode(User, s)!
144 // println(u)
145 assert u.age == 10
146 assert u.last_name == 'Johnson'
147 assert u.is_registered == true
148 assert u.nums.len == 3
149 assert u.nums[0] == 1
150 assert u.nums[1] == 2
151 assert u.nums[2] == 3
152 assert u.typ == 1
153 assert u.pets == '{"name":"Bob","animal":"Dog"}'
154}
155
156fn test_encode_decode_time() {
157 user := User2{
158 age: 25
159 reg_date: time.new_time(year: 2020, month: 12, day: 22, hour: 7, minute: 23)
160 }
161 s := json.encode(user)
162 // println(s)
163 assert s.contains('"reg_date":1608621780')
164 user2 := json.decode(User2, s)!
165 assert user2.reg_date.str() == '2020-12-22 07:23:00'
166 // println(user2)
167 // println(user2.reg_date)
168}
169
170fn (mut u User) foo() string {
171 return json.encode(u)
172}
173
174fn test_encode_user() {
175 mut usr := User{
176 age: 10
177 nums: [1, 2, 3]
178 last_name: 'Johnson'
179 is_registered: true
180 typ: 0
181 pets: 'foo'
182 }
183 expected := '{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"foo"}'
184 out := json.encode(usr)
185 // println(out)
186 assert out == expected
187 // Test json.encode on mutable pointers
188 assert usr.foo() == expected
189}
190
191struct Color {
192 space string
193 point string [raw]
194}
195
196fn test_raw_json_field() {
197 color := json.decode(Color, '{"space": "YCbCr", "point": {"Y": 123}}') or {
198 // println('text')
199 return
200 }
201 assert color.point == '{"Y":123}'
202 assert color.space == 'YCbCr'
203}
204
205fn test_bad_raw_json_field() {
206 color := json.decode(Color, '{"space": "YCbCr"}') or {
207 // println('text')
208 return
209 }
210 assert color.point == ''
211 assert color.space == 'YCbCr'
212}
213
214struct City {
215 name string
216}
217
218struct Country {
219 cities []City
220 name string
221}
222
223fn test_struct_in_struct() {
224 country := json.decode(Country, '{ "name": "UK", "cities": [{"name":"London"}, {"name":"Manchester"}]}')!
225 assert country.name == 'UK'
226 assert country.cities.len == 2
227 assert country.cities[0].name == 'London'
228 assert country.cities[1].name == 'Manchester'
229 // println(country.cities)
230}
231
232fn test_encode_map() {
233 expected := '{"one":1,"two":2,"three":3,"four":4}'
234 numbers := {
235 'one': 1
236 'two': 2
237 'three': 3
238 'four': 4
239 }
240 out := json.encode(numbers)
241 // println(out)
242 assert out == expected
243}
244
245fn test_parse_map() {
246 expected := {
247 'one': 1
248 'two': 2
249 'three': 3
250 'four': 4
251 }
252 out := json.decode(map[string]int, '{"one":1,"two":2,"three":3,"four":4}')!
253 // println(out)
254 assert out == expected
255}
256
257struct Data {
258 countries []Country
259 users map[string]User
260 extra map[string]map[string]int
261}
262
263fn test_nested_type() {
264 data_expected := '{"countries":[{"cities":[{"name":"London"},{"name":"Manchester"}],"name":"UK"},{"cities":[{"name":"Donlon"},{"name":"Termanches"}],"name":"KU"}],"users":{"Foo":{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"little foo"},"Boo":{"age":20,"nums":[5,3,1],"lastName":"Smith","IsRegistered":false,"type":4,"pet_animals":"little boo"}},"extra":{"2":{"n1":2,"n2":4,"n3":8,"n4":16},"3":{"n1":3,"n2":9,"n3":27,"n4":81}}}'
265 data := Data{
266 countries: [
267 Country{
268 name: 'UK'
269 cities: [City{'London'}, City{'Manchester'}]
270 },
271 Country{
272 name: 'KU'
273 cities: [City{'Donlon'}, City{'Termanches'}]
274 },
275 ]
276 users: {
277 'Foo': User{
278 age: 10
279 nums: [1, 2, 3]
280 last_name: 'Johnson'
281 is_registered: true
282 typ: 0
283 pets: 'little foo'
284 }
285 'Boo': User{
286 age: 20
287 nums: [5, 3, 1]
288 last_name: 'Smith'
289 is_registered: false
290 typ: 4
291 pets: 'little boo'
292 }
293 }
294 extra: {
295 '2': {
296 'n1': 2
297 'n2': 4
298 'n3': 8
299 'n4': 16
300 }
301 '3': {
302 'n1': 3
303 'n2': 9
304 'n3': 27
305 'n4': 81
306 }
307 }
308 }
309 out := json.encode(data)
310 // println(out)
311 assert out == data_expected
312 data2 := json.decode(Data, data_expected)!
313 assert data2.countries.len == data.countries.len
314 for i in 0 .. 1 {
315 assert data2.countries[i].name == data.countries[i].name
316 assert data2.countries[i].cities.len == data.countries[i].cities.len
317 for j in 0 .. 1 {
318 assert data2.countries[i].cities[j].name == data.countries[i].cities[j].name
319 }
320 }
321 for key, user in data.users {
322 assert data2.users[key].age == user.age
323 assert data2.users[key].nums == user.nums
324 assert data2.users[key].last_name == user.last_name
325 assert data2.users[key].is_registered == user.is_registered
326 assert data2.users[key].typ == user.typ
327 // assert data2.users[key].pets == user.pets // TODO FIX
328 }
329 for k, v in data.extra {
330 for k2, v2 in v {
331 assert data2.extra[k][k2] == v2
332 }
333 }
334}
335
336struct Foo[T] {
337pub:
338 name string
339 data T
340}
341
342fn test_generic_struct() {
343 foo_int := Foo[int]{'bar', 12}
344 foo_enc := json.encode(foo_int)
345 assert foo_enc == '{"name":"bar","data":12}'
346 foo_dec := json.decode(Foo[int], foo_enc)!
347 assert foo_dec.name == 'bar'
348 assert foo_dec.data == 12
349}
350
351fn test_errors() {
352 invalid_array := fn () {
353 data := '{"countries":[{"cities":[{"name":"London"},{"name":"Manchester"}],"name":"UK"},{"cities":{"name":"Donlon"},"name":"KU"}],"users":{"Foo":{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"little foo"},"Boo":{"age":20,"nums":[5,3,1],"lastName":"Smith","IsRegistered":false,"type":4,"pet_animals":"little boo"}},"extra":{"2":{"n1":2,"n2":4,"n3":8,"n4":16},"3":{"n1":3,"n2":9,"n3":27,"n4":81}}}'
354 json.decode(Data, data) or {
355 // println(err)
356 assert err.msg().starts_with('Json element is not an array:')
357 return
358 }
359 assert false
360 }
361 invalid_object := fn () {
362 data := '{"countries":[{"cities":[{"name":"London"},{"name":"Manchester"}],"name":"UK"},{"cities":[{"name":"Donlon"},{"name":"Termanches"}],"name":"KU"}],"users":[{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"little foo"},{"age":20,"nums":[5,3,1],"lastName":"Smith","IsRegistered":false,"type":4,"pet_animals":"little boo"}],"extra":{"2":{"n1":2,"n2":4,"n3":8,"n4":16},"3":{"n1":3,"n2":9,"n3":27,"n4":81}}}'
363 json.decode(Data, data) or {
364 // println(err)
365 assert err.msg().starts_with('Json element is not an object:')
366 return
367 }
368 assert false
369 }
370 invalid_array()
371 invalid_object()
372}
373
374type ID = string
375type GG = int
376
377struct Message {
378 id ID
379 ij GG
380}
381
382fn test_decode_alias_struct() {
383 msg := json.decode(Message, '{"id": "118499178790780929"}')!
384 // hacky way of comparing aliased strings
385 assert msg.id.str() == '118499178790780929'
386 assert msg.ij.str() == '0'
387}
388
389fn test_encode_alias_struct() {
390 expected := '{"id":"118499178790780929","ij":999998888}'
391 msg := Message{'118499178790780929', 999998888}
392 out := json.encode(msg)
393 assert out == expected
394}
395
396struct List {
397 id int
398 items []string
399}
400
401fn test_list() {
402 list := json.decode(List, '{"id": 1, "items": ["1", "2"]}')!
403 assert list.id == 1
404 assert list.items == ['1', '2']
405}
406
407fn test_list_no_id() {
408 list := json.decode(List, '{"items": ["1", "2"]}')!
409 assert list.id == 0
410 assert list.items == ['1', '2']
411}
412
413fn test_list_no_items() {
414 list := json.decode(List, '{"id": 1}')!
415 assert list.id == 1
416 assert list.items == []
417}
418
419struct Info {
420 id int
421 items []string
422 maps map[string]string
423}
424
425fn test_decode_null_object() {
426 info := json.decode(Info, '{"id": 22, "items": null, "maps": null}')!
427 assert info.id == 22
428 assert '${info.items}' == '[]'
429 assert '${info.maps}' == '{}'
430}
431
432fn test_decode_missing_maps_field() {
433 info := json.decode(Info, '{"id": 22, "items": null}')!
434 assert info.id == 22
435 assert '${info.items}' == '[]'
436 assert '${info.maps}' == '{}'
437}
438
439struct Foo2 {
440 name string
441}
442
443fn test_pretty() {
444 foo := Foo2{'Bob'}
445 assert json.encode_pretty(foo) == '{
446 "name": "Bob"
447}'
448}
449
450struct Foo3 {
451 name string
452 age int [omitempty]
453}
454
455fn test_omit_empty() {
456 foo := Foo3{'Bob', 0}
457 assert json.encode_pretty(foo) == '{
458 "name": "Bob"
459}'
460 // println('omitempty:')
461 // println(json.encode_pretty(foo))
462}
463
464struct Asdasd {
465 data GamePacketData
466}
467
468type GamePacketData = GPEquipItem | GPScale
469
470struct GPScale {
471 value f32
472}
473
474struct GPEquipItem {
475 name string
476}
477
478fn create_game_packet(data &GamePacketData) string {
479 return json.encode(data)
480}
481
482fn test_encode_sumtype_defined_ahead() {
483 ret := create_game_packet(&GamePacketData(GPScale{}))
484 // println(ret)
485 assert ret == '{"value":0,"_type":"GPScale"}'
486}
487
488struct StByteArray {
489 ba []byte
490}
491
492fn test_byte_array() {
493 assert json.encode(StByteArray{ ba: [byte(1), 2, 3, 4, 5] }) == '{"ba":[1,2,3,4,5]}'
494}
495
496struct Aa {
497 sub AliasType
498}
499
500struct Bb {
501 a int
502}
503
504type AliasType = Bb
505
506fn test_encode_alias_field() {
507 s := json.encode(Aa{
508 sub: Bb{
509 a: 1
510 }
511 })
512 println(s)
513 assert s == '{"sub":{"a":1}}'
514}
515
516//
517
518struct APrice {}
519
520struct Association {
521 association &Association = unsafe { nil }
522 price APrice
523}
524
525fn test_encoding_struct_with_pointers() {
526 value := Association{
527 association: &Association{
528 price: APrice{}
529 }
530 price: APrice{}
531 }
532 assert json.encode(value) == '{"association":{"price":{}},"price":{}}'
533}