import x.json2 as json import time enum JobTitle { manager executive worker } pub struct Employee { pub mut: name string age int salary f32 title JobTitle } const currency_id = 'cconst' pub struct Price { net f64 currency_id string [json: currencyId] = currency_id } //! BUGFIX fn test_field_with_default_expr() { data := '[{"net":1},{"net":2,"currencyId":"cjson"}]' prices := json.decode[[]Price](data)! assert prices == [Price{ net: 1 currency_id: 'cconst' }, Price{ net: 2 currency_id: 'cjson' }] } //! BUGFIX - .from_json(res) fn test_decode_top_level_array() { s := '[{"name":"Peter", "age": 29}, {"name":"Bob", "age":31}]' x := json.decode[[]Employee](s) or { panic(err) } assert x.len == 2 assert x[0].name == 'Peter' assert x[0].age == 29 assert x[1].name == 'Bob' assert x[1].age == 31 } struct Human { name string } struct Item { tag string } enum Animal { dog // Will be encoded as `0` cat } type Entity = Animal | Human | Item | string | time.Time struct SomeGame { title string player Entity other []Entity } //! BUGFIX - .from_json(res) fn test_encode_decode_sumtype() { t := time.now() game := SomeGame{ title: 'Super Mega Game' player: Human{'Monke'} other: [ Entity(Item{'Pen'}), Item{'Cookie'}, Animal.cat, 'Stool', t, ] } enc := json.encode(game) assert enc == '{"title":"Super Mega Game","player":{"name":"Monke","_type":"Human"},"other":[{"tag":"Pen","_type":"Item"},{"tag":"Cookie","_type":"Item"},1,"Stool",{"_type":"Time","value":${t.unix_time()}}]}' dec := json.decode[SomeGame](enc)! assert game.title == dec.title assert game.player == dec.player assert (game.other[2] as Animal) == (dec.other[2] as Animal) assert (game.other[4] as time.Time).unix_time() == (dec.other[4] as time.Time).unix_time() } struct User2 { mut: age int nums []int reg_date time.Time } // User struct needs to be `pub mut` for now in order to access and manipulate values struct User { pub mut: age int nums []int last_name string [json: lastName] is_registered bool [json: IsRegistered] typ int [json: 'type'] pets string [json: 'pet_animals'; raw] } fn test_parse_user() { s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}' u2 := json.decode[User2](s)! u := json.decode[User](s)! assert u.age == 10 assert u.last_name == 'Johnson' assert u.is_registered == true assert u.nums.len == 3 assert u.nums[0] == 1 assert u.nums[1] == 2 assert u.nums[2] == 3 assert u.typ == 1 assert u.pets == '{"name":"Bob","animal":"Dog"}' } //! BUGFIX - .from_json(res) fn test_encode_decode_time() { user := User2{ age: 25 reg_date: time.new_time(year: 2020, month: 12, day: 22, hour: 7, minute: 23) } s := json.encode(user) assert s.contains('"reg_date":1608621780') user2 := json.decode[User2](s)! assert user2.reg_date.str() == '2020-12-22 07:23:00' struct City { name string } struct Country { cities []City name string } //! BUGFIX - .from_json(res) fn test_struct_in_struct() { country := json.decode[Country]('{ "name": "UK", "cities": [{"name":"London"}, {"name":"Manchester"}]}')! assert country.name == 'UK' assert country.cities.len == 2 assert country.cities[0].name == 'London' assert country.cities[1].name == 'Manchester' } //! BUGFIX - .from_json(res) fn test_parse_map() { expected := { 'one': 1 'two': 2 'three': 3 'four': 4 } out := json.decode[map[string]int]('{"one":1,"two":2,"three":3,"four":4}')! assert out == expected } struct Data { countries []Country users map[string]User extra map[string]map[string]int } //! BUGFIX - .from_json(res) fn test_nested_type() { 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}}}' data := Data{ countries: [ Country{ name: 'UK' cities: [City{'London'}, City{'Manchester'}] }, Country{ name: 'KU' cities: [City{'Donlon'}, City{'Termanches'}] }, ] users: { 'Foo': User{ age: 10 nums: [1, 2, 3] last_name: 'Johnson' is_registered: true typ: 0 pets: 'little foo' } 'Boo': User{ age: 20 nums: [5, 3, 1] last_name: 'Smith' is_registered: false typ: 4 pets: 'little boo' } } extra: { '2': { 'n1': 2 'n2': 4 'n3': 8 'n4': 16 } '3': { 'n1': 3 'n2': 9 'n3': 27 'n4': 81 } } } out := json.encode(data) assert out == data_expected data2 := json.decode[Data](data_expected)! assert data2.countries.len == data.countries.len for i in 0 .. 1 { assert data2.countries[i].name == data.countries[i].name assert data2.countries[i].cities.len == data.countries[i].cities.len for j in 0 .. 1 { assert data2.countries[i].cities[j].name == data.countries[i].cities[j].name } } for key, user in data.users { assert data2.users[key].age == user.age assert data2.users[key].nums == user.nums assert data2.users[key].last_name == user.last_name assert data2.users[key].is_registered == user.is_registered assert data2.users[key].typ == user.typ //!assert data2.users[key].pets == user.pets TODO FIX } for k, v in data.extra { for k2, v2 in v { assert data2.extra[k][k2] == v2 } } } //! BUGFIX - .from_json(res) fn test_errors() { invalid_array := fn () { 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}}}' json.decode[Data](data) or { assert err.msg().starts_with('Json element is not an array:') return } assert false } invalid_object := fn () { 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}}}' json.decode[Data](data) or { assert err.msg().starts_with('Json element is not an object:') return } assert false } invalid_array() invalid_object() } type ID = string type GG = int struct Message { id ID ij GG } //! BUGFIX - .from_json(res) fn test_decode_alias_struct() { msg := json.decode[Message]('{"id": "118499178790780929"}')! // hacky way of comparing aliased strings assert msg.id.str() == '118499178790780929' } struct List { id int items []string } //! BUGFIX - .from_json(res) fn test_list() { list := json.decode[List]('{"id": 1, "items": ["1", "2"]}')! assert list.id == 1 assert list.items == ['1', '2'] } //! BUGFIX - .from_json(res) fn test_list_no_id() { list := json.decode[List]('{"items": ["1", "2"]}')! assert list.id == 0 assert list.items == ['1', '2'] } //! BUGFIX - .from_json(res) fn test_list_no_items() { list := json.decode[List]('{"id": 1}')! assert list.id == 1 assert list.items == [] } struct Info { id int items []string maps map[string]string } //! BUGFIX - .from_json(res) fn test_decode_null_object() { info := json.decode[Info]('{"id": 22, "items": null, "maps": null}')! assert info.id == 22 assert '${info.items}' == '[]' assert '${info.maps}' == '{}' } //! BUGFIX - .from_json(res) fn test_decode_missing_maps_field() { info := json.decode[Info]('{"id": 22, "items": null}')! assert info.id == 22 assert '${info.items}' == '[]' assert '${info.maps}' == '{}' } struct Foo3 { name string age int [omitempty] } //! BUGFIX - .from_json(res) fn test_omit_empty() { foo := Foo3{'Bob', 0} assert json.encode_pretty(foo) == '{ "name": "Bob" }' } struct Asdasd { data GamePacketData } type GamePacketData = GPEquipItem | GPScale struct GPScale { value f32 } struct GPEquipItem { name string } fn create_game_packet(data &GamePacketData) string { return json.encode(data) } //! FIX: returning null fn test_encode_sumtype_defined_ahead() { ret := create_game_packet(&GamePacketData(GPScale{})) assert ret == '{"value":0,"_type":"GPScale"}' } struct APrice {} struct Association { association &Association = unsafe { nil } price APrice } //! FIX: returning null fn test_encoding_struct_with_pointers() { value := Association{ association: &Association{ price: APrice{} } price: APrice{} } assert json.encode(value) == '{"association":{"price":{}},"price":{}}' }