Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/core/io/test_json_native.cpp
45997 views
1
/**************************************************************************/
2
/* test_json_native.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "tests/test_macros.h"
32
33
TEST_FORCE_LINK(test_json_native)
34
35
#include "core/io/json.h"
36
#include "core/variant/typed_array.h"
37
#include "core/variant/typed_dictionary.h"
38
39
namespace TestJSONNative {
40
41
String encode(const Variant &p_variant, bool p_full_objects = false) {
42
return JSON::stringify(JSON::from_native(p_variant, p_full_objects), "", false);
43
}
44
45
Variant decode(const String &p_string, bool p_allow_objects = false) {
46
return JSON::to_native(JSON::parse_string(p_string), p_allow_objects);
47
}
48
49
void test(const Variant &p_variant, const String &p_string, bool p_with_objects = false) {
50
CHECK(encode(p_variant, p_with_objects) == p_string);
51
CHECK(decode(p_string, p_with_objects).get_construct_string() == p_variant.get_construct_string());
52
}
53
54
TEST_CASE("[JSON][Native] Conversion between native and JSON formats") {
55
// `Nil` and `bool` (represented as JSON keyword literals).
56
test(Variant(), "null");
57
test(false, "false");
58
test(true, "true");
59
60
// Numbers and strings (represented as JSON strings).
61
test(1, R"("i:1")");
62
test(1.0, R"("f:1.0")");
63
test(Math::INF, R"("f:inf")");
64
test(-Math::INF, R"("f:-inf")");
65
test(Math::NaN, R"("f:nan")");
66
test(String("abc"), R"("s:abc")");
67
test(StringName("abc"), R"("sn:abc")");
68
test(NodePath("abc"), R"("np:abc")");
69
70
// Non-serializable types (always empty after deserialization).
71
test(RID(), R"({"type":"RID"})");
72
test(Callable(), R"({"type":"Callable"})");
73
test(Signal(), R"({"type":"Signal"})");
74
75
// Math types.
76
77
test(Vector2(1, 2), R"({"type":"Vector2","args":[1.0,2.0]})");
78
test(Vector2i(1, 2), R"({"type":"Vector2i","args":[1,2]})");
79
test(Rect2(1, 2, 3, 4), R"({"type":"Rect2","args":[1.0,2.0,3.0,4.0]})");
80
test(Rect2i(1, 2, 3, 4), R"({"type":"Rect2i","args":[1,2,3,4]})");
81
test(Vector3(1, 2, 3), R"({"type":"Vector3","args":[1.0,2.0,3.0]})");
82
test(Vector3i(1, 2, 3), R"({"type":"Vector3i","args":[1,2,3]})");
83
test(Transform2D(1, 2, 3, 4, 5, 6), R"({"type":"Transform2D","args":[1.0,2.0,3.0,4.0,5.0,6.0]})");
84
test(Vector4(1, 2, 3, 4), R"({"type":"Vector4","args":[1.0,2.0,3.0,4.0]})");
85
test(Vector4i(1, 2, 3, 4), R"({"type":"Vector4i","args":[1,2,3,4]})");
86
test(Plane(1, 2, 3, 4), R"({"type":"Plane","args":[1.0,2.0,3.0,4.0]})");
87
test(Quaternion(1, 2, 3, 4), R"({"type":"Quaternion","args":[1.0,2.0,3.0,4.0]})");
88
test(AABB(Vector3(1, 2, 3), Vector3(4, 5, 6)), R"({"type":"AABB","args":[1.0,2.0,3.0,4.0,5.0,6.0]})");
89
90
const Basis b(Vector3(1, 2, 3), Vector3(4, 5, 6), Vector3(7, 8, 9));
91
test(b, R"({"type":"Basis","args":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]})");
92
93
const Transform3D tr3d(Vector3(1, 2, 3), Vector3(4, 5, 6), Vector3(7, 8, 9), Vector3(10, 11, 12));
94
test(tr3d, R"({"type":"Transform3D","args":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0]})");
95
96
const Projection p(Vector4(1, 2, 3, 4), Vector4(5, 6, 7, 8), Vector4(9, 10, 11, 12), Vector4(13, 14, 15, 16));
97
test(p, R"({"type":"Projection","args":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0]})");
98
99
test(Color(1, 2, 3, 4), R"({"type":"Color","args":[1.0,2.0,3.0,4.0]})");
100
101
// `Object`.
102
103
Ref<Resource> res;
104
res.instantiate();
105
106
// The properties are stored in an array because the order in which they are assigned may be important during initialization.
107
const String res_repr = R"({"type":"Resource","props":["resource_local_to_scene",false,"resource_name","s:","script",null]})";
108
109
test(res, res_repr, true);
110
ERR_PRINT_OFF;
111
CHECK(encode(res) == "null");
112
CHECK(decode(res_repr).get_type() == Variant::NIL);
113
ERR_PRINT_ON;
114
115
// `Dictionary`.
116
117
Dictionary dict;
118
dict[false] = true;
119
dict[0] = 1;
120
dict[0.0] = 1.0;
121
122
// Godot dictionaries preserve insertion order, so an array is used for keys/values.
123
test(dict, R"({"type":"Dictionary","args":[false,true,"i:0","i:1","f:0.0","f:1.0"]})");
124
125
TypedDictionary<int64_t, int64_t> int_int_dict;
126
int_int_dict[1] = 2;
127
int_int_dict[3] = 4;
128
129
test(int_int_dict, R"({"type":"Dictionary","key_type":"int","value_type":"int","args":["i:1","i:2","i:3","i:4"]})");
130
131
TypedDictionary<int64_t, Variant> int_var_dict;
132
int_var_dict[1] = "2";
133
int_var_dict[3] = "4";
134
135
test(int_var_dict, R"({"type":"Dictionary","key_type":"int","args":["i:1","s:2","i:3","s:4"]})");
136
137
TypedDictionary<Variant, int64_t> var_int_dict;
138
var_int_dict["1"] = 2;
139
var_int_dict["3"] = 4;
140
141
test(var_int_dict, R"({"type":"Dictionary","value_type":"int","args":["s:1","i:2","s:3","i:4"]})");
142
143
Dictionary dict2;
144
dict2["x"] = res;
145
146
const String dict2_repr = vformat(R"({"type":"Dictionary","args":["s:x",%s]})", res_repr);
147
148
test(dict2, dict2_repr, true);
149
ERR_PRINT_OFF;
150
CHECK(encode(dict2) == R"({"type":"Dictionary","args":["s:x",null]})");
151
CHECK(decode(dict2_repr).get_construct_string() == "{\n\"x\": null\n}");
152
ERR_PRINT_ON;
153
154
TypedDictionary<String, Resource> res_dict;
155
res_dict["x"] = res;
156
157
const String res_dict_repr = vformat(R"({"type":"Dictionary","key_type":"String","value_type":"Resource","args":["s:x",%s]})", res_repr);
158
159
test(res_dict, res_dict_repr, true);
160
ERR_PRINT_OFF;
161
CHECK(encode(res_dict) == "null");
162
CHECK(decode(res_dict_repr).get_type() == Variant::NIL);
163
ERR_PRINT_ON;
164
165
// `Array`.
166
167
Array arr = { true, 1, "abc" };
168
test(arr, R"([true,"i:1","s:abc"])");
169
170
TypedArray<int64_t> int_arr = { 1, 2, 3 };
171
test(int_arr, R"({"type":"Array","elem_type":"int","args":["i:1","i:2","i:3"]})");
172
173
Array arr2 = { 1, res, 9 };
174
const String arr2_repr = vformat(R"(["i:1",%s,"i:9"])", res_repr);
175
176
test(arr2, arr2_repr, true);
177
ERR_PRINT_OFF;
178
CHECK(encode(arr2) == R"(["i:1",null,"i:9"])");
179
CHECK(decode(arr2_repr).get_construct_string() == "[1, null, 9]");
180
ERR_PRINT_ON;
181
182
TypedArray<Resource> res_arr = { res };
183
const String res_arr_repr = vformat(R"({"type":"Array","elem_type":"Resource","args":[%s]})", res_repr);
184
185
test(res_arr, res_arr_repr, true);
186
ERR_PRINT_OFF;
187
CHECK(encode(res_arr) == "null");
188
CHECK(decode(res_arr_repr).get_type() == Variant::NIL);
189
ERR_PRINT_ON;
190
191
// Packed arrays.
192
193
test(PackedByteArray({ 1, 2, 3 }), R"({"type":"PackedByteArray","args":[1,2,3]})");
194
test(PackedInt32Array({ 1, 2, 3 }), R"({"type":"PackedInt32Array","args":[1,2,3]})");
195
test(PackedInt64Array({ 1, 2, 3 }), R"({"type":"PackedInt64Array","args":[1,2,3]})");
196
test(PackedFloat32Array({ 1, 2, 3 }), R"({"type":"PackedFloat32Array","args":[1.0,2.0,3.0]})");
197
test(PackedFloat64Array({ 1, 2, 3 }), R"({"type":"PackedFloat64Array","args":[1.0,2.0,3.0]})");
198
test(PackedStringArray({ "a", "b", "c" }), R"({"type":"PackedStringArray","args":["a","b","c"]})");
199
200
const PackedVector2Array pv2arr({ Vector2(1, 2), Vector2(3, 4), Vector2(5, 6) });
201
test(pv2arr, R"({"type":"PackedVector2Array","args":[1.0,2.0,3.0,4.0,5.0,6.0]})");
202
203
const PackedVector3Array pv3arr({ Vector3(1, 2, 3), Vector3(4, 5, 6), Vector3(7, 8, 9) });
204
test(pv3arr, R"({"type":"PackedVector3Array","args":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]})");
205
206
const PackedColorArray pcolarr({ Color(1, 2, 3, 4), Color(5, 6, 7, 8), Color(9, 10, 11, 12) });
207
test(pcolarr, R"({"type":"PackedColorArray","args":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0]})");
208
209
const PackedVector4Array pv4arr({ Vector4(1, 2, 3, 4), Vector4(5, 6, 7, 8), Vector4(9, 10, 11, 12) });
210
test(pv4arr, R"({"type":"PackedVector4Array","args":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0]})");
211
}
212
213
} // namespace TestJSONNative
214
215