/**************************************************************************** ** ** Copyright (C) 2018 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include class tst_QCborStreamWriter : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase_data(); void fixed_data(); void fixed(); void strings_data(); void strings() { fixed(); } void nonAsciiStrings_data(); void nonAsciiStrings(); void arraysAndMaps_data(); void arraysAndMaps() { fixed(); } void tags_data(); void tags(); void arrays_data() { tags_data(); } void arrays(); void maps_data() { tags_data(); } void maps(); }; // Get the data from TinyCBOR (see src/3rdparty/tinycbor/tests/encoder/data.cpp) typedef quint64 CborTag; #include "data.cpp" void encodeVariant(QCborStreamWriter &writer, const QVariant &v) { int type = v.userType(); switch (type) { case QVariant::Int: case QVariant::LongLong: return writer.append(v.toLongLong()); case QVariant::UInt: case QVariant::ULongLong: return writer.append(v.toULongLong()); case QVariant::Bool: return writer.append(v.toBool()); case QVariant::Invalid: return writer.appendUndefined(); case QMetaType::VoidStar: return writer.append(nullptr); case QVariant::Double: return writer.append(v.toDouble()); case QMetaType::Float: return writer.append(v.toFloat()); case QVariant::String: return writer.append(v.toString()); case QVariant::ByteArray: return writer.append(v.toByteArray()); default: if (type == qMetaTypeId()) return writer.append(QCborNegativeInteger(v.value().abs)); if (type == qMetaTypeId()) return writer.append(QCborSimpleType(v.value().type)); if (type == qMetaTypeId()) return writer.append(v.value()); if (type == qMetaTypeId()) { writer.append(QCborTag(v.value().tag)); return encodeVariant(writer, v.value().tagged); } if (type == QVariant::List || type == qMetaTypeId()) { QVariantList list = v.toList(); if (type == qMetaTypeId()) { list = v.value(); writer.startArray(); } else { writer.startArray(list.length()); } for (const QVariant &v2 : qAsConst(list)) encodeVariant(writer, v2); QVERIFY(writer.endArray()); return; } if (type == qMetaTypeId() || type == qMetaTypeId()) { Map map = v.value(); if (type == qMetaTypeId()) { map = v.value(); writer.startMap(); } else { writer.startMap(map.length()); } for (auto pair : qAsConst(map)) { encodeVariant(writer, pair.first); encodeVariant(writer, pair.second); } QVERIFY(writer.endMap()); return; } } QFAIL("Shouldn't have got here"); } void compare(const QVariant &input, const QByteArray &output) { QFETCH_GLOBAL(bool, useDevice); if (useDevice) { QBuffer buffer; buffer.open(QIODevice::WriteOnly); QCborStreamWriter writer(&buffer); encodeVariant(writer, input); QCOMPARE(buffer.data(), output); } else { QByteArray buffer; QCborStreamWriter writer(&buffer); encodeVariant(writer, input); QCOMPARE(buffer, output); } } void tst_QCborStreamWriter::initTestCase_data() { QTest::addColumn("useDevice"); QTest::newRow("QByteArray") << false; QTest::newRow("QIODevice") << true; } void tst_QCborStreamWriter::fixed_data() { addColumns(); addFixedData(); } void tst_QCborStreamWriter::fixed() { QFETCH(QVariant, input); QFETCH(QByteArray, output); compare(input, output); } void tst_QCborStreamWriter::strings_data() { addColumns(); addStringsData(); } void tst_QCborStreamWriter::nonAsciiStrings_data() { QTest::addColumn("output"); QTest::addColumn("input"); QTest::addColumn("isLatin1"); QByteArray latin1 = u8"Résumé"; QTest::newRow("shortlatin1") << ("\x68" + latin1) << QString::fromUtf8(latin1) << true; // replicate it 5 times (total 40 bytes) latin1 += latin1 + latin1 + latin1 + latin1; QTest::newRow("longlatin1") << ("\x78\x28" + latin1) << QString::fromUtf8(latin1) << true; QByteArray nonlatin1 = u8"Χαίρετε"; QTest::newRow("shortnonlatin1") << ("\x6e" + nonlatin1) << QString::fromUtf8(nonlatin1) << false; // replicate it 4 times (total 56 bytes) nonlatin1 = nonlatin1 + nonlatin1 + nonlatin1 + nonlatin1; QTest::newRow("longnonlatin1") << ("\x78\x38" + nonlatin1) << QString::fromUtf8(nonlatin1) << false; } void tst_QCborStreamWriter::nonAsciiStrings() { QFETCH(QByteArray, output); QFETCH(QString, input); QFETCH(bool, isLatin1); QFETCH_GLOBAL(bool, useDevice); // will be wrong if !isLatin1 QByteArray latin1 = input.toLatin1(); if (useDevice) { { QBuffer buffer; buffer.open(QIODevice::WriteOnly); QCborStreamWriter writer(&buffer); writer.append(input); QCOMPARE(buffer.data(), output); } if (isLatin1) { QBuffer buffer; buffer.open(QIODevice::WriteOnly); QCborStreamWriter writer(&buffer); writer.append(QLatin1String(latin1.constData(), latin1.size())); QCOMPARE(buffer.data(), output); } } else { { QByteArray buffer; QCborStreamWriter writer(&buffer); encodeVariant(writer, input); QCOMPARE(buffer, output); } if (isLatin1) { QByteArray buffer; QCborStreamWriter writer(&buffer); writer.append(QLatin1String(latin1.constData(), latin1.size())); QCOMPARE(buffer, output); } } } void tst_QCborStreamWriter::arraysAndMaps_data() { addColumns(); addArraysAndMaps(); } void tst_QCborStreamWriter::tags_data() { addColumns(); addFixedData(); addStringsData(); addArraysAndMaps(); } void tst_QCborStreamWriter::tags() { QFETCH(QVariant, input); QFETCH(QByteArray, output); compare(QVariant::fromValue(Tag{1, input}), "\xc1" + output); } void tst_QCborStreamWriter::arrays() { QFETCH(QVariant, input); QFETCH(QByteArray, output); compare(make_list(input), "\x81" + output); if (QTest::currentTestFailed()) return; compare(make_list(input, input), "\x82" + output + output); if (QTest::currentTestFailed()) return; // nested lists compare(make_list(make_list(input)), "\x81\x81" + output); if (QTest::currentTestFailed()) return; compare(make_list(make_list(input), make_list(input)), "\x82\x81" + output + "\x81" + output); } void tst_QCborStreamWriter::maps() { QFETCH(QVariant, input); QFETCH(QByteArray, output); compare(make_map({{1, input}}), "\xa1\1" + output); if (QTest::currentTestFailed()) return; compare(make_map({{1, input}, {input, 24}}), "\xa2\1" + output + output + "\x18\x18"); } QTEST_MAIN(tst_QCborStreamWriter) #include "tst_qcborstreamwriter.moc"