mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
builtin, cgen: support FieldData.unaliased_typ, use it for generalising x.json2
(able to encode type aliased struct fields) (#16469)
This commit is contained in:
parent
06764bc559
commit
45854882b9
16 changed files with 981 additions and 317 deletions
|
@ -110,12 +110,13 @@ pub:
|
||||||
// FieldData holds information about a field. Fields reside on structs.
|
// FieldData holds information about a field. Fields reside on structs.
|
||||||
pub struct FieldData {
|
pub struct FieldData {
|
||||||
pub:
|
pub:
|
||||||
name string
|
name string
|
||||||
attrs []string
|
attrs []string
|
||||||
is_pub bool
|
is_pub bool
|
||||||
is_mut bool
|
is_mut bool
|
||||||
is_shared bool
|
is_shared bool
|
||||||
typ int
|
typ int
|
||||||
|
unaliased_typ int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum AttributeKind {
|
pub enum AttributeKind {
|
||||||
|
|
|
@ -371,20 +371,23 @@ fn test_errors() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ID = string
|
type ID = string
|
||||||
|
type GG = int
|
||||||
|
|
||||||
struct Message {
|
struct Message {
|
||||||
id ID
|
id ID
|
||||||
|
ij GG
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_decode_alias_struct() {
|
fn test_decode_alias_struct() {
|
||||||
msg := json.decode(Message, '{"id": "118499178790780929"}')!
|
msg := json.decode(Message, '{"id": "118499178790780929"}')!
|
||||||
// hacky way of comparing aliased strings
|
// hacky way of comparing aliased strings
|
||||||
assert msg.id.str() == '118499178790780929'
|
assert msg.id.str() == '118499178790780929'
|
||||||
|
assert msg.ij.str() == '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encode_alias_struct() {
|
fn test_encode_alias_struct() {
|
||||||
expected := '{"id":"118499178790780929"}'
|
expected := '{"id":"118499178790780929","ij":999998888}'
|
||||||
msg := Message{'118499178790780929'}
|
msg := Message{'118499178790780929', 999998888}
|
||||||
out := json.encode(msg)
|
out := json.encode(msg)
|
||||||
assert out == expected
|
assert out == expected
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,6 +312,7 @@ pub mut:
|
||||||
default_expr_typ Type
|
default_expr_typ Type
|
||||||
name string
|
name string
|
||||||
typ Type
|
typ Type
|
||||||
|
unaliased_typ Type
|
||||||
anon_struct_decl StructDecl // only if the field is an anonymous struct
|
anon_struct_decl StructDecl // only if the field is an anonymous struct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -575,7 +575,10 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
||||||
// field_sym := g.table.sym(field.typ)
|
// field_sym := g.table.sym(field.typ)
|
||||||
// g.writeln('\t${node.val_var}.typ = _SLIT("$field_sym.name");')
|
// g.writeln('\t${node.val_var}.typ = _SLIT("$field_sym.name");')
|
||||||
styp := field.typ
|
styp := field.typ
|
||||||
|
unaliased_styp := g.table.unaliased_type(styp)
|
||||||
|
|
||||||
g.writeln('\t${node.val_var}.typ = ${styp.idx()};')
|
g.writeln('\t${node.val_var}.typ = ${styp.idx()};')
|
||||||
|
g.writeln('\t${node.val_var}.unaliased_typ = ${unaliased_styp.idx()};')
|
||||||
g.writeln('\t${node.val_var}.is_pub = ${field.is_pub};')
|
g.writeln('\t${node.val_var}.is_pub = ${field.is_pub};')
|
||||||
g.writeln('\t${node.val_var}.is_mut = ${field.is_mut};')
|
g.writeln('\t${node.val_var}.is_mut = ${field.is_mut};')
|
||||||
g.writeln('\t${node.val_var}.is_shared = ${field.typ.has_flag(.shared_f)};')
|
g.writeln('\t${node.val_var}.is_shared = ${field.typ.has_flag(.shared_f)};')
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import x.json2
|
import x.json2 as json
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sample_data = {
|
sample_data = {
|
||||||
'int': json2.Any(int(1))
|
'int': json.Any(int(1))
|
||||||
'i64': json2.Any(i64(128))
|
'i64': json.Any(i64(128))
|
||||||
'f32': json2.Any(f32(2.0))
|
'f32': json.Any(f32(2.0))
|
||||||
'f64': json2.Any(f64(1.283))
|
'f64': json.Any(f64(1.283))
|
||||||
'bool': json2.Any(false)
|
'bool': json.Any(false)
|
||||||
'str': json2.Any('test')
|
'str': json.Any('test')
|
||||||
'null': json2.Any(json2.null)
|
'null': json.Any(json.null)
|
||||||
'arr': json2.Any([json2.Any('lol')])
|
'arr': json.Any([json.Any('lol')])
|
||||||
'obj': json2.Any({
|
'obj': json.Any({
|
||||||
'foo': json2.Any(10)
|
'foo': json.Any(10)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
fn is_null(f json2.Any) bool {
|
fn is_null(f json.Any) bool {
|
||||||
match f {
|
match f {
|
||||||
json2.Null { return true }
|
json.Null { return true }
|
||||||
else { return false }
|
else { return false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,9 +57,9 @@ fn test_int() {
|
||||||
assert sample_data['i64'] or { 0 }.int() == 128
|
assert sample_data['i64'] or { 0 }.int() == 128
|
||||||
assert sample_data['f32'] or { 0 }.int() == 2
|
assert sample_data['f32'] or { 0 }.int() == 2
|
||||||
assert sample_data['f64'] or { 0 }.int() == 1
|
assert sample_data['f64'] or { 0 }.int() == 1
|
||||||
assert json2.Any(true).int() == 1
|
assert json.Any(true).int() == 1
|
||||||
// invalid conversions
|
// invalid conversions
|
||||||
assert json2.Any('123').int() == 0
|
assert json.Any('123').int() == 0
|
||||||
assert sample_data['null'] or { 0 }.int() == 0
|
assert sample_data['null'] or { 0 }.int() == 0
|
||||||
assert sample_data['arr'] or { 0 }.int() == 0
|
assert sample_data['arr'] or { 0 }.int() == 0
|
||||||
assert sample_data['obj'] or { 0 }.int() == 0
|
assert sample_data['obj'] or { 0 }.int() == 0
|
||||||
|
@ -71,9 +71,9 @@ fn test_i64() {
|
||||||
assert sample_data['i64'] or { 0 }.i64() == 128
|
assert sample_data['i64'] or { 0 }.i64() == 128
|
||||||
assert sample_data['f32'] or { 0 }.i64() == 2
|
assert sample_data['f32'] or { 0 }.i64() == 2
|
||||||
assert sample_data['f64'] or { 0 }.i64() == 1
|
assert sample_data['f64'] or { 0 }.i64() == 1
|
||||||
assert json2.Any(true).i64() == 1
|
assert json.Any(true).i64() == 1
|
||||||
// invalid conversions
|
// invalid conversions
|
||||||
assert json2.Any('123').i64() == 0
|
assert json.Any('123').i64() == 0
|
||||||
assert sample_data['null'] or { 0 }.i64() == 0
|
assert sample_data['null'] or { 0 }.i64() == 0
|
||||||
assert sample_data['arr'] or { 0 }.i64() == 0
|
assert sample_data['arr'] or { 0 }.i64() == 0
|
||||||
assert sample_data['obj'] or { 0 }.i64() == 0
|
assert sample_data['obj'] or { 0 }.i64() == 0
|
||||||
|
@ -106,7 +106,7 @@ fn test_arr() {
|
||||||
fn test_bool() {
|
fn test_bool() {
|
||||||
// valid conversions
|
// valid conversions
|
||||||
assert sample_data['bool'] or { 0 }.bool() == false
|
assert sample_data['bool'] or { 0 }.bool() == false
|
||||||
assert json2.Any('true').bool() == true
|
assert json.Any('true').bool() == true
|
||||||
// invalid conversions
|
// invalid conversions
|
||||||
assert sample_data['int'] or { 0 }.bool() == true
|
assert sample_data['int'] or { 0 }.bool() == true
|
||||||
assert sample_data['i64'] or { 0 }.bool() == true
|
assert sample_data['i64'] or { 0 }.bool() == true
|
||||||
|
|
|
@ -155,6 +155,7 @@ fn (e &Encoder) encode_value_with_level<T>(val T, level int, mut wr io.Writer) !
|
||||||
} $else $if T is $Enum {
|
} $else $if T is $Enum {
|
||||||
e.encode_any(Any(int(val)), level, mut wr)!
|
e.encode_any(Any(int(val)), level, mut wr)!
|
||||||
} $else {
|
} $else {
|
||||||
|
// dump(val.str())
|
||||||
return error('cannot encode value with ${typeof(val).name} type')
|
return error('cannot encode value with ${typeof(val).name} type')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,8 +185,33 @@ fn (e &Encoder) encode_struct<U>(val U, level int, mut wr io.Writer) ! {
|
||||||
if e.newline != 0 {
|
if e.newline != 0 {
|
||||||
wr.write(json2.space_bytes)!
|
wr.write(json2.space_bytes)!
|
||||||
}
|
}
|
||||||
field_value := val.$(field.name)
|
if typeof(val.$(field.name)).name.contains('?') {
|
||||||
e.encode_value_with_level(field_value, level + 1, mut wr)!
|
if field.typ == 20 {
|
||||||
|
if val.$(field.name).str() == 'Option(error: none)' {
|
||||||
|
// TODO?
|
||||||
|
} else {
|
||||||
|
e.encode_string(val.$(field.name).str().replace("Option('", '').trim_string_right("')"), mut
|
||||||
|
wr)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match field.unaliased_typ {
|
||||||
|
string_type_idx {
|
||||||
|
e.encode_string(val.$(field.name).str(), mut wr)!
|
||||||
|
}
|
||||||
|
int_type_idx {
|
||||||
|
wr.write(val.$(field.name).str().bytes())!
|
||||||
|
}
|
||||||
|
byte_array_type_idx {
|
||||||
|
//! array
|
||||||
|
e.encode_array(val.$(field.name), level, mut wr)!
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
field_value := val.$(field.name)
|
||||||
|
e.encode_value_with_level(field_value, level + 1, mut wr)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if i < fields_len - 1 {
|
if i < fields_len - 1 {
|
||||||
wr.write(json2.comma_bytes)!
|
wr.write(json2.comma_bytes)!
|
||||||
}
|
}
|
||||||
|
@ -200,7 +226,7 @@ fn (e &Encoder) encode_array<U>(val U, level int, mut wr io.Writer) ! {
|
||||||
wr.write([u8(`[`)])!
|
wr.write([u8(`[`)])!
|
||||||
for i in 0 .. val.len {
|
for i in 0 .. val.len {
|
||||||
e.encode_newline(level, mut wr)!
|
e.encode_newline(level, mut wr)!
|
||||||
e.encode_value_with_level(&val[i], level + 1, mut wr)!
|
e.encode_value_with_level(val[i], level + 1, mut wr)!
|
||||||
if i < val.len - 1 {
|
if i < val.len - 1 {
|
||||||
wr.write(json2.comma_bytes)!
|
wr.write(json2.comma_bytes)!
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,50 @@
|
||||||
import x.json2
|
import x.json2 as json
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
fn test_json_string_characters() {
|
fn test_json_string_characters() {
|
||||||
text := json2.raw_decode(r'"\n\r\b\f\t\\\"\/"') or { '' }
|
text := json.raw_decode(r'"\n\r\b\f\t\\\"\/"') or { '' }
|
||||||
assert text.json_str() == '"\\n\\r\\b\\f\\t\\\\\\"\\/"'
|
assert text.json_str() == '"\\n\\r\\b\\f\\t\\\\\\"\\/"'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_json_escape_low_chars() {
|
fn test_json_escape_low_chars() {
|
||||||
esc := '\u001b'
|
esc := '\u001b'
|
||||||
assert esc.len == 1
|
assert esc.len == 1
|
||||||
text := json2.Any(esc)
|
text := json.Any(esc)
|
||||||
assert text.json_str() == r'"\u001b"'
|
assert text.json_str() == r'"\u001b"'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_json_string() {
|
fn test_json_string() {
|
||||||
text := json2.Any('te✔st')
|
text := json.Any('te✔st')
|
||||||
assert text.json_str() == r'"te\u2714st"'
|
assert text.json_str() == r'"te\u2714st"'
|
||||||
boolean := json2.Any(true)
|
boolean := json.Any(true)
|
||||||
assert boolean.json_str() == 'true'
|
assert boolean.json_str() == 'true'
|
||||||
integer := json2.Any(int(-5))
|
integer := json.Any(int(-5))
|
||||||
assert integer.json_str() == '-5'
|
assert integer.json_str() == '-5'
|
||||||
u64integer := json2.Any(u64(5000))
|
u64integer := json.Any(u64(5000))
|
||||||
assert u64integer.json_str() == '5000'
|
assert u64integer.json_str() == '5000'
|
||||||
i64integer := json2.Any(i64(-17))
|
i64integer := json.Any(i64(-17))
|
||||||
assert i64integer.json_str() == '-17'
|
assert i64integer.json_str() == '-17'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_json_string_emoji() {
|
fn test_json_string_emoji() {
|
||||||
text := json2.Any('🐈')
|
text := json.Any('🐈')
|
||||||
assert text.json_str() == r'" "'
|
assert text.json_str() == r'" "'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_json_string_non_ascii() {
|
fn test_json_string_non_ascii() {
|
||||||
text := json2.Any('ひらがな')
|
text := json.Any('ひらがな')
|
||||||
assert text.json_str() == r'"\u3072\u3089\u304c\u306a"'
|
assert text.json_str() == r'"\u3072\u3089\u304c\u306a"'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_utf8_strings_are_not_modified() {
|
fn test_utf8_strings_are_not_modified() {
|
||||||
original := '{"s":"Schilddrüsenerkrankungen"}'
|
original := '{"s":"Schilddrüsenerkrankungen"}'
|
||||||
deresult := json2.raw_decode(original)!
|
deresult := json.raw_decode(original)!
|
||||||
assert deresult.str() == original
|
assert deresult.str() == original
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encoder_unescaped_utf32() ! {
|
fn test_encoder_unescaped_utf32() ! {
|
||||||
jap_text := json2.Any('ひらがな')
|
jap_text := json.Any('ひらがな')
|
||||||
enc := json2.Encoder{
|
enc := json.Encoder{
|
||||||
escape_unicode: false
|
escape_unicode: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,20 +57,20 @@ fn test_encoder_unescaped_utf32() ! {
|
||||||
assert sb.str() == '"${jap_text}"'
|
assert sb.str() == '"${jap_text}"'
|
||||||
sb.go_back_to(0)
|
sb.go_back_to(0)
|
||||||
|
|
||||||
emoji_text := json2.Any('🐈')
|
emoji_text := json.Any('🐈')
|
||||||
enc.encode_value(emoji_text, mut sb)!
|
enc.encode_value(emoji_text, mut sb)!
|
||||||
assert sb.str() == '"${emoji_text}"'
|
assert sb.str() == '"${emoji_text}"'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encoder_prettify() {
|
fn test_encoder_prettify() {
|
||||||
obj := {
|
obj := {
|
||||||
'hello': json2.Any('world')
|
'hello': json.Any('world')
|
||||||
'arr': [json2.Any('im a string'), [json2.Any('3rd level')]]
|
'arr': [json.Any('im a string'), [json.Any('3rd level')]]
|
||||||
'obj': {
|
'obj': {
|
||||||
'map': json2.Any('map inside a map')
|
'map': json.Any('map inside a map')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enc := json2.Encoder{
|
enc := json.Encoder{
|
||||||
newline: `\n`
|
newline: `\n`
|
||||||
newline_spaces_count: 2
|
newline_spaces_count: 2
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ pub struct Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encode_struct() {
|
fn test_encode_struct() {
|
||||||
enc := json2.encode(Test{'hello!'})
|
enc := json.encode(Test{'hello!'})
|
||||||
assert enc == '{"val":"hello!"}'
|
assert enc == '{"val":"hello!"}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,14 +112,14 @@ pub fn (u Uri) json_str() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encode_encodable() {
|
fn test_encode_encodable() {
|
||||||
assert json2.encode(Uri{'file', 'path/to/file'}) == '"file://path/to/file"'
|
assert json.encode(Uri{'file', 'path/to/file'}) == '"file://path/to/file"'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encode_array() {
|
fn test_encode_array() {
|
||||||
assert json2.encode([1, 2, 3]) == '[1,2,3]'
|
assert json.encode([1, 2, 3]) == '[1,2,3]'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encode_simple() {
|
fn test_encode_simple() {
|
||||||
assert json2.encode('hello!') == '"hello!"'
|
assert json.encode('hello!') == '"hello!"'
|
||||||
assert json2.encode(1) == '1'
|
assert json.encode(1) == '1'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import x.json2
|
import x.json2 as json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
enum JobTitle {
|
enum JobTitle {
|
||||||
|
@ -15,12 +15,21 @@ pub mut:
|
||||||
title JobTitle
|
title JobTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EmployeeOp {
|
||||||
|
pub mut:
|
||||||
|
name ?string = none
|
||||||
|
last_name ?string = none
|
||||||
|
age ?int
|
||||||
|
salary f32
|
||||||
|
title JobTitle
|
||||||
|
}
|
||||||
|
|
||||||
fn (e Employee) to_json() string {
|
fn (e Employee) to_json() string {
|
||||||
mut mp := map[string]json2.Any{}
|
mut mp := map[string]json.Any{}
|
||||||
mp['name'] = json2.Any(e.name)
|
mp['name'] = json.Any(e.name)
|
||||||
mp['age'] = json2.Any(e.age)
|
mp['age'] = json.Any(e.age)
|
||||||
mp['salary'] = json2.Any(e.salary)
|
mp['salary'] = json.Any(e.salary)
|
||||||
mp['title'] = json2.Any(int(e.title))
|
mp['title'] = json.Any(int(e.title))
|
||||||
/*
|
/*
|
||||||
$for field in Employee.fields {
|
$for field in Employee.fields {
|
||||||
d := e.$(field.name)
|
d := e.$(field.name)
|
||||||
|
@ -35,34 +44,38 @@ fn (e Employee) to_json() string {
|
||||||
return mp.str()
|
return mp.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut e Employee) from_json(any json2.Any) {
|
fn (mut e Employee) from_json(any json.Any) {
|
||||||
mp := any.as_map()
|
mp := any.as_map()
|
||||||
e.name = mp['name'] or { json2.Any('') }.str()
|
e.name = mp['name'] or { json.Any('') }.str()
|
||||||
e.age = mp['age'] or { json2.Any(0) }.int()
|
e.age = mp['age'] or { json.Any(0) }.int()
|
||||||
e.salary = mp['salary'] or { json2.Any(0) }.f32()
|
e.salary = mp['salary'] or { json.Any(0) }.f32()
|
||||||
e.title = unsafe { JobTitle(mp['title'] or { json2.Any(0) }.int()) }
|
e.title = unsafe { JobTitle(mp['title'] or { json.Any(0) }.int()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_simple() {
|
// ! BUGFIX
|
||||||
x := Employee{'Peter', 28, 95000.5, .worker}
|
// fn test_simplegg() {
|
||||||
s := json2.encode<Employee>(x)
|
// // x := EmployeeOp{'Peter', 28, 95000.5, .worker}
|
||||||
assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2}'
|
// x := EmployeeOp{
|
||||||
y := json2.decode<Employee>(s) or {
|
// name: 'vshfvhsd'
|
||||||
println(err)
|
// }
|
||||||
assert false
|
// s := json.encode<EmployeeOp>(x)
|
||||||
return
|
// assert s == '{"name":"vshfvhsd","age":0,"salary":0.0,"title":0.0}'
|
||||||
}
|
// // y := json.decode<EmployeeOp>(s) or {
|
||||||
assert y.name == 'Peter'
|
// // println(err)
|
||||||
assert y.age == 28
|
// // assert false
|
||||||
assert y.salary == 95000.5
|
// // return
|
||||||
assert y.title == .worker
|
// // }
|
||||||
}
|
// // assert y.name == 'Peter'
|
||||||
|
// // assert y.age == 28
|
||||||
|
// // assert y.salary == 95000.5
|
||||||
|
// // assert y.title == .worker
|
||||||
|
// }
|
||||||
|
|
||||||
fn test_fast_raw_decode() {
|
fn test_fast_raw_decode() {
|
||||||
s := '{"name":"Peter","age":28,"salary":95000.5,"title":2}'
|
s := '{"name":"Peter","age":28,"salary":95000.5,"title":2}'
|
||||||
o := json2.fast_raw_decode(s) or {
|
o := json.fast_raw_decode(s) or {
|
||||||
assert false
|
assert false
|
||||||
json2.Any(json2.null)
|
json.Any(json.null)
|
||||||
}
|
}
|
||||||
str := o.str()
|
str := o.str()
|
||||||
assert str == '{"name":"Peter","age":"28","salary":"95000.5","title":"2"}'
|
assert str == '{"name":"Peter","age":"28","salary":"95000.5","title":"2"}'
|
||||||
|
@ -76,7 +89,7 @@ fn test_character_unescape() {
|
||||||
"quotes": "\"quotes\"",
|
"quotes": "\"quotes\"",
|
||||||
"slash":"\/dev\/null"
|
"slash":"\/dev\/null"
|
||||||
}'
|
}'
|
||||||
mut obj := json2.raw_decode(message) or {
|
mut obj := json.raw_decode(message) or {
|
||||||
println(err)
|
println(err)
|
||||||
assert false
|
assert false
|
||||||
return
|
return
|
||||||
|
@ -89,7 +102,7 @@ fn test_character_unescape() {
|
||||||
assert lines['slash'] or { 0 }.str() == '/dev/null'
|
assert lines['slash'] or { 0 }.str() == '/dev/null'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut u User2) from_json(an json2.Any) {
|
fn (mut u User2) from_json(an json.Any) {
|
||||||
mp := an.as_map()
|
mp := an.as_map()
|
||||||
mut js_field_name := ''
|
mut js_field_name := ''
|
||||||
$for field in User.fields {
|
$for field in User.fields {
|
||||||
|
@ -109,13 +122,12 @@ fn (mut u User2) from_json(an json2.Any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct User2 {
|
struct User2 {
|
||||||
mut:
|
pub mut:
|
||||||
age int
|
age int
|
||||||
nums []int
|
nums []int
|
||||||
reg_date time.Time
|
reg_date time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// User struct needs to be `pub mut` for now in order to access and manipulate values
|
|
||||||
struct User {
|
struct User {
|
||||||
pub mut:
|
pub mut:
|
||||||
age int
|
age int
|
||||||
|
@ -126,7 +138,7 @@ pub mut:
|
||||||
pets string [json: 'pet_animals'; raw]
|
pets string [json: 'pet_animals'; raw]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut u User) from_json(an json2.Any) {
|
fn (mut u User) from_json(an json.Any) {
|
||||||
mp := an.as_map()
|
mp := an.as_map()
|
||||||
mut js_field_name := ''
|
mut js_field_name := ''
|
||||||
$for field in User.fields {
|
$for field in User.fields {
|
||||||
|
@ -153,72 +165,23 @@ fn (mut u User) from_json(an json2.Any) {
|
||||||
fn (u User) to_json() string {
|
fn (u User) to_json() string {
|
||||||
// TODO: derive from field
|
// TODO: derive from field
|
||||||
mut mp := {
|
mut mp := {
|
||||||
'age': json2.Any(u.age)
|
'age': json.Any(u.age)
|
||||||
}
|
}
|
||||||
mp['nums'] = u.nums.map(json2.Any(it))
|
mp['nums'] = u.nums.map(json.Any(it))
|
||||||
mp['lastName'] = json2.Any(u.last_name)
|
mp['lastName'] = json.Any(u.last_name)
|
||||||
mp['IsRegistered'] = json2.Any(u.is_registered)
|
mp['IsRegistered'] = json.Any(u.is_registered)
|
||||||
mp['type'] = json2.Any(u.typ)
|
mp['type'] = json.Any(u.typ)
|
||||||
mp['pet_animals'] = json2.Any(u.pets)
|
mp['pet_animals'] = json.Any(u.pets)
|
||||||
return mp.str()
|
return mp.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_parse_user() {
|
|
||||||
s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}'
|
|
||||||
u2 := json2.decode<User2>(s)!
|
|
||||||
u := json2.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"}'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 := json2.encode(user)
|
|
||||||
// // println(s) //{"age":25,"nums":[],"reg_date":{"year":2020,"month":12,"day":22,"hour":7,"minute":23,"second":0,"microsecond":0,"unix":1608621780,"is_local":false}}
|
|
||||||
// assert s.contains('"reg_date":1608621780')
|
|
||||||
// user2 := json2.decode<User2>(s)!
|
|
||||||
// assert user2.reg_date.str() == '2020-12-22 07:23:00'
|
|
||||||
// // println(user2)
|
|
||||||
// // println(user2.reg_date)
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn (mut u User) foo() string {
|
|
||||||
return json2.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 := json2.encode<User>(usr)
|
|
||||||
assert out == expected
|
|
||||||
// Test json.encode on mutable pointers
|
|
||||||
assert usr.foo() == expected
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
pub mut:
|
pub mut:
|
||||||
space string
|
space string
|
||||||
point string [raw]
|
point string [raw]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Color) from_json(an json2.Any) {
|
fn (mut c Color) from_json(an json.Any) {
|
||||||
mp := an.as_map()
|
mp := an.as_map()
|
||||||
$for field in Color.fields {
|
$for field in Color.fields {
|
||||||
match field.name {
|
match field.name {
|
||||||
|
@ -228,180 +191,3 @@ fn (mut c Color) from_json(an json2.Any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_raw_json_field() {
|
|
||||||
color := json2.decode<Color>('{"space": "YCbCr", "point": {"Y": 123}}') or {
|
|
||||||
assert false
|
|
||||||
Color{}
|
|
||||||
}
|
|
||||||
assert color.point == '{"Y":123}'
|
|
||||||
assert color.space == 'YCbCr'
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct City {
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Country {
|
|
||||||
cities []City
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
fn test_struct_in_struct() {
|
|
||||||
country := json2.decode<Country>('{ "name": "UK", "cities": [{"name":"London"}, {"name":"Manchester"}]}') or {
|
|
||||||
assert false
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
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': json2.Any(1)
|
|
||||||
'two': json2.Any(2)
|
|
||||||
'three': json2.Any(3)
|
|
||||||
'four': json2.Any(4)
|
|
||||||
}
|
|
||||||
out := numbers.str()
|
|
||||||
assert out == expected
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
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}') or {
|
|
||||||
assert false
|
|
||||||
r := {
|
|
||||||
'': 0
|
|
||||||
}
|
|
||||||
r
|
|
||||||
}
|
|
||||||
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) or {
|
|
||||||
assert false
|
|
||||||
Data{}
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.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.starts_with('Json element is not an object:')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
assert false
|
|
||||||
}
|
|
||||||
invalid_array()
|
|
||||||
invalid_object()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
import x.json2 as 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
|
||||||
|
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 == []
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
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().len < 2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_decode_error_message_should_have_enough_context_just_brace() {
|
||||||
|
json.decode<DbConfig>('{') or {
|
||||||
|
assert err.msg() == '{'
|
||||||
|
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() == ' "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() == 'ost", "dbname": "alex" "user":'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert false
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import x.json2 as 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,24 @@
|
||||||
|
import x.json2 as json
|
||||||
|
|
||||||
|
struct Result<T> {
|
||||||
|
ok bool
|
||||||
|
result T
|
||||||
|
}
|
||||||
|
|
||||||
|
struct User {
|
||||||
|
id int
|
||||||
|
username string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func<T>() !T {
|
||||||
|
text := '{"ok": true, "result":{"id":37467243, "username": "ciao"}}'
|
||||||
|
a := json.decode<Result<T>>(text)!
|
||||||
|
return a.result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_decode_with_generic_struct() {
|
||||||
|
ret := func<User>()!
|
||||||
|
println(ret)
|
||||||
|
assert ret.id == 37467243
|
||||||
|
assert ret.username == 'ciao'
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import x.json2 as json
|
||||||
|
import os
|
||||||
|
|
||||||
|
struct DbConfig {}
|
||||||
|
|
||||||
|
fn test_json_decode_with_optional_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,21 @@
|
||||||
|
import x.json2 as json
|
||||||
|
|
||||||
|
type Test = []bool | []int | []string | string
|
||||||
|
|
||||||
|
struct Some {
|
||||||
|
t Test
|
||||||
|
}
|
||||||
|
|
||||||
|
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])
|
||||||
|
}
|
149
vlib/x/json2/json_module_compatibility_test/json_test.v
Normal file
149
vlib/x/json2/json_module_compatibility_test/json_test.v
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
import x.json2 as json
|
||||||
|
import time
|
||||||
|
|
||||||
|
enum JobTitle {
|
||||||
|
manager
|
||||||
|
executive
|
||||||
|
worker
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Employee {
|
||||||
|
pub mut:
|
||||||
|
name string
|
||||||
|
age int
|
||||||
|
salary f32
|
||||||
|
title JobTitle
|
||||||
|
sub_employee SubEmployee
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SubEmployee {
|
||||||
|
pub mut:
|
||||||
|
name string
|
||||||
|
age int
|
||||||
|
salary f32
|
||||||
|
title JobTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_simple() {
|
||||||
|
sub_employee := SubEmployee{
|
||||||
|
name: 'João'
|
||||||
|
}
|
||||||
|
x := Employee{'Peter', 28, 95000.5, .worker, sub_employee}
|
||||||
|
s := json.encode<Employee>(x)
|
||||||
|
assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2,"sub_employee":{"name":"João","age":0,"salary":0.0,"title":0}}'
|
||||||
|
// y := json.decode<Employee>(s) or {
|
||||||
|
// println(err)
|
||||||
|
// assert false
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// assert y.name == 'Peter'
|
||||||
|
// assert y.age == 28
|
||||||
|
// assert y.salary == 95000.5
|
||||||
|
// assert y.title == .worker
|
||||||
|
// x := Employee{'Peter', 28, 95000.5, .worker}
|
||||||
|
// s := json.encode<Employee>(x)
|
||||||
|
// assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2}'
|
||||||
|
// // y := json.decode<Employee>(s) or {
|
||||||
|
// // println(err)
|
||||||
|
// // assert false
|
||||||
|
// // return
|
||||||
|
// // }
|
||||||
|
// // 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 [json: currencyId] = currency_id
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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 (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<User>(usr)
|
||||||
|
// println(out)
|
||||||
|
assert out == expected
|
||||||
|
// Test json.encode on mutable pointers
|
||||||
|
assert usr.foo() == expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct Color {
|
||||||
|
// pub mut:
|
||||||
|
// space string
|
||||||
|
// point string [raw]
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn test_encode_map() {
|
||||||
|
expected := '{"one":1,"two":2,"three":3,"four":4}'
|
||||||
|
numbers := {
|
||||||
|
'one': json.Any(1)
|
||||||
|
'two': json.Any(2)
|
||||||
|
'three': json.Any(3)
|
||||||
|
'four': json.Any(4)
|
||||||
|
}
|
||||||
|
// numbers := {
|
||||||
|
// 'one': 1
|
||||||
|
// 'two': 2
|
||||||
|
// 'three': 3
|
||||||
|
// 'four': 4
|
||||||
|
// }
|
||||||
|
// out := json.encode(numbers)
|
||||||
|
out := numbers.str()
|
||||||
|
assert out == expected
|
||||||
|
}
|
||||||
|
|
||||||
|
type ID = string
|
||||||
|
type GG = int
|
||||||
|
|
||||||
|
struct Message {
|
||||||
|
id ID
|
||||||
|
ij GG
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_encode_alias_struct() {
|
||||||
|
expected := '{"id":"118499178790780929","ij":999998888}'
|
||||||
|
msg := Message{'118499178790780929', 999998888}
|
||||||
|
out := json.encode<Message>(msg)
|
||||||
|
assert out == expected
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StByteArray {
|
||||||
|
ba []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_byte_array() {
|
||||||
|
assert json.encode(StByteArray{ ba: [byte(1), 2, 3, 4, 5] }) == '{"ba":[1,2,3,4,5]}'
|
||||||
|
}
|
471
vlib/x/json2/json_module_compatibility_test/json_todo_test.vv
Normal file
471
vlib/x/json2/json_module_compatibility_test/json_todo_test.vv
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
import x.json2 as json
|
||||||
|
import time
|
||||||
|
|
||||||
|
enum JobTitle {
|
||||||
|
manager
|
||||||
|
executive
|
||||||
|
worker
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Employee {
|
||||||
|
pub mut:
|
||||||
|
name string
|
||||||
|
age int
|
||||||
|
salary f32
|
||||||
|
title JobTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
const currency_id = 'cconst'
|
||||||
|
|
||||||
|
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 Bar {
|
||||||
|
x string
|
||||||
|
}
|
||||||
|
|
||||||
|
//! BUGFIX - .from_json(res)
|
||||||
|
fn test_generic() {
|
||||||
|
result := bar<Bar>('{"x":"test"}') or { Bar{} }
|
||||||
|
assert result.x == 'test'
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Color {
|
||||||
|
pub mut:
|
||||||
|
space string
|
||||||
|
point string [raw]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_raw_json_field() {
|
||||||
|
color := json.decode<Color>('{"space": "YCbCr", "point": {"Y": 123}}') or {
|
||||||
|
assert false
|
||||||
|
Color{}
|
||||||
|
}
|
||||||
|
assert color.point == '{"Y":123}'
|
||||||
|
assert color.space == 'YCbCr'
|
||||||
|
}
|
||||||
|
|
||||||
|
//! FIX: returning 0
|
||||||
|
fn test_bad_raw_json_field() {
|
||||||
|
color := json.decode<Color>('{"space": "YCbCr"}') or {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert color.point == ''
|
||||||
|
assert color.space == 'YCbCr'
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo<T> {
|
||||||
|
pub:
|
||||||
|
name string
|
||||||
|
data T
|
||||||
|
}
|
||||||
|
|
||||||
|
//! BUGFIX - .from_json(res)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
//! 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 Foo2 {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
//! BUGFIX - .from_json(res)
|
||||||
|
fn test_pretty() {
|
||||||
|
foo := Foo2{'Bob'}
|
||||||
|
assert json.encode_pretty(foo) == '{
|
||||||
|
"name": "Bob"
|
||||||
|
}'
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Aa {
|
||||||
|
sub AliasType
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bb {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
type AliasType = Bb
|
||||||
|
|
||||||
|
//! FIX: returning null
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
//! FIX: returning null
|
||||||
|
fn test_encoding_struct_with_pointers() {
|
||||||
|
value := Association{
|
||||||
|
association: &Association{
|
||||||
|
price: APrice{}
|
||||||
|
}
|
||||||
|
price: APrice{}
|
||||||
|
}
|
||||||
|
assert json.encode(value) == '{"association":{"price":{}},"price":{}}'
|
||||||
|
}
|
31
vlib/x/json2/temporary_workaround_types_id.v
Normal file
31
vlib/x/json2/temporary_workaround_types_id.v
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
module json2
|
||||||
|
|
||||||
|
fn gen_workaround<T>(result T) T {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_workaround_result<T>(result T) ?T {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_workaround_optional<T>(result T) !T {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
string_type_idx = typeof(gen_workaround<string>(unsafe { nil })).idx
|
||||||
|
result_string_type_idx = typeof(gen_workaround_result<string>(unsafe { nil })).idx
|
||||||
|
optional_string_type_idx = typeof(gen_workaround_optional<string>(unsafe { nil })).idx
|
||||||
|
|
||||||
|
int_type_idx = typeof(gen_workaround<int>(unsafe { nil })).idx
|
||||||
|
result_int_type_idx = typeof(gen_workaround_result<int>(unsafe { nil })).idx
|
||||||
|
optional_int_type_idx = typeof(gen_workaround_optional<int>(unsafe { nil })).idx
|
||||||
|
|
||||||
|
int_array_type_idx = typeof(gen_workaround<[]int>(unsafe { nil })).idx
|
||||||
|
result_int_array_type_idx = typeof(gen_workaround_result<[]int>(unsafe { nil })).idx
|
||||||
|
optional_int_array_type_idx = typeof(gen_workaround_optional<[]int>(unsafe { nil })).idx
|
||||||
|
|
||||||
|
byte_array_type_idx = typeof(gen_workaround<[]byte>(unsafe { nil })).idx
|
||||||
|
result_byte_array_type_idx = typeof(gen_workaround_result<[]byte>(unsafe { nil })).idx
|
||||||
|
optional_byte_array_type_idx = typeof(gen_workaround_optional<[]byte>(unsafe { nil })).idx
|
||||||
|
)
|
Loading…
Add table
Add a link
Reference in a new issue