]>
Commit | Line | Data |
---|---|---|
e735f4d4 MP |
1 | /*** |
2 | This file is part of systemd. | |
3 | ||
4 | Copyright 2014 Lennart Poettering | |
5 | ||
6 | systemd is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU Lesser General Public License as published by | |
8 | the Free Software Foundation; either version 2.1 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | systemd is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public License | |
17 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
18 | ***/ | |
19 | ||
20 | #include <math.h> | |
21 | ||
db2df898 | 22 | #include "alloc-util.h" |
e735f4d4 | 23 | #include "json.h" |
db2df898 MP |
24 | #include "string-util.h" |
25 | #include "util.h" | |
e735f4d4 MP |
26 | |
27 | static void test_one(const char *data, ...) { | |
28 | void *state = NULL; | |
29 | va_list ap; | |
30 | ||
31 | va_start(ap, data); | |
32 | ||
33 | for (;;) { | |
34 | _cleanup_free_ char *str = NULL; | |
35 | union json_value v = {}; | |
36 | int t, tt; | |
37 | ||
38 | t = json_tokenize(&data, &str, &v, &state, NULL); | |
39 | tt = va_arg(ap, int); | |
40 | ||
41 | assert_se(t == tt); | |
42 | ||
43 | if (t == JSON_END || t < 0) | |
44 | break; | |
45 | ||
46 | else if (t == JSON_STRING) { | |
47 | const char *nn; | |
48 | ||
49 | nn = va_arg(ap, const char *); | |
50 | assert_se(streq_ptr(nn, str)); | |
51 | ||
52 | } else if (t == JSON_REAL) { | |
53 | double d; | |
54 | ||
55 | d = va_arg(ap, double); | |
56 | assert_se(fabs(d - v.real) < 0.001); | |
57 | ||
58 | } else if (t == JSON_INTEGER) { | |
59 | intmax_t i; | |
60 | ||
61 | i = va_arg(ap, intmax_t); | |
62 | assert_se(i == v.integer); | |
63 | ||
64 | } else if (t == JSON_BOOLEAN) { | |
65 | bool b; | |
66 | ||
67 | b = va_arg(ap, int); | |
68 | assert_se(b == v.boolean); | |
69 | } | |
70 | } | |
71 | ||
72 | va_end(ap); | |
73 | } | |
74 | ||
e3bff60a MP |
75 | typedef void (*Test)(JsonVariant *); |
76 | ||
77 | static void test_file(const char *data, Test test) { | |
78 | _cleanup_json_variant_unref_ JsonVariant *v = NULL; | |
79 | int r; | |
80 | ||
81 | r = json_parse(data, &v); | |
82 | assert_se(r == 0); | |
83 | assert_se(v != NULL); | |
84 | assert_se(v->type == JSON_VARIANT_OBJECT); | |
85 | ||
86 | if (test) | |
87 | test(v); | |
88 | } | |
89 | ||
90 | static void test_1(JsonVariant *v) { | |
91 | JsonVariant *p, *q; | |
92 | unsigned i; | |
93 | ||
94 | /* 3 keys + 3 values */ | |
95 | assert_se(v->size == 6); | |
96 | ||
97 | /* has k */ | |
98 | p = json_variant_value(v, "k"); | |
99 | assert_se(p && p->type == JSON_VARIANT_STRING); | |
100 | ||
101 | /* k equals v */ | |
102 | assert_se(streq(json_variant_string(p), "v")); | |
103 | ||
104 | /* has foo */ | |
105 | p = json_variant_value(v, "foo"); | |
106 | assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 3); | |
107 | ||
108 | /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */ | |
109 | for (i = 0; i < 3; ++i) { | |
110 | q = json_variant_element(p, i); | |
111 | assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == (i+1)); | |
112 | } | |
113 | ||
114 | /* has bar */ | |
115 | p = json_variant_value(v, "bar"); | |
116 | assert_se(p && p->type == JSON_VARIANT_OBJECT && p->size == 2); | |
117 | ||
118 | /* zap is null */ | |
119 | q = json_variant_value(p, "zap"); | |
120 | assert_se(q && q->type == JSON_VARIANT_NULL); | |
121 | } | |
122 | ||
123 | static void test_2(JsonVariant *v) { | |
124 | JsonVariant *p, *q; | |
125 | ||
126 | /* 2 keys + 2 values */ | |
127 | assert_se(v->size == 4); | |
128 | ||
129 | /* has mutant */ | |
130 | p = json_variant_value(v, "mutant"); | |
131 | assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 4); | |
132 | ||
133 | /* mutant[0] == 1 */ | |
134 | q = json_variant_element(p, 0); | |
135 | assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1); | |
136 | ||
137 | /* mutant[1] == null */ | |
138 | q = json_variant_element(p, 1); | |
139 | assert_se(q && q->type == JSON_VARIANT_NULL); | |
140 | ||
141 | /* mutant[2] == "1" */ | |
142 | q = json_variant_element(p, 2); | |
143 | assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); | |
144 | ||
145 | /* mutant[3] == JSON_VARIANT_OBJECT */ | |
146 | q = json_variant_element(p, 3); | |
147 | assert_se(q && q->type == JSON_VARIANT_OBJECT && q->size == 2); | |
148 | ||
149 | /* has 1 */ | |
150 | p = json_variant_value(q, "1"); | |
151 | assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 2); | |
152 | ||
153 | /* "1"[0] == 1 */ | |
154 | q = json_variant_element(p, 0); | |
155 | assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1); | |
156 | ||
157 | /* "1"[1] == "1" */ | |
158 | q = json_variant_element(p, 1); | |
159 | assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); | |
160 | ||
161 | /* has blah */ | |
162 | p = json_variant_value(v, "blah"); | |
163 | assert_se(p && p->type == JSON_VARIANT_REAL && fabs(json_variant_real(p) - 1.27) < 0.001); | |
164 | } | |
165 | ||
e735f4d4 MP |
166 | int main(int argc, char *argv[]) { |
167 | ||
168 | test_one("x", -EINVAL); | |
169 | test_one("", JSON_END); | |
170 | test_one(" ", JSON_END); | |
171 | test_one("0", JSON_INTEGER, (intmax_t) 0, JSON_END); | |
172 | test_one("1234", JSON_INTEGER, (intmax_t) 1234, JSON_END); | |
173 | test_one("3.141", JSON_REAL, 3.141, JSON_END); | |
174 | test_one("0.0", JSON_REAL, 0.0, JSON_END); | |
175 | test_one("7e3", JSON_REAL, 7e3, JSON_END); | |
176 | test_one("-7e-3", JSON_REAL, -7e-3, JSON_END); | |
177 | test_one("true", JSON_BOOLEAN, true, JSON_END); | |
178 | test_one("false", JSON_BOOLEAN, false, JSON_END); | |
179 | test_one("null", JSON_NULL, JSON_END); | |
180 | test_one("{}", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END); | |
181 | test_one("\t {\n} \n", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END); | |
182 | test_one("[]", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END); | |
183 | test_one("\t [] \n\n", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END); | |
184 | test_one("\"\"", JSON_STRING, "", JSON_END); | |
185 | test_one("\"foo\"", JSON_STRING, "foo", JSON_END); | |
186 | test_one("\"foo\\nfoo\"", JSON_STRING, "foo\nfoo", JSON_END); | |
187 | test_one("{\"foo\" : \"bar\"}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_STRING, "bar", JSON_OBJECT_CLOSE, JSON_END); | |
188 | test_one("{\"foo\" : [true, false]}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_ARRAY_OPEN, JSON_BOOLEAN, true, JSON_COMMA, JSON_BOOLEAN, false, JSON_ARRAY_CLOSE, JSON_OBJECT_CLOSE, JSON_END); | |
189 | test_one("\"\xef\xbf\xbd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END); | |
190 | test_one("\"\\ufffd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END); | |
191 | test_one("\"\\uf\"", -EINVAL); | |
192 | test_one("\"\\ud800a\"", -EINVAL); | |
193 | test_one("\"\\udc00\\udc00\"", -EINVAL); | |
194 | test_one("\"\\ud801\\udc37\"", JSON_STRING, "\xf0\x90\x90\xb7", JSON_END); | |
195 | ||
e3bff60a MP |
196 | test_one("[1, 2]", JSON_ARRAY_OPEN, JSON_INTEGER, (intmax_t) 1, JSON_COMMA, JSON_INTEGER, (intmax_t) 2, JSON_ARRAY_CLOSE, JSON_END); |
197 | ||
198 | test_file("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1); | |
199 | test_file("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"blah\": 1.27}", test_2); | |
200 | ||
e735f4d4 MP |
201 | return 0; |
202 | } |