Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+26
View File
@@ -0,0 +1,26 @@
import json
pub struct User {
name string
age int
height f64
}
type Users = map[string]User
const json_users = '{
"tom": { "name": "Tom", "age": 45, "height": 1.97 },
"martin": { "name": "Martin", "age": 40, "height": 1.8 }
}'
fn test_alias_with_map() {
a := json.decode(map[string]User, json_users)!
b := json.decode(Users, json_users)!
assert Users(a) == b
c := json.encode(a)
d := json.encode(b)
assert c == d
}
@@ -0,0 +1,9 @@
import json
fn test_main() {
json_text := '{ "a": "b" }'
b := json.decode(struct {
a string
}, json_text)!.a
assert dump(b) == 'b'
}
@@ -0,0 +1,10 @@
import json
struct Test {
a string
}
fn test_main() {
x := json.decode([]&Test, '[{"a":"a"}]') or { exit(1) }
assert x[0].a == 'a'
}
@@ -0,0 +1,28 @@
module main
import json
struct Json2 {
inner []f64
}
struct Json {
Json2
test f64
}
fn test_main() {
str := '{
"inner": [1, 2, 3, 4, 5],
"test": 1.0
}'
data := json.decode(Json, str) or {
eprintln('Failed to decode json, error: ${err}')
return
}
println(data)
assert data.inner.len == 5
assert data.inner[0] == 1.0
assert data.inner[4] == 5.0
assert data.test == 1.0
}
@@ -0,0 +1,16 @@
module main
import json
struct Req {
height ?int
width ?i32
}
const payload = '{}'
fn test_main() {
r := json.decode(Req, payload) or { panic(err) }
assert r.height == none
assert r.width == none
}
@@ -0,0 +1,20 @@
import json
struct Empty {}
struct SomeStruct {
random_field_a ?string
random_field_b ?string
empty_field ?Empty
}
type Alias = SomeStruct
fn test_main() {
data := json.decode(Alias, '{"empty_field":{}}')!
assert data.str() == 'Alias(SomeStruct{
random_field_a: Option(none)
random_field_b: Option(none)
empty_field: Option(Empty{})
})'
}
@@ -0,0 +1,18 @@
import json
enum Lang {
en = 1
}
struct Request {
lang ?Lang // ?string, ?int are ok
}
fn test_main() {
assert dump(json.decode(Request, '{}')!) == Request{
lang: ?Lang(none)
}
assert dump(json.decode(Request, '{"lang": "en"}')!) == Request{
lang: .en
}
}
@@ -0,0 +1,20 @@
import json
struct Bar {
b []int = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
struct Foo {
Bar
a []int = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
fn test_main() {
str := json.encode(Foo{})
assert json.decode(Foo, str)!.str() == 'Foo{
Bar: Bar{
b: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
a: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}'
}
@@ -0,0 +1,42 @@
import json
struct Message {
mut:
id int
text string
reply_to &Message
}
struct OptionalMessage {
mut:
id int
text string
reply_to ?&OptionalMessage
}
fn test_main() {
mut json_data := '{"id": 1, "text": "Hello", "reply_to": {"id": 2, "text": "Hi"}}'
mut message := json.decode(Message, json_data)!
assert message.reply_to.id == 2
json_data = '{"id": 1, "text": "Hello", "reply_to": {"id": 2, "text": "Hi", "reply_to": {}}}'
message = json.decode(Message, json_data)!
assert message.reply_to.reply_to.reply_to == unsafe { nil }
json_data = '{"id": 1, "text": "Hello", "reply_to": {"id": 2, "text": "Hi", "reply_to": {"id": 5}}}'
message = json.decode(Message, json_data)!
assert message.reply_to.reply_to.id == 5
}
fn test_recursive_optional_struct_ptr() {
json_data := '{"id": 1, "text": "Hello", "reply_to": {"id": 2, "text": "Hi", "reply_to": null}}'
message := json.decode(OptionalMessage, json_data)!
reply := message.reply_to or {
assert false
return
}
assert reply.id == 2
assert reply.text == 'Hi'
assert reply.reply_to == none
}
@@ -0,0 +1,34 @@
import json
pub struct Response {
pub:
results []Result = []Result{len: 0} @[json: list]
tags []string = []string{len: 0} @[json: tags]
kind string @[json: result_type]
}
pub struct Result {
pub:
id int @[json: defid]
author string @[json: author]
definition string @[json: definition]
link string @[json: permalink]
thumbs_down int @[json: thumbs_down]
thumbs_up int @[json: thumbs_up]
word string @[json: word]
date string @[json: written_on]
audio_samples []string @[json: sound_urls]
example string @[json: example]
}
pub fn define(word string) !&Response {
resp := '{"list":[{"defid":3439287}]}'
response := json.decode(Response, resp) or { return err }
return &response
}
fn test_main() {
response := define('')!
assert response.results.len > 0
assert response.results[0].id == 3439287
}
@@ -0,0 +1,8 @@
import json
type Any = string | f32 | bool | ?int
fn test_main() {
x := json.decode([]Any, '["hi", -9.8e7, true, null]')!
assert dump(x) == [Any('hi'), Any(f32(-9.8e+7)), Any(true), Any(?int(none))]
}
+165
View File
@@ -0,0 +1,165 @@
import json
struct TestTwin {
id int
seed string
pubkey string
}
struct TestTwins {
mut:
twins []TestTwin @[required]
}
fn test_json_decode_fails_to_decode_unrecognised_array_of_dicts() {
data := '[{"twins":[{"id":123,"seed":"abcde","pubkey":"xyzasd"},{"id":456,"seed":"dfgdfgdfgd","pubkey":"skjldskljh45sdf"}]}]'
json.decode(TestTwins, data) or {
assert err.msg() == "expected field 'twins' is missing"
return
}
assert false
}
fn test_json_decode_works_with_a_dict_of_arrays() {
data := '{"twins":[{"id":123,"seed":"abcde","pubkey":"xyzasd"},{"id":456,"seed":"dfgdfgdfgd","pubkey":"skjldskljh45sdf"}]}'
res := json.decode(TestTwins, data) or {
assert false
exit(1)
}
assert res.twins[0].id == 123
assert res.twins[0].seed == 'abcde'
assert res.twins[0].pubkey == 'xyzasd'
assert res.twins[1].id == 456
assert res.twins[1].seed == 'dfgdfgdfgd'
assert res.twins[1].pubkey == 'skjldskljh45sdf'
}
struct Mount {
size u64
}
fn test_decode_u64() {
data := '{"size": 10737418240}'
m := json.decode(Mount, data)!
assert m.size == 10737418240
// println(m)
}
fn test_decode_large_u64_from_decimal_json() {
cases := [
u64(9007199254740991),
u64(9007199254740992),
u64(9007199254740993),
u64(9223372036854775807),
u64(9223372036854775808),
u64(9223372036854775809),
u64(18446744073709551614),
u64(18446744073709551615),
]
for want in cases {
got := json.decode([]u64, '[${want}]')!
assert got.len == 1
assert got[0] == want
}
}
fn test_encode_decode_large_u64_roundtrip() {
cases := [
u64(9007199254740991),
u64(9007199254740992),
u64(9007199254740993),
u64(9223372036854775807),
u64(9223372036854775808),
u64(9223372036854775809),
u64(18446744073709551614),
u64(18446744073709551615),
]
for want in cases {
encoded := json.encode([want])
assert encoded == '[${want}]'
got := json.decode([]u64, encoded)!
assert got.len == 1
assert got[0] == want
}
}
//
pub struct Comment {
pub mut:
id string
comment string
}
pub struct Task {
mut:
description string
id int
total_comments int
file_name string @[skip]
comments []Comment @[skip]
skip_field string @[json: '-']
}
fn test_skip_fields_should_be_initialised_by_json_decode() {
data := '{"total_comments": 55, "id": 123}'
mut task := json.decode(Task, data)!
assert task.id == 123
assert task.total_comments == 55
assert task.comments == []
}
fn test_skip_should_be_ignored() {
data := '{"total_comments": 55, "id": 123, "skip_field": "foo"}'
mut task := json.decode(Task, data)!
assert task.id == 123
assert task.total_comments == 55
assert task.comments == []
assert task.skip_field == ''
}
//
struct DbConfig {
host string
dbname string
user string
}
fn test_decode_error_message_should_have_enough_context_empty() {
json.decode(DbConfig, '') or {
assert err.msg() == 'failed to decode JSON string'
return
}
assert false
}
fn test_decode_error_message_should_have_enough_context_just_brace() {
json.decode(DbConfig, '{') or {
assert err.msg() == 'failed to decode JSON string: {'
return
}
assert false
}
fn test_decode_error_message_should_have_enough_context_trailing_comma_at_end() {
txt := '{
"host": "localhost",
"dbname": "alex",
"user": "alex",
}'
json.decode(DbConfig, txt) or {
assert err.msg().contains(' "user": "alex",\n}')
return
}
assert false
}
fn test_decode_error_message_should_have_enough_context_in_the_middle() {
txt := '{"host": "localhost", "dbname": "alex" "user": "alex", "port": "1234"}'
json.decode(DbConfig, txt) or {
assert err.msg().contains('ost", "dbname": "alex" "user":')
return
}
assert false
}
@@ -0,0 +1,12 @@
import json
struct TodoDto {
foo int
}
fn test_decode_with_encode_arg() {
body := TodoDto{}
ret := json.decode(TodoDto, json.encode(body))!
println(ret)
assert ret.foo == 0
}
@@ -0,0 +1,44 @@
import json
struct Response[T] {
time string
cars []T
}
struct Car {
brand string
power int
}
fn string_to_response[T](text string) {
result := json.decode([]Response[T], text) or { panic(err) }
println(result)
assert result.len == 2
assert result[0].time == '12ms'
assert result[0].cars[0].brand == 'Ferrari'
assert result[0].cars[0].power == 232
assert result[0].cars[1].brand == 'Lamborghini'
assert result[0].cars[1].power == 345
assert result[1].time == '12ms'
assert result[1].cars[0].brand == 'Ferrari'
assert result[1].cars[0].power == 232
assert result[1].cars[1].brand == 'Lamborghini'
assert result[1].cars[1].power == 345
}
fn test_json_decode_with_generic_array() {
text := '[
{ "time":"12ms",
"cars":[
{"brand":"Ferrari","power":232},
{"brand":"Lamborghini", "power":345}
]},
{ "time":"12ms",
"cars":[
{"brand":"Ferrari","power":232},
{"brand":"Lamborghini", "power":345}
]}
]'
string_to_response[Car](text)
}
@@ -0,0 +1,49 @@
import json
struct Result[T] {
ok bool
result T
}
struct User {
id int
username string
}
struct Box[T] {
items []T
}
fn func[T]() !T {
text := '{"ok": true, "result":{"id":37467243, "username": "ciao"}}'
a := json.decode(Result[T], text)!
return a.result
}
fn string_decode[T](text string) !T {
return json.decode(T, text)
}
fn open_box[T](text string) ![]T {
box := string_decode[Box[T]](text)!
return box.items
}
fn test_decode_with_generic_struct() {
ret := func[User]()!
println(ret)
assert ret.id == 37467243
assert ret.username == 'ciao'
}
fn test_decode_with_nested_generic_struct() {
text := '{"items":[{},{"id":37467243,"username":"ciao"},{}]}'
items := open_box[User](text)!
assert items.len == 3
assert items[0].id == 0
assert items[0].username == ''
assert items[1].id == 37467243
assert items[1].username == 'ciao'
assert items[2].id == 0
assert items[2].username == ''
}
@@ -0,0 +1,19 @@
import json
import os
struct DbConfig {}
fn test_json_decode_with_option_arg() {
if ret := print_info() {
println(ret)
} else {
println(err)
}
assert true
}
fn print_info() !string {
dbconf := json.decode(DbConfig, os.read_file('dbconf.json')!)!
println(dbconf)
return '${dbconf}'
}
@@ -0,0 +1,104 @@
import json
type Test = []bool | []int | []string | string
struct Some {
t Test
}
type GetBlockResult = string | GetBlockResultB
struct GetBlockResponse {
result GetBlockResult
}
struct GetBlockResultB {
hash string
confirmations u64
}
fn test_json_decode_with_sumtype() {
v1 := json.decode(Some, '{"t": ["string", "string2"]}')!
println(v1)
assert v1.t == Test(['string', 'string2'])
v2 := json.decode(Some, '{"t": [11, 22]}')!
println(v2)
assert v2.t == Test([11, 22])
v3 := json.decode(Some, '{"t": [true, false]}')!
println(v3)
assert v3.t == Test([true, false])
}
struct ComplexValue {
foo string
}
type StringOrComplexValue = ComplexValue | string
fn test_json_decode_with_sumtype_struct_variant_without_type_field() {
decoded := json.decode([]StringOrComplexValue, '["abc",{"foo":"bar"}]')!
assert decoded.len == 2
assert decoded[0] == StringOrComplexValue('abc')
assert decoded[1] == StringOrComplexValue(ComplexValue{
foo: 'bar'
})
}
struct OtherComplexValue {
bar string
}
type AmbiguousStringOrComplexValue = ComplexValue | OtherComplexValue | string
fn test_json_decode_with_sumtype_ambiguous_struct_variant_without_type_field_errors() {
json.decode([]AmbiguousStringOrComplexValue, '[{"foo":"bar"}]') or {
assert err.msg().contains('cannot decode')
assert err.msg().contains('AmbiguousStringOrComplexValue')
return
}
assert false
}
fn test_json_decode_with_sumtype_struct_field_without_type_field() {
decoded := json.decode(GetBlockResponse,
'{ "result": { "hash": "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", "confirmations": 743970 } }')!
assert decoded.result == GetBlockResult(GetBlockResultB{
hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09'
confirmations: 743970
})
}
type ApiDetails = string | map[string]string
fn test_json_decode_with_sumtype_map_variant_without_type_field() {
api_docs_file := r'
[
{
"CloseHandle": [
"https://learn.microsoft.com/windows/win32/api/handleapi/nf-handleapi-closehandle",
"Closes an open object handle.",
"The \n<b>CloseHandle</b> function ...",
{
"hObject": "A valid handle to an open object."
},
{},
"If the function succeeds, ..."
]
}
]
'
decoded := json.decode([]map[string][]ApiDetails, api_docs_file)!
close_handle := decoded[0]['CloseHandle'] or { panic('missing CloseHandle docs') }
assert close_handle.len == 6
assert close_handle[0] == ApiDetails('https://learn.microsoft.com/windows/win32/api/handleapi/nf-handleapi-closehandle')
assert close_handle[3] == ApiDetails({
'hObject': 'A valid handle to an open object.'
})
assert close_handle[4] == ApiDetails(map[string]string{})
assert close_handle[5] == ApiDetails('If the function succeeds, ...')
}
+31
View File
@@ -0,0 +1,31 @@
import json
struct Json3 {
embed f64
}
struct Json2 {
Json3
inner []f64
}
struct Json {
Json2
test f64
}
fn test_main() {
str := '{"inner": [1, 2, 3, 4, 5],"test": 1.0, "embed": 2.0}'
data := json.decode(Json, str) or {
eprintln('Failed to decode json, error: ${err}')
return
}
println(data)
assert data.inner.len == 5
assert data.inner[0] == 1.0
assert data.inner[4] == 5.0
assert data.test == 1.0
assert data.embed == 2.0
assert dump(json.encode(data)) == '{"embed":2,"inner":[1,2,3,4,5],"test":1}'
}
@@ -0,0 +1,24 @@
import json
struct RefArrayItem {
a int
}
fn ref_array_item(value int, is_nil bool) &RefArrayItem {
return if is_nil {
unsafe { nil }
} else {
&RefArrayItem{
a: value
}
}
}
fn test_json_encode_array_of_references_with_nil() {
value := [
ref_array_item(1, false),
ref_array_item(0, true),
ref_array_item(2, false),
]
assert json.encode(value) == '[{"a":1},null,{"a":2}]'
}
@@ -0,0 +1,12 @@
// vtest vflags: -w
module main
import json
struct Test {
id ?string = none
}
fn test_main() {
assert json.encode(Test{}) == '{}'
}
@@ -0,0 +1,56 @@
import json
struct Json2 {
inner []f64
}
struct Json {
Json2
test f64
}
struct Article {
title string
description string
}
struct ArticlePlus {
Article
perex string
}
fn test_main() {
str := '{"inner":[1,2,3,4,5],"test":1.2}'
data := json.decode(Json, str) or {
eprintln('Failed to decode json, error: ${err}')
return
}
println(data)
assert data.inner.len == 5
assert data.inner[0] == 1.0
assert data.inner[4] == 5.0
assert data.test == 1.2
data_json := json.encode(data)
dump(data_json)
assert data_json == str
}
fn test_encode_array_of_embedded_structs() {
list_of_object := [
ArticlePlus{
title: 'One good title'
description: 'this is the first'
},
ArticlePlus{
title: 'Other good title'
description: 'more one'
},
ArticlePlus{
title: 'Other good title'
description: 'more one'
perex: 'good perex'
},
]
assert json.encode(list_of_object) == '[{"title":"One good title","description":"this is the first","perex":""},{"title":"Other good title","description":"more one","perex":""},{"title":"Other good title","description":"more one","perex":"good perex"}]'
}
@@ -0,0 +1,135 @@
import json
@[json_as_number]
pub enum MessageType {
error = 1
warning = 2
info = 3
log = 4
}
pub enum MessageType2 {
error = 1
warning = 2
info = 3
log = 4
}
enum TestEnum {
one = 1
two
}
type TestAlias = TestEnum
type TestSum = TestEnum | string
type TestSum2 = MessageType | string
type TestAliasAttr = MessageType
struct TestStruct {
test []TestEnum
test2 TestEnum
test3 TestAlias
test4 TestSum
test5 MessageType
}
struct TestStruct2 {
a TestAliasAttr
b TestSum2
c TestSum2
}
struct Test {
ab ?int
a ?MessageType
}
struct Test2 {
a ?MessageType2
}
type TSum = MessageType | string
type TSum2 = MessageType2 | string
struct Test3 {
a ?TSum
}
struct Test4 {
a ?TSum2
}
fn test_encode_with_enum() {
out := json.encode(TestStruct{
test: [TestEnum.one, TestEnum.one]
test2: TestEnum.two
test3: TestEnum.one
test4: TestEnum.two
test5: .log
})
assert out == '{"test":["one","one"],"test2":"two","test3":"one","test4":"two","test5":4}'
}
fn test_encode_direct_enum() {
assert json.encode(TestEnum.one) == '"one"'
}
fn test_encode_alias_and_sumtype() {
assert json.decode(TestStruct,
'{"test":["one","one"],"test2":"two","test3": "one", "test4": "two", "test5":4}')! == TestStruct{
test: [.one, .one]
test2: .two
test3: TestAlias(.one)
test4: TestSum('two')
test5: .log
}
}
fn test_enum_attr() {
assert dump(json.encode(MessageType.log)) == '4'
assert dump(json.encode(MessageType.error)) == '1'
}
fn test_enum_attr_decode() {
assert json.decode(TestStruct2, '{"a": 1, "b":4, "c": "test"}')! == TestStruct2{
a: .error
b: MessageType.log
c: 'test'
}
}
fn test_enum_attr_encode() {
assert json.encode(TestStruct2{
a: .error
b: MessageType.log
c: 'test'
}) == '{"a":1,"b":4,"c":"test"}'
}
fn test_option_enum() {
assert dump(json.encode(Test{none, none})) == '{}'
assert dump(json.encode(Test{none, MessageType.log})) == '{"a":4}'
t := dump(json.decode(Test, '{"a":4}')!)
assert t.ab == none
assert t.a? == .log
t2 := dump(json.decode(Test, '{"a":null}')!)
assert t2.a == none
assert json.encode(Test2{none}) == '{}'
assert dump(json.encode(Test2{MessageType2.log})) == '{"a":"log"}'
z := dump(json.decode(Test2, '{"a":"log"}')!)
assert z.a? == .log
a := dump(json.decode(Test2, '{"a": null}')!)
assert a.a == none
}
fn test_option_sumtype_enum() {
assert dump(json.encode(Test3{none})) == '{}'
assert dump(json.encode(Test3{ a: 'foo' })) == '{"a":"foo"}'
assert dump(json.encode(Test3{ a: MessageType.warning })) == '{"a":2}'
assert dump(json.encode(Test4{none})) == '{}'
assert dump(json.encode(Test4{ a: 'foo' })) == '{"a":"foo"}'
assert dump(json.encode(Test4{ a: MessageType2.warning })) == '{"a":"warning"}'
}
@@ -0,0 +1,21 @@
import json
struct Wrap[T] {
val T
}
fn encode[T](value T) string {
return json.encode(Wrap[T]{
val: value
})
}
fn test_json_encode_generic_fixed_array_regression() {
assert encode('x') == '{"val":"x"}'
assert encode([1, 2]!) == '{"val":[1,2]}'
}
fn test_json_encode_generic_fixed_array_regression_reversed() {
assert encode([1, 2]!) == '{"val":[1,2]}'
assert encode('x') == '{"val":"x"}'
}
@@ -0,0 +1,22 @@
import json
struct Test {
optional_string ?string
optional_array ?[]string
optional_struct_array ?[]string
optional_map ?map[string]string
}
fn test_main() {
test := Test{}
encoded := json.encode(test)
assert dump(encoded) == '{}'
test2 := Test{
optional_map: {
'foo': 'bar'
}
}
encoded2 := json.encode(test2)
assert dump(encoded2) == '{"optional_map":{"foo":"bar"}}'
}
@@ -0,0 +1,54 @@
import json
struct Test {
field MySumType
}
type MyInt = int
type MyString = string
type MySumType = MyString | int | string
struct UnicodeString {
emoji string
}
fn test_alias_to_primitive() {
mut test := Test{
field: MyString('foo')
}
mut encoded := json.encode(test)
assert dump(encoded) == '{"field":"foo"}'
assert json.decode(Test, '{"field": "foo"}')!.field == MySumType('foo')
test = Test{
field: 'foo'
}
encoded = json.encode(test)
assert dump(encoded) == '{"field":"foo"}'
assert json.decode(Test, '{"field":"foo"}')! == test
test = Test{
field: 1
}
encoded = json.encode(test)
assert dump(encoded) == '{"field":1}'
assert json.decode(Test, '{"field":1}')! == test
mut test2 := MyString('foo')
encoded = json.encode(test2)
assert dump(encoded) == '"foo"'
mut test3 := MyInt(1000)
encoded = json.encode(test3)
assert dump(encoded) == '1000'
}
fn test_encode_unicode_as_ascii_escape_sequences() {
valid_json := r'{"emoji":"\u3007"}'
decoded := json.decode(UnicodeString, valid_json)!
assert decoded.emoji == '〇'
assert json.encode(UnicodeString{
emoji: '〇'
}) == valid_json
assert json.encode('😀') == r'"\uD83D\ude00"'
}
@@ -0,0 +1,31 @@
import json
struct Number {
min int
max int
}
pub struct Resp {
pub:
options []string @[omitempty]
number &Number = unsafe { nil } @[omitempty]
}
fn (r Resp) str() string {
return json.encode(r)
}
fn test_main() {
r1 := Resp{
options: ['first', 'second']
}
r2 := Resp{
number: &Number{0, 0}
}
r3 := Resp{
number: &Number{1, 2}
}
assert r1.str() == '{"options":["first","second"]}'
assert r2.str() == '{"number":{"min":0,"max":0}}'
assert r3.str() == '{"number":{"min":1,"max":2}}'
}
@@ -0,0 +1,19 @@
import json
struct PostTag {
id string
parent ?&PostTag
visibility string
created_at string @[json: 'createdAt']
metadata string @[raw]
}
fn test_main() {
new_post_tag := &PostTag{}
assert json.encode(new_post_tag) == '{"id":"","visibility":"","createdAt":"","metadata":""}'
new_post_tag2 := PostTag{
parent: new_post_tag
}
assert json.encode(new_post_tag2) == '{"id":"","parent":{"id":"","visibility":"","createdAt":"","metadata":""},"visibility":"","createdAt":"","metadata":""}'
}
@@ -0,0 +1,29 @@
import json
import x.json2
struct Foo {
name string
num ?int
}
fn test_json_encode_struct_with_option_field() {
f1 := Foo{
name: 'hello'
}
ret1 := json.encode(f1)
println(ret1)
assert ret1 == '{"name":"hello"}'
ret2 := json2.encode(f1)
println(ret2)
assert ret2 == '{"name":"hello"}'
f2 := Foo{'hello', 22}
ret3 := json.encode(f2)
println(ret3)
assert ret3 == '{"name":"hello","num":22}'
ret4 := json2.encode(f2)
println(ret4)
assert ret4 == '{"name":"hello","num":22}'
}
@@ -0,0 +1,13 @@
import json
struct Test {
optional_sumtype ?MySumtype
}
type MySumtype = int | string
fn test_simple() {
test := Test{}
encoded := json.encode(test)
assert dump(encoded) == '{}'
}
@@ -0,0 +1,42 @@
module main
import json
pub enum PlatformType {
unknown
osx
ubuntu
alpine
}
pub enum CPUType {
unknown
intel
arm
intel32
arm32
}
@[heap]
pub struct Node {
pub:
name string = 'mymachine'
pub mut:
platform PlatformType
cputype CPUType
done map[string]string
environment map[string]string
}
pub fn (mut node Node) save() ! {
data := json.encode(node)
dump(data)
}
fn test_encode_with_mut_struct() {
mut n := Node{
platform: .osx
cputype: .unknown
}
n.save() or { panic(err) }
}
@@ -0,0 +1,28 @@
import json
struct User {
name string
}
struct MyStruct {
user &User //
users map[string]User
users2 map[string]&User
}
fn test_json_encode_with_ptr() {
user := User{
name: 'foo'
}
data := MyStruct{
user: &user
users: {
'keyfoo': user
}
users2: {
'keyfoo': &user
}
}
assert json.encode(data) == '{"user":{"name":"foo"},"users":{"keyfoo":{"name":"foo"}},"users2":{"keyfoo":{"name":"foo"}}}'
}
@@ -0,0 +1,14 @@
import json
struct F64ArrayPayload {
arr []f64
}
fn test_encode_decode_struct_with_f64_array_roundtrips() ! {
original := F64ArrayPayload{
arr: [0.9716157205240175, 0.9336099585062241]
}
encoded := json.encode(original)
assert encoded == '{"arr":[0.9716157205240175,0.9336099585062241]}'
assert json.decode(F64ArrayPayload, encoded)! == original
}
@@ -0,0 +1,25 @@
import json
struct Base {
options Options
profiles Profiles
}
struct Options {
cfg [6]u8
}
struct Profiles {
cfg [4][7]u8
}
fn test_main() {
a := json.encode(Base{})
println(a)
assert a.contains('"cfg":[[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]]')
b := json.decode(Base, a)!
assert b.options.cfg.len == 6
assert b.profiles.cfg.len == 4
assert b.profiles.cfg[0].len == 7
}
@@ -0,0 +1,47 @@
import json
pub struct DocumentFindFilter[T] {
pub:
selector ?T
selector2 ?[]T
selector3 ?[1]T
limit ?int
skip ?int
fields ?[]string // This breaks the compiler when encoding to JSON
conflicts ?bool
read_quorum ?int @[json: r]
update ?bool
stable ?bool
stale ?string
execution_stats ?bool
}
fn test_string() {
t := DocumentFindFilter[string]{
selector: 'aa'
selector2: ['a', 'b']
selector3: ['z']!
}
assert json.encode(t) == '{"selector":"aa","selector2":["a","b"],"selector3":["z"]}'
assert json.decode(DocumentFindFilter[string],
'{"selector":"aa","selector2":["a","b"],"selector3":["z"]}')! == t
}
fn test_int() ! {
t := DocumentFindFilter[int]{
selector: 1
selector2: [1, 2]
selector3: [3]!
}
assert json.encode(t) == '{"selector":1,"selector2":[1,2],"selector3":[3]}'
assert json.decode(DocumentFindFilter[int], '{"selector":1,"selector2":[1,2],"selector3":[3]}')! == t
}
fn test_none() ! {
t := DocumentFindFilter[int]{}
assert json.encode(t) == '{}'
assert json.decode(DocumentFindFilter[int], '{}')! == t
}
+16
View File
@@ -0,0 +1,16 @@
import json
pub struct StructB {
kind string
value i32
}
fn test_json_i32() {
struct_b := json.decode(StructB, '{"kind": "Int32", "value": 100}')!
assert struct_b == StructB{
kind: 'Int32'
value: 100
}
assert json.encode(struct_b) == '{"kind":"Int32","value":100}'
}
@@ -0,0 +1,26 @@
import json
struct Bar {
name ?string @[json_null]
}
struct Foo {
name ?string @[json_null]
age ?int @[json_null]
text ?string
other ?Bar
other2 ?Bar @[json_null]
}
fn test_main() {
assert json.encode(Foo{}) == '{"name":null,"age":null,"other2":null}'
assert json.encode(Foo{ name: '' }) == '{"name":"","age":null,"other2":null}'
assert json.encode(Foo{ age: 10 }) == '{"name":null,"age":10,"other2":null}'
assert json.encode(Foo{
age: 10
other2: Bar{
name: none
}
}) == '{"name":null,"age":10,"other2":{"name":null}}'
assert json.decode(Foo, json.encode(Foo{}))! == Foo{}
}
@@ -0,0 +1,12 @@
import json
fn q_and_a(mut db_json map[string][]string) {
x := json.encode(db_json)
assert x == '{}'
}
fn test_main() {
mut db_json := json.decode(map[string][]string, '{}')!
assert db_json == {}
q_and_a(mut db_json)
}
@@ -0,0 +1,25 @@
import json
pub struct MyStruct {
pub mut:
code int
message string
data string @[omitempty]
data2 ?string @[omitempty]
}
fn test_simple() {
obj := MyStruct{
code: 1
message: 'yes'
data2: 'a'
}
assert dump(json.encode(obj)) == '{"code":1,"message":"yes","data2":"a"}'
}
fn test_none() {
obj := MyStruct{
code: 1
}
assert dump(json.encode(obj)) == '{"code":1,"message":""}'
}
@@ -0,0 +1,119 @@
import json
struct OmitEmptyStruct {
bug Struct @[omitempty]
}
type MyAlias = string
struct OmitEmptyAlias {
bug MyAlias @[omitempty]
}
struct Struct {
name string
}
struct OmitEmptyMap {
bug map[string]string @[omitempty]
}
struct OmitEmptyArray {
bug []string @[omitempty]
}
type MySum = int | string
struct OmitEmptySumType {
bug MySum @[omitempty]
}
struct FNumStruct {
f_num f64
}
struct OmitEmptyFNumStruct {
bug FNumStruct @[omitempty]
}
fn test_struct() {
test := OmitEmptyStruct{
bug: Struct{}
}
encoded := json.encode(test)
dump(encoded)
test2 := OmitEmptyStruct{
bug: Struct{
name: 'mybug'
}
}
encoded2 := json.encode(test2)
dump(encoded2)
}
fn test_fnum_struct() {
test := OmitEmptyFNumStruct{
bug: FNumStruct{}
}
encoded := json.encode(test)
dump(encoded)
test2 := OmitEmptyFNumStruct{
bug: FNumStruct{
f_num: 1.5
}
}
encoded2 := json.encode(test2)
dump(encoded2)
}
fn test_alias() {
test := OmitEmptyAlias{
bug: ''
}
encoded := json.encode(test)
dump(encoded)
test2 := OmitEmptyAlias{
bug: 'foo'
}
encoded2 := json.encode(test2)
dump(encoded2)
}
fn test_map() {
test := OmitEmptyMap{
bug: {}
}
encoded := json.encode(test)
dump(encoded)
test2 := OmitEmptyMap{
bug: {
'foo': 'bar'
}
}
encoded2 := json.encode(test2)
dump(encoded2)
}
fn test_sumtype() {
test := OmitEmptySumType{}
encoded := json.encode(test)
dump(encoded)
test2 := OmitEmptySumType{
bug: 1
}
encoded2 := json.encode(test2)
dump(encoded2)
}
fn test_array() {
test := OmitEmptyArray{
bug: []
}
encoded := json.encode(test)
dump(encoded)
test2 := OmitEmptyArray{
bug: ['1']
}
encoded2 := json.encode(test2)
dump(encoded2)
}
@@ -0,0 +1,41 @@
import json
struct Test {
optional_alias ?MyAlias // primitive
optional_struct ?MyAlias2 // complex
}
struct Complex {
a int = 3
}
type MyAlias = int
type MyAlias2 = Complex
fn test_empty() {
test := Test{}
encoded := json.encode(test)
assert dump(encoded) == '{}'
assert json.decode(Test, '{}')! == test
}
fn test_value() {
test := Test{
optional_alias: 1
}
encoded := json.encode(test)
assert dump(encoded) == '{"optional_alias":1}'
assert json.decode(Test, '{"optional_alias":1}')! == test
}
fn test_value_2() {
test := Test{
optional_alias: 1
optional_struct: Complex{
a: 1
}
}
encoded := json.encode(test)
assert dump(encoded) == '{"optional_alias":1,"optional_struct":{"a":1}}'
assert json.decode(Test, '{"optional_alias":1,"optional_struct":{"a":1}}')! == test
}
@@ -0,0 +1,46 @@
import json
struct Struct {
a int
}
struct Test {
a ?int
b ?string
c ?Struct
}
fn test_main() {
a := json.decode(Test, '{"a": 1, "b": "foo"}')!
dump(a)
assert a.a != none
assert a.b != none
b := json.decode(Test, '{"a": 1}')!
dump(b)
assert b.a != none
assert b.b == none
c := json.decode(Test, '{"a": 1, "b": null}')!
dump(b)
assert c.a != none
assert c.b == none
d := json.decode(Test, '{"a": null, "b": null}')!
dump(d)
assert d.a == none
assert d.b == none
e := json.decode(Test, '{"a": null, "b": null, "c": null}')!
dump(e)
assert e.a == none
assert e.b == none
assert e.c == none
f := json.decode(Test, '{"a": null, "b": null, "c": {"a":1}}')!
dump(f)
assert f.a == none
assert f.b == none
assert f.c != none
}
@@ -0,0 +1,62 @@
import json
pub struct Dto {
pub:
key string @[raw]
key2 string @[raw]
data ?string @[raw]
optional ?string @[raw]
}
fn test_main() {
raw_json := '{
"key": [1, 2, "test"],
"key2": { "test": 1 },
"data": { "test": 1 },
"optional": "test"
}'
dto := json.decode(Dto, raw_json)!
println(dto)
assert dto.data? == '{"test":1}'
}
fn test_none() {
raw_json := '{
"key": [1, 2, "test"],
"optional": "test"
}'
dto := json.decode(Dto, raw_json)!
println(dto)
assert dto.data == none
assert dto.optional? == '"test"'
}
fn test_null() {
raw_json := '{
"key": [1, 2, "test"],
"key2": null,
"data": null,
"optional": "test"
}'
dto := json.decode(Dto, raw_json)!
println(dto)
assert dto.key2 == 'null'
assert dto.data? == 'null'
}
fn test_not_set() {
raw_json := '{
}'
dto := json.decode(Dto, raw_json)!
println(dto)
assert dto.data == none
assert dto.optional == none
}
@@ -0,0 +1,23 @@
import json
pub struct SomeStruct {
pub mut:
test ?string
}
pub struct MyStruct {
pub mut:
result ?SomeStruct
id string
}
fn test_main() {
a := MyStruct{
id: 'some id'
result: SomeStruct{}
}
encoded_string := json.encode(a)
assert encoded_string == '{"result":{},"id":"some id"}'
test := json.decode(MyStruct, encoded_string)!
assert test == a
}
@@ -0,0 +1,68 @@
import json
pub struct MyStruct {
pub mut:
valuea int
}
pub struct MyStruct2 {
pub mut:
valuea int
valueb ?MyStruct
}
struct Node {
location NodeLocation @[json: 'loc']
}
struct NodeLocation {
source_file ?SourceFile @[json: 'includedFrom']
}
struct SourceFile {
path string @[json: 'file']
}
fn test_encode_decode() {
assert json.encode(MyStruct2{ valuea: 1 }) == '{"valuea":1}'
assert json.decode(MyStruct2, '{"valuea": 1}')! == MyStruct2{
valuea: 1
valueb: none
}
}
fn test_encode_decode2() {
assert json.encode(MyStruct2{ valuea: 1, valueb: none }) == '{"valuea":1}'
assert json.decode(MyStruct2, '{"valuea": 1}')! == MyStruct2{
valuea: 1
valueb: none
}
}
fn test_encode_decode3() {
assert json.encode(MyStruct2{
valuea: 1
valueb: MyStruct{
valuea: 123
}
}) == '{"valuea":1,"valueb":{"valuea":123}}'
assert json.decode(MyStruct2, '{"valuea": 1}')! == MyStruct2{
valuea: 1
valueb: none
}
}
fn test_main() {
node := json.decode(Node, '{"loc": { "includedFrom": { "file": "/bin/foo" } } }')!
source_file := node.location.source_file or {
SourceFile{
path: '-'
}
}
assert source_file.path == '/bin/foo'
}
@@ -0,0 +1,40 @@
module main
import json
struct MyStruct {
name string // should fail
age ?int
active bool
}
struct TestStructOne {
property_one string @[json: 'propertyOne']
property_two string @[json: 'propertyTwo']
}
fn test_main() {
mut errors := 0
json.decode(MyStruct, '{ "name": 1}') or {
errors++
assert err.msg() == "type mismatch for field 'name', expecting `string` type, got: 1"
}
json.decode(MyStruct, '{ "name": "John Doe", "age": ""}') or {
errors++
assert err.msg() == 'type mismatch for field \'age\', expecting `?int` type, got: ""'
}
json.decode(MyStruct, '{ "name": "John Doe", "age": 1, "active": ""}') or {
errors++
assert err.msg() == 'type mismatch for field \'active\', expecting `bool` type, got: ""'
}
res := json.decode(MyStruct, '{ "name": "John Doe", "age": "1"}') or { panic(err) }
assert errors == 3
assert res.name == 'John Doe'
}
fn test_decode_object_into_string_field() {
payload := '{"propertyOne":"property_two should stay a regular string {}","propertyTwo":{}}'
res := json.decode(TestStructOne, payload) or { panic(err) }
assert res.property_one == 'property_two should stay a regular string {}'
assert res.property_two == '{}'
}
+52
View File
@@ -0,0 +1,52 @@
import json
struct TestOptionalRawString {
id int
data ?string @[raw]
}
struct TestRawStringifiedObject {
metadata string @[raw]
}
fn test_raw_opt() {
test := TestOptionalRawString{
id: 1
data: 't
e
s
t'
}
encoded := json.encode(test)
assert json.decode(TestOptionalRawString, encoded)!.data? == r'"t\ne\ns\nt"'
}
fn test_raw_none() {
test := TestOptionalRawString{
id: 1
data: none
}
encoded := json.encode(test)
r := json.decode(TestOptionalRawString, encoded)!.data
assert r == none
}
fn test_raw_empty_string() {
test := TestOptionalRawString{
id: 1
data: ''
}
encoded := json.encode(test)
r := json.decode(TestOptionalRawString, encoded)!.data or { 'z' }
assert r == '""'
}
fn test_stringified_object_returns_error_for_raw_field() {
stringified_json :=
json.encode('{"metadata":{"topLevelProperty":{"nestedProperty1":"Value 1"}}}')
json.decode(TestRawStringifiedObject, stringified_json) or {
assert err.msg().starts_with('Json element is not an object:')
return
}
assert false
}
@@ -0,0 +1,46 @@
import json
pub struct MyStruct[T] {
pub mut:
result ?T
id string
}
fn test_gn_struct_string() ! {
a := MyStruct[string]{
result: 'test'
id: 'some id'
}
encoded_string := json.encode(a)
dump(encoded_string)
test := json.decode(MyStruct[string], encoded_string)!
dump(test)
assert a == test
}
fn test_gn_struct_int() ! {
a := MyStruct[int]{
result: 1
id: 'some id'
}
encoded_string := json.encode(a)
dump(encoded_string)
test := json.decode(MyStruct[int], encoded_string)!
dump(test)
assert a == test
}
fn test_gn_struct_f64() ! {
a := MyStruct[f64]{
result: 1.2
id: 'some id'
}
encoded_string := json.encode(a)
dump(encoded_string)
test := json.decode(MyStruct[f64], encoded_string)!
dump(test)
assert a == test
}
+127
View File
@@ -0,0 +1,127 @@
import json
type Prices = Price | []Price
pub struct ShopResponseData {
attributes Attributes
}
struct Attributes {
price ?Prices
}
struct Price {
net f64
}
type Animal = Cat | Dog
struct Cat {
cat_name string
}
struct Dog {
dog_name string
}
fn test_main() {
data := '{"attributes": {"price": [{"net": 1, "_type": "Price"}, {"net": 2, "_type": "Price"}]}}'
entity := json.decode(ShopResponseData, data) or { panic(err) }
assert entity == ShopResponseData{
attributes: Attributes{
price: Prices([Price{
net: 1
}, Price{
net: 2
}])
}
}
data2 := '{"attributes": {"price": {"net": 1, "_type": "Price"}}}'
entity2 := json.decode(ShopResponseData, data2) or { panic(err) }
assert entity2 == ShopResponseData{
attributes: Attributes{
price: Prices(Price{
net: 1
})
}
}
data3 := json.encode(ShopResponseData{
attributes: Attributes{
price: Prices([Price{
net: 1.2
}])
}
})
assert data3 == '{"attributes":{"price":[{"net":1.2,"_type":"Price"}]}}'
entity3 := json.decode(ShopResponseData, data3) or { panic(err) }
assert entity3 == ShopResponseData{
attributes: Attributes{
price: Prices([Price{
net: 1.2
}])
}
}
}
fn test_sum_types() {
data1 := json.encode(Animal(Dog{
dog_name: 'Caramelo'
}))
assert data1 == '{"dog_name":"Caramelo","_type":"Dog"}'
s := '{"_type":"Cat","cat_name":"Whiskers"}'
animal := json.decode(Animal, s) or {
println(err)
assert false
return
}
assert animal is Cat
if animal is Cat {
assert animal.cat_name == 'Whiskers'
} else {
assert false, 'Wrong sumtype decode. In this case animal is a Cat'
}
s2 := '[{"_type":"Cat","cat_name":"Whiskers"}, {"_type":"Dog","dog_name":"Goofie"}]'
animals := json.decode([]Animal, s2) or {
println(err)
assert false
return
}
assert animals.len == 2
assert animals[0] is Cat
assert animals[1] is Dog
cat := animals[0] as Cat
dog := animals[1] as Dog
assert cat.cat_name == 'Whiskers'
assert dog.dog_name == 'Goofie'
j := json.encode(animals[0])
assert j == '{"cat_name":"Whiskers","_type":"Cat"}'
}
type Value = string | i32
struct Node {
value Value
}
fn test_sum_types_with_i32() {
data1 := json.encode([Node{i32(128)}, Node{'mystring'}])
assert data1 == '[{"value":128},{"value":"mystring"}]'
node := json.decode([]Node, data1) or {
println(err)
assert false
return
}
assert node.len == 2
assert node[0].value == Value(i32(128))
assert node[1].value == Value('mystring')
}
+604
View File
@@ -0,0 +1,604 @@
import json
import time
enum JobTitle {
manager
executive
worker
}
struct Employee {
name string
age int
salary f32
title JobTitle
}
fn test_simple() {
x := Employee{'Peter', 28, 95000.5, .worker}
s := json.encode(x)
// eprintln('Employee x: ${s}')
assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":"worker"}'
y := json.decode(Employee, s)!
// eprintln('Employee y: ${y}')
assert y.name == 'Peter'
assert y.age == 28
assert y.salary == 95000.5
assert y.title == .worker
}
const currency_id = 'cconst'
struct Price {
net f64
currency_id string = currency_id @[json: currencyId]
}
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'
}]
}
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
}
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,
]
}
// eprintln('Game: ${game}')
enc := json.encode(game)
// eprintln('Encoded Game: ${enc}')
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()}}]}'
dec := json.decode(SomeGame, enc)!
// eprintln('Decoded Game: ${dec}')
assert game.title == dec.title
assert game.player == dec.player
assert (game.other[2] as Animal) == .cat
assert dec.other[2] == Entity('cat')
assert (game.other[4] as time.Time).unix() == (dec.other[4] as time.Time).unix()
}
fn bar[T](payload string) !Bar { // ?T doesn't work currently
result := json.decode(T, payload)!
return result
}
struct Bar {
x string
}
fn test_generic() {
result := bar[Bar]('{"x":"test"}') or { Bar{} }
assert result.x == 'test'
}
struct User2 {
age int
nums []int
reg_date time.Time
}
struct User {
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)!
// println(u2)
u := json.decode(User, s)!
// println(u)
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"}'
}
fn test_encode_decode_time() {
user := User2{
age: 25
reg_date: time.new(year: 2020, month: 12, day: 22, hour: 7, minute: 23)
}
s := json.encode(user)
// println(s)
assert s.contains('"reg_date":1608621780')
user2 := json.decode(User2, s)!
assert user2.reg_date.str() == '2020-12-22 07:23:00'
// println(user2)
// println(user2.reg_date)
}
fn test_decode_time_string_into_struct_field() {
user := json.decode(User2, '{"age": 25, "reg_date": "2001-01-01"}')!
assert user.reg_date.str() == '2001-01-01 00:00:00'
}
fn (mut u User) foo() string {
return json.encode(u)
}
fn test_encode_user() {
mut usr := User{
age: 10
nums: [1, 2, 3]
last_name: 'Johnson'
is_registered: true
typ: 0
pets: 'foo'
}
expected := '{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"foo"}'
out := json.encode(usr)
// println(out)
assert out == expected
// Test json.encode on mutable pointers
assert usr.foo() == expected
}
struct Color {
space string
point string @[raw]
}
fn test_raw_json_field() {
color := json.decode(Color, '{"space": "YCbCr", "point": {"Y": 123}}') or {
// println('text')
return
}
assert color.point == '{"Y":123}'
assert color.space == 'YCbCr'
}
fn test_bad_raw_json_field() {
color := json.decode(Color, '{"space": "YCbCr"}') or {
// println('text')
return
}
assert color.point == ''
assert color.space == 'YCbCr'
}
struct City {
name string
}
struct Country {
cities []City
name string
}
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'
// println(country.cities)
}
fn test_encode_map() {
expected := '{"one":1,"two":2,"three":3,"four":4}'
numbers := {
'one': 1
'two': 2
'three': 3
'four': 4
}
out := json.encode(numbers)
// println(out)
assert out == expected
assert json.encode_pretty(numbers) == '{
"one": 1,
"two": 2,
"three": 3,
"four": 4
}'
}
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}')!
// println(out)
assert out == expected
}
struct Data {
countries []Country
users map[string]User
extra map[string]map[string]int
}
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)
// println(out)
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
}
}
}
struct Foo[T] {
pub:
name string
data T
}
fn test_generic_struct() {
foo_int := Foo[int]{'bar', 12}
foo_enc := json.encode(foo_int)
assert foo_enc == '{"name":"bar","data":12}'
foo_dec := json.decode(Foo[int], foo_enc)!
assert foo_dec.name == 'bar'
assert foo_dec.data == 12
}
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 {
// println(err)
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 {
// println(err)
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
}
fn test_decode_alias_struct() {
msg := json.decode(Message, '{"id": "118499178790780929"}')!
// hacky way of comparing aliased strings
assert msg.id.str() == '118499178790780929'
assert msg.ij.str() == '0'
}
fn test_encode_alias_struct() {
expected := '{"id":"118499178790780929","ij":999998888}'
msg := Message{'118499178790780929', 999998888}
out := json.encode(msg)
assert out == expected
}
struct List {
id int
items []string
}
fn test_list() {
list := json.decode(List, '{"id": 1, "items": ["1", "2"]}')!
assert list.id == 1
assert list.items == ['1', '2']
}
fn test_list_no_id() {
list := json.decode(List, '{"items": ["1", "2"]}')!
assert list.id == 0
assert list.items == ['1', '2']
}
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
}
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}' == '{}'
}
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 Foo2 {
name string
}
fn test_pretty() {
foo := Foo2{'Bob'}
assert json.encode_pretty(foo) == '{
"name": "Bob"
}'
}
struct Foo3 {
name string
age int @[omitempty]
}
fn test_omit_empty() {
foo := Foo3{'Bob', 0}
assert json.encode_pretty(foo) == '{
"name": "Bob"
}'
// println('omitempty:')
// println(json.encode_pretty(foo))
}
fn test_encode_struct_expression() {
assert json.encode(Foo2{'Foo'}) == '{"name":"Foo"}'
assert json.encode_pretty(Foo2{'Bar'}) == '{
"name": "Bar"
}'
}
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)
}
fn test_encode_sumtype_defined_ahead() {
ret := create_game_packet(&GamePacketData(GPScale{}))
// println(ret)
assert ret == '{"value":0,"_type":"GPScale"}'
}
struct StByteArray {
ba []u8
}
fn test_byte_array() {
assert json.encode(StByteArray{ ba: [u8(1), 2, 3, 4, 5] }) == '{"ba":[1,2,3,4,5]}'
}
struct Aa {
sub AliasType
}
struct Bb {
a int
}
type AliasType = Bb
fn test_encode_alias_field() {
s := json.encode(Aa{
sub: Bb{
a: 1
}
})
assert s == '{"sub":{"a":1}}'
}
struct APrice {}
struct Association {
association &Association = unsafe { nil }
price APrice
}
fn test_encoding_struct_with_pointers() {
value := Association{
association: &Association{
price: APrice{}
}
price: APrice{}
}
assert json.encode(value) == '{"association":{"price":{}},"price":{}}'
}
struct ChildNullish {
name string
}
struct NullishStruct {
name string
lastname string
age int
salary f32
child ChildNullish
}
struct RequiredStruct {
name string @[required]
lastname string
}
fn test_required() {
nullish_one := json.decode(NullishStruct,
'{"name":"Peter", "lastname":null, "age":28,"salary":95000.5,"title":"worker"}')!
assert nullish_one.name == 'Peter'
assert nullish_one.lastname == ''
assert nullish_one.age == 28
assert nullish_one.salary == 95000.5
assert nullish_one.child.name == ''
nullish_two := json.decode(NullishStruct,
'{"name":"Peter", "lastname": "Parker", "age":28,"salary":95000.5,"title":"worker"}')!
assert nullish_two.name == 'Peter'
assert nullish_two.lastname == 'Parker'
assert nullish_two.age == 28
assert nullish_two.salary == 95000.5
assert nullish_two.child.name == ''
nullish_third := json.decode(NullishStruct,
'{"name":"Peter", "age":28,"salary":95000.5,"title":"worker", "child": {"name":"Nullish"}}')!
assert nullish_third.name == 'Peter'
assert nullish_third.lastname == ''
assert nullish_third.age == 28
assert nullish_third.salary == 95000.5
assert nullish_third.child.name == 'Nullish'
required_struct := json.decode(RequiredStruct, '{"name":"Peter", "lastname": "Parker"}')!
assert required_struct.name == 'Peter'
assert required_struct.lastname == 'Parker'
required_struct_err := json.decode(RequiredStruct, '{"name": null, "lastname": "Parker"}') or {
assert err.msg() == "type mismatch for field 'name', expecting `string` type, got: null"
RequiredStruct{
name: 'Peter'
lastname: 'Parker'
}
}
}