Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 09:09:23

0001 // Copyright (C) 2021 The Qt Company Ltd.
0002 // Copyright (C) 2024 Intel Corporation.
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
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> // Output registered enums
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))); // int cast is necessary to support enum classes
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> // Fallback; for built-in types debug streaming must be possible
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> // Output QFlags of registered enumerations
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> // Fallback: Output hex value
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); // 2 for 0x, two hex digits per byte, 1 for '\0'
0083     char *msg = new char[space];
0084     std::snprintf(msg, space, "0x%x", unsigned(f.toInt()));
0085     return msg;
0086 }
0087 
0088 } // namespace Internal
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 // datestring
0191 
0192 template<> inline char *toString(const QCborError &c)
0193 {
0194     // use the Q_ENUM formatting
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         // include the equivalent value in seconds, in parentheses
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     // Generate a table of N + 1 elements where N is the number of
0482     // elements in the tuple.
0483     // The last element is needed to support the empty tuple use case.
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 } // namespace QTest
0501 
0502 QT_END_NAMESPACE
0503 
0504 #endif // QTESTTOSTRING_H