diff options
Diffstat (limited to 'v_windows/v/old/vlib/json')
| -rw-r--r-- | v_windows/v/old/vlib/json/json_decode_test.v | 35 | ||||
| -rw-r--r-- | v_windows/v/old/vlib/json/json_primitives.v | 204 | ||||
| -rw-r--r-- | v_windows/v/old/vlib/json/json_test.v | 358 | 
3 files changed, 597 insertions, 0 deletions
diff --git a/v_windows/v/old/vlib/json/json_decode_test.v b/v_windows/v/old/vlib/json/json_decode_test.v new file mode 100644 index 0000000..2c4448f --- /dev/null +++ b/v_windows/v/old/vlib/json/json_decode_test.v @@ -0,0 +1,35 @@ +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' +} diff --git a/v_windows/v/old/vlib/json/json_primitives.v b/v_windows/v/old/vlib/json/json_primitives.v new file mode 100644 index 0000000..0631899 --- /dev/null +++ b/v_windows/v/old/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.valueint) +} + +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/old/vlib/json/json_test.v b/v_windows/v/old/vlib/json/json_test.v new file mode 100644 index 0000000..8191462 --- /dev/null +++ b/v_windows/v/old/vlib/json/json_test.v @@ -0,0 +1,358 @@ +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 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 := map{ +		'one':   1 +		'two':   2 +		'three': 3 +		'four':  4 +	} +	out := json.encode(numbers) +	println(out) +	assert out == expected +} + +fn test_parse_map() ? { +	expected := map{ +		'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: map{ +			'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: map{ +			'2': map{ +				'n1': 2 +				'n2': 4 +				'n3': 8 +				'n4': 16 +			} +			'3': map{ +				'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" +}' +}  | 
