File indexing completed on 2025-09-15 09:09:23
0001
0002
0003
0004
0005 #ifndef QTESTTOSTRING_H
0006 #define QTESTTOSTRING_H
0007
0008 #include <QtTest/qttestglobal.h>
0009
0010 #include <QtCore/qttypetraits.h>
0011
0012 #if QT_CONFIG(itemmodel)
0013 # include <QtCore/qabstractitemmodel.h>
0014 #endif
0015 #include <QtCore/qbitarray.h>
0016 #include <QtCore/qbytearray.h>
0017 #include <QtCore/qcborarray.h>
0018 #include <QtCore/qcborcommon.h>
0019 #include <QtCore/qcbormap.h>
0020 #include <QtCore/qcborvalue.h>
0021 #include <QtCore/qdebug.h>
0022 #include <QtCore/qdatetime.h>
0023 #include <QtCore/qmetaobject.h>
0024 #include <QtCore/qmetatype.h>
0025 #include <QtCore/qobject.h>
0026 #include <QtCore/qpoint.h>
0027 #include <QtCore/qrect.h>
0028 #include <QtCore/qsize.h>
0029 #include <QtCore/qstring.h>
0030 #include <QtCore/qstringlist.h>
0031 #include <QtCore/qurl.h>
0032 #include <QtCore/quuid.h>
0033 #include <QtCore/qvariant.h>
0034
0035 #include <cstdio>
0036 #include <QtCore/q20memory.h>
0037
0038 QT_BEGIN_NAMESPACE
0039
0040 namespace QTest {
0041 namespace Internal {
0042
0043 template<typename T>
0044 inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
0045 {
0046 QMetaEnum me = QMetaEnum::fromType<T>();
0047 return qstrdup(me.valueToKey(int(e)));
0048 }
0049
0050 template <typename T>
0051 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e)
0052 {
0053 return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
0054 }
0055
0056 template <typename T>
0057 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t)
0058 {
0059 char *result = nullptr;
0060 #ifndef QT_NO_DEBUG_STREAM
0061 if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) {
0062 result = qstrdup(QDebug::toBytes(t).constData());
0063 } else {
0064 static_assert(!QMetaTypeId2<T>::IsBuiltIn,
0065 "Built-in type must implement debug streaming operator "
0066 "or provide QTest::toString specialization");
0067 }
0068 #endif
0069 return result;
0070 }
0071
0072 template<typename F>
0073 inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
0074 {
0075 const QMetaEnum me = QMetaEnum::fromType<F>();
0076 return qstrdup(me.valueToKeys(int(f.toInt())).constData());
0077 }
0078
0079 template <typename F>
0080 inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
0081 {
0082 const size_t space = 3 + 2 * sizeof(unsigned);
0083 char *msg = new char[space];
0084 std::snprintf(msg, space, "0x%x", unsigned(f.toInt()));
0085 return msg;
0086 }
0087
0088 }
0089
0090 Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
0091 const char *expected, const char *file, int line);
0092 Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
0093 Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
0094 Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
0095 Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
0096
0097 template <typename T>
0098 inline char *toString(const T &t)
0099 {
0100 return Internal::toString(t);
0101 }
0102
0103 template <typename T1, typename T2>
0104 inline char *toString(const std::pair<T1, T2> &pair);
0105
0106 template <class... Types>
0107 inline char *toString(const std::tuple<Types...> &tuple);
0108
0109 template <typename Rep, typename Period>
0110 inline char *toString(std::chrono::duration<Rep, Period> duration);
0111
0112 Q_TESTLIB_EXPORT char *toString(const char *);
0113 Q_TESTLIB_EXPORT char *toString(const volatile void *);
0114 Q_TESTLIB_EXPORT char *toString(const QObject *);
0115 Q_TESTLIB_EXPORT char *toString(const volatile QObject *);
0116
0117 #define QTEST_COMPARE_DECL(KLASS)\
0118 template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
0119 #ifndef Q_QDOC
0120 QTEST_COMPARE_DECL(short)
0121 QTEST_COMPARE_DECL(ushort)
0122 QTEST_COMPARE_DECL(int)
0123 QTEST_COMPARE_DECL(uint)
0124 QTEST_COMPARE_DECL(long)
0125 QTEST_COMPARE_DECL(ulong)
0126 QTEST_COMPARE_DECL(qint64)
0127 QTEST_COMPARE_DECL(quint64)
0128
0129 QTEST_COMPARE_DECL(float)
0130 QTEST_COMPARE_DECL(double)
0131 QTEST_COMPARE_DECL(qfloat16)
0132 QTEST_COMPARE_DECL(char)
0133 QTEST_COMPARE_DECL(signed char)
0134 QTEST_COMPARE_DECL(unsigned char)
0135 QTEST_COMPARE_DECL(bool)
0136 #endif
0137 #undef QTEST_COMPARE_DECL
0138
0139 template <> inline char *toString(const QStringView &str)
0140 {
0141 return QTest::toPrettyUnicode(str);
0142 }
0143
0144 template<> inline char *toString(const QString &str)
0145 {
0146 return toString(QStringView(str));
0147 }
0148
0149 template<> inline char *toString(const QLatin1StringView &str)
0150 {
0151 return toString(QString(str));
0152 }
0153
0154 template<> inline char *toString(const QByteArray &ba)
0155 {
0156 return QTest::toPrettyCString(ba.constData(), ba.size());
0157 }
0158
0159 template<> inline char *toString(const QBitArray &ba)
0160 {
0161 qsizetype size = ba.size();
0162 char *str = new char[size + 1];
0163 for (qsizetype i = 0; i < size; ++i)
0164 str[i] = "01"[ba.testBit(i)];
0165 str[size] = '\0';
0166 return str;
0167 }
0168
0169 #if QT_CONFIG(datestring)
0170 template<> inline char *toString(const QTime &time)
0171 {
0172 return time.isValid()
0173 ? qstrdup(qPrintable(time.toString(u"hh:mm:ss.zzz")))
0174 : qstrdup("Invalid QTime");
0175 }
0176
0177 template<> inline char *toString(const QDate &date)
0178 {
0179 return date.isValid()
0180 ? qstrdup(qPrintable(date.toString(u"yyyy/MM/dd")))
0181 : qstrdup("Invalid QDate");
0182 }
0183
0184 template<> inline char *toString(const QDateTime &dateTime)
0185 {
0186 return dateTime.isValid()
0187 ? qstrdup(qPrintable(dateTime.toString(u"yyyy/MM/dd hh:mm:ss.zzz[t]")))
0188 : qstrdup("Invalid QDateTime");
0189 }
0190 #endif
0191
0192 template<> inline char *toString(const QCborError &c)
0193 {
0194
0195 return toString(c.c);
0196 }
0197
0198 template<> inline char *toString(const QChar &c)
0199 {
0200 const ushort uc = c.unicode();
0201 if (uc < 128) {
0202 char msg[32];
0203 std::snprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
0204 return qstrdup(msg);
0205 }
0206 return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
0207 }
0208
0209 #if QT_CONFIG(itemmodel)
0210 template<> inline char *toString(const QModelIndex &idx)
0211 {
0212 char msg[128];
0213 std::snprintf(msg, sizeof(msg), "QModelIndex(%d,%d,%p,%p)",
0214 idx.row(), idx.column(), idx.internalPointer(),
0215 static_cast<const void*>(idx.model()));
0216 return qstrdup(msg);
0217 }
0218 #endif
0219
0220 template<> inline char *toString(const QPoint &p)
0221 {
0222 char msg[128];
0223 std::snprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
0224 return qstrdup(msg);
0225 }
0226
0227 template<> inline char *toString(const QSize &s)
0228 {
0229 char msg[128];
0230 std::snprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
0231 return qstrdup(msg);
0232 }
0233
0234 template<> inline char *toString(const QRect &s)
0235 {
0236 char msg[256];
0237 std::snprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
0238 s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
0239 return qstrdup(msg);
0240 }
0241
0242 template<> inline char *toString(const QPointF &p)
0243 {
0244 char msg[64];
0245 std::snprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
0246 return qstrdup(msg);
0247 }
0248
0249 template<> inline char *toString(const QSizeF &s)
0250 {
0251 char msg[64];
0252 std::snprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
0253 return qstrdup(msg);
0254 }
0255
0256 template<> inline char *toString(const QRectF &s)
0257 {
0258 char msg[256];
0259 std::snprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
0260 s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
0261 return qstrdup(msg);
0262 }
0263
0264 template<> inline char *toString(const QUrl &uri)
0265 {
0266 if (!uri.isValid())
0267 return qstrdup(qPrintable(QLatin1StringView("Invalid URL: ") + uri.errorString()));
0268 return qstrdup(uri.toEncoded().constData());
0269 }
0270
0271 template <> inline char *toString(const QUuid &uuid)
0272 {
0273 return qstrdup(uuid.toByteArray().constData());
0274 }
0275
0276 template<> inline char *toString(const QVariant &v)
0277 {
0278 QByteArray vstring("QVariant(");
0279 if (v.isValid()) {
0280 QByteArray type(v.typeName());
0281 if (type.isEmpty()) {
0282 type = QByteArray::number(v.userType());
0283 }
0284 vstring.append(type);
0285 if (!v.isNull()) {
0286 vstring.append(',');
0287 if (v.canConvert<QString>()) {
0288 vstring.append(v.toString().toLocal8Bit());
0289 }
0290 else {
0291 vstring.append("<value not representable as string>");
0292 }
0293 }
0294 }
0295 vstring.append(')');
0296
0297 return qstrdup(vstring.constData());
0298 }
0299
0300 template<> inline char *toString(const QPartialOrdering &o)
0301 {
0302 if (o == QPartialOrdering::Less)
0303 return qstrdup("Less");
0304 if (o == QPartialOrdering::Equivalent)
0305 return qstrdup("Equivalent");
0306 if (o == QPartialOrdering::Greater)
0307 return qstrdup("Greater");
0308 if (o == QPartialOrdering::Unordered)
0309 return qstrdup("Unordered");
0310 return qstrdup("<invalid>");
0311 }
0312
0313 namespace Internal {
0314 struct QCborValueFormatter
0315 {
0316 private:
0317 using UP = std::unique_ptr<char[]>;
0318 enum { BufferLen = 256 };
0319
0320 static UP createBuffer() { return q20::make_unique_for_overwrite<char[]>(BufferLen); }
0321
0322 static UP formatSimpleType(QCborSimpleType st)
0323 {
0324 auto buf = createBuffer();
0325 std::snprintf(buf.get(), BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
0326 return buf;
0327 }
0328
0329 static UP formatTag(QCborTag tag, const QCborValue &taggedValue)
0330 {
0331 auto buf = createBuffer();
0332 const std::unique_ptr<char[]> hold(format(taggedValue));
0333 std::snprintf(buf.get(), BufferLen, "QCborValue(QCborTag(%llu), %s)",
0334 qToUnderlying(tag), hold.get());
0335 return buf;
0336 }
0337
0338 static UP innerFormat(QCborValue::Type t, const UP &str)
0339 {
0340 static const QMetaEnum typeEnum = []() {
0341 int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
0342 return QCborValue::staticMetaObject.enumerator(idx);
0343 }();
0344
0345 auto buf = createBuffer();
0346 const char *typeName = typeEnum.valueToKey(t);
0347 if (typeName)
0348 std::snprintf(buf.get(), BufferLen, "QCborValue(%s, %s)", typeName, str ? str.get() : "");
0349 else
0350 std::snprintf(buf.get(), BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
0351 return buf;
0352 }
0353
0354 template<typename T> static UP format(QCborValue::Type type, const T &t)
0355 {
0356 const std::unique_ptr<char[]> hold(QTest::toString(t));
0357 return innerFormat(type, hold);
0358 }
0359
0360 public:
0361
0362 static UP format(const QCborValue &v)
0363 {
0364 switch (v.type()) {
0365 case QCborValue::Integer:
0366 return format(v.type(), v.toInteger());
0367 case QCborValue::ByteArray:
0368 return format(v.type(), v.toByteArray());
0369 case QCborValue::String:
0370 return format(v.type(), v.toString());
0371 case QCborValue::Array:
0372 return innerFormat(v.type(), format(v.toArray()));
0373 case QCborValue::Map:
0374 return innerFormat(v.type(), format(v.toMap()));
0375 case QCborValue::Tag:
0376 return formatTag(v.tag(), v.taggedValue());
0377 case QCborValue::SimpleType:
0378 break;
0379 case QCborValue::True:
0380 return UP{qstrdup("QCborValue(true)")};
0381 case QCborValue::False:
0382 return UP{qstrdup("QCborValue(false)")};
0383 case QCborValue::Null:
0384 return UP{qstrdup("QCborValue(nullptr)")};
0385 case QCborValue::Undefined:
0386 return UP{qstrdup("QCborValue()")};
0387 case QCborValue::Double:
0388 return format(v.type(), v.toDouble());
0389 case QCborValue::DateTime:
0390 case QCborValue::Url:
0391 case QCborValue::RegularExpression:
0392 return format(v.type(), v.taggedValue().toString());
0393 case QCborValue::Uuid:
0394 return format(v.type(), v.toUuid());
0395 case QCborValue::Invalid:
0396 return UP{qstrdup("QCborValue(<invalid>)")};
0397 }
0398
0399 if (v.isSimpleType())
0400 return formatSimpleType(v.toSimpleType());
0401 return innerFormat(v.type(), nullptr);
0402 }
0403
0404 static UP format(const QCborArray &a)
0405 {
0406 QByteArray out(1, '[');
0407 const char *comma = "";
0408 for (QCborValueConstRef v : a) {
0409 const std::unique_ptr<char[]> s(format(v));
0410 out += comma;
0411 out += s.get();
0412 comma = ", ";
0413 }
0414 out += ']';
0415 return UP{qstrdup(out.constData())};
0416 }
0417
0418 static UP format(const QCborMap &m)
0419 {
0420 QByteArray out(1, '{');
0421 const char *comma = "";
0422 for (auto pair : m) {
0423 const std::unique_ptr<char[]> key(format(pair.first));
0424 const std::unique_ptr<char[]> value(format(pair.second));
0425 out += comma;
0426 out += key.get();
0427 out += ": ";
0428 out += value.get();
0429 comma = ", ";
0430 }
0431 out += '}';
0432 return UP{qstrdup(out.constData())};
0433 }
0434 };
0435 }
0436
0437 template<> inline char *toString(const QCborValue &v)
0438 {
0439 return Internal::QCborValueFormatter::format(v).release();
0440 }
0441
0442 template<> inline char *toString(const QCborValueRef &v)
0443 {
0444 return toString(QCborValue(v));
0445 }
0446
0447 template<> inline char *toString(const QCborArray &a)
0448 {
0449 return Internal::QCborValueFormatter::format(a).release();
0450 }
0451
0452 template<> inline char *toString(const QCborMap &m)
0453 {
0454 return Internal::QCborValueFormatter::format(m).release();
0455 }
0456
0457 template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
0458 {
0459 QString r;
0460 QDebug d(&r);
0461 d.nospace() << qSetRealNumberPrecision(9) << dur;
0462 if constexpr (Period::num != 1 || Period::den != 1) {
0463
0464 using namespace std::chrono;
0465 d << " (" << duration_cast<duration<qreal>>(dur).count() << "s)";
0466 }
0467 return qstrdup(std::move(r).toUtf8().constData());
0468 }
0469
0470 template <typename T1, typename T2>
0471 inline char *toString(const std::pair<T1, T2> &pair)
0472 {
0473 const std::unique_ptr<char[]> first(toString(pair.first));
0474 const std::unique_ptr<char[]> second(toString(pair.second));
0475 return formatString("std::pair(", ")", 2, first.get(), second.get());
0476 }
0477
0478 template <typename Tuple, std::size_t... I>
0479 inline char *tupleToString(const Tuple &tuple, std::index_sequence<I...>) {
0480 using UP = std::unique_ptr<char[]>;
0481
0482
0483
0484 const UP data[] = {
0485 UP(toString(std::get<I>(tuple)))..., UP{}
0486 };
0487 return formatString("std::tuple(", ")", sizeof...(I), data[I].get()...);
0488 }
0489
0490 template <class... Types>
0491 inline char *toString(const std::tuple<Types...> &tuple)
0492 {
0493 return tupleToString(tuple, std::make_index_sequence<sizeof...(Types)>{});
0494 }
0495
0496 inline char *toString(std::nullptr_t)
0497 {
0498 return toString(QStringView(u"nullptr"));
0499 }
0500 }
0501
0502 QT_END_NAMESPACE
0503
0504 #endif