1 /*
2 * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
3 *
4 * Jansson is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
7
8 #include "util.h"
9 #include <jansson.h>
10 #include <string.h>
11
test_copy_simple(void)12 static void test_copy_simple(void) {
13 json_t *value, *copy;
14
15 if (json_copy(NULL))
16 fail("copying NULL doesn't return NULL");
17
18 /* true */
19 value = json_true();
20 copy = json_copy(value);
21 if (value != copy)
22 fail("copying true failed");
23 json_decref(value);
24 json_decref(copy);
25
26 /* false */
27 value = json_false();
28 copy = json_copy(value);
29 if (value != copy)
30 fail("copying false failed");
31 json_decref(value);
32 json_decref(copy);
33
34 /* null */
35 value = json_null();
36 copy = json_copy(value);
37 if (value != copy)
38 fail("copying null failed");
39 json_decref(value);
40 json_decref(copy);
41
42 /* string */
43 value = json_string("foo");
44 if (!value)
45 fail("unable to create a string");
46 copy = json_copy(value);
47 if (!copy)
48 fail("unable to copy a string");
49 if (copy == value)
50 fail("copying a string doesn't copy");
51 if (!json_equal(copy, value))
52 fail("copying a string produces an inequal copy");
53 if (value->refcount != 1 || copy->refcount != 1)
54 fail("invalid refcounts");
55 json_decref(value);
56 json_decref(copy);
57
58 /* integer */
59 value = json_integer(543);
60 if (!value)
61 fail("unable to create an integer");
62 copy = json_copy(value);
63 if (!copy)
64 fail("unable to copy an integer");
65 if (copy == value)
66 fail("copying an integer doesn't copy");
67 if (!json_equal(copy, value))
68 fail("copying an integer produces an inequal copy");
69 if (value->refcount != 1 || copy->refcount != 1)
70 fail("invalid refcounts");
71 json_decref(value);
72 json_decref(copy);
73
74 /* real */
75 value = json_real(123e9);
76 if (!value)
77 fail("unable to create a real");
78 copy = json_copy(value);
79 if (!copy)
80 fail("unable to copy a real");
81 if (copy == value)
82 fail("copying a real doesn't copy");
83 if (!json_equal(copy, value))
84 fail("copying a real produces an inequal copy");
85 if (value->refcount != 1 || copy->refcount != 1)
86 fail("invalid refcounts");
87 json_decref(value);
88 json_decref(copy);
89 }
90
test_deep_copy_simple(void)91 static void test_deep_copy_simple(void) {
92 json_t *value, *copy;
93
94 if (json_deep_copy(NULL))
95 fail("deep copying NULL doesn't return NULL");
96
97 /* true */
98 value = json_true();
99 copy = json_deep_copy(value);
100 if (value != copy)
101 fail("deep copying true failed");
102 json_decref(value);
103 json_decref(copy);
104
105 /* false */
106 value = json_false();
107 copy = json_deep_copy(value);
108 if (value != copy)
109 fail("deep copying false failed");
110 json_decref(value);
111 json_decref(copy);
112
113 /* null */
114 value = json_null();
115 copy = json_deep_copy(value);
116 if (value != copy)
117 fail("deep copying null failed");
118 json_decref(value);
119 json_decref(copy);
120
121 /* string */
122 value = json_string("foo");
123 if (!value)
124 fail("unable to create a string");
125 copy = json_deep_copy(value);
126 if (!copy)
127 fail("unable to deep copy a string");
128 if (copy == value)
129 fail("deep copying a string doesn't copy");
130 if (!json_equal(copy, value))
131 fail("deep copying a string produces an inequal copy");
132 if (value->refcount != 1 || copy->refcount != 1)
133 fail("invalid refcounts");
134 json_decref(value);
135 json_decref(copy);
136
137 /* integer */
138 value = json_integer(543);
139 if (!value)
140 fail("unable to create an integer");
141 copy = json_deep_copy(value);
142 if (!copy)
143 fail("unable to deep copy an integer");
144 if (copy == value)
145 fail("deep copying an integer doesn't copy");
146 if (!json_equal(copy, value))
147 fail("deep copying an integer produces an inequal copy");
148 if (value->refcount != 1 || copy->refcount != 1)
149 fail("invalid refcounts");
150 json_decref(value);
151 json_decref(copy);
152
153 /* real */
154 value = json_real(123e9);
155 if (!value)
156 fail("unable to create a real");
157 copy = json_deep_copy(value);
158 if (!copy)
159 fail("unable to deep copy a real");
160 if (copy == value)
161 fail("deep copying a real doesn't copy");
162 if (!json_equal(copy, value))
163 fail("deep copying a real produces an inequal copy");
164 if (value->refcount != 1 || copy->refcount != 1)
165 fail("invalid refcounts");
166 json_decref(value);
167 json_decref(copy);
168 }
169
test_copy_array(void)170 static void test_copy_array(void) {
171 const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
172
173 json_t *array, *copy;
174 size_t i;
175
176 array = json_loads(json_array_text, 0, NULL);
177 if (!array)
178 fail("unable to parse an array");
179
180 copy = json_copy(array);
181 if (!copy)
182 fail("unable to copy an array");
183 if (copy == array)
184 fail("copying an array doesn't copy");
185 if (!json_equal(copy, array))
186 fail("copying an array produces an inequal copy");
187
188 for (i = 0; i < json_array_size(copy); i++) {
189 if (json_array_get(array, i) != json_array_get(copy, i))
190 fail("copying an array modifies its elements");
191 }
192
193 json_decref(array);
194 json_decref(copy);
195 }
196
test_deep_copy_array(void)197 static void test_deep_copy_array(void) {
198 const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
199
200 json_t *array, *copy;
201 size_t i;
202
203 array = json_loads(json_array_text, 0, NULL);
204 if (!array)
205 fail("unable to parse an array");
206
207 copy = json_deep_copy(array);
208 if (!copy)
209 fail("unable to deep copy an array");
210 if (copy == array)
211 fail("deep copying an array doesn't copy");
212 if (!json_equal(copy, array))
213 fail("deep copying an array produces an inequal copy");
214
215 for (i = 0; i < json_array_size(copy); i++) {
216 if (json_array_get(array, i) == json_array_get(copy, i))
217 fail("deep copying an array doesn't copy its elements");
218 }
219
220 json_decref(array);
221 json_decref(copy);
222 }
223
test_copy_object(void)224 static void test_copy_object(void) {
225 const char *json_object_text =
226 "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
227
228 const char *keys[] = {"foo", "a", "b", "c"};
229 int i;
230
231 json_t *object, *copy;
232 void *iter;
233
234 object = json_loads(json_object_text, 0, NULL);
235 if (!object)
236 fail("unable to parse an object");
237
238 copy = json_copy(object);
239 if (!copy)
240 fail("unable to copy an object");
241 if (copy == object)
242 fail("copying an object doesn't copy");
243 if (!json_equal(copy, object))
244 fail("copying an object produces an inequal copy");
245
246 i = 0;
247 iter = json_object_iter(object);
248 while (iter) {
249 const char *key;
250 json_t *value1, *value2;
251
252 key = json_object_iter_key(iter);
253 value1 = json_object_iter_value(iter);
254 value2 = json_object_get(copy, key);
255
256 if (value1 != value2)
257 fail("copying an object modifies its items");
258
259 if (strcmp(key, keys[i]) != 0)
260 fail("copying an object doesn't preserve key order");
261
262 iter = json_object_iter_next(object, iter);
263 i++;
264 }
265
266 json_decref(object);
267 json_decref(copy);
268 }
269
test_deep_copy_object(void)270 static void test_deep_copy_object(void) {
271 const char *json_object_text =
272 "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
273
274 const char *keys[] = {"foo", "a", "b", "c"};
275 int i;
276
277 json_t *object, *copy;
278 void *iter;
279
280 object = json_loads(json_object_text, 0, NULL);
281 if (!object)
282 fail("unable to parse an object");
283
284 copy = json_deep_copy(object);
285 if (!copy)
286 fail("unable to deep copy an object");
287 if (copy == object)
288 fail("deep copying an object doesn't copy");
289 if (!json_equal(copy, object))
290 fail("deep copying an object produces an inequal copy");
291
292 i = 0;
293 iter = json_object_iter(object);
294 while (iter) {
295 const char *key;
296 json_t *value1, *value2;
297
298 key = json_object_iter_key(iter);
299 value1 = json_object_iter_value(iter);
300 value2 = json_object_get(copy, key);
301
302 if (value1 == value2)
303 fail("deep copying an object doesn't copy its items");
304
305 if (strcmp(key, keys[i]) != 0)
306 fail("deep copying an object doesn't preserve key order");
307
308 iter = json_object_iter_next(object, iter);
309 i++;
310 }
311
312 json_decref(object);
313 json_decref(copy);
314 }
315
test_deep_copy_circular_references(void)316 static void test_deep_copy_circular_references(void) {
317 /* Construct a JSON object/array with a circular reference:
318
319 object: {"a": {"b": {"c": <circular reference to $.a>}}}
320 array: [[[<circular reference to the $[0] array>]]]
321
322 Deep copy it, remove the circular reference and deep copy again.
323 */
324
325 json_t *json;
326 json_t *copy;
327
328 json = json_object();
329 json_object_set_new(json, "a", json_object());
330 json_object_set_new(json_object_get(json, "a"), "b", json_object());
331 json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
332 json_object_get(json, "a"));
333
334 copy = json_deep_copy(json);
335 if (copy)
336 fail("json_deep_copy copied a circular reference!");
337
338 json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
339
340 copy = json_deep_copy(json);
341 if (!copy)
342 fail("json_deep_copy failed!");
343
344 json_decref(copy);
345 json_decref(json);
346
347 json = json_array();
348 json_array_append_new(json, json_array());
349 json_array_append_new(json_array_get(json, 0), json_array());
350 json_array_append(json_array_get(json_array_get(json, 0), 0),
351 json_array_get(json, 0));
352
353 copy = json_deep_copy(json);
354 if (copy)
355 fail("json_deep_copy copied a circular reference!");
356
357 json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
358
359 copy = json_deep_copy(json);
360 if (!copy)
361 fail("json_deep_copy failed!");
362
363 json_decref(copy);
364 json_decref(json);
365 }
366
run_tests()367 static void run_tests() {
368 test_copy_simple();
369 test_deep_copy_simple();
370 test_copy_array();
371 test_deep_copy_array();
372 test_copy_object();
373 test_deep_copy_object();
374 test_deep_copy_circular_references();
375 }
376