QCborValue: add support for QCOMPARE string output

Change-Id: Ibdc95e9af7bd456a94ecfffd16066c47ea9766d0
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Thiago Macieira 2020-04-16 19:09:34 -03:00
parent e635568985
commit 99ce02f692
3 changed files with 358 additions and 77 deletions

View File

@ -2995,68 +2995,6 @@ size_t qHash(const QCborValue &value, size_t seed)
return qHash(value.toSimpleType(), seed);
}
#if !defined(QT_NO_DEBUG_STREAM)
static QDebug debugContents(QDebug &dbg, const QCborValue &v)
{
switch (v.type()) {
case QCborValue::Integer:
return dbg << v.toInteger();
case QCborValue::ByteArray:
return dbg << "QByteArray(" << v.toByteArray() << ')';
case QCborValue::String:
return dbg << v.toString();
case QCborValue::Array:
return dbg << v.toArray();
case QCborValue::Map:
return dbg << v.toMap();
case QCborValue::Tag:
dbg << v.tag() << ", ";
return debugContents(dbg, v.taggedValue());
case QCborValue::SimpleType:
break;
case QCborValue::True:
return dbg << true;
case QCborValue::False:
return dbg << false;
case QCborValue::Null:
return dbg << "nullptr";
case QCborValue::Undefined:
return dbg;
case QCborValue::Double: {
qint64 i = qint64(v.toDouble());
if (i == v.toDouble())
return dbg << i << ".0";
else
return dbg << v.toDouble();
}
case QCborValue::DateTime:
return dbg << v.toDateTime();
#ifndef QT_BOOTSTRAPPED
case QCborValue::Url:
return dbg << v.toUrl();
#endif
#if QT_CONFIG(regularexpression)
case QCborValue::RegularExpression:
return dbg << v.toRegularExpression();
#endif
case QCborValue::Uuid:
return dbg << v.toUuid();
case QCborValue::Invalid:
return dbg << "<invalid>";
default:
break;
}
if (v.isSimpleType())
return dbg << v.toSimpleType();
return dbg << "<unknown type " << Qt::hex << int(v.type()) << Qt::dec << '>';
}
QDebug operator<<(QDebug dbg, const QCborValue &v)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "QCborValue(";
return debugContents(dbg, v) << ')';
}
Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
{
switch (st) {
@ -3072,16 +3010,6 @@ Q_CORE_EXPORT const char *qt_cbor_simpletype_id(QCborSimpleType st)
return nullptr;
}
QDebug operator<<(QDebug dbg, QCborSimpleType st)
{
QDebugStateSaver saver(dbg);
const char *id = qt_cbor_simpletype_id(st);
if (id)
return dbg.nospace() << "QCborSimpleType::" << id;
return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
}
Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
{
// Casting to QCborKnownTags's underlying type will make the comparison
@ -3140,6 +3068,84 @@ Q_CORE_EXPORT const char *qt_cbor_tag_id(QCborTag tag)
return nullptr;
}
#if !defined(QT_NO_DEBUG_STREAM)
static QDebug debugContents(QDebug &dbg, const QCborValue &v)
{
switch (v.type()) {
case QCborValue::Integer:
return dbg << v.toInteger();
case QCborValue::ByteArray:
return dbg << "QByteArray(" << v.toByteArray() << ')';
case QCborValue::String:
return dbg << v.toString();
case QCborValue::Array:
return dbg << v.toArray();
case QCborValue::Map:
return dbg << v.toMap();
case QCborValue::Tag: {
QCborTag tag = v.tag();
const char *id = qt_cbor_tag_id(tag);
if (id)
dbg.nospace() << "QCborKnownTags::" << id << ", ";
else
dbg.nospace() << "QCborTag(" << quint64(tag) << "), ";
return dbg << v.taggedValue();
}
case QCborValue::SimpleType:
break;
case QCborValue::True:
return dbg << true;
case QCborValue::False:
return dbg << false;
case QCborValue::Null:
return dbg << "nullptr";
case QCborValue::Undefined:
return dbg;
case QCborValue::Double: {
qint64 i;
if (convertDoubleTo(v.toDouble(), &i))
return dbg << i << ".0";
else
return dbg << v.toDouble();
}
case QCborValue::DateTime:
return dbg << v.toDateTime();
#ifndef QT_BOOTSTRAPPED
case QCborValue::Url:
return dbg << v.toUrl();
#if QT_CONFIG(regularexpression)
case QCborValue::RegularExpression:
return dbg << v.toRegularExpression();
#endif
case QCborValue::Uuid:
return dbg << v.toUuid();
#endif
case QCborValue::Invalid:
return dbg << "<invalid>";
default:
break;
}
if (v.isSimpleType())
return dbg << v.toSimpleType();
return dbg << "<unknown type 0x" << Qt::hex << int(v.type()) << Qt::dec << '>';
}
QDebug operator<<(QDebug dbg, const QCborValue &v)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "QCborValue(";
return debugContents(dbg, v) << ')';
}
QDebug operator<<(QDebug dbg, QCborSimpleType st)
{
QDebugStateSaver saver(dbg);
const char *id = qt_cbor_simpletype_id(st);
if (id)
return dbg.nospace() << "QCborSimpleType::" << id;
return dbg.nospace() << "QCborSimpleType(" << uint(st) << ')';
}
QDebug operator<<(QDebug dbg, QCborTag tag)
{
QDebugStateSaver saver(dbg);

View File

@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtTest module of the Qt Toolkit.
@ -48,6 +48,10 @@
#include <QtCore/qbitarray.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qcborarray.h>
#include <QtCore/qcborcommon.h>
#include <QtCore/qcbormap.h>
#include <QtCore/qcborvalue.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qcborcommon.h>
@ -69,7 +73,6 @@
QT_BEGIN_NAMESPACE
namespace QTest
{
@ -232,6 +235,142 @@ template<> inline char *toString(const QVariant &v)
return qstrdup(vstring.constData());
}
namespace Internal {
struct QCborValueFormatter
{
enum { BufferLen = 256 };
static char *formatSimpleType(QCborSimpleType st)
{
char *buf = new char[BufferLen];
qsnprintf(buf, BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
return buf;
}
static char *formatTag(QCborTag tag, const QCborValue &taggedValue)
{
QScopedArrayPointer<char> hold(format(taggedValue));
char *buf = new char[BufferLen];
qsnprintf(buf, BufferLen, "QCborValue(QCborTag(%llu), %s)", tag, hold.get());
return buf;
}
static char *innerFormat(QCborValue::Type t, const char *str)
{
static const QMetaEnum typeEnum = []() {
int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
return QCborValue::staticMetaObject.enumerator(idx);
}();
char *buf = new char[BufferLen];
const char *typeName = typeEnum.valueToKey(t);
if (typeName)
qsnprintf(buf, BufferLen, "QCborValue(%s, %s)", typeName, str);
else
qsnprintf(buf, BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
return buf;
}
template<typename T> static char *format(QCborValue::Type type, const T &t)
{
QScopedArrayPointer<char> hold(QTest::toString(t));
return innerFormat(type, hold.get());
}
static char *format(const QCborValue &v)
{
switch (v.type()) {
case QCborValue::Integer:
return format(v.type(), v.toInteger());
case QCborValue::ByteArray:
return format(v.type(), v.toByteArray());
case QCborValue::String:
return format(v.type(), v.toString());
case QCborValue::Array:
return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toArray())).get());
case QCborValue::Map:
return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toMap())).get());
case QCborValue::Tag:
return formatTag(v.tag(), v.taggedValue());
case QCborValue::SimpleType:
break;
case QCborValue::True:
return qstrdup("QCborValue(true)");
case QCborValue::False:
return qstrdup("QCborValue(false)");
case QCborValue::Null:
return qstrdup("QCborValue(nullptr)");
case QCborValue::Undefined:
return qstrdup("QCborValue()");
case QCborValue::Double:
return format(v.type(), v.toDouble());
case QCborValue::DateTime:
case QCborValue::Url:
case QCborValue::RegularExpression:
return format(v.type(), v.taggedValue().toString());
case QCborValue::Uuid:
return format(v.type(), v.toUuid());
case QCborValue::Invalid:
return qstrdup("QCborValue(<invalid>)");
}
if (v.isSimpleType())
return formatSimpleType(v.toSimpleType());
return innerFormat(v.type(), "");
}
static char *format(const QCborArray &a)
{
QByteArray out(1, '[');
const char *comma = "";
for (const QCborValueRef v : a) {
QScopedArrayPointer<char> s(format(v));
out += comma;
out += s.get();
comma = ", ";
}
out += ']';
return qstrdup(out.constData());
}
static char *format(const QCborMap &m)
{
QByteArray out(1, '{');
const char *comma = "";
for (auto pair : m) {
QScopedArrayPointer<char> key(format(pair.first));
QScopedArrayPointer<char> value(format(pair.second));
out += comma;
out += key.get();
out += ": ";
out += value.get();
comma = ", ";
}
out += '}';
return qstrdup(out.constData());
}
};
}
template<> inline char *toString(const QCborValue &v)
{
return Internal::QCborValueFormatter::format(v);
}
template<> inline char *toString(const QCborValueRef &v)
{
return toString(QCborValue(v));
}
template<> inline char *toString(const QCborArray &a)
{
return Internal::QCborValueFormatter::format(a);
}
template<> inline char *toString(const QCborMap &m)
{
return Internal::QCborValueFormatter::format(m);
}
template <typename T1, typename T2>
inline char *toString(const std::pair<T1, T2> &pair)
{

View File

@ -120,6 +120,10 @@ private slots:
void datastreamSerialization_data();
void datastreamSerialization();
void streamVariantSerialization();
void debugOutput_data();
void debugOutput();
void testlibFormatting_data();
void testlibFormatting();
};
namespace SimpleEncodeToCbor {
@ -456,8 +460,8 @@ void tst_QCborValue::extendedTypes()
QVERIFY(extended.isTag());
QVERIFY(tagged.isTag());
QCOMPARE(tagged.taggedValue(), correctedTaggedValue);
QVERIFY(extended == tagged);
QVERIFY(tagged == extended);
QCOMPARE(tagged, extended);
QCOMPARE(extended, tagged);
QCOMPARE(extended.tag(), tagged.tag());
QCOMPARE(extended.taggedValue(), tagged.taggedValue());
@ -2474,6 +2478,138 @@ void tst_QCborValue::streamVariantSerialization()
}
}
void tst_QCborValue::debugOutput_data()
{
QTest::addColumn<QCborValue>("v");
QTest::addColumn<QString>("expected");
QDateTime dt(QDate(2020, 4, 18), QTime(13, 41, 22, 123), Qt::UTC);
QBitArray bits = QBitArray::fromBits("\x79\x03", 11);
QTest::newRow("Undefined") << QCborValue() << "QCborValue()";
QTest::newRow("Null") << QCborValue(nullptr) << "QCborValue(nullptr)";
QTest::newRow("False") << QCborValue(false) << "QCborValue(false)";
QTest::newRow("True") << QCborValue(true) << "QCborValue(true)";
QTest::newRow("simpletype")
<< QCborValue(QCborSimpleType(0)) << "QCborValue(QCborSimpleType(0))";
QTest::newRow("Integer:0") << QCborValue(0) << "QCborValue(0)";
QTest::newRow("Double:0") << QCborValue(0.) << "QCborValue(0.0)";
QTest::newRow("ByteArray")
<< QCborValue(raw("Hello\0World")) << "QCborValue(QByteArray(\"Hello\\x00World\"))";
QTest::newRow("String")
<< QCborValue("Hello\x7fWorld") << "QCborValue(\"Hello\\u007FWorld\")";
QTest::newRow("DateTime")
<< QCborValue(dt) << "QCborValue(QDateTime(2020-04-18 13:41:22.123 UTC Qt::UTC))";
QTest::newRow("Url")
<< QCborValue(QUrl("http://example.com")) << "QCborValue(QUrl(\"http://example.com\"))";
QTest::newRow("RegularExpression")
<< QCborValue(QRegularExpression("^.*$"))
<< "QCborValue(QRegularExpression(\"^.*$\", QRegularExpression::PatternOptions(\"NoPatternOption\")))";
QTest::newRow("Uuid")
<< QCborValue(QUuid()) << "QCborValue(QUuid(\"{00000000-0000-0000-0000-000000000000}\"))";
QTest::newRow("Tag-1387671238")
<< QCborValue(QCborTag(1387671238), QCborValue())
<< "QCborValue(QCborTag(1387671238), QCborValue())";
QTest::newRow("Tag-55799")
<< QCborValue(QCborKnownTags::Signature, QCborValue("Signature"))
<< "QCborValue(QCborKnownTags::Signature, QCborValue(\"Signature\"))";
// arrays and maps
QTest::newRow("Array:Empty") << QCborValue(QCborArray()) << "QCborValue(QCborArray{})";
QTest::newRow("Map:Empty") << QCborValue(QCborMap()) << "QCborValue(QCborMap{})";
QTest::newRow("Array")
<< QCborValue(QCborArray{1, 2., nullptr})
<< "QCborValue(QCborArray{QCborValue(1), QCborValue(2.0), QCborValue(nullptr)})";
QTest::newRow("Map")
<< QCborValue(QCborMap{{1, 2.}, {nullptr, "Hello"}, {"World", QCborArray()}})
<< "QCborValue(QCborMap{"
"{QCborValue(1), QCborValue(2.0)}, "
"{QCborValue(nullptr), QCborValue(\"Hello\")}, "
"{QCborValue(\"World\"), QCborValue(QCborArray{})}"
"})";
// usually impossible types
QTest::newRow("Unknown-Basic")
<< QCborValue(QCborValue::Type(0xfb)) << "QCborValue(<unknown type 0xfb>)";
QTest::newRow("Unknown-Extended")
<< QCborValue(QCborValue::Type(0x10000 + 21)) << "QCborValue(<unknown type 0x10015>)";
QTest::newRow("Invalid") << QCborValue(QCborValue::Invalid) << "QCborValue(<invalid>)";
}
void tst_QCborValue::debugOutput()
{
QFETCH(QCborValue, v);
QFETCH(QString, expected);
QTest::ignoreMessage(QtDebugMsg, expected.toUtf8());
qDebug() << v;
}
void tst_QCborValue::testlibFormatting_data()
{
QTest::addColumn<QCborValue>("v");
QTest::addColumn<QString>("expected");
QDateTime dt = QDateTime::currentDateTimeUtc();
QTest::newRow("Undefined") << QCborValue() << "QCborValue()";
QTest::newRow("Null") << QCborValue(nullptr) << "QCborValue(nullptr)";
QTest::newRow("False") << QCborValue(false) << "QCborValue(false)";
QTest::newRow("True") << QCborValue(true) << "QCborValue(true)";
QTest::newRow("simpletype")
<< QCborValue(QCborSimpleType(0)) << "QCborValue(QCborSimpleType(0))";
QTest::newRow("Integer:0") << QCborValue(0) << "QCborValue(Integer, 0)";
QTest::newRow("Double:0") << QCborValue(0.) << "QCborValue(Double, 0)"; // must be integer!
QTest::newRow("ByteArray")
<< QCborValue(raw("Hello\0World")) << "QCborValue(ByteArray, \"Hello\\x00World\")";
QTest::newRow("String")
<< QCborValue("Hej v\xc3\xa4rlden") << "QCborValue(String, \"Hej v\\u00E4rlden\")";
QTest::newRow("DateTime")
<< QCborValue(dt) << QString("QCborValue(DateTime, \"%1\")").arg(dt.toString(Qt::ISODateWithMs));
QTest::newRow("Url")
<< QCborValue(QUrl("http://example.com")) << "QCborValue(Url, \"http://example.com\")";
QTest::newRow("RegularExpression")
<< QCborValue(QRegularExpression("^.*$")) << "QCborValue(RegularExpression, \"^.*$\")";
QTest::newRow("Uuid")
<< QCborValue(QUuid()) << "QCborValue(Uuid, {00000000-0000-0000-0000-000000000000})";
QTest::newRow("Tag")
<< QCborValue(QCborKnownTags::Signature, QCborValue())
<< "QCborValue(QCborTag(55799), QCborValue())";
// arrays and maps
QTest::newRow("Array:Empty") << QCborValue(QCborArray()) << "QCborValue(Array, [])";
QTest::newRow("Map:Empty") << QCborValue(QCborMap()) << "QCborValue(Map, {})";
QTest::newRow("Array")
<< QCborValue(QCborArray{1, 2., nullptr})
<< "QCborValue(Array, [QCborValue(Integer, 1), QCborValue(Double, 2), QCborValue(nullptr)])";
QTest::newRow("Map")
<< QCborValue(QCborMap{{1, 2.}, {nullptr, "Hello"}, {"World", QCborArray()}})
<< "QCborValue(Map, {"
"QCborValue(Integer, 1): QCborValue(Double, 2), "
"QCborValue(nullptr): QCborValue(String, \"Hello\"), "
"QCborValue(String, \"World\"): QCborValue(Array, [])"
"})";
// usually impossible types
QTest::newRow("Unknown-Basic")
<< QCborValue(QCborValue::Type(0xfb)) << "QCborValue(<unknown type 0xfb>)";
QTest::newRow("Unknown-Extended")
<< QCborValue(QCborValue::Type(0x10000 + 21)) << "QCborValue(<unknown type 0x10015>)";
QTest::newRow("Invalid") << QCborValue(QCborValue::Invalid) << "QCborValue(<invalid>)";
}
void tst_QCborValue::testlibFormatting()
{
QFETCH(QCborValue, v);
QFETCH(QString, expected);
QScopedArrayPointer<char> hold(QTest::toString(v));
QString actual = hold.get();
QCOMPARE(actual, expected);
}
QTEST_MAIN(tst_QCborValue)
#include "tst_qcborvalue.moc"