1/*
2 * Copyright (c) 2009-2014 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 <jansson.h>
9#include <string.h>
10#include "util.h"
11
12static void file_not_found()
13{
14    json_t *json;
15    json_error_t error;
16    char *pos;
17
18    json = json_load_file("/path/to/nonexistent/file.json", 0, &error);
19    if(json)
20        fail("json_load_file returned non-NULL for a nonexistent file");
21    if(error.line != -1)
22        fail("json_load_file returned an invalid line number");
23
24    /* The error message is locale specific, only check the beginning
25       of the error message. */
26
27    pos = strchr(error.text, ':');
28    if(!pos)
29        fail("json_load_file returne an invalid error message");
30
31    *pos = '\0';
32
33    if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0)
34        fail("json_load_file returned an invalid error message");
35}
36
37static void reject_duplicates()
38{
39    json_error_t error;
40
41    if(json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error))
42        fail("json_loads did not detect a duplicate key");
43    check_error("duplicate object key near '\"foo\"'", "<string>", 1, 16, 16);
44}
45
46static void disable_eof_check()
47{
48    json_error_t error;
49    json_t *json;
50
51    const char *text = "{\"foo\": 1} garbage";
52
53    if(json_loads(text, 0, &error))
54        fail("json_loads did not detect garbage after JSON text");
55    check_error("end of file expected near 'garbage'", "<string>", 1, 18, 18);
56
57    json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error);
58    if(!json)
59        fail("json_loads failed with JSON_DISABLE_EOF_CHECK");
60
61    json_decref(json);
62}
63
64static void decode_any()
65{
66    json_t *json;
67    json_error_t error;
68
69    json = json_loads("\"foo\"", JSON_DECODE_ANY, &error);
70    if (!json || !json_is_string(json))
71        fail("json_load decoded any failed - string");
72    json_decref(json);
73
74    json = json_loads("42", JSON_DECODE_ANY, &error);
75    if (!json || !json_is_integer(json))
76        fail("json_load decoded any failed - integer");
77    json_decref(json);
78
79    json = json_loads("true", JSON_DECODE_ANY, &error);
80    if (!json || !json_is_true(json))
81        fail("json_load decoded any failed - boolean");
82    json_decref(json);
83
84    json = json_loads("null", JSON_DECODE_ANY, &error);
85    if (!json || !json_is_null(json))
86        fail("json_load decoded any failed - null");
87    json_decref(json);
88}
89
90static void decode_int_as_real()
91{
92    json_t *json;
93    json_error_t error;
94
95#if JSON_INTEGER_IS_LONG_LONG
96    const char *imprecise;
97    json_int_t expected;
98#endif
99
100    json = json_loads("42", JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
101    if (!json || !json_is_real(json) || json_real_value(json) != 42.0)
102        fail("json_load decode int as real failed - int");
103    json_decref(json);
104
105#if JSON_INTEGER_IS_LONG_LONG
106    /* This number cannot be represented exactly by a double */
107    imprecise = "9007199254740993";
108    expected = 9007199254740992ll;
109
110    json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY,
111                      &error);
112    if (!json || !json_is_real(json) || expected != (json_int_t)json_real_value(json))
113        fail("json_load decode int as real failed - expected imprecision");
114    json_decref(json);
115#endif
116}
117
118static void allow_nul()
119{
120    const char *text = "\"nul byte \\u0000 in string\"";
121    const char *expected = "nul byte \0 in string";
122    size_t len = 20;
123    json_t *json;
124
125    json = json_loads(text, JSON_ALLOW_NUL | JSON_DECODE_ANY, NULL);
126    if(!json || !json_is_string(json))
127        fail("unable to decode embedded NUL byte");
128
129    if(json_string_length(json) != len)
130        fail("decoder returned wrong string length");
131
132    if(memcmp(json_string_value(json), expected, len + 1))
133        fail("decoder returned wrong string content");
134
135    json_decref(json);
136}
137
138static void load_wrong_args()
139{
140    json_t *json;
141    json_error_t error;
142
143    json = json_loads(NULL, 0, &error);
144    if (json)
145        fail("json_loads should return NULL if the first argument is NULL");
146
147    json = json_loadb(NULL, 0, 0, &error);
148    if (json)
149        fail("json_loadb should return NULL if the first argument is NULL");
150
151    json = json_loadf(NULL, 0, &error);
152    if (json)
153        fail("json_loadf should return NULL if the first argument is NULL");
154
155    json = json_load_file(NULL, 0, &error);
156    if (json)
157        fail("json_loadf should return NULL if the first argument is NULL");
158}
159
160static void position()
161{
162    json_t *json;
163    size_t flags = JSON_DISABLE_EOF_CHECK;
164    json_error_t error;
165
166    json = json_loads("{\"foo\": \"bar\"}", 0, &error);
167    if(error.position != 14)
168        fail("json_loads returned a wrong position");
169    json_decref(json);
170
171    json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error);
172    if(error.position != 14)
173        fail("json_loads returned a wrong position");
174    json_decref(json);
175}
176
177static void run_tests()
178{
179    file_not_found();
180    reject_duplicates();
181    disable_eof_check();
182    decode_any();
183    decode_int_as_real();
184    allow_nul();
185    load_wrong_args();
186    position();
187}
188