fd41a44fc839f611edf6755e7036cfc6e0975af7
[buliscores] / qjson / tests / parser / testparser.cpp
1 /* This file is part of QJson
2  *
3  * Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include <QtTest/QtTest>
22
23 #include "parser.h"
24 #include "serializer.h"
25
26 #include <QtCore/QVariant>
27 #include <cmath>
28
29 class TestParser: public QObject
30 {
31   Q_OBJECT
32   private slots:
33     void parseNonAsciiString();
34     void parseSimpleObject();
35     void parseEmptyObject();
36     void parseEmptyValue();
37     void parseUrl();
38     void parseMultipleObject();
39
40     void parseSimpleArray();
41     void parseInvalidObject();
42     void parseInvalidObject_data();
43     void parseMultipleArray();
44
45     void testTrueFalseNullValues();
46     void testEscapeChars();
47     void testNumbers();
48     void testNumbers_data();
49     void testTopLevelValues();
50     void testTopLevelValues_data();
51     void testSpecialNumbers();
52     void testSpecialNumbers_data();
53     void testReadWrite();
54     void testReadWrite_data();
55 };
56
57 Q_DECLARE_METATYPE(QVariant)
58 Q_DECLARE_METATYPE(QVariant::Type)
59
60 using namespace QJson;
61
62 void TestParser::parseSimpleObject() {
63   QByteArray json = "{\"foo\":\"bar\"}";
64   QVariantMap map;
65   map.insert (QLatin1String("foo"), QLatin1String("bar"));
66   QVariant expected(map);
67
68   Parser parser;
69   bool ok;
70   QVariant result = parser.parse (json, &ok);
71   QVERIFY (ok);
72   QCOMPARE(result, expected);
73 }
74
75 void TestParser::parseEmptyObject() {
76   QByteArray json = "{}";
77   QVariantMap map;
78   QVariant expected (map);
79
80   Parser parser;
81   bool ok;
82   QVariant result = parser.parse (json, &ok);
83   QVERIFY (ok);
84   QCOMPARE(result, expected);
85 }
86
87 void TestParser::parseEmptyValue() {
88   QByteArray json = "{\"value\": \"\"}";
89
90   QVariantMap map;
91   map.insert (QLatin1String("value"), QString(QLatin1String("")));
92   QVariant expected (map);
93
94   Parser parser;
95   bool ok;
96   QVariant result = parser.parse (json, &ok);
97   QVERIFY (ok);
98   QCOMPARE(result, expected);
99   QVERIFY (result.toMap().value(QLatin1String("value")).type() == QVariant::String);
100
101   QString value = result.toMap().value(QLatin1String("value")).toString();
102   QVERIFY (value.isEmpty());
103 }
104
105 void TestParser::parseInvalidObject() {
106   QFETCH(QByteArray, json);
107
108   Parser parser;
109   bool ok;
110   QVariant result = parser.parse (json, &ok);
111   QVERIFY (!ok);
112 }
113
114 void TestParser::parseInvalidObject_data() {
115   QTest::addColumn<QByteArray>("json");
116
117   QTest::newRow("unclosed object") <<  QByteArray("{\"foo\":\"bar\"");
118   QTest::newRow("infinum (disallow") << QByteArray("Infinum");
119   QTest::newRow("Nan (disallow") << QByteArray("NaN");
120 }
121
122
123 void TestParser::parseNonAsciiString() {
124   QByteArray json = "{\"artist\":\"Queensr\\u00ffche\"}";
125   QVariantMap map;
126
127   QChar unicode_char (0x00ff);
128   QString unicode_string;
129   unicode_string.setUnicode(&unicode_char, 1);
130   unicode_string = QLatin1String("Queensr") + unicode_string + QLatin1String("che");
131
132   map.insert (QLatin1String("artist"), unicode_string);
133   QVariant expected (map);
134
135   Parser parser;
136   bool ok;
137   QVariant result = parser.parse (json, &ok);
138   QVERIFY (ok);
139   QCOMPARE(result, expected);
140 }
141
142 void TestParser::parseMultipleObject() {
143   //put also some extra spaces inside the json string
144   QByteArray json = "{ \"foo\":\"bar\",\n\"number\" : 51.3 , \"array\":[\"item1\", 123]}";
145   QVariantMap map;
146   map.insert (QLatin1String("foo"), QLatin1String("bar"));
147   map.insert (QLatin1String("number"), 51.3);
148   QVariantList list;
149   list.append (QLatin1String("item1"));
150   list.append (QLatin1String("123"));
151   map.insert (QLatin1String("array"), list);
152   QVariant expected (map);
153
154   Parser parser;
155   bool ok;
156   QVariant result = parser.parse (json, &ok);
157   QVERIFY (ok);
158   QCOMPARE(result, expected);
159   QVERIFY (result.toMap().value(QLatin1String("number")).canConvert<float>());
160   QVERIFY (result.toMap().value(QLatin1String("array")).canConvert<QVariantList>());
161 }
162
163 void TestParser::parseUrl(){
164   //"http:\/\/www.last.fm\/venue\/8926427"
165   QByteArray json = "[\"http:\\/\\/www.last.fm\\/venue\\/8926427\"]";
166   QVariantList list;
167   list.append (QVariant(QLatin1String("http://www.last.fm/venue/8926427")));
168   QVariant expected (list);
169
170   Parser parser;
171   bool ok;
172   QVariant result = parser.parse (json, &ok);
173   QVERIFY (ok);
174   QCOMPARE(result, expected);
175 }
176
177  void TestParser::parseSimpleArray() {
178   QByteArray json = "[\"foo\",\"bar\"]";
179   QVariantList list;
180   list.append (QLatin1String("foo"));
181   list.append (QLatin1String("bar"));
182   QVariant expected (list);
183
184   Parser parser;
185   bool ok;
186   QVariant result = parser.parse (json, &ok);
187   QVERIFY (ok);
188   QCOMPARE(result, expected);
189 }
190
191 void TestParser::parseMultipleArray() {
192   //put also some extra spaces inside the json string
193   QByteArray json = "[ {\"foo\":\"bar\"},\n\"number\",51.3 , [\"item1\", 123]]";
194   QVariantMap map;
195   map.insert (QLatin1String("foo"), QLatin1String("bar"));
196
197   QVariantList array;
198   array.append (QLatin1String("item1"));
199   array.append (123);
200
201   QVariantList list;
202   list.append (map);
203   list.append (QLatin1String("number"));
204   list.append (QLatin1String("51.3"));
205   list.append ((QVariant) array);
206
207   QVariant expected (list);
208
209   Parser parser;
210   bool ok;
211   QVariant result = parser.parse (json, &ok);
212   QVERIFY (ok);
213   QCOMPARE(result, expected);
214 }
215
216 void TestParser::testTrueFalseNullValues() {
217   QByteArray json = "[true,false, null, {\"foo\" : true}]";
218   QVariantList list;
219   list.append (QVariant(true));
220   list.append (QVariant(false));
221   list.append (QVariant());
222   QVariantMap map;
223   map.insert (QLatin1String("foo"), true);
224   list.append (map);
225   QVariant expected (list);
226
227   Parser parser;
228   bool ok;
229   QVariant result = parser.parse (json, &ok);
230   QVERIFY (ok);
231   QCOMPARE(result, expected);
232   QCOMPARE (result.toList().at(0).toBool(), true);
233   QCOMPARE (result.toList().at(1).toBool(), false);
234   QVERIFY (result.toList().at(2).isNull());
235 }
236
237 void TestParser::testEscapeChars() {
238   QByteArray json = "[\"\\b \\f \\n \\r \\t \", \" \\\\ \\/ \\\\\", \"http:\\/\\/foo.com\"]";
239
240   QVariantList list;
241   list.append (QLatin1String("\b \f \n \r \t "));
242   list.append (QLatin1String(" \\ / \\"));
243   list.append (QLatin1String("http://foo.com"));
244
245   QVariant expected (list);
246
247   Parser parser;
248   bool ok;
249   QVariant result = parser.parse (json, &ok);
250   QVERIFY (ok);
251   QCOMPARE(result.toList().size(), expected.toList().size() );
252   QCOMPARE(result, expected);
253 }
254
255 void TestParser::testNumbers() {
256   QFETCH(QByteArray, input);
257   QFETCH(QVariant, expected);
258   QFETCH(QVariant::Type, type);
259
260   Parser parser;
261   bool ok;
262   QVariant result = parser.parse ("[" + input +"]", &ok);
263   QVERIFY (ok);
264
265   QVariant value = result.toList().at(0);
266   QCOMPARE(value, expected);
267   QCOMPARE( value.type(), type);
268 }
269
270 void TestParser::testNumbers_data() {
271   QTest::addColumn<QByteArray>( "input" );
272   QTest::addColumn<QVariant>( "expected" );
273   QTest::addColumn<QVariant::Type>( "type" );
274
275   QByteArray input;
276   QVariant output;
277
278   // simple ulonglong
279   input = QByteArray("1");
280   output = QVariant(QVariant::ULongLong);
281   output.setValue(1);
282
283   QTest::newRow("simple ulonglong") << input << output << QVariant::ULongLong;
284
285   // big number
286   input = QByteArray("12345678901234567890");
287   output = QVariant(QVariant::ULongLong);
288   output.setValue(12345678901234567890ull);
289
290   QTest::newRow("big number") << input << output << QVariant::ULongLong;
291
292   // simple double
293   input = QByteArray("2.004");
294   output = QVariant(QVariant::Double);
295   output.setValue(2.004);
296
297   QTest::newRow("simple double") << input << output << QVariant::Double;
298
299   // negative int
300   input = QByteArray("-100");
301   output = QVariant(QVariant::LongLong);
302   output.setValue(-100);
303
304   QTest::newRow("negative int") << input << output << QVariant::LongLong;
305
306   // negative double
307   input = QByteArray("-3.4");
308   output = QVariant(QVariant::Double);
309   output.setValue(-3.4);
310
311   QTest::newRow("negative double") << input << output << QVariant::Double;
312
313   // exp1
314   input = QByteArray("-5e+");
315   output = QVariant(QVariant::ByteArray);
316   output.setValue(input);
317
318   QTest::newRow("exp1") << input << output << QVariant::ByteArray;
319
320   // exp2
321   input = QByteArray("2e");
322   output = QVariant(QVariant::ByteArray);
323   output.setValue(input);
324
325   QTest::newRow("exp2") << input << output << QVariant::ByteArray;
326
327   // exp3
328   input = QByteArray("3e+");
329   output = QVariant(QVariant::ByteArray);
330   output.setValue(input);
331
332   QTest::newRow("exp3") << input << output << QVariant::ByteArray;
333
334   // exp4
335   input = QByteArray("4.3E");
336   output = QVariant(QVariant::ByteArray);
337   output.setValue(input);
338
339   QTest::newRow("exp4") << input << output << QVariant::ByteArray;
340
341   // exp5
342   input = QByteArray("5.4E-");
343   output = QVariant(QVariant::ByteArray);
344   output.setValue(input);
345
346   QTest::newRow("exp5") << input << output << QVariant::ByteArray;
347 }
348
349 void TestParser::testTopLevelValues() {
350   QFETCH(QByteArray, input);
351   QFETCH(QVariant, expected);
352   QFETCH(QVariant::Type, type);
353
354   Parser parser;
355   bool ok;
356   QVariant result = parser.parse (input, &ok);
357   QVERIFY (ok);
358
359   QCOMPARE(result, expected);
360   QCOMPARE(result.type(), type);
361 }
362
363 void TestParser::testTopLevelValues_data() {
364   QTest::addColumn<QByteArray>( "input" );
365   QTest::addColumn<QVariant>( "expected" );
366   QTest::addColumn<QVariant::Type>( "type" );
367
368   QByteArray input;
369   QVariant output;
370
371   // string
372   input = QByteArray("\"foo bar\"");
373   output = QVariant(QLatin1String("foo bar"));
374   QTest::newRow("string") << input << output << QVariant::String;
375
376   // number
377   input = QByteArray("2.4");
378   output = QVariant(QVariant::Double);
379   output.setValue(2.4);
380   QTest::newRow("simple double") << input << output << QVariant::Double;
381
382   // boolean
383   input = QByteArray("true");
384   output = QVariant(QVariant::Bool);
385   output.setValue(true);
386   QTest::newRow("bool") << input << output << QVariant::Bool;
387
388   // null
389   input = QByteArray("null");
390   output = QVariant();
391   QTest::newRow("null") << input << output << QVariant::Invalid;
392
393   // array
394   input = QByteArray("[1,2,3]");
395   QVariantList list;
396   list << QVariant(1) << QVariant(2) << QVariant(3);
397   output = QVariant(QVariant::List);
398   output.setValue(list);
399   QTest::newRow("array") << input << output << QVariant::List;
400
401   // object
402   input = QByteArray("{\"foo\" : \"bar\"}");
403   QVariantMap map;
404   map.insert(QLatin1String("foo"), QLatin1String("bar"));
405   output = QVariant(QVariant::Map);
406   output.setValue(map);
407   QTest::newRow("object") << input << output << QVariant::Map;
408 }
409
410 void TestParser::testSpecialNumbers() {
411   QFETCH(QByteArray, input);
412   QFETCH(bool, isOk);
413   QFETCH(bool, isInfinity);
414   QFETCH(bool, isNegative);
415   QFETCH(bool, isNan);
416
417   Parser parser;
418   QVERIFY(!parser.specialNumbersAllowed());
419   parser.allowSpecialNumbers(true);
420   QVERIFY(parser.specialNumbersAllowed());
421   bool ok;
422   QVariant value = parser.parse(input, &ok);
423   QCOMPARE(ok, isOk);
424   QVERIFY(value.type() == QVariant::Double);
425   if (ok) {
426     double v = value.toDouble();
427 #ifdef Q_OS_SYMBIAN
428     QCOMPARE(bool(isinf(v)), isInfinity);
429 #else
430 // skip this test for MSVC, because there is no "isinf" function.
431 #ifndef Q_CC_MSVC
432     QCOMPARE(bool(std::isinf(v)), isInfinity);
433 #endif
434 #endif
435     QCOMPARE(v<0, isNegative);
436 #ifdef Q_OS_SYMBIAN
437     QCOMPARE(bool(isnan(v)), isNan);
438 #else
439 // skip this test for MSVC, because there is no "isinf" function.
440 #ifndef Q_CC_MSVC
441     QCOMPARE(bool(std::isnan(v)), isNan);
442 #endif
443 #endif
444   }
445 }
446 void TestParser::testSpecialNumbers_data() {
447   QTest::addColumn<QByteArray>("input");
448   QTest::addColumn<bool>("isOk");
449   QTest::addColumn<bool>("isInfinity");
450   QTest::addColumn<bool>("isNegative");
451   QTest::addColumn<bool>("isNan");
452
453   QTest::newRow("42.0") << QByteArray("42.0") << true << false << false << false;
454   QTest::newRow("0.0") << QByteArray("0.0") << true << false << false << false;
455   QTest::newRow("-42.0") << QByteArray("-42.0") << true << false << true << false;
456   QTest::newRow("Infinity") << QByteArray("Infinity") << true << true << false << false;
457   QTest::newRow("-Infinity") << QByteArray("-Infinity") << true << true << true << false;
458   QTest::newRow("NaN") << QByteArray("NaN") << true << false << false << true;
459 }
460
461 void TestParser::testReadWrite()
462 {
463   QFETCH( QVariant, variant );
464   Serializer serializer;
465   bool ok;
466   
467   QByteArray json = serializer.serialize(variant);
468   QVERIFY(!json.isNull());
469
470   Parser parser;
471   QVariant result = parser.parse( json, &ok );
472   QVERIFY(ok);
473   QCOMPARE( result, variant );
474 }
475
476 void TestParser::testReadWrite_data()
477 {
478     QTest::addColumn<QVariant>( "variant" );
479
480     // array tests
481     QTest::newRow( "empty array" ) << QVariant(QVariantList());
482     
483     // basic array
484     QVariantList list;
485     list << QString(QLatin1String("hello"));
486     list << 12; 
487     QTest::newRow( "basic array" ) << QVariant(list);
488
489     // simple map 
490     QVariantMap map;
491     map[QString(QLatin1String("Name"))] = 32;
492     QTest::newRow( "complicated array" ) << QVariant(map);
493 }
494
495 QTEST_MAIN(TestParser)
496
497 #ifdef QMAKE_BUILD
498   #include "testparser.moc"
499 #else
500   #include "moc_testparser.cxx"
501 #endif