Initial commit.

This commit is contained in:
Jonas Kvinge
2018-02-27 18:06:05 +01:00
parent 85d9664df7
commit b2b1ba7abe
1393 changed files with 177311 additions and 1 deletions

1
3rdparty/qjson/tests/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Makefile

15
3rdparty/qjson/tests/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,15 @@
IF (Qt5Core_FOUND)
FIND_PACKAGE( Qt5Test REQUIRED )
INCLUDE_DIRECTORIES(${Qt5Test_INCLUDE_DIRS})
ADD_DEFINITIONS(${Qt5Test_DEFINITIONS})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Test_EXECUTABLE_COMPILE_FLAGS}")
SET (TEST_LIBRARIES ${Qt5Test_LIBRARIES})
ENDIF()
ADD_SUBDIRECTORY(cmdline_tester)
ADD_SUBDIRECTORY(parser)
ADD_SUBDIRECTORY(scanner)
ADD_SUBDIRECTORY(qobjecthelper)
ADD_SUBDIRECTORY(serializer)

View File

@@ -0,0 +1,38 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
parsingbenchmark
qlocalevsstrtod_l
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
ADD_EXECUTABLE(
${test}
${test}.cpp
)
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson${QJSON_SUFFIX}
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@@ -0,0 +1,55 @@
/* This file is part of QJson
*
* Copyright (C) 2014 Sune Vuorela <sune@ange.dk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QJson/Parser>
#include <QJson/Serializer>
#include <QtTest/QTest>
#include <QFile>
class ParsingBenchmark: public QObject {
Q_OBJECT
private Q_SLOTS:
void benchmark();
};
void ParsingBenchmark::benchmark() {
QString path = QFINDTESTDATA("largefile.json");
QVERIFY(QFile::exists(path));
QFile f(path);
QVERIFY(f.open(QIODevice::ReadOnly));
QByteArray data = f.readAll();
QVariant result;
QJson::Parser parser;
QBENCHMARK {
result = parser.parse(data);
}
Q_UNUSED(result);
}
QTEST_MAIN(ParsingBenchmark)
#include "parsingbenchmark.moc"

View File

@@ -0,0 +1,70 @@
/* This file is part of QJson
*
* Copyright (C) 2014 Sune Vuorela <sune@ange.dk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QObject>
#include <QtTest>
#include <locale.h>
class QLocaleVsStrtod_l : public QObject {
Q_OBJECT
private Q_SLOTS:
void benchmark();
void benchmark_data();
};
void QLocaleVsStrtod_l::benchmark() {
QFETCH(bool, useQLocale);
QList<char*> l;
l << strdup("0.123") << strdup("0.947834") << strdup("8.8373") << strdup("884.82921");
double result;
if(useQLocale) {
QLocale c(QLocale::C);
QBENCHMARK {
Q_FOREACH(const char* str, l) {
result = c.toDouble(QString(str));
}
}
} else {
locale_t c = newlocale(LC_NUMERIC_MASK, "C", NULL);
QBENCHMARK {
Q_FOREACH(const char* str, l) {
result = strtod_l(str, NULL, c);
}
}
}
Q_FOREACH(char* str, l) {
free(str);
}
}
void QLocaleVsStrtod_l::benchmark_data() {
QTest::addColumn<bool>("useQLocale");
QTest::newRow("using QLocale") << true;
QTest::newRow("using strtod_l") << false;
}
QTEST_MAIN(QLocaleVsStrtod_l);
#include "qlocalevsstrtod_l.moc"

View File

@@ -0,0 +1,4 @@
Makefile
*.o
*.moc
cmdline_tester

View File

@@ -0,0 +1,35 @@
##### Probably don't want to edit below this line #####
IF (WIN32 AND Qt5Core_FOUND)
FIND_PACKAGE( Qt5Widgets REQUIRED )
INCLUDE_DIRECTORIES(${Qt5Widgets_INCLUDE_DIRS})
ADD_DEFINITIONS(${Qt5Widgets_DEFINITIONS})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
ENDIF()
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
ADD_EXECUTABLE(
cmdline_tester
cmdline_tester.cpp
cmdlineparser.cpp
)
TARGET_LINK_LIBRARIES(
cmdline_tester
${QT_LIBRARIES}
${Qt5Widgets_LIBRARIES}
qjson${QJSON_SUFFIX}
)

View File

@@ -0,0 +1,99 @@
/* This file is part of QJson
*
* Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtCore/QTextCodec>
#include <QtCore/QTime>
#include <QJson/Parser>
#include <QJson/Serializer>
#include "cmdlineparser.h"
using namespace QJson;
int main(int argc, char *argv[]) {
QCoreApplication app (argc, argv);
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForCStrings(codec);
#endif
QTime time;
int duration;
CmdLineParser cmd (app.arguments());
CmdLineParser::Result res = cmd.parse();
if (res == CmdLineParser::Help)
return 0;
else if (res == CmdLineParser::Error)
return -1;
QString filename = cmd.file();
if (!QFile::exists ( filename )) {
qCritical ("The file you specified doesn't exist!");
exit (1);
}
Parser parser;
bool ok;
QFile file (filename);
time.start();
QVariant data = parser.parse (&file, &ok);
duration = time.elapsed();
if (!ok) {
qCritical("%s:%i - Error: %s", filename.toLatin1().data(), parser.errorLine(), qPrintable(parser.errorString()));
exit (1);
}
else {
qDebug() << "Parsing of" << filename << "took" << duration << "ms";
if (!cmd.quiet())
qDebug() << data;
}
if (cmd.serialize()) {
// serializer tests
qDebug() << "Serializing... ";
QJson::Serializer serializer;
serializer.setIndentMode(cmd.indentationMode());
time.start();
QByteArray b = serializer.serialize(data, &ok);
if (!ok) {
qCritical() << "Serialization failed:" << serializer.errorMessage();
exit(1);
} else {
duration = time.elapsed();
qDebug() << "Serialization took:" << duration << "ms";
if (!cmd.quiet())
qDebug() << b;
}
}
qDebug() << "JOB DONE, BYE";
return 0;
}

View File

@@ -0,0 +1,170 @@
/* This file is part of qjson
*
* Copyright (C) 2010 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <QtCore/QStringBuilder>
#ifdef Q_OS_WIN
//using Qt5
#ifdef QT_WIDGETS_LIB
#include <QtWidgets/QMessageBox>
#else
//using Qt4
#include <QtGui/QMessageBox>
#endif
#endif
#include "cmdlineparser.h"
using namespace QJson;
const QString CmdLineParser::m_helpMessage = QLatin1String(
"Usage: cmdline_tester [options] file\n\n"
"This program converts the json data read from 'file' to a QVariant object.\n"
"--quiet Do not print output generated by parser and serializer.\n"
"--serialize Parses the QVariant object back to json.\n"
"--indent Sets the indentation level used by the 'serialize' option.\n"
" Allowed values:\n"
" - none [default]\n"
" - compact\n"
" - minimum\n"
" - medium\n"
" - full\n"
"--help Displays this help.\n"
);
CmdLineParser::CmdLineParser(const QStringList &arguments)
: m_pos(0),
m_indentationMode(IndentNone),
m_serialize(false),
m_quiet(false)
{
for (int i = 1; i < arguments.count(); ++i) {
const QString &arg = arguments.at(i);
m_arguments.append(arg);
}
}
CmdLineParser::Result CmdLineParser::parse()
{
bool showHelp = false;
while (m_error.isEmpty() && hasMoreArgs()) {
const QString &arg = nextArg();
if (arg.toLower() == QLatin1String("--indent"))
handleSetIndentationMode();
else if (arg.toLower() == QLatin1String("--help"))
showHelp = true;
else if (arg.toLower() == QLatin1String("--serialize"))
m_serialize = true;
else if (arg.toLower() == QLatin1String("--quiet"))
m_quiet = true;
else if (!arg.startsWith(QLatin1String("--")))
m_file = arg;
else
m_error = QString(QLatin1String("Unknown option: %1")).arg(arg);
}
if (m_file.isEmpty()) {
m_error = QLatin1String("You have to specify the file containing the json data.");
}
if (!m_error.isEmpty()) {
showMessage(m_error + QLatin1String("\n\n\n") + m_helpMessage, true);
return Error;
} else if (showHelp) {
showMessage(m_helpMessage, false);
return Help;
}
return Ok;
}
bool CmdLineParser::hasMoreArgs() const
{
return m_pos < m_arguments.count();
}
const QString &CmdLineParser::nextArg()
{
Q_ASSERT(hasMoreArgs());
return m_arguments.at(m_pos++);
}
void CmdLineParser::handleSetIndentationMode()
{
if (hasMoreArgs()) {
const QString &indentationMode = nextArg();
if (indentationMode.compare(QLatin1String("none"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentNone;
else if (indentationMode.compare(QLatin1String("compact"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentCompact;
else if (indentationMode.compare(QLatin1String("minimum"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentMinimum;
else if (indentationMode.compare(QLatin1String("medium"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentMedium;
else if (indentationMode.compare(QLatin1String("full"), Qt::CaseInsensitive) == 0)
m_indentationMode = IndentFull;
else
m_error = QString(QLatin1String("Unknown indentation mode '%1'.")).
arg(indentationMode);
} else {
m_error = QLatin1String("Missing indentation level.");
}
}
void CmdLineParser::showMessage(const QString &msg, bool error)
{
#ifdef Q_OS_WIN
QString message = QLatin1String("<pre>") % msg % QLatin1String("</pre>");
if (error)
QMessageBox::critical(0, QLatin1String("Error"), message);
else
QMessageBox::information(0, QLatin1String("Notice"), message);
#else
fprintf(error ? stderr : stdout, "%s\n", qPrintable(msg));
#endif
}
void CmdLineParser::setIndentationMode(const IndentMode &mode)
{
m_indentationMode = mode;
}
IndentMode CmdLineParser::indentationMode() const
{
return m_indentationMode;
}
QString CmdLineParser::file() const
{
return m_file;
}
bool CmdLineParser::serialize()
{
return m_serialize;
}
bool CmdLineParser::quiet()
{
return m_quiet;
}

View File

@@ -0,0 +1,64 @@
/* This file is part of qjson
*
* Copyright (C) 2010 Flavio Castelli <flavio@castelli.name>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef CMDLINEPARSER_H
#define CMDLINEPARSER_H
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QJson/Serializer>
namespace QJson {
class CmdLineParser
{
public:
enum Result {Ok, Help, Error};
CmdLineParser(const QStringList &arguments);
Result parse();
void setIndentationMode(const IndentMode &mode);
IndentMode indentationMode() const;
QString helpFile() const;
QString file() const;
bool serialize();
bool quiet();
void showMessage(const QString &msg, bool error);
private:
bool hasMoreArgs() const;
const QString &nextArg();
void handleSetIndentationMode();
QStringList m_arguments;
int m_pos;
IndentMode m_indentationMode;
QString m_file;
bool m_serialize;
bool m_quiet;
static const QString m_helpMessage;
QString m_error;
};
}
#endif

View File

@@ -0,0 +1,22 @@
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

View File

@@ -0,0 +1,4 @@
Makefile
*.o
*.moc
parser

View File

@@ -0,0 +1,46 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
testparser
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson${QJSON_SUFFIX}
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@@ -0,0 +1,477 @@
/* This file is part of QJson
*
* Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <cmath>
#include <QtCore/QVariant>
#include <QtTest/QtTest>
#include <QJson/Parser>
#include <QJson/Serializer>
#include <QLocale>
class TestParser: public QObject
{
Q_OBJECT
private slots:
void parseInvalidEmptyJson();
void parseInvalidEmptyJson_data();
void parseNonAsciiString();
void parseSimpleObject();
void parseEmptyObject();
void parseEmptyValue();
void parseUrl();
void parseMultipleObject();
void parseSimpleArray();
void parseInvalidObject();
void parseInvalidObject_data();
void parseMultipleArray();
void reuseSameParser();
void testTrueFalseNullValues();
void testEscapeChars();
void testNumbers();
void testNumbers_data();
void testDoubleParsingWithDifferentLocale();
void testTopLevelValues();
void testTopLevelValues_data();
void testReadWrite();
void testReadWrite_data();
};
Q_DECLARE_METATYPE(QVariant)
Q_DECLARE_METATYPE(QVariant::Type)
using namespace QJson;
void TestParser::parseInvalidEmptyJson()
{
QFETCH(QByteArray, json);
Parser parser;
bool ok;
QVariant result = parser.parse(json, &ok);
QVERIFY(!ok);
QVERIFY(!parser.errorString().isEmpty());
}
void TestParser::parseInvalidEmptyJson_data()
{
QTest::addColumn<QByteArray>("json");
QTest::newRow("empty") << QByteArray("");
QTest::newRow("empty with spaces") << QByteArray(" \n");
}
void TestParser::parseSimpleObject() {
QByteArray json = "{\"foo\":\"bar\"}";
QVariantMap map;
map.insert (QLatin1String("foo"), QLatin1String("bar"));
QVariant expected(map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseEmptyObject() {
QByteArray json = "{}";
QVariantMap map;
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseEmptyValue() {
QByteArray json = "{\"value\": \"\"}";
QVariantMap map;
map.insert (QLatin1String("value"), QString(QLatin1String("")));
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QVERIFY (result.toMap().value(QLatin1String("value")).type() == QVariant::String);
QString value = result.toMap().value(QLatin1String("value")).toString();
QVERIFY (value.isEmpty());
}
void TestParser::parseInvalidObject() {
QFETCH(QByteArray, json);
Parser parser;
bool ok;
parser.parse (json, &ok);
QVERIFY (!ok);
QVERIFY(!parser.errorString().isEmpty());
}
void TestParser::parseInvalidObject_data() {
QTest::addColumn<QByteArray>("json");
QTest::newRow("unclosed object") << QByteArray("{\"foo\":\"bar\"");
QTest::newRow("infinum (disallow") << QByteArray("Infinum");
QTest::newRow("Nan (disallow") << QByteArray("NaN");
QTest::newRow("no data") << QByteArray("");
}
void TestParser::parseNonAsciiString() {
QByteArray json = "{\"artist\":\"Queensr\\u00ffche\"}";
QVariantMap map;
QChar unicode_char (0x00ff);
QString unicode_string;
unicode_string.setUnicode(&unicode_char, 1);
unicode_string = QLatin1String("Queensr") + unicode_string + QLatin1String("che");
map.insert (QLatin1String("artist"), unicode_string);
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseMultipleObject() {
//put also some extra spaces inside the json string
QByteArray json = "{ \"foo\":\"bar\",\n\"number\" : 51.3 , \"array\":[\"item1\", 123]}";
QVariantMap map;
map.insert (QLatin1String("foo"), QLatin1String("bar"));
map.insert (QLatin1String("number"), 51.3);
QVariantList list;
list.append (QLatin1String("item1"));
list.append (QLatin1String("123"));
map.insert (QLatin1String("array"), list);
QVariant expected (map);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QVERIFY (result.toMap().value(QLatin1String("number")).canConvert<float>());
QVERIFY (result.toMap().value(QLatin1String("array")).canConvert<QVariantList>());
}
void TestParser::parseUrl(){
//"http:\/\/www.last.fm\/venue\/8926427"
QByteArray json = "[\"http:\\/\\/www.last.fm\\/venue\\/8926427\"]";
QVariantList list;
list.append (QVariant(QLatin1String("http://www.last.fm/venue/8926427")));
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseSimpleArray() {
QByteArray json = "[\"foo\",\"bar\"]";
QVariantList list;
list.append (QLatin1String("foo"));
list.append (QLatin1String("bar"));
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::parseMultipleArray() {
//put also some extra spaces inside the json string
QByteArray json = "[ {\"foo\":\"bar\"},\n\"number\",51.3 , [\"item1\", 123]]";
QVariantMap map;
map.insert (QLatin1String("foo"), QLatin1String("bar"));
QVariantList array;
array.append (QLatin1String("item1"));
array.append (123);
QVariantList list;
list.append (map);
list.append (QLatin1String("number"));
list.append (QLatin1String("51.3"));
list.append ((QVariant) array);
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
}
void TestParser::testTrueFalseNullValues() {
QByteArray json = "[true,false, null, {\"foo\" : true}]";
QVariantList list;
list.append (QVariant(true));
list.append (QVariant(false));
list.append (QVariant());
QVariantMap map;
map.insert (QLatin1String("foo"), true);
list.append (map);
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QCOMPARE (result.toList().at(0).toBool(), true);
QCOMPARE (result.toList().at(1).toBool(), false);
QVERIFY (result.toList().at(2).isNull());
}
void TestParser::testEscapeChars() {
QByteArray json = "[\"\\b \\f \\n \\r \\t \", \" \\\\ \\/ \\\\\", \"http:\\/\\/foo.com\"]";
QVariantList list;
list.append (QLatin1String("\b \f \n \r \t "));
list.append (QLatin1String(" \\ / \\"));
list.append (QLatin1String("http://foo.com"));
QVariant expected (list);
Parser parser;
bool ok;
QVariant result = parser.parse (json, &ok);
QVERIFY (ok);
QCOMPARE(result.toList().size(), expected.toList().size() );
QCOMPARE(result, expected);
}
void TestParser::testNumbers() {
QFETCH(QByteArray, input);
QFETCH(QVariant, expected);
QFETCH(QVariant::Type, type);
Parser parser;
bool ok;
QVariant result = parser.parse ('[' + input + ']', &ok);
QVERIFY (ok);
QVariant value = result.toList().at(0);
QCOMPARE(value, expected);
QCOMPARE( value.type(), type);
}
void TestParser::testNumbers_data() {
QTest::addColumn<QByteArray>( "input" );
QTest::addColumn<QVariant>( "expected" );
QTest::addColumn<QVariant::Type>( "type" );
QByteArray input;
QVariant output;
// simple ulonglong
input = QByteArray("1");
output = QVariant(QVariant::ULongLong);
output.setValue(1);
QTest::newRow("simple ulonglong") << input << output << QVariant::ULongLong;
// big number
input = QByteArray("12345678901234567890");
output = QVariant(QVariant::ULongLong);
output.setValue(12345678901234567890ull);
QTest::newRow("big number") << input << output << QVariant::ULongLong;
// simple double
input = QByteArray("2.004");
output = QVariant(QVariant::Double);
output.setValue(2.004);
QTest::newRow("simple double") << input << output << QVariant::Double;
// negative int
input = QByteArray("-100");
output = QVariant(QVariant::LongLong);
output.setValue(-100);
QTest::newRow("negative int") << input << output << QVariant::LongLong;
// negative double
input = QByteArray("-3.4");
output = QVariant(QVariant::Double);
output.setValue(-3.4);
QTest::newRow("negative double") << input << output << QVariant::Double;
}
void TestParser::testTopLevelValues() {
QFETCH(QByteArray, input);
QFETCH(QVariant, expected);
QFETCH(QVariant::Type, type);
Parser parser;
bool ok;
QVariant result = parser.parse (input, &ok);
QVERIFY (ok);
QCOMPARE(result, expected);
QCOMPARE(result.type(), type);
}
void TestParser::testTopLevelValues_data() {
QTest::addColumn<QByteArray>( "input" );
QTest::addColumn<QVariant>( "expected" );
QTest::addColumn<QVariant::Type>( "type" );
QByteArray input;
QVariant output;
// string
input = QByteArray("\"foo bar\"");
output = QVariant(QLatin1String("foo bar"));
QTest::newRow("string") << input << output << QVariant::String;
// number
input = QByteArray("2.4");
output = QVariant(QVariant::Double);
output.setValue(2.4);
QTest::newRow("simple double") << input << output << QVariant::Double;
// boolean
input = QByteArray("true");
output = QVariant(QVariant::Bool);
output.setValue(true);
QTest::newRow("bool") << input << output << QVariant::Bool;
// null
input = QByteArray("null");
output = QVariant();
QTest::newRow("null") << input << output << QVariant::Invalid;
// array
input = QByteArray("[1,2,3]");
QVariantList list;
list << QVariant(1) << QVariant(2) << QVariant(3);
output = QVariant(QVariant::List);
output.setValue(list);
QTest::newRow("array") << input << output << QVariant::List;
// object
input = QByteArray("{\"foo\" : \"bar\"}");
QVariantMap map;
map.insert(QLatin1String("foo"), QLatin1String("bar"));
output = QVariant(QVariant::Map);
output.setValue(map);
QTest::newRow("object") << input << output << QVariant::Map;
}
void TestParser::testDoubleParsingWithDifferentLocale() {
QLocale oldLocale;
QLocale itLocale(QLatin1String("it_IT.utf8"));
QCOMPARE(itLocale.name(), QLatin1String("it_IT") );
// the Italian locale uses ',' as digit separator.
QLocale::setDefault(itLocale);
Parser parser;
bool ok;
QVariant result = parser.parse ("12.3", &ok);
QVERIFY (ok);
QCOMPARE(result.toDouble(), 12.3);
QLocale::setDefault(oldLocale);
}
void TestParser::testReadWrite()
{
QFETCH( QVariant, variant );
Serializer serializer;
bool ok;
QByteArray json = serializer.serialize(variant, &ok);
QVERIFY(ok);
Parser parser;
QVariant result = parser.parse( json, &ok );
QVERIFY(ok);
QCOMPARE( result, variant );
}
void TestParser::testReadWrite_data()
{
QTest::addColumn<QVariant>( "variant" );
// array tests
QTest::newRow( "empty array" ) << QVariant(QVariantList());
// basic array
QVariantList list;
list << QString(QLatin1String("hello"));
list << 12;
QTest::newRow( "basic array" ) << QVariant(list);
// simple map
QVariantMap map;
map[QString(QLatin1String("Name"))] = 32;
QTest::newRow( "complicated array" ) << QVariant(map);
}
void TestParser::reuseSameParser()
{
Parser parser;
bool ok;
parser.parse ("12.3", &ok);
QVERIFY (ok);
parser.parse ("wrong entry", &ok);
QVERIFY (!ok);
parser.parse ("12.3", &ok);
QVERIFY (ok);
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestParser)
#include "moc_testparser.cxx"
#else
QTEST_GUILESS_MAIN(TestParser)
#include "testparser.moc"
#endif

View File

@@ -0,0 +1,5 @@
Makefile
*.o
*.moc
moc_*
qobjecthelper

View File

@@ -0,0 +1,55 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET (qjson_test_support_SRCS person.cpp)
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(qjson_test_support_MOC_SRCS person.h)
ENDIF()
ADD_LIBRARY (qjson_test_support STATIC ${qjson_test_support_SRCS}
${qjson_test_support_MOC_SRCS})
SET( UNIT_TESTS
testqobjecthelper
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson${QJSON_SUFFIX}
qjson_test_support
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@@ -0,0 +1,75 @@
#include "person.h"
Person::Person(QObject* parent)
: QObject(parent),
m_name(),
m_phoneNumber(0),
m_gender(Female),
m_luckyNumber(0)
{
}
Person::~Person()
{
}
QString Person::name() const
{
return m_name;
}
void Person::setName(const QString& name)
{
m_name = name;
}
int Person::phoneNumber() const
{
return m_phoneNumber;
}
void Person::setPhoneNumber(const int phoneNumber)
{
m_phoneNumber = phoneNumber;
}
void Person::setGender(Gender gender)
{
m_gender = gender;
}
Person::Gender Person::gender() const
{
return m_gender;
}
QDate Person::dob() const
{
return m_dob;
}
void Person::setDob(const QDate& dob)
{
m_dob = dob;
}
QVariant Person::customField() const
{
return m_customField;
}
void Person::setCustomField(const QVariant& customField)
{
m_customField = customField;
}
const quint16 Person::luckyNumber() const
{
return m_luckyNumber;
}
void Person::setLuckyNumber(const quint16 luckyNumber)
{
m_luckyNumber = luckyNumber;
}

View File

@@ -0,0 +1,73 @@
/* This file is part of qjson
*
* Copyright (C) 2009 Till Adam <adam@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef PERSON_H
#define PERSON_H
#include <QtCore/QDate>
#include <QtCore/QtGlobal>
#include <QtCore/QObject>
#include <QtCore/QVariant>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int phoneNumber READ phoneNumber WRITE setPhoneNumber)
Q_PROPERTY(Gender gender READ gender WRITE setGender)
Q_PROPERTY(QDate dob READ dob WRITE setDob)
Q_PROPERTY(QVariant customField READ customField WRITE setCustomField)
Q_PROPERTY(quint16 luckyNumber READ luckyNumber WRITE setLuckyNumber)
Q_ENUMS(Gender)
public:
Person(QObject* parent = 0);
~Person();
QString name() const;
void setName(const QString& name);
int phoneNumber() const;
void setPhoneNumber(const int phoneNumber);
enum Gender {Male, Female};
void setGender(Gender gender);
Gender gender() const;
QDate dob() const;
void setDob(const QDate& dob);
QVariant customField() const;
void setCustomField(const QVariant& customField);
const quint16 luckyNumber() const;
void setLuckyNumber(const quint16 luckyNumber);
private:
QString m_name;
int m_phoneNumber;
Gender m_gender;
QDate m_dob;
QVariant m_customField;
quint16 m_luckyNumber;
};
#endif

View File

@@ -0,0 +1,126 @@
/* This file is part of QJson
*
* Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <limits>
#include <QtCore/QVariant>
#include <QtCore/QVariantList>
#include <QtTest/QtTest>
#include <QJson/Parser>
#include <QJson/Serializer>
#include <QJson/QObjectHelper>
#include "person.h"
class TestQObjectHelper: public QObject
{
Q_OBJECT
private slots:
void testQObject2QVariant();
void testQVariant2QObject();
};
using namespace QJson;
void TestQObjectHelper::testQObject2QVariant()
{
QString name = QLatin1String("Flavio Castelli");
int phoneNumber = 123456;
Person::Gender gender = Person::Male;
QDate dob (1982, 7, 12);
QVariantList nicknames;
nicknames << QLatin1String("nickname1") << QLatin1String("nickname2");
quint16 luckyNumber = 123;
Person person;
person.setName(name);
person.setPhoneNumber(phoneNumber);
person.setGender(gender);
person.setDob(dob);
person.setCustomField(nicknames);
person.setLuckyNumber(luckyNumber);
QVariantMap expected;
expected[QLatin1String("name")] = QVariant(name);
expected[QLatin1String("phoneNumber")] = QVariant(phoneNumber);
expected[QLatin1String("gender")] = QVariant(gender);
expected[QLatin1String("dob")] = QVariant(dob);
expected[QLatin1String("customField")] = nicknames;
expected[QLatin1String("luckyNumber")] = luckyNumber;
QVariantMap result = QObjectHelper::qobject2qvariant(&person);
QCOMPARE(result, expected);
}
void TestQObjectHelper::testQVariant2QObject()
{
bool ok;
QString name = QLatin1String("Flavio Castelli");
int phoneNumber = 123456;
Person::Gender gender = Person::Male;
QDate dob (1982, 7, 12);
QVariantList nicknames;
nicknames << QLatin1String("nickname1") << QLatin1String("nickname2");
quint16 luckyNumber = 123;
Person expected_person;
expected_person.setName(name);
expected_person.setPhoneNumber(phoneNumber);
expected_person.setGender(gender);
expected_person.setDob(dob);
expected_person.setCustomField(nicknames);
expected_person.setLuckyNumber(luckyNumber);
QVariantMap variant = QObjectHelper::qobject2qvariant(&expected_person);
Serializer serializer;
QByteArray json = serializer.serialize(variant, &ok);
qDebug() << "json is" << json;
QVERIFY(ok);
Parser parser;
QVariant parsedVariant = parser.parse(json,&ok);
QVERIFY(ok);
qDebug() << parsedVariant;
QVERIFY(parsedVariant.canConvert(QVariant::Map));
Person person;
QCOMPARE(Person::Female, person.gender());
QObjectHelper::qvariant2qobject(parsedVariant.toMap(), &person);
QCOMPARE(person.name(), name);
QCOMPARE(person.phoneNumber(), phoneNumber);
QCOMPARE(person.gender(), gender);
QCOMPARE(person.dob(), dob);
QCOMPARE(person.customField(), QVariant(nicknames));
QCOMPARE(person.luckyNumber(), luckyNumber);
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestQObjectHelper)
#include "moc_testqobjecthelper.cxx"
#else
QTEST_GUILESS_MAIN(TestQObjectHelper)
#include "testqobjecthelper.moc"
#endif

View File

@@ -0,0 +1,52 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../src
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
testscanner
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
if(WIN32 AND BUILD_SHARED_LIBS)
set(QJSON_SCANNER qjson_scanner)
endif()
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson${QJSON_SUFFIX}
${QJSON_SCANNER}
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@@ -0,0 +1,262 @@
/* This file is part of QJson
*
* Copyright (C) 2013 Silvio Moioli <silvio@moioli.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QtCore/QVariant>
#include <QtTest/QtTest>
// cmath does #undef for isnan and isinf macroses what can be defined in math.h
#if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
# include <math.h>
#else
# include <cmath>
#endif
#include "json_scanner.h"
#include "json_parser.hh"
#include "location.hh"
#define TOKEN(type) (int)yy::json_parser::token::type
class TestScanner: public QObject
{
Q_OBJECT
private slots:
void scanClosedDevice();
void scanTokens();
void scanTokens_data();
void scanSpecialNumbers();
void scanSpecialNumbers_data();
};
Q_DECLARE_METATYPE(QVariant)
Q_DECLARE_METATYPE(QVariant::Type)
using namespace QJson;
void TestScanner::scanClosedDevice() {
QBuffer buffer;
int expectedResult = -1;
JSonScanner scanner(&buffer);
QVariant yylval;
yy::location location;
int result = scanner.yylex(&yylval, &location);
QCOMPARE(result, expectedResult);
}
void TestScanner::scanTokens() {
QFETCH(QByteArray, input);
QFETCH(bool, allowSpecialNumbers);
QFETCH(bool, skipFirstToken);
QFETCH(int, expectedResult);
QFETCH(QVariant, expectedYylval);
QFETCH(int, expectedLocationBeginLine);
QFETCH(int, expectedLocationBeginColumn);
QFETCH(int, expectedLocationEndLine);
QFETCH(int, expectedLocationEndColumn);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
buffer.write(input);
buffer.seek(0);
JSonScanner scanner(&buffer);
scanner.allowSpecialNumbers(allowSpecialNumbers);
QVariant yylval;
yy::position position(YY_NULL, 1, 0);
yy::location location(position, position);
int result = scanner.yylex(&yylval, &location);
if (skipFirstToken) {
result = scanner.yylex(&yylval, &location);
}
QCOMPARE(result, expectedResult);
QCOMPARE(yylval, expectedYylval);
QCOMPARE(location.begin.line, (uint)expectedLocationBeginLine);
QCOMPARE(location.begin.column, (uint)expectedLocationBeginColumn);
QCOMPARE(location.end.line, (uint)expectedLocationEndLine);
QCOMPARE(location.end.column, (uint)expectedLocationEndColumn);
}
void TestScanner::scanTokens_data() {
QTest::addColumn<QByteArray>("input");
QTest::addColumn<bool>("allowSpecialNumbers");
QTest::addColumn<bool>("skipFirstToken");
QTest::addColumn<int>("expectedResult");
QTest::addColumn<QVariant>("expectedYylval");
QTest::addColumn<int>("expectedLocationBeginLine");
QTest::addColumn<int>("expectedLocationBeginColumn");
QTest::addColumn<int>("expectedLocationEndLine");
QTest::addColumn<int>("expectedLocationEndColumn");
QTest::newRow("empty json") << QByteArray("") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 0;
QTest::newRow("carriage return") << QByteArray("\r") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 2 << 1;
QTest::newRow("new line") << QByteArray("\n") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 2 << 1;
QTest::newRow("formfeed") << QByteArray("\f") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("vertical tab") << QByteArray("\v") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("space") << QByteArray(" ") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("tab") << QByteArray("\t") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("all spaces") << QByteArray("\r\n\f\v \t") << true << false << TOKEN(END) << QVariant() << 1 << 0 << 3 << 5;
QTest::newRow("true") << QByteArray("true") << true << false << TOKEN(TRUE_VAL) << QVariant(true) << 1 << 0 << 1 << 4;
QTest::newRow("false") << QByteArray("false") << true << false << TOKEN(FALSE_VAL) << QVariant(false) << 1 << 0 << 1 << 5;
QTest::newRow("null") << QByteArray("null") << true << false << TOKEN(NULL_VAL) << QVariant() << 1 << 0 << 1 << 4;
QTest::newRow("alphabetic string") << QByteArray("\"abcde\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("abcde")) << 1 << 0 << 1 << 2;
QTest::newRow("ecaped string") << QByteArray("\"abcde\\b\\f\\n\\r\\t\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("abcde\b\f\n\r\t")) << 1 << 0 << 1 << 2;
QTest::newRow("invalid ecaped string") << QByteArray("\"\\x\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("x")) << 1 << 0 << 1 << 2;
QTest::newRow("escaped unicode sequence") << QByteArray("\"\\u005A\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("Z")) << 1 << 0 << 1 << 2;
QTest::newRow("invalid unicode sequence") << QByteArray("\"\\u005Z\"") << true << false << TOKEN(INVALID) << QVariant(QLatin1String("")) << 1 << 0 << 1 << 2;
QTest::newRow("empty string") << QByteArray("\"\"") << true << false << TOKEN(STRING) << QVariant(QLatin1String("")) << 1 << 0 << 1 << 2;
QTest::newRow("unterminated empty string") << QByteArray("\"") << true << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 2;
QTest::newRow("unterminated string") << QByteArray("\"abcde") << true << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 2;
QTest::newRow("unterminated unicode sequence") << QByteArray("\"\\u005A") << true << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 2;
QTest::newRow("single digit") << QByteArray("0") << true << false << TOKEN(NUMBER) << QVariant(0u) << 1 << 0 << 1 << 1;
QTest::newRow("multiple digits") << QByteArray("123456789") << true << false << TOKEN(NUMBER) << QVariant(123456789u) << 1 << 0 << 1 << 9;
QTest::newRow("negative single digit") << QByteArray("-0") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 2;
QTest::newRow("negative multiple digits") << QByteArray("-123456789") << true << false << TOKEN(NUMBER) << QVariant(-123456789) << 1 << 0 << 1 << 10;
QTest::newRow("fractional single digit") << QByteArray("0.1") << true << false << TOKEN(NUMBER) << QVariant(0.1) << 1 << 0 << 1 << 3;
QTest::newRow("fractional multiple digits") << QByteArray("123456789.12") << true << false << TOKEN(NUMBER) << QVariant(123456789.12) << 1 << 0 << 1 << 12;
QTest::newRow("fractional negative single digit") << QByteArray("-0.3") << true << false << TOKEN(NUMBER) << QVariant(-0.3) << 1 << 0 << 1 << 4;
QTest::newRow("fractional negative multiple digits") << QByteArray("-123456789.23") << true << false << TOKEN(NUMBER) << QVariant(-123456789.23) << 1 << 0 << 1 << 13;
QTest::newRow("exponential single digit") << QByteArray("10e2") << true << false << TOKEN(NUMBER) << QVariant(1000) << 1 << 0 << 1 << 4;
QTest::newRow("exponential multiple digits") << QByteArray("10e23") << true << false << TOKEN(NUMBER) << QVariant(10e23) << 1 << 0 << 1 << 5;
QTest::newRow("exponential zero") << QByteArray("0e23") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 4;
QTest::newRow("exponential fractional") << QByteArray("0.12354e23") << true << false << TOKEN(NUMBER) << QVariant(0.12354e23) << 1 << 0 << 1 << 10;
QTest::newRow("exponential fractional multiple digits") << QByteArray("120.12354e23") << true << false << TOKEN(NUMBER) << QVariant(120.12354e23) << 1 << 0 << 1 << 12;
QTest::newRow("uppercase exponential") << QByteArray("120.12354E23") << true << false << TOKEN(NUMBER) << QVariant(120.12354E23) << 1 << 0 << 1 << 12;
QTest::newRow("negative exponential single digit") << QByteArray("-10e2") << true << false << TOKEN(NUMBER) << QVariant(-1000) << 1 << 0 << 1 << 5;
QTest::newRow("negative exponential multiple digits") << QByteArray("-10e23") << true << false << TOKEN(NUMBER) << QVariant(-10e23) << 1 << 0 << 1 << 6;
QTest::newRow("negative exponential zero") << QByteArray("-0e23") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 5;
QTest::newRow("negative exponential fractional") << QByteArray("-0.12354e23") << true << false << TOKEN(NUMBER) << QVariant(-0.12354e23) << 1 << 0 << 1 << 11;
QTest::newRow("negative exponential fractional multiple digits") << QByteArray("-120.12354e23") << true << false << TOKEN(NUMBER) << QVariant(-120.12354e23) << 1 << 0 << 1 << 13;
QTest::newRow("negative exponent") << QByteArray("10e-2") << true << false << TOKEN(NUMBER) << QVariant(10e-2) << 1 << 0 << 1 << 5;
QTest::newRow("positive exponent with plus") << QByteArray("10e+2") << true << false << TOKEN(NUMBER) << QVariant(1000) << 1 << 0 << 1 << 5;
QTest::newRow("invalid multiple digits") << QByteArray("001") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 1;
QTest::newRow("invalid negative multiple digits") << QByteArray("-001") << true << false << TOKEN(NUMBER) << QVariant(0) << 1 << 0 << 1 << 2;
QTest::newRow("invalid fractional") << QByteArray("12.") << true << true << TOKEN(INVALID) << QVariant(12) << 1 << 2 << 1 << 3;
QTest::newRow("invalid exponential 1") << QByteArray("-5e+") << true << true << TOKEN(INVALID) << QVariant(-5) << 1 << 2 << 1 << 3;
QTest::newRow("invalid exponential 2") << QByteArray("2e") << true << true << TOKEN(INVALID) << QVariant(2) << 1 << 1 << 1 << 2;
QTest::newRow("invalid exponential 3") << QByteArray("3e+") << true << true << TOKEN(INVALID) << QVariant(3) << 1 << 1 << 1 << 2;
QTest::newRow("invalid exponential 4") << QByteArray("4.3E") << true << true << TOKEN(INVALID) << QVariant(4.3) << 1 << 3 << 1 << 4;
QTest::newRow("invalid exponential 5") << QByteArray("5.4E-") << true << true << TOKEN(INVALID) << QVariant(5.4) << 1 << 3 << 1 << 4;
QTest::newRow("colon") << QByteArray(":") << true << false << TOKEN(COLON) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("comma") << QByteArray(",") << true << false << TOKEN(COMMA) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("square bracket open") << QByteArray("[") << true << false << TOKEN(SQUARE_BRACKET_OPEN) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("square bracket close") << QByteArray("]") << true << false << TOKEN(SQUARE_BRACKET_CLOSE) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("curly bracket open") << QByteArray("{") << true << false << TOKEN(CURLY_BRACKET_OPEN) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("curly bracket close") << QByteArray("}") << true << false << TOKEN(CURLY_BRACKET_CLOSE) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("too large unsinged number") << QByteArray("18446744073709551616") << false << false << TOKEN(INVALID) << QVariant(ULLONG_MAX) << 1 << 0 << 1 << 20;
QTest::newRow("too large signed number") << QByteArray("-9223372036854775808") << false << false << TOKEN(INVALID) << QVariant(LLONG_MIN) << 1 << 0 << 1 << 20;
QTest::newRow("too large exponential") << QByteArray("1.7976931348623157e309") << false << false << TOKEN(INVALID) << QVariant(0) << 1 << 0 << 1 << 22;
QTest::newRow("not allowed nan") << QByteArray("nan") << false << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("not allowed infinity") << QByteArray("Infinity") << false << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 1;
QTest::newRow("unknown") << QByteArray("*") << true << false << TOKEN(INVALID) << QVariant() << 1 << 0 << 1 << 1;
}
void TestScanner::scanSpecialNumbers() {
QFETCH(QByteArray, input);
QFETCH(bool, isInfinity);
QFETCH(bool, isNegative);
QFETCH(bool, isNan);
QFETCH(int, expectedLocationBeginLine);
QFETCH(int, expectedLocationBeginColumn);
QFETCH(int, expectedLocationEndLine);
QFETCH(int, expectedLocationEndColumn);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
buffer.write(input);
buffer.seek(0);
JSonScanner scanner(&buffer);
scanner.allowSpecialNumbers(true);
QVariant yylval;
yy::position position(YY_NULL, 1, 0);
yy::location location(position, position);
int result = scanner.yylex(&yylval, &location);
QCOMPARE(result, TOKEN(NUMBER));
QVERIFY(yylval.type() == QVariant::Double);
double doubleResult = yylval.toDouble();
#if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY)
QCOMPARE(bool(isinf(doubleResult)), isInfinity);
#else
// skip this test for MSVC, because there is no "isinf" function.
#ifndef Q_CC_MSVC
QCOMPARE(bool(std::isinf(doubleResult)), isInfinity);
#endif
#endif
QCOMPARE(doubleResult<0, isNegative);
#if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY)
QCOMPARE(bool(isnan(doubleResult)), isNan);
#else
// skip this test for MSVC, because there is no "isinf" function.
#ifndef Q_CC_MSVC
QCOMPARE(bool(std::isnan(doubleResult)), isNan);
#endif
#endif
QCOMPARE(location.begin.line, (uint)expectedLocationBeginLine);
QCOMPARE(location.begin.column, (uint)expectedLocationBeginColumn);
QCOMPARE(location.end.line, (uint)expectedLocationEndLine);
QCOMPARE(location.end.column, (uint)expectedLocationEndColumn);
}
void TestScanner::scanSpecialNumbers_data() {
QTest::addColumn<QByteArray>("input");
QTest::addColumn<bool>("isInfinity");
QTest::addColumn<bool>("isNegative");
QTest::addColumn<bool>("isNan");
QTest::addColumn<int>("expectedLocationBeginLine");
QTest::addColumn<int>("expectedLocationBeginColumn");
QTest::addColumn<int>("expectedLocationEndLine");
QTest::addColumn<int>("expectedLocationEndColumn");
QTest::newRow("nan") << QByteArray("nan") << false << false << true << 1 << 0 << 1 << 3;
QTest::newRow("NAN") << QByteArray("NAN") << false << false << true << 1 << 0 << 1 << 3;
QTest::newRow("NaN") << QByteArray("NaN") << false << false << true << 1 << 0 << 1 << 3;
QTest::newRow("infinity") << QByteArray("infinity") << true << false << false << 1 << 0 << 1 << 8;
QTest::newRow("Infinity") << QByteArray("infinity") << true << false << false << 1 << 0 << 1 << 8;
QTest::newRow("-infinity") << QByteArray("-infinity") << true << true << false << 1 << 0 << 1 << 9;
QTest::newRow("-Infinity") << QByteArray("-Infinity") << true << true << false << 1 << 0 << 1 << 9;
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestScanner)
#include "moc_testscanner.cxx"
#else
QTEST_GUILESS_MAIN(TestScanner)
#include "testscanner.moc"
#endif

View File

@@ -0,0 +1,4 @@
Makefile
*.o
*.moc
serializer

View File

@@ -0,0 +1,46 @@
##### Probably don't want to edit below this line #####
SET( QT_USE_QTTEST TRUE )
IF (NOT Qt5Core_FOUND)
# Use it
INCLUDE( ${QT_USE_FILE} )
ENDIF()
INCLUDE(AddFileDependencies)
# Include the library include directories, and the current build directory (moc)
INCLUDE_DIRECTORIES(
../../include
${CMAKE_CURRENT_BINARY_DIR}
)
SET( UNIT_TESTS
testserializer
)
# Build the tests
FOREACH(test ${UNIT_TESTS})
MESSAGE(STATUS "Building ${test}")
IF (NOT Qt5Core_FOUND)
QT4_WRAP_CPP(MOC_SOURCE ${test}.cpp)
ENDIF()
ADD_EXECUTABLE(
${test}
${test}.cpp
)
ADD_FILE_DEPENDENCIES(${test}.cpp ${MOC_SOURCE})
TARGET_LINK_LIBRARIES(
${test}
${QT_LIBRARIES}
${TEST_LIBRARIES}
qjson${QJSON_SUFFIX}
)
if (QJSON_TEST_OUTPUT STREQUAL "xml")
# produce XML output
add_test( ${test} ${test} -xml -o ${test}.tml )
else (QJSON_TEST_OUTPUT STREQUAL "xml")
add_test( ${test} ${test} )
endif (QJSON_TEST_OUTPUT STREQUAL "xml")
ENDFOREACH()

View File

@@ -0,0 +1,649 @@
/* This file is part of QJson
*
* Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <limits>
#include <QtCore/QVariant>
#include <QtTest/QtTest>
#include <QJson/Parser>
#include <QJson/Serializer>
class TestSerializer: public QObject
{
Q_OBJECT
private slots:
void testReadWriteEmptyDocument();
void testReadWrite();
void testReadWrite_data();
void testValueNull();
void testValueString();
void testValueString_data();
void testValueStringList();
void testValueStringList_data();
void testValueHashMap();
void testValueInteger();
void testValueInteger_data();
void testValueDouble();
void testValueDouble_data();
void testSetDoublePrecision();
void testValueFloat();
void testValueFloat_data();
void testValueBoolean();
void testValueBoolean_data();
void testSpecialNumbers();
void testSpecialNumbers_data();
void testIndentation();
void testIndentation_data();
void testSerializetoQIODevice();
void testSerializeWithoutOkParam();
void testEscapeChars();
void testEscapeChars_data();
private:
void valueTest( const QVariant& value, const QString& expectedRegExp, bool errorExpected = false );
void valueTest( const QObject* object, const QString& expectedRegExp );
};
Q_DECLARE_METATYPE(QVariant)
using namespace QJson;
void TestSerializer::testReadWriteEmptyDocument()
{
QByteArray json = "";
Parser parser;
bool ok;
QVariant result = parser.parse( json, &ok );
QVERIFY(!ok);
QVERIFY( ! result.isValid() );
Serializer serializer;
const QByteArray serialized = serializer.serialize( result, &ok);
QVERIFY( ok );
QByteArray expected = "null";
QCOMPARE(expected, serialized);
}
void TestSerializer::testReadWrite()
{
QFETCH( QByteArray, json );
Parser parser;
bool ok;
QVariant result = parser.parse( json, &ok );
QVERIFY(ok);
Serializer serializer;
const QByteArray serialized = serializer.serialize( result, &ok);
QVERIFY(ok);
QVariant writtenThenRead = parser.parse( serialized, &ok );
QVERIFY(ok);
QCOMPARE( result, writtenThenRead );
}
void TestSerializer::testReadWrite_data()
{
QTest::addColumn<QByteArray>( "json" );
// array tests
QTest::newRow( "empty array" ) << QByteArray("[]");
QTest::newRow( "basic array" ) << QByteArray("[\"person\",\"bar\"]");
QTest::newRow( "single int array" ) << QByteArray("[6]");
QTest::newRow( "int array" ) << QByteArray("[6,5,6,7]");
const QByteArray json = "[1,2.4, -100, -3.4, -5e+0, 2e0,3e+0,4.3E0,5.4E-0]";
QTest::newRow( QByteArray("array of various numbers") ) << json;
// document tests
QTest::newRow( "empty object" ) << QByteArray("{}");
QTest::newRow( "basic document" ) << QByteArray("{\"person\":\"bar\"}");
QTest::newRow( "object with ints" ) << QByteArray("{\"person\":6}");
const QByteArray json2 = "{ \"person\":\"bar\",\n\"number\" : 51.3 , \"array\":[\"item1\", 123]}";
QTest::newRow( "complicated document" ) << json2;
// more complex cases
const QByteArray json3 = "[ {\"person\":\"bar\"},\n\"number\",51.3 , [\"item1\", 123]]";
QTest::newRow( "complicated array" ) << json3;
}
void TestSerializer::testIndentation()
{
QFETCH( QByteArray, json );
QFETCH( QByteArray, expected_compact );
QFETCH( QByteArray, expected_min );
QFETCH( QByteArray, expected_med );
QFETCH( QByteArray, expected_full );
// parse
Parser parser;
bool ok;
QVariant parsed = parser.parse( json, &ok );
QVERIFY(ok);
Serializer serializer;
QVariant reparsed;
QByteArray serialized;
// serialize with indent compact and reparse
serializer.setIndentMode(QJson::IndentCompact);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_compact);
reparsed = parser.parse( serialized, &ok);
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
// serialize with indent minimum and reparse
serializer.setIndentMode(QJson::IndentMinimum);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_min);
reparsed = parser.parse( serialized, &ok);
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
// serialize with indent medium and reparse
serializer.setIndentMode(QJson::IndentMedium);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_med);
reparsed = parser.parse( serialized, &ok );
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
// serialize with indent full and reparse
serializer.setIndentMode(QJson::IndentFull);
serialized = serializer.serialize( parsed, &ok);
QVERIFY(ok);
QCOMPARE( serialized, expected_full);
reparsed = parser.parse( serialized, &ok );
QVERIFY(ok);
QCOMPARE( parsed, reparsed);
}
void TestSerializer::testIndentation_data()
{
QTest::addColumn<QByteArray>( "json" );
QTest::addColumn<QByteArray>( "expected_compact" );
QTest::addColumn<QByteArray>( "expected_min" );
QTest::addColumn<QByteArray>( "expected_med" );
QTest::addColumn<QByteArray>( "expected_full" );
const QByteArray json = " { \"foo\" : 0, \"foo1\" : 1, \"foo2\" : [ { \"bar\" : 1, \"foo\" : 0, \"foobar\" : 0 }, { \"bar\" : 1, \"foo\" : 1, \"foobar\" : 1 } ], \"foo3\" : [ 1, 2, 3, 4, 5, 6 ], \"foobaz\" : [ \"one\", \"two\", \"three\", \"four\" ] }";
const QByteArray ex_compact =
"{\"foo\":0,\"foo1\":1,\"foo2\":[{\"bar\":1,\"foo\":0,\"foobar\":0},{\"bar\":1,\"foo\":1,\"foobar\":1}],\"foo3\":[1,2,3,4,5,6],\"foobaz\":[\"one\",\"two\",\"three\",\"four\"]}";
const QByteArray ex_min =
"{ \"foo\" : 0, \"foo1\" : 1, \"foo2\" : [\n"
" { \"bar\" : 1, \"foo\" : 0, \"foobar\" : 0 },\n"
" { \"bar\" : 1, \"foo\" : 1, \"foobar\" : 1 }\n"
" ], \"foo3\" : [\n"
" 1,\n"
" 2,\n"
" 3,\n"
" 4,\n"
" 5,\n"
" 6\n"
" ], \"foobaz\" : [\n"
" \"one\",\n"
" \"two\",\n"
" \"three\",\n"
" \"four\"\n"
" ] }";
const QByteArray ex_med =
"{\n"
" \"foo\" : 0, \"foo1\" : 1, \"foo2\" : [\n"
" {\n"
" \"bar\" : 1, \"foo\" : 0, \"foobar\" : 0\n"
" },\n"
" {\n"
" \"bar\" : 1, \"foo\" : 1, \"foobar\" : 1\n"
" }\n"
" ], \"foo3\" : [\n"
" 1,\n"
" 2,\n"
" 3,\n"
" 4,\n"
" 5,\n"
" 6\n"
" ], \"foobaz\" : [\n"
" \"one\",\n"
" \"two\",\n"
" \"three\",\n"
" \"four\"\n"
" ]\n}";
const QByteArray ex_full =
"{\n"
" \"foo\" : 0,\n"
" \"foo1\" : 1,\n"
" \"foo2\" : [\n"
" {\n"
" \"bar\" : 1,\n"
" \"foo\" : 0,\n"
" \"foobar\" : 0\n"
" },\n"
" {\n"
" \"bar\" : 1,\n"
" \"foo\" : 1,\n"
" \"foobar\" : 1\n"
" }\n"
" ],\n"
" \"foo3\" : [\n"
" 1,\n"
" 2,\n"
" 3,\n"
" 4,\n"
" 5,\n"
" 6\n"
" ],\n"
" \"foobaz\" : [\n"
" \"one\",\n"
" \"two\",\n"
" \"three\",\n"
" \"four\"\n"
" ]\n"
"}";
QTest::newRow( "test indents" ) << json << ex_compact << ex_min << ex_med << ex_full;
}
void TestSerializer::valueTest( const QVariant& value, const QString& expectedRegExp, bool errorExpected )
{
Serializer serializer;
bool ok;
const QByteArray serialized = serializer.serialize( value, &ok);
QCOMPARE(ok, !errorExpected);
QCOMPARE(serialized.isNull(), errorExpected);
const QString serializedUnicode = QString::fromUtf8( serialized );
if (!errorExpected) {
QRegExp expected( expectedRegExp );
QVERIFY( expected.isValid() );
QVERIFY2( expected.exactMatch( serializedUnicode ),
qPrintable( QString( QLatin1String( "Expected regexp \"%1\" but got \"%2\"." ) )
.arg( expectedRegExp ).arg( serializedUnicode ) ) );
} else {
QVERIFY(!serializer.errorMessage().isEmpty());
}
}
void TestSerializer::valueTest( const QObject* object, const QString& expectedRegExp )
{
Serializer serializer;
bool ok;
const QByteArray serialized = serializer.serialize( object, &ok);
QVERIFY(ok);
const QString serializedUnicode = QString::fromUtf8( serialized );
QRegExp expected( expectedRegExp );
QVERIFY( expected.isValid() );
QVERIFY2( expected.exactMatch( serializedUnicode ),
qPrintable( QString( QLatin1String( "Expected regexp \"%1\" but got \"%2\"." ) )
.arg( expectedRegExp ).arg( serializedUnicode ) ) );
}
void TestSerializer::testValueNull()
{
valueTest( QVariant(), QLatin1String( "\\s*null\\s*" ) );
QVariantMap map;
map[QLatin1String("value")] = QVariant();
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:\\s*null\\s*\\}\\s*" ) );
}
void TestSerializer::testValueString()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueString_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "null string" ) << QVariant( QString() ) << QString( QLatin1String( "\\s*\"\"\\s*" ) );
QTest::newRow( "empty string" ) << QVariant( QString( QLatin1String( "" ) ) ) << QString( QLatin1String( "\\s*\"\"\\s*" ) );
QTest::newRow( "Simple String" ) << QVariant( QString( QLatin1String( "simpleString" ) ) ) << QString( QLatin1String( "\\s*\"simpleString\"\\s*" ) );
QTest::newRow( "string with tab" ) << QVariant( QString( QLatin1String( "string\tstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\tstring\"\\s*" ) );
QTest::newRow( "string with newline" ) << QVariant( QString( QLatin1String( "string\nstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\nstring\"\\s*" ) );
QTest::newRow( "string with bell" ) << QVariant( QString( QLatin1String( "string\bstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\bstring\"\\s*" ) );
QTest::newRow( "string with return" ) << QVariant( QString( QLatin1String( "string\rstring" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\rstring\"\\s*" ) );
QTest::newRow( "string with double quote" ) << QVariant( QString( QLatin1String( "string\"string" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\\"string\"\\s*" ) );
QTest::newRow( "string with backslash" ) << QVariant( QString( QLatin1String( "string\\string" ) ) ) << QString( QLatin1String( "\\s*\"string\\\\\\\\string\"\\s*" ) );
QString testStringWithUnicode = QString( QLatin1String( "string" ) ) + QChar( 0x2665 ) + QLatin1String( "string" );
QString testEscapedString = QString( QLatin1String( "string" ) ) + QLatin1String("\\\\u2665") + QLatin1String( "string" );
QTest::newRow( "string with unicode" ) << QVariant( testStringWithUnicode ) << QString( QLatin1String( "\\s*\"" ) + testEscapedString + QLatin1String( "\"\\s*" ) );
}
void TestSerializer::testValueStringList()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueStringList_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QStringList stringlist;
QString expected;
// simple QStringList
stringlist << QLatin1String("hello") << QLatin1String("world");
expected = QLatin1String( "\\s*\\[\\s*\"hello\"\\s*,\\s*\"world\"\\s*\\]\\s*" );
QTest::newRow( "simple QStringList" ) << QVariant( stringlist) << expected;
}
void TestSerializer::testValueInteger()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueInteger_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "int 0" ) << QVariant( static_cast<int>( 0 ) ) << QString( QLatin1String( "\\s*0\\s*" ) );
QTest::newRow( "uint 0" ) << QVariant( static_cast<uint>( 0 ) ) << QString( QLatin1String( "\\s*0\\s*" ) );
QTest::newRow( "int -1" ) << QVariant( static_cast<int>( -1 ) ) << QString( QLatin1String( "\\s*-1\\s*" ) );
QTest::newRow( "int 2133149800" ) << QVariant( static_cast<int>(2133149800) ) << QString( QLatin1String( "\\s*2133149800\\s*" ) );
QTest::newRow( "uint 4133149800" ) << QVariant( static_cast<uint>(4133149800u) ) << QString( QLatin1String( "\\s*4133149800\\s*" ) );
QTest::newRow( "uint64 932838457459459" ) << QVariant( Q_UINT64_C(932838457459459) ) << QString( QLatin1String( "\\s*932838457459459\\s*" ) );
QTest::newRow( "max unsigned long long" ) << QVariant( std::numeric_limits<unsigned long long>::max() ) << QString( QLatin1String( "\\s*%1\\s*" ) ).arg(std::numeric_limits<unsigned long long>::max());
}
void TestSerializer::testValueDouble()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
QFETCH( bool, errorExpected );
valueTest( value, expected, errorExpected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ), errorExpected );
}
void TestSerializer::testValueDouble_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::addColumn<bool>( "errorExpected" );
QTest::newRow( "double 0" ) << QVariant( 0.0 ) << QString( QLatin1String( "\\s*0.0\\s*" ) ) << false;
QTest::newRow( "double -1" ) << QVariant( -1.0 ) << QString( QLatin1String( "\\s*-1.0\\s*" ) ) << false;
QTest::newRow( "double 1.5E-20" ) << QVariant( 1.5e-20 ) << QString( QLatin1String( "\\s*1.5[Ee]-20\\s*" ) ) << false;
QTest::newRow( "double -1.5E-20" ) << QVariant( -1.5e-20 ) << QString( QLatin1String( "\\s*-1.5[Ee]-20\\s*" ) ) << false;
QTest::newRow( "double 2.0E-20" ) << QVariant( 2.0e-20 ) << QString( QLatin1String( "\\s*2(?:.0)?[Ee]-20\\s*" ) ) << false;
QTest::newRow( "double infinity" ) << QVariant( std::numeric_limits< double >::infinity() ) << QString( ) << true;
QTest::newRow( "double -infinity" ) << QVariant( -std::numeric_limits< double >::infinity() ) << QString( ) << true;
QTest::newRow( "double NaN" ) << QVariant( std::numeric_limits< double >::quiet_NaN() ) << QString( ) << true;
}
void TestSerializer::testSetDoublePrecision()
{
bool ok;
Serializer serializer;
QByteArray actual;
QString expected, actualUnicode;
double num = 0.12345678;
// Set 1 as double precision
serializer.setDoublePrecision(1);
expected = QString(QLatin1String("0.1"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
// Set 2 as double precision
serializer.setDoublePrecision(2);
expected = QString(QLatin1String("0.12"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
// Set 4 as double precision
serializer.setDoublePrecision(4);
expected = QString(QLatin1String("0.1235"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
// Set 14 as double precision
serializer.setDoublePrecision(14);
expected = QString(QLatin1String("0.12345678"));
actual = serializer.serialize( QVariant(num), &ok);
QVERIFY(ok);
actualUnicode = QString::fromUtf8(actual);
QVERIFY2( QString::compare(expected, actualUnicode ) == 0,
qPrintable( QString( QLatin1String( "Expected \"%1\" but got \"%2\"." ) )
.arg( expected ).arg( actualUnicode ) ) );
}
void TestSerializer::testValueFloat()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
QFETCH( bool, errorExpected );
valueTest( value, expected, errorExpected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ), errorExpected );
}
void TestSerializer::testValueFloat_data()
{
QVariant v;
float value;
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::addColumn<bool>( "errorExpected" );
value = 0;
v.setValue(value);
QTest::newRow( "float 0" ) << v << QString( QLatin1String( "\\s*0.0\\s*" ) ) << false;
value = -1;
v.setValue(value);
QTest::newRow( "float -1" ) << v << QString( QLatin1String( "\\s*-1.0\\s*" ) ) << false;
value = 1.12f;
v.setValue(value);
QTest::newRow( "float 1.12" ) << v << QString( QLatin1String( "\\s*1.12\\s*" ) ) << false;
}
void TestSerializer::testValueBoolean()
{
QFETCH( QVariant, value );
QFETCH( QString, expected );
valueTest( value, expected );
QVariantMap map;
map[QLatin1String("value")] = value;
valueTest( QVariant(map), QLatin1String( "\\s*\\{\\s*\"value\"\\s*:" ) + expected + QLatin1String( "\\}\\s*" ) );
}
void TestSerializer::testValueBoolean_data()
{
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "bool false" ) << QVariant( false ) << QString( QLatin1String( "\\s*false\\s*" ) );
QTest::newRow( "bool true" ) << QVariant( true ) << QString( QLatin1String( "\\s*true\\s*" ) );
}
void TestSerializer::testSpecialNumbers() {
bool ok;
QFETCH( QVariant, value );
QFETCH( QString, expected );
Serializer specialSerializer;
QVERIFY(!specialSerializer.specialNumbersAllowed());
specialSerializer.allowSpecialNumbers(true);
QVERIFY(specialSerializer.specialNumbersAllowed());
QByteArray serialized = specialSerializer.serialize(value, &ok);
QVERIFY(ok);
QCOMPARE(QString::fromLocal8Bit(serialized), expected);
}
void TestSerializer::testSpecialNumbers_data() {
QTest::addColumn<QVariant>( "value" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "Infinity" ) << QVariant( std::numeric_limits< double >::infinity() ) << QString::fromLocal8Bit("Infinity");
QTest::newRow( "-Infinity" ) << QVariant( -std::numeric_limits< double >::infinity() ) << QString::fromLocal8Bit("-Infinity");
QTest::newRow( "Infinity" ) << QVariant( std::numeric_limits< double >::quiet_NaN() ) << QString::fromLocal8Bit("NaN");
}
void TestSerializer::testSerializetoQIODevice() {
QBuffer buffer;
QVariantList variant;
variant << QVariant(QLatin1String("Hello"));
variant << QVariant(QLatin1String("world!"));
Serializer serializer;
bool ok;
serializer.serialize(variant, &buffer, &ok);
QCOMPARE(QString(QLatin1String(buffer.data())),
QString(QLatin1String("[ \"Hello\", \"world!\" ]")));
QVERIFY(ok);
}
void TestSerializer::testSerializeWithoutOkParam() {
QBuffer buffer;
QVariantList variant;
variant << QVariant(QLatin1String("Hello"));
variant << QVariant(QLatin1String("world!"));
Serializer serializer;
const QByteArray serialized = serializer.serialize(variant);
const QByteArray expected = "[ \"Hello\", \"world!\" ]";
QCOMPARE(expected, serialized);
// test a serialization which produces an error
QVariant brokenVariant ( std::numeric_limits< double >::quiet_NaN() );
QVERIFY(serializer.serialize(brokenVariant).isEmpty());
}
void TestSerializer::testValueHashMap()
{
Serializer serializer;
bool ok;
QVariantHash hash;
hash[QLatin1String("one")] = 1;
hash[QLatin1String("three")] = 3;
hash[QLatin1String("seven")] = 7;
QByteArray json = serializer.serialize(hash, &ok);
QVERIFY(ok);
Parser parser;
QVariant var = parser.parse(json, &ok);
QVERIFY(ok);
QVariantMap vmap = var.toMap();
QHashIterator<QString, QVariant> hIt( hash );
while ( hIt.hasNext() ) {
hIt.next();
QString key = hIt.key();
QVariant value = hIt.value();
QMap<QString, QVariant>::const_iterator mIt = vmap.constFind(key);
QVERIFY(mIt != vmap.constEnd());
QCOMPARE(mIt.value(), value);
}
}
void TestSerializer::testEscapeChars()
{
QFETCH(QString, input);
QFETCH(QString, escaped);
Serializer serializer;
bool ok;
QVariantHash hash;
hash.insert(QLatin1String("key"), input);
QByteArray json = serializer.serialize(hash, &ok);
QVERIFY(ok);
QString expected = QString(QLatin1String("{ \"key\" : \"%1\" }")).arg(escaped);
QString actual = QString::fromUtf8(json.data(), json.length());
QCOMPARE(actual, expected);
}
void TestSerializer::testEscapeChars_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<QString>("escaped");
QTest::newRow("simple ASCII string") << "input" << "input";
QTest::newRow("ASCII new lines and tabs") << "line1\nline2\rline\t3" << "line1\\nline2\\rline\\t3";
QTest::newRow("backspace, backslash and quotes") << "one\\two\bthree\"four" << "one\\\\two\\bthree\\\"four";
QChar unicodeSnowman(0x2603);
QTest::newRow("non-ASCII unicode char") << QString(unicodeSnowman) << "\\u2603";
QTest::newRow("control chars") << QString(QChar(0x06)) << "\\u0006";
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// using Qt4 rather then Qt5
QTEST_MAIN(TestSerializer)
#include "moc_testserializer.cxx"
#else
QTEST_GUILESS_MAIN(TestSerializer)
#include "testserializer.moc"
#endif