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