v/vlib/toml/tests/encode_and_decode_test.v

329 lines
6.5 KiB
V

import toml
enum JobTitle {
worker
executive
manager
}
struct Pet {
name string
nicknames []string
age u64
income int
height f32
has_furr bool
title JobTitle
address Address
meal_frequency map[string]int
// *¹ Currently it is only possible to decode a single nested struct generically.
// As soon as we decode another nested struct (e.g. within this struct, like `contact` below)
// or only one nested struct within another struct, it results in wrong values or errors.
// Related issue: https://github.com/vlang/v/issues/18110
// contact Contact
}
struct Address {
street string
city string
}
// *¹
/*
struct Contact {
phone string
}*/
struct AnyStruct {
val toml.Any
}
struct Employee {
mut:
name string
age int
salary f32
is_human bool
title JobTitle
}
struct Arrs {
strs []string
bools []bool
ints []int
i64s []i64
u64s []u64
f32s []f32
f64s []f64
dts []toml.DateTime
dates []toml.Date
times []toml.Time
}
// individual because toml.decode[Foo](str)! == foo is false
struct AnyArr {
arr []toml.Any
}
fn test_encode_and_decode() {
// *¹
// p := Pet{'Mr. Scratchy McEvilPaws', ['Freddy', 'Fred', 'Charles'], 8, -1, 0.8, true, .manager, Address{'1428 Elm Street', 'Springwood'}, Contact{'123-456-7890'}}
p := Pet{'Mr. Scratchy McEvilPaws', ['Freddy', 'Fred', 'Charles'], 8, -1, 0.8, true, .manager, Address{'1428 Elm Street', 'Springwood'}, {
'bones': 2
'kibble': 5
}}
s := 'name = "Mr. Scratchy McEvilPaws"
nicknames = [
"Freddy",
"Fred",
"Charles"
]
age = 8
income = -1
height = 0.8
has_furr = true
title = 2
address = { street = "1428 Elm Street", city = "Springwood" }
meal_frequency = { bones = 2, kibble = 5 }'
// contact = { phone = "123-456-7890" }' // *¹
assert toml.encode[Pet](p) == s
assert toml.decode[Pet](s)! == p
}
fn test_encode_and_decode_any() {
a := AnyStruct{toml.Any(10)}
s := 'val = 10'
assert toml.encode[AnyStruct](a) == s
assert toml.decode[AnyStruct](s)!.val.int() == 10
}
pub fn (e Employee) to_toml() string {
mut mp := map[string]toml.Any{}
mp['name'] = toml.Any(e.name)
mp['age'] = toml.Any(e.age)
mp['is_human'] = toml.Any(e.is_human)
// Change some values to assert that the custom method is used instead of generic encoding.
mp['salary'] = toml.Any(f32(e.salary) + 5000.0)
mp['title'] = toml.Any(int(e.title) + 1)
return mp.to_toml()
}
pub fn (mut e Employee) from_toml(any toml.Any) {
mp := any.as_map()
e.name = mp['name'] or { toml.Any('') }.string()
e.age = mp['age'] or { toml.Any(0) }.int()
e.is_human = mp['is_human'] or { toml.Any(false) }.bool()
// Change some values to assert that the custom method is used instead of generic decoding.
e.salary = mp['salary'] or { toml.Any(0) }.f32() - 15000.0
e.title = unsafe { JobTitle(mp['title'] or { toml.Any(0) }.int() - 2) }
}
fn test_custom_encode_and_decode() {
x := Employee{'Peter', 28, 95000.5, true, .executive}
s := toml.encode[Employee](x)
eprintln('Employee x: ${s}')
assert s == r'name = "Peter"
age = 28
is_human = true
salary = 100000.5
title = 2'
y := toml.decode[Employee](s) or {
println(err)
assert false
return
}
eprintln('Employee y: ${y}')
assert y.name == 'Peter'
assert y.age == 28
assert y.salary == 85000.5
assert y.is_human == true
assert y.title == .worker
}
struct Example1 {
arr []Problem
}
struct Example2 {
arr []Problem
}
struct Problem {
x int
}
pub fn (example Example1) to_toml() string {
return '[This is Valid]'
}
pub fn (problem Problem) to_toml() string {
return 'a problem'
}
fn test_custom_encode_of_complex_struct() {
assert toml.encode(Example1{}) == '[This is Valid]'
assert toml.encode(Example2{[Problem{}, Problem{}]}) == 'arr = [
"a problem",
"a problem"
]'
}
struct Example3 {
arr_arr [][]Problem
}
struct Example4 {
mp map[string]Problem
}
pub fn (example Example3) to_toml() string {
return '[This is Valid]'
}
pub fn (example Example4) to_toml() string {
return '[This is Valid]'
}
fn test_custom_encode_of_nested_complex_struct() {
assert toml.encode(Example3{}) == '[This is Valid]'
assert toml.encode(Example4{}) == '[This is Valid]'
}
struct Example5 {
mp map[string]Problem
}
fn test_map_encode_of_complex_struct() {
mut mp := map[string]Problem{}
mp['key_one'] = Problem{}
mp['key_two'] = Problem{}
assert toml.encode(Example5{ mp: mp }) == 'mp = { key_one = "a problem", key_two = "a problem" }'
}
struct Example6 {
ptr voidptr
r rune
}
fn test_encode_for_exotic_types() {
assert toml.encode(Example6{ ptr: unsafe { &voidptr(nil) }, r: `🚀` }) == 'ptr = "0x0"\nr = "🚀"'
}
fn test_array_encode_decode() {
a := Arrs{
strs: ['foo', 'bar']
bools: [true, false]
ints: [-1, 2]
i64s: [i64(-2)]
u64s: [u64(123)]
f32s: [f32(1.0), f32(2.5)]
f64s: [100000.5, -123.0]
dts: [toml.DateTime{'1979-05-27T07:32:00Z'}, toml.DateTime{'1979-05-27T07:32:00Z'}]
dates: [toml.Date{'1979-05-27'}, toml.Date{'2022-12-31'}]
times: [toml.Time{'07:32:59'}, toml.Time{'17:32:04'}]
}
s := 'strs = [
"foo",
"bar"
]
bools = [
true,
false
]
ints = [
-1,
2
]
i64s = [
-2
]
u64s = [
123
]
f32s = [
1.0,
2.5
]
f64s = [
100000.5,
-123.0
]
dts = [
1979-05-27T07:32:00Z,
1979-05-27T07:32:00Z
]
dates = [
1979-05-27,
2022-12-31
]
times = [
07:32:59,
17:32:04
]'
assert toml.encode[Arrs](a) == s
assert toml.decode[Arrs](s)! == a
any_a := AnyArr{[toml.Any(10), 20, 30]}
any_s := 'arr = [
10,
20,
30
]'
assert toml.encode[AnyArr](any_a) == any_s
assert toml.decode[AnyArr](any_s)!.arr.map(it.int()) == [10, 20, 30]
}
fn test_decode_doc() {
doc := toml.parse_text('name = "Peter"
age = 28
is_human = true
salary = 100000.5
title = 2')!
e := doc.decode[Employee]()!
assert e.name == 'Peter'
assert e.age == 28
assert e.salary == 100000.5
assert e.is_human == true
assert e.title == .manager
}
fn test_unsupported_type() {
s := 'name = "Peter"'
err_msg := 'toml.decode: expected struct, found '
if _ := toml.decode[string](s) {
assert false
} else {
assert err.msg() == err_msg + 'string'
}
if _ := toml.decode[[]string](s) {
assert false
} else {
assert err.msg() == err_msg + '[]string'
}
if _ := toml.decode[int](s) {
assert false
} else {
assert err.msg() == err_msg + 'int'
}
if _ := toml.decode[[]f32](s) {
assert false
} else {
assert err.msg() == err_msg + '[]f32'
}
// ...
doc := toml.parse_text('name = "Peter"')!
assert doc.value('name').string() == 'Peter'
if _ := doc.decode[string]() {
assert false
} else {
assert err.msg() == 'Doc.decode: expected struct, found string'
}
}