diff options
author | Indrajith K L | 2022-12-03 17:00:20 +0530 |
---|---|---|
committer | Indrajith K L | 2022-12-03 17:00:20 +0530 |
commit | f5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch) | |
tree | 2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/vlib/json | |
download | cli-tools-windows-master.tar.gz cli-tools-windows-master.tar.bz2 cli-tools-windows-master.zip |
Diffstat (limited to 'v_windows/v/vlib/json')
-rw-r--r-- | v_windows/v/vlib/json/json_decode_test.v | 46 | ||||
-rw-r--r-- | v_windows/v/vlib/json/json_primitives.v | 204 | ||||
-rw-r--r-- | v_windows/v/vlib/json/json_test.v | 368 |
3 files changed, 618 insertions, 0 deletions
diff --git a/v_windows/v/vlib/json/json_decode_test.v b/v_windows/v/vlib/json/json_decode_test.v new file mode 100644 index 0000000..5b21838 --- /dev/null +++ b/v_windows/v/vlib/json/json_decode_test.v @@ -0,0 +1,46 @@ +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) +} diff --git a/v_windows/v/vlib/json/json_primitives.v b/v_windows/v/vlib/json/json_primitives.v new file mode 100644 index 0000000..2e635e5 --- /dev/null +++ b/v_windows/v/vlib/json/json_primitives.v @@ -0,0 +1,204 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module json + +#flag -I @VEXEROOT/thirdparty/cJSON +#flag @VEXEROOT/thirdparty/cJSON/cJSON.o +#include "cJSON.h" +#define js_get(object, key) cJSON_GetObjectItemCaseSensitive((object), (key)) + +struct C.cJSON { + valueint int + valuedouble f32 + valuestring &char +} + +fn C.cJSON_IsTrue(&C.cJSON) bool + +fn C.cJSON_CreateNumber(int) &C.cJSON + +fn C.cJSON_CreateBool(bool) &C.cJSON + +fn C.cJSON_CreateString(&char) &C.cJSON + +fn C.cJSON_Parse(&char) &C.cJSON + +fn C.cJSON_PrintUnformatted(&C.cJSON) &char + +fn C.cJSON_Print(&C.cJSON) &char + +pub fn decode(typ voidptr, s string) ?voidptr { + // compiler implementation + return 0 +} + +pub fn encode(x voidptr) string { + // compiler implementation + return '' +} + +pub fn encode_pretty(x voidptr) string { + // compiler implementation + return '' +} + +fn decode_int(root &C.cJSON) int { + if isnil(root) { + return 0 + } + return root.valueint +} + +fn decode_i8(root &C.cJSON) i8 { + if isnil(root) { + return i8(0) + } + return i8(root.valueint) +} + +fn decode_i16(root &C.cJSON) i16 { + if isnil(root) { + return i16(0) + } + return i16(root.valueint) +} + +fn decode_i64(root &C.cJSON) i64 { + if isnil(root) { + return i64(0) + } + return i64(root.valuedouble) // i64 is double in C +} + +fn decode_byte(root &C.cJSON) byte { + if isnil(root) { + return byte(0) + } + return byte(root.valueint) +} + +fn decode_u16(root &C.cJSON) u16 { + if isnil(root) { + return u16(0) + } + return u16(root.valueint) +} + +fn decode_u32(root &C.cJSON) u32 { + if isnil(root) { + return u32(0) + } + return u32(root.valueint) +} + +fn decode_u64(root &C.cJSON) u64 { + if isnil(root) { + return u64(0) + } + return u64(root.valuedouble) +} + +fn decode_f32(root &C.cJSON) f32 { + if isnil(root) { + return f32(0) + } + return root.valuedouble +} + +fn decode_f64(root &C.cJSON) f64 { + if isnil(root) { + return f64(0) + } + return f64(root.valuedouble) +} + +fn decode_string(root &C.cJSON) string { + if isnil(root) { + return '' + } + if isnil(root.valuestring) { + return '' + } + // println('decode string valuestring="$root.valuestring"') + // return tos(root.valuestring, _strlen(root.valuestring)) + return unsafe { tos_clone(&byte(root.valuestring)) } // , _strlen(root.valuestring)) +} + +fn decode_bool(root &C.cJSON) bool { + if isnil(root) { + return false + } + return C.cJSON_IsTrue(root) +} + +// /////////////////// +fn encode_int(val int) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_i8(val i8) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_i16(val i16) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_i64(val i64) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_byte(val byte) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_u16(val u16) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_u32(val u32) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_u64(val u64) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_f32(val f32) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_f64(val f64) &C.cJSON { + return C.cJSON_CreateNumber(val) +} + +fn encode_bool(val bool) &C.cJSON { + return C.cJSON_CreateBool(val) +} + +fn encode_string(val string) &C.cJSON { + return C.cJSON_CreateString(&char(val.str)) +} + +// /////////////////////// +// user := decode_User(json_parse(js_string_var)) +fn json_parse(s string) &C.cJSON { + return C.cJSON_Parse(&char(s.str)) +} + +// json_string := json_print(encode_User(user)) +fn json_print(json &C.cJSON) string { + s := C.cJSON_PrintUnformatted(json) + return unsafe { tos(&byte(s), C.strlen(&char(s))) } +} + +fn json_print_pretty(json &C.cJSON) string { + s := C.cJSON_Print(json) + return unsafe { tos(&byte(s), C.strlen(&char(s))) } +} + +// / cjson wrappers +// fn json_array_for_each(val, root &C.cJSON) { +// #cJSON_ArrayForEach (val ,root) +// } diff --git a/v_windows/v/vlib/json/json_test.v b/v_windows/v/vlib/json/json_test.v new file mode 100644 index 0000000..ca6b2ac --- /dev/null +++ b/v_windows/v/vlib/json/json_test.v @@ -0,0 +1,368 @@ +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":2}' + 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 +} + +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 +} + +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_time(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 (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 +} + +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 + +struct Message { + id ID +} + +fn test_decode_alias_struct() ? { + msg := json.decode(Message, '{"id": "118499178790780929"}') ? + // hacky way of comparing aliased strings + assert msg.id.str() == '118499178790780929' +} + +fn test_encode_alias_struct() { + expected := '{"id":"118499178790780929"}' + msg := Message{'118499178790780929'} + 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' == '{}' +} + +struct Foo2 { + name string +} + +fn test_pretty() { + foo := Foo2{'Bob'} + assert json.encode_pretty(foo) == '{ + "name": "Bob" +}' +} |