VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTJson.cpp@ 74175

Last change on this file since 74175 was 74027, checked in by vboxsync, 6 years ago

IPRT/json: Implemented support for parsing floating point values. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: tstRTJson.cpp 74027 2018-09-02 14:49:45Z vboxsync $ */
2/** @file
3 * IPRT Testcase - JSON API.
4 */
5
6/*
7 * Copyright (C) 2016-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/json.h>
32#include <iprt/string.h>
33#include <iprt/test.h>
34
35static const char *g_pszJson =
36 "{\n"
37 " \"integer\": 100,\n"
38 " \"number\": 22.22,\n"
39 " \"string\": \"test\",\n"
40 " \"array\": [1, 2, 3, 4, 5, \"6\"],\n"
41 " \"subobject\":\n"
42 " {\n"
43 " \"false\": false,\n"
44 " \"true\": true,\n"
45 " \"null\": null\n"
46 " }\n"
47 "}\n";
48
49/**
50 * Some basic tests to detect malformed JSON.
51 */
52static void tstBasic(RTTEST hTest)
53{
54 RTTestSub(hTest, "Basic valid/malformed tests");
55 static struct
56 {
57 const char *pszJson;
58 int iRcResult;
59 } const aTests[] =
60 {
61 { "", VERR_JSON_MALFORMED },
62 { ",", VERR_JSON_MALFORMED },
63 { ":", VERR_JSON_MALFORMED },
64 { " \n\t{", VERR_JSON_MALFORMED },
65 { "}", VERR_JSON_MALFORMED },
66 { "[", VERR_JSON_MALFORMED },
67 { "]", VERR_JSON_MALFORMED },
68 { "[ \"test\" : ", VERR_JSON_MALFORMED },
69 { "null", VINF_SUCCESS },
70 { "true", VINF_SUCCESS },
71 { "false", VINF_SUCCESS },
72 { "100", VINF_SUCCESS },
73 { "\"test\"", VINF_SUCCESS },
74 { "{ }", VINF_SUCCESS },
75 { "[ ]", VINF_SUCCESS },
76 { "[ 100, 200 ]", VINF_SUCCESS },
77 { "{ \"1\": 1 }", VINF_SUCCESS },
78 { "{ \"1\": 1, \"2\": 2 }", VINF_SUCCESS },
79 { "20", VINF_SUCCESS },
80 { "-20", VINF_SUCCESS },
81 { "{\"positive\":20}", VINF_SUCCESS },
82 { "{\"negative\":-20}", VINF_SUCCESS },
83 };
84 for (unsigned iTest = 0; iTest < RT_ELEMENTS(aTests); iTest++)
85 {
86 RTERRINFOSTATIC ErrInfo;
87 RTJSONVAL hJsonVal = NIL_RTJSONVAL;
88 int rc = RTJsonParseFromString(&hJsonVal, aTests[iTest].pszJson, RTErrInfoInitStatic(&ErrInfo));
89 if (rc != aTests[iTest].iRcResult)
90 {
91 if (RTErrInfoIsSet(&ErrInfo.Core))
92 RTTestFailed(hTest, "RTJsonParseFromString() for \"%s\" failed, expected %Rrc got %Rrc\n%s",
93 aTests[iTest].pszJson, aTests[iTest].iRcResult, rc, ErrInfo.Core.pszMsg);
94 else
95 RTTestFailed(hTest, "RTJsonParseFromString() for \"%s\" failed, expected %Rrc got %Rrc",
96 aTests[iTest].pszJson, aTests[iTest].iRcResult, rc);
97 }
98 else if (rc == VERR_JSON_MALFORMED && !RTErrInfoIsSet(&ErrInfo.Core))
99 RTTestFailed(hTest, "RTJsonParseFromString() did not return error info for \"%s\" failed", aTests[iTest].pszJson);
100 if (RT_SUCCESS(rc))
101 {
102 if (hJsonVal != NIL_RTJSONVAL)
103 RTJsonValueRelease(hJsonVal);
104 else
105 RTTestFailed(hTest, "RTJsonParseFromString() returned success but no value\n");
106 }
107 else if (hJsonVal != NIL_RTJSONVAL)
108 RTTestFailed(hTest, "RTJsonParseFromString() failed but a JSON value was returned\n");
109 }
110}
111
112/**
113 * Checks that methods not indended for the given type return the correct error.
114 */
115static void tstCorrectnessRcForInvalidType(RTTEST hTest, RTJSONVAL hJsonVal, RTJSONVALTYPE enmType)
116{
117 bool fSavedMayPanic = RTAssertSetMayPanic(false);
118 bool fSavedQuiet = RTAssertSetQuiet(true);
119
120 if ( enmType != RTJSONVALTYPE_OBJECT
121 && enmType != RTJSONVALTYPE_ARRAY)
122 {
123 /* The iterator API should return errors. */
124 RTJSONIT hJsonIt = NIL_RTJSONIT;
125 RTTEST_CHECK_RC(hTest, RTJsonIteratorBegin(hJsonVal, &hJsonIt), VERR_JSON_VALUE_INVALID_TYPE);
126 }
127
128 if (enmType != RTJSONVALTYPE_ARRAY)
129 {
130 /* The Array access methods should return errors. */
131 uint32_t cItems = 0;
132 RTJSONVAL hJsonValItem = NIL_RTJSONVAL;
133 RTTEST_CHECK(hTest, RTJsonValueGetArraySize(hJsonVal) == 0);
134 RTTEST_CHECK_RC(hTest, RTJsonValueQueryArraySize(hJsonVal, &cItems), VERR_JSON_VALUE_INVALID_TYPE);
135 RTTEST_CHECK_RC(hTest, RTJsonValueQueryByIndex(hJsonVal, 0, &hJsonValItem), VERR_JSON_VALUE_INVALID_TYPE);
136 }
137
138 if (enmType != RTJSONVALTYPE_OBJECT)
139 {
140 /* The object access methods should return errors. */
141 RTJSONVAL hJsonValMember = NIL_RTJSONVAL;
142 RTTEST_CHECK_RC(hTest, RTJsonValueQueryByName(hJsonVal, "test", &hJsonValMember), VERR_JSON_VALUE_INVALID_TYPE);
143 }
144
145 if (enmType != RTJSONVALTYPE_INTEGER)
146 {
147 int64_t i64Num = 0;
148 RTTEST_CHECK_RC(hTest, RTJsonValueQueryInteger(hJsonVal, &i64Num), VERR_JSON_VALUE_INVALID_TYPE);
149 }
150
151 if (enmType != RTJSONVALTYPE_NUMBER)
152 {
153 double rdNum = 0.0;
154 RTTEST_CHECK_RC(hTest, RTJsonValueQueryNumber(hJsonVal, &rdNum), VERR_JSON_VALUE_INVALID_TYPE);
155 }
156
157 if (enmType != RTJSONVALTYPE_STRING)
158 {
159 const char *psz = NULL;
160 RTTEST_CHECK(hTest, RTJsonValueGetString(hJsonVal) == NULL);
161 RTTEST_CHECK_RC(hTest, RTJsonValueQueryString(hJsonVal, &psz), VERR_JSON_VALUE_INVALID_TYPE);
162 }
163
164 RTAssertSetMayPanic(fSavedMayPanic);
165 RTAssertSetQuiet(fSavedQuiet);
166}
167
168/**
169 * Tests the array accessors.
170 */
171static void tstArray(RTTEST hTest, RTJSONVAL hJsonVal)
172{
173 uint32_t cItems = 0;
174 RTTEST_CHECK(hTest, RTJsonValueGetArraySize(hJsonVal) == 6);
175 RTTEST_CHECK_RC_OK(hTest, RTJsonValueQueryArraySize(hJsonVal, &cItems));
176 RTTEST_CHECK(hTest, cItems == RTJsonValueGetArraySize(hJsonVal));
177
178 for (uint32_t i = 1; i <= 5; i++)
179 {
180 int64_t i64Num = 0;
181 RTJSONVAL hJsonValItem = NIL_RTJSONVAL;
182 RTTEST_CHECK_RC_OK_RETV(hTest, RTJsonValueQueryByIndex(hJsonVal, i - 1, &hJsonValItem));
183 RTTEST_CHECK(hTest, RTJsonValueGetType(hJsonValItem) == RTJSONVALTYPE_INTEGER);
184 RTTEST_CHECK_RC_OK_RETV(hTest, RTJsonValueQueryInteger(hJsonValItem, &i64Num));
185 RTTEST_CHECK(hTest, i64Num == (int64_t)i);
186 RTTEST_CHECK(hTest, RTJsonValueRelease(hJsonValItem) == 1);
187 }
188
189 /* Last should be string. */
190 const char *pszStr = NULL;
191 RTJSONVAL hJsonValItem = NIL_RTJSONVAL;
192 RTTEST_CHECK_RC_OK_RETV(hTest, RTJsonValueQueryByIndex(hJsonVal, 5, &hJsonValItem));
193 RTTEST_CHECK(hTest, RTJsonValueGetType(hJsonValItem) == RTJSONVALTYPE_STRING);
194 RTTEST_CHECK_RC_OK_RETV(hTest, RTJsonValueQueryString(hJsonValItem, &pszStr));
195 RTTEST_CHECK(hTest, RTJsonValueGetString(hJsonValItem) == pszStr);
196 RTTEST_CHECK(hTest, strcmp(pszStr, "6") == 0);
197 RTTEST_CHECK(hTest, RTJsonValueRelease(hJsonValItem) == 1);
198}
199
200/**
201 * Tests the iterator API for the given JSON array or object value.
202 */
203static void tstIterator(RTTEST hTest, RTJSONVAL hJsonVal)
204{
205 RTJSONIT hJsonIt = NIL_RTJSONIT;
206 int rc = RTJsonIteratorBegin(hJsonVal, &hJsonIt);
207 RTTEST_CHECK(hTest, RT_SUCCESS(rc));
208 if (RT_SUCCESS(rc))
209 {
210 const char *pszName = NULL;
211 RTJSONVAL hJsonValMember = NIL_RTJSONVAL;
212 rc = RTJsonIteratorQueryValue(hJsonIt, &hJsonValMember, &pszName);
213 RTTEST_CHECK(hTest, RT_SUCCESS(rc));
214 RTTEST_CHECK(hTest, pszName != NULL);
215 RTTEST_CHECK(hTest, hJsonValMember != NIL_RTJSONVAL);
216 while (RT_SUCCESS(rc))
217 {
218 RTJSONVALTYPE enmTypeMember = RTJsonValueGetType(hJsonValMember);
219 tstCorrectnessRcForInvalidType(hTest, hJsonValMember, enmTypeMember);
220
221 switch (enmTypeMember)
222 {
223 case RTJSONVALTYPE_OBJECT:
224 RTTEST_CHECK(hTest, strcmp(pszName, "subobject") == 0);
225 tstIterator(hTest, hJsonValMember);
226 break;
227 case RTJSONVALTYPE_ARRAY:
228 RTTEST_CHECK(hTest, strcmp(pszName, "array") == 0);
229 tstArray(hTest, hJsonValMember);
230 break;
231 case RTJSONVALTYPE_STRING:
232 {
233 RTTEST_CHECK(hTest, strcmp(pszName, "string") == 0);
234 const char *pszStr = NULL;
235 RTTEST_CHECK_RC_OK(hTest, RTJsonValueQueryString(hJsonValMember, &pszStr));
236 RTTEST_CHECK(hTest, strcmp(pszStr, "test") == 0);
237 break;
238 }
239 case RTJSONVALTYPE_INTEGER:
240 {
241 RTTEST_CHECK(hTest, strcmp(pszName, "integer") == 0);
242 int64_t i64Num = 0;
243 RTTEST_CHECK_RC_OK(hTest, RTJsonValueQueryInteger(hJsonValMember, &i64Num));
244 RTTEST_CHECK(hTest, i64Num == 100);
245 break;
246 }
247 case RTJSONVALTYPE_NUMBER:
248 {
249 RTTEST_CHECK(hTest, strcmp(pszName, "number") == 0);
250 double rdNum = 0.0;
251 RTTEST_CHECK_RC_OK(hTest, RTJsonValueQueryNumber(hJsonValMember, &rdNum));
252 double const rdExpect = 22.22;
253 RTTEST_CHECK(hTest, rdNum == rdExpect);
254 break;
255 }
256 case RTJSONVALTYPE_NULL:
257 RTTEST_CHECK(hTest, strcmp(pszName, "null") == 0);
258 break;
259 case RTJSONVALTYPE_TRUE:
260 RTTEST_CHECK(hTest, strcmp(pszName, "true") == 0);
261 break;
262 case RTJSONVALTYPE_FALSE:
263 RTTEST_CHECK(hTest, strcmp(pszName, "false") == 0);
264 break;
265 default:
266 RTTestFailed(hTest, "Invalid JSON value type %u returned\n", enmTypeMember);
267 }
268
269 RTTEST_CHECK(hTest, RTJsonValueRelease(hJsonValMember) == 1);
270 rc = RTJsonIteratorNext(hJsonIt);
271 RTTEST_CHECK(hTest, rc == VINF_SUCCESS || rc == VERR_JSON_ITERATOR_END);
272 if (RT_SUCCESS(rc))
273 RTTEST_CHECK_RC_OK(hTest, RTJsonIteratorQueryValue(hJsonIt, &hJsonValMember, &pszName));
274 }
275 RTJsonIteratorFree(hJsonIt);
276 }
277}
278
279/**
280 * Test that the parser returns the correct values for a valid JSON.
281 */
282static void tstCorrectness(RTTEST hTest)
283{
284 RTTestSub(hTest, "Correctness");
285
286 RTJSONVAL hJsonVal = NIL_RTJSONVAL;
287 RTTEST_CHECK_RC_OK_RETV(hTest, RTJsonParseFromString(&hJsonVal, g_pszJson, NULL));
288
289 if (hJsonVal != NIL_RTJSONVAL)
290 {
291 RTJSONVALTYPE enmType = RTJsonValueGetType(hJsonVal);
292 if (enmType == RTJSONVALTYPE_OBJECT)
293 {
294 /* Excercise the other non object APIs to return VERR_JSON_VALUE_INVALID_TYPE. */
295 tstCorrectnessRcForInvalidType(hTest, hJsonVal, enmType);
296 tstIterator(hTest, hJsonVal);
297 }
298 else
299 RTTestFailed(hTest, "RTJsonParseFromString() returned an invalid JSON value, expected OBJECT got %u\n", enmType);
300 RTTEST_CHECK(hTest, RTJsonValueRelease(hJsonVal) == 0);
301 }
302 else
303 RTTestFailed(hTest, "RTJsonParseFromString() returned success but no value\n");
304}
305
306int main(int argc, char **argv)
307{
308 RTTEST hTest;
309 int rc = RTTestInitExAndCreate(argc, &argv, 0, "tstRTJson", &hTest);
310 if (rc)
311 return rc;
312 RTTestBanner(hTest);
313
314 tstBasic(hTest);
315 tstCorrectness(hTest);
316 for (int i = 1; i < argc; i++)
317 {
318 RTTestSubF(hTest, "file %Rbn", argv[i]);
319 RTERRINFOSTATIC ErrInfo;
320 RTJSONVAL hFileValue = NIL_RTJSONVAL;
321 rc = RTJsonParseFromFile(&hFileValue, argv[i], RTErrInfoInitStatic(&ErrInfo));
322 if (RT_SUCCESS(rc))
323 RTJsonValueRelease(hFileValue);
324 else if (RTErrInfoIsSet(&ErrInfo.Core))
325 RTTestFailed(hTest, "%Rrc - %s", rc, ErrInfo.Core.pszMsg);
326 else
327 RTTestFailed(hTest, "%Rrc", rc);
328 }
329
330 /*
331 * Summary.
332 */
333 return RTTestSummaryAndDestroy(hTest);
334}
335
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette