aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/x/json2/json2_test.v
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/vlib/x/json2/json2_test.v')
-rw-r--r--v_windows/v/vlib/x/json2/json2_test.v398
1 files changed, 398 insertions, 0 deletions
diff --git a/v_windows/v/vlib/x/json2/json2_test.v b/v_windows/v/vlib/x/json2/json2_test.v
new file mode 100644
index 0000000..3fc29f7
--- /dev/null
+++ b/v_windows/v/vlib/x/json2/json2_test.v
@@ -0,0 +1,398 @@
+import x.json2
+
+enum JobTitle {
+ manager
+ executive
+ worker
+}
+
+struct Employee {
+pub mut:
+ name string
+ age int
+ salary f32
+ title JobTitle
+}
+
+fn (e Employee) to_json() string {
+ mut mp := map[string]json2.Any{}
+ mp['name'] = e.name
+ mp['age'] = e.age
+ mp['salary'] = e.salary
+ mp['title'] = int(e.title)
+ /*
+ $for field in Employee.fields {
+ d := e.$(field.name)
+
+ $if field.typ is JobTitle {
+ mp[field.name] = json.encode<int>(d)
+ } $else {
+ mp[field.name] = d
+ }
+ }
+ */
+ return mp.str()
+}
+
+fn (mut e Employee) from_json(any json2.Any) {
+ mp := any.as_map()
+ e.name = mp['name'].str()
+ e.age = mp['age'].int()
+ e.salary = mp['salary'].f32()
+ e.title = JobTitle(mp['title'].int())
+}
+
+fn test_simple() {
+ x := Employee{'Peter', 28, 95000.5, .worker}
+ s := json2.encode<Employee>(x)
+ eprintln('Employee x: $s')
+ assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2}'
+ y := json2.decode<Employee>(s) or {
+ println(err)
+ assert false
+ return
+ }
+ eprintln('Employee y: $y')
+ assert y.name == 'Peter'
+ assert y.age == 28
+ assert y.salary == 95000.5
+ assert y.title == .worker
+}
+
+fn test_fast_raw_decode() {
+ s := '{"name":"Peter","age":28,"salary":95000.5,"title":2}'
+ o := json2.fast_raw_decode(s) or {
+ assert false
+ json2.Any(json2.null)
+ }
+ str := o.str()
+ assert str == '{"name":"Peter","age":"28","salary":"95000.5","title":"2"}'
+}
+
+fn test_character_unescape() {
+ message := r'{
+ "newline": "new\nline",
+ "tab": "\ttab",
+ "backslash": "back\\slash",
+ "quotes": "\"quotes\"",
+ "slash":"\/dev\/null"
+}'
+ mut obj := json2.raw_decode(message) or {
+ println(err)
+ assert false
+ return
+ }
+ lines := obj.as_map()
+ eprintln('$lines')
+ assert lines['newline'].str() == 'new\nline'
+ assert lines['tab'].str() == '\ttab'
+ assert lines['backslash'].str() == 'back\\slash'
+ assert lines['quotes'].str() == '"quotes"'
+ assert lines['slash'].str() == '/dev/null'
+}
+
+struct User2 {
+pub mut:
+ age int
+ nums []int
+}
+
+fn (mut u User2) from_json(an json2.Any) {
+ mp := an.as_map()
+ mut js_field_name := ''
+ $for field in User.fields {
+ js_field_name = field.name
+ for attr in field.attrs {
+ if attr.starts_with('json:') {
+ js_field_name = attr.all_after('json:').trim_left(' ')
+ break
+ }
+ }
+ match field.name {
+ 'age' { u.age = mp[js_field_name].int() }
+ 'nums' { u.nums = mp[js_field_name].arr().map(it.int()) }
+ else {}
+ }
+ }
+}
+
+// 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) from_json(an json2.Any) {
+ mp := an.as_map()
+ mut js_field_name := ''
+ $for field in User.fields {
+ // FIXME: C error when initializing js_field_name inside comptime for
+ js_field_name = field.name
+ for attr in field.attrs {
+ if attr.starts_with('json:') {
+ js_field_name = attr.all_after('json:').trim_left(' ')
+ break
+ }
+ }
+ match field.name {
+ 'age' { u.age = mp[js_field_name].int() }
+ 'nums' { u.nums = mp[js_field_name].arr().map(it.int()) }
+ 'last_name' { u.last_name = mp[js_field_name].str() }
+ 'is_registered' { u.is_registered = mp[js_field_name].bool() }
+ 'typ' { u.typ = mp[js_field_name].int() }
+ 'pets' { u.pets = mp[js_field_name].str() }
+ else {}
+ }
+ }
+}
+
+fn (u User) to_json() string {
+ // TODO: derive from field
+ mut mp := {
+ 'age': json2.Any(u.age)
+ }
+ mp['nums'] = u.nums.map(json2.Any(it))
+ mp['lastName'] = u.last_name
+ mp['IsRegistered'] = u.is_registered
+ mp['type'] = u.typ
+ mp['pet_animals'] = u.pets
+ 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) or {
+ println(err)
+ assert false
+ return
+ }
+ println(u2)
+ u := json2.decode<User>(s) or {
+ println(err)
+ assert false
+ return
+ }
+ 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_user() {
+ 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
+}
+
+struct Color {
+pub mut:
+ space string
+ point string [raw]
+}
+
+fn (mut c Color) from_json(an json2.Any) {
+ mp := an.as_map()
+ $for field in Color.fields {
+ match field.name {
+ 'space' { c.space = mp[field.name].str() }
+ 'point' { c.point = mp[field.name].str() }
+ else {}
+ }
+ }
+}
+
+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 := json.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()
+}
+*/