Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtesttostring.h
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2024 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QTESTTOSTRING_H
6#define QTESTTOSTRING_H
7
8#include <QtTest/qttestglobal.h>
9
10#if QT_CONFIG(itemmodel)
11# include <QtCore/qabstractitemmodel.h>
12#endif
13#include <QtCore/qbitarray.h>
14#include <QtCore/qbytearray.h>
15#include <QtCore/qcborarray.h>
16#include <QtCore/qcborcommon.h>
17#include <QtCore/qcbormap.h>
18#include <QtCore/qcborvalue.h>
19#include <QtCore/qdatetime.h>
20#include <QtCore/qmetaobject.h>
21#include <QtCore/qmetatype.h>
22#include <QtCore/qobject.h>
23#include <QtCore/qpoint.h>
24#include <QtCore/qrect.h>
25#include <QtCore/qsize.h>
26#include <QtCore/qstring.h>
27#include <QtCore/qstringlist.h>
28#include <QtCore/qurl.h>
29#include <QtCore/quuid.h>
30#include <QtCore/qvariant.h>
31
33
34namespace QTest {
35namespace Internal {
36
37template<typename T> // Output registered enums
38inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
39{
40 QMetaEnum me = QMetaEnum::fromType<T>();
41 return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes
42}
43
44template <typename T>
45inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e)
46{
47 return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
48}
49
50template <typename T> // Fallback; for built-in types debug streaming must be possible
51inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t)
52{
53 char *result = nullptr;
54#ifndef QT_NO_DEBUG_STREAM
55 if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) {
56 result = qstrdup(QDebug::toString(t).toUtf8().constData());
57 } else {
58 static_assert(!QMetaTypeId2<T>::IsBuiltIn,
59 "Built-in type must implement debug streaming operator "
60 "or provide QTest::toString specialization");
61 }
62#endif
63 return result;
64}
65
66template<typename F> // Output QFlags of registered enumerations
67inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
68{
69 const QMetaEnum me = QMetaEnum::fromType<F>();
70 return qstrdup(me.valueToKeys(int(f.toInt())).constData());
71}
72
73template <typename F> // Fallback: Output hex value
74inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
75{
76 const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
77 char *msg = new char[space];
78 qsnprintf(msg, space, "0x%x", unsigned(f.toInt()));
79 return msg;
80}
81
82template <typename T>
83constexpr bool is_suitable_type_helper_v = std::disjunction_v<std::is_same<T, char>,
84 std::is_same<T, void>,
85 std::is_same<T, QObject>
86 >;
87
88template <typename T>
90 std::enable_if_t<!(std::is_pointer_v<T>
92 std::remove_const_t<std::remove_pointer_t<T>>>),
93 bool>;
94
95} // namespace Internal
96
97Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
98 const char *expected, const char *file, int line);
99Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
100Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
101Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
102Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
103Q_TESTLIB_EXPORT char *toString(const char *);
104Q_TESTLIB_EXPORT char *toString(const volatile void *);
105Q_TESTLIB_EXPORT char *toString(const volatile QObject *);
106
107template<typename T, Internal::is_suitable_type_v<T> = true>
108inline char *toString(const T &t)
109{
110 return Internal::toString(t);
111}
112
113template <typename T1, typename T2>
114inline char *toString(const std::pair<T1, T2> &pair);
115
116template <class... Types>
117inline char *toString(const std::tuple<Types...> &tuple);
118
119template <typename Rep, typename Period>
120inline char *toString(std::chrono::duration<Rep, Period> duration);
121
122#define QTEST_COMPARE_DECL(KLASS)\
123 template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
124#ifndef Q_QDOC
133
135QTEST_COMPARE_DECL(double)
138QTEST_COMPARE_DECL(signed char)
139QTEST_COMPARE_DECL(unsigned char)
141#endif
142#undef QTEST_COMPARE_DECL
143
144template <> inline char *toString(const QStringView &str)
145{
147}
148
149template<> inline char *toString(const QString &str)
150{
151 return toString(QStringView(str));
152}
153
154template<> inline char *toString(const QLatin1StringView &str)
155{
156 return toString(QString(str));
157}
158
159template<> inline char *toString(const QByteArray &ba)
160{
162}
163
164template<> inline char *toString(const QBitArray &ba)
165{
166 qsizetype size = ba.size();
167 char *str = new char[size + 1];
168 for (qsizetype i = 0; i < size; ++i)
169 str[i] = "01"[ba.testBit(i)];
170 str[size] = '\0';
171 return str;
172}
173
174#if QT_CONFIG(datestring)
175template<> inline char *toString(const QTime &time)
176{
177 return time.isValid()
178 ? qstrdup(qPrintable(time.toString(u"hh:mm:ss.zzz")))
179 : qstrdup("Invalid QTime");
180}
181
182template<> inline char *toString(const QDate &date)
183{
184 return date.isValid()
185 ? qstrdup(qPrintable(date.toString(u"yyyy/MM/dd")))
186 : qstrdup("Invalid QDate");
187}
188
189template<> inline char *toString(const QDateTime &dateTime)
190{
191 return dateTime.isValid()
192 ? qstrdup(qPrintable(dateTime.toString(u"yyyy/MM/dd hh:mm:ss.zzz[t]")))
193 : qstrdup("Invalid QDateTime");
194}
195#endif // datestring
196
197template<> inline char *toString(const QCborError &c)
198{
199 // use the Q_ENUM formatting
200 return toString(c.c);
201}
202
203template<> inline char *toString(const QChar &c)
204{
205 const ushort uc = c.unicode();
206 if (uc < 128) {
207 char msg[32] = {'\0'};
208 qsnprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
209 return qstrdup(msg);
210 }
211 return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
212}
213
214#if QT_CONFIG(itemmodel)
215template<> inline char *toString(const QModelIndex &idx)
216{
217 char msg[128];
218 qsnprintf(msg, sizeof(msg), "QModelIndex(%d,%d,%p,%p)", idx.row(), idx.column(), idx.internalPointer(), idx.model());
219 return qstrdup(msg);
220}
221#endif
222
223template<> inline char *toString(const QPoint &p)
224{
225 char msg[128] = {'\0'};
226 qsnprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
227 return qstrdup(msg);
228}
229
230template<> inline char *toString(const QSize &s)
231{
232 char msg[128] = {'\0'};
233 qsnprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
234 return qstrdup(msg);
235}
236
237template<> inline char *toString(const QRect &s)
238{
239 char msg[256] = {'\0'};
240 qsnprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
241 s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
242 return qstrdup(msg);
243}
244
245template<> inline char *toString(const QPointF &p)
246{
247 char msg[64] = {'\0'};
248 qsnprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
249 return qstrdup(msg);
250}
251
252template<> inline char *toString(const QSizeF &s)
253{
254 char msg[64] = {'\0'};
255 qsnprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
256 return qstrdup(msg);
257}
258
259template<> inline char *toString(const QRectF &s)
260{
261 char msg[256] = {'\0'};
262 qsnprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
263 s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
264 return qstrdup(msg);
265}
266
267template<> inline char *toString(const QUrl &uri)
268{
269 if (!uri.isValid())
270 return qstrdup(qPrintable(QLatin1StringView("Invalid URL: ") + uri.errorString()));
271 return qstrdup(uri.toEncoded().constData());
272}
273
274template <> inline char *toString(const QUuid &uuid)
275{
276 return qstrdup(uuid.toByteArray().constData());
277}
278
279template<> inline char *toString(const QVariant &v)
280{
281 QByteArray vstring("QVariant(");
282 if (v.isValid()) {
283 QByteArray type(v.typeName());
284 if (type.isEmpty()) {
285 type = QByteArray::number(v.userType());
286 }
287 vstring.append(type);
288 if (!v.isNull()) {
289 vstring.append(',');
290 if (v.canConvert<QString>()) {
291 vstring.append(v.toString().toLocal8Bit());
292 }
293 else {
294 vstring.append("<value not representable as string>");
295 }
296 }
297 }
298 vstring.append(')');
299
300 return qstrdup(vstring.constData());
301}
302
303template<> inline char *toString(const QPartialOrdering &o)
304{
306 return qstrdup("Less");
308 return qstrdup("Equivalent");
310 return qstrdup("Greater");
312 return qstrdup("Unordered");
313 return qstrdup("<invalid>");
314}
315
316namespace Internal {
318{
319 enum { BufferLen = 256 };
321 {
322 char *buf = new char[BufferLen];
323 qsnprintf(buf, BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
324 return buf;
325 }
326
327 static char *formatTag(QCborTag tag, const QCborValue &taggedValue)
328 {
329 QScopedArrayPointer<char> hold(format(taggedValue));
330 char *buf = new char[BufferLen];
331 qsnprintf(buf, BufferLen, "QCborValue(QCborTag(%llu), %s)", tag, hold.get());
332 return buf;
333 }
334
335 static char *innerFormat(QCborValue::Type t, const char *str)
336 {
337 static const QMetaEnum typeEnum = []() {
338 int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
339 return QCborValue::staticMetaObject.enumerator(idx);
340 }();
341
342 char *buf = new char[BufferLen];
343 const char *typeName = typeEnum.valueToKey(t);
344 if (typeName)
345 qsnprintf(buf, BufferLen, "QCborValue(%s, %s)", typeName, str);
346 else
347 qsnprintf(buf, BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
348 return buf;
349 }
350
351 template<typename T> static char *format(QCborValue::Type type, const T &t)
352 {
353 QScopedArrayPointer<char> hold(QTest::toString(t));
354 return innerFormat(type, hold.get());
355 }
356
357 static char *format(const QCborValue &v)
358 {
359 switch (v.type()) {
361 return format(v.type(), v.toInteger());
363 return format(v.type(), v.toByteArray());
365 return format(v.type(), v.toString());
367 return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toArray())).get());
368 case QCborValue::Map:
369 return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toMap())).get());
370 case QCborValue::Tag:
371 return formatTag(v.tag(), v.taggedValue());
373 break;
374 case QCborValue::True:
375 return qstrdup("QCborValue(true)");
377 return qstrdup("QCborValue(false)");
378 case QCborValue::Null:
379 return qstrdup("QCborValue(nullptr)");
381 return qstrdup("QCborValue()");
383 return format(v.type(), v.toDouble());
385 case QCborValue::Url:
387 return format(v.type(), v.taggedValue().toString());
388 case QCborValue::Uuid:
389 return format(v.type(), v.toUuid());
391 return qstrdup("QCborValue(<invalid>)");
392 }
393
394 if (v.isSimpleType())
395 return formatSimpleType(v.toSimpleType());
396 return innerFormat(v.type(), "");
397 }
398
399 static char *format(const QCborArray &a)
400 {
401 QByteArray out(1, '[');
402 const char *comma = "";
403 for (QCborValueConstRef v : a) {
404 QScopedArrayPointer<char> s(format(v));
405 out += comma;
406 out += s.get();
407 comma = ", ";
408 }
409 out += ']';
410 return qstrdup(out.constData());
411 }
412
413 static char *format(const QCborMap &m)
414 {
415 QByteArray out(1, '{');
416 const char *comma = "";
417 for (auto pair : m) {
418 QScopedArrayPointer<char> key(format(pair.first));
419 QScopedArrayPointer<char> value(format(pair.second));
420 out += comma;
421 out += key.get();
422 out += ": ";
423 out += value.get();
424 comma = ", ";
425 }
426 out += '}';
427 return qstrdup(out.constData());
428 }
429};
430}
431
432template<> inline char *toString(const QCborValue &v)
433{
435}
436
437template<> inline char *toString(const QCborValueRef &v)
438{
439 return toString(QCborValue(v));
440}
441
442template<> inline char *toString(const QCborArray &a)
443{
445}
446
447template<> inline char *toString(const QCborMap &m)
448{
450}
451
452template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
453{
454 QString r;
455 QDebug d(&r);
456 d.nospace() << qSetRealNumberPrecision(9) << dur;
457 if constexpr (Period::num != 1 || Period::den != 1) {
458 // include the equivalent value in seconds, in parentheses
459 using namespace std::chrono;
460 d << " (" << duration_cast<duration<qreal>>(dur).count() << "s)";
461 }
462 return qstrdup(std::move(r).toUtf8().constData());
463}
464
465template <typename T1, typename T2>
466inline char *toString(const std::pair<T1, T2> &pair)
467{
468 const QScopedArrayPointer<char> first(toString(pair.first));
469 const QScopedArrayPointer<char> second(toString(pair.second));
470 return formatString("std::pair(", ")", 2, first.data(), second.data());
471}
472
473template <typename Tuple, std::size_t... I>
474inline char *tupleToString(const Tuple &tuple, std::index_sequence<I...>) {
475 using UP = std::unique_ptr<char[]>;
476 // Generate a table of N + 1 elements where N is the number of
477 // elements in the tuple.
478 // The last element is needed to support the empty tuple use case.
479 const UP data[] = {
480 UP(toString(std::get<I>(tuple)))..., UP{}
481 };
482 return formatString("std::tuple(", ")", sizeof...(I), data[I].get()...);
483}
484
485template <class... Types>
486inline char *toString(const std::tuple<Types...> &tuple)
487{
488 return tupleToString(tuple, std::make_index_sequence<sizeof...(Types)>{});
489}
490
491inline char *toString(std::nullptr_t)
492{
493 return toString(QStringView(u"nullptr"));
494}
495} // namespace QTest
496
498
499#endif // QTESTTOSTRING_H
\inmodule QtCore
Definition qbitarray.h:13
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
\inmodule QtCore\reentrant
Definition qcborarray.h:20
\inmodule QtCore\reentrant
Definition qcbormap.h:21
\inmodule QtCore\reentrant
Definition qcborvalue.h:47
Type
This enum represents the QCborValue type.
Definition qcborvalue.h:70
@ RegularExpression
Definition qcborvalue.h:90
\inmodule QtCore
\inmodule QtCore\reentrant
Definition qdatetime.h:283
bool isValid() const
Returns true if this datetime represents a definite moment, otherwise false.
\inmodule QtCore \reentrant
Definition qdatetime.h:29
constexpr bool isValid() const
Returns true if this date is valid; otherwise returns false.
Definition qdatetime.h:71
\inmodule QtCore
\inmodule QtCore
const char * valueToKey(int value) const
Returns the string that is used as the name of the given enumeration value, or \nullptr if value is n...
QByteArray valueToKeys(int value) const
Returns a byte array of '|'-separated keys that represents the given value.
\inmodule QtCore
constexpr int row() const noexcept
Returns the row this model index refers to.
constexpr const QAbstractItemModel * model() const noexcept
Returns a pointer to the model containing the item that this index refers to.
constexpr int column() const noexcept
Returns the column this model index refers to.
void * internalPointer() const noexcept
Returns a {void} {*} pointer used by the model to associate the index with the internal data structur...
\inmodule QtCore
Definition qobject.h:103
\variable Qt::partial_ordering::less
Definition qcompare.h:679
static const QPartialOrdering Less
Definition qcompare.h:681
static const QPartialOrdering Greater
Definition qcompare.h:683
static const QPartialOrdering Equivalent
Definition qcompare.h:682
static const QPartialOrdering Unordered
Definition qcompare.h:684
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qsize.h:25
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore \reentrant
Definition qdatetime.h:215
bool isValid() const
Returns true if the time is valid; otherwise returns false.
\inmodule QtCore
Definition qurl.h:94
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1882
QByteArray toEncoded(FormattingOptions options=FullyEncoded) const
Returns the encoded representation of the URL if it's valid; otherwise an empty QByteArray is returne...
Definition qurl.cpp:2967
QString errorString() const
Definition qurl.cpp:3604
\inmodule QtCore
Definition quuid.h:31
QByteArray toByteArray(StringFormat mode=WithBraces) const
Definition quuid.cpp:691
\inmodule QtCore
Definition qvariant.h:65
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:47
QJSValue expected
Definition qjsengine.cpp:12
QString str
[2]
QDate date
[1]
Combined button and popup list for selecting options.
const char * toString(QSizePolicy::Policy p)
std::enable_if_t<!(std::is_pointer_v< T > &&is_suitable_type_helper_v< std::remove_const_t< std::remove_pointer_t< T > > >), bool > is_suitable_type_v
constexpr bool is_suitable_type_helper_v
char * toString(const MyPoint &point)
char * tupleToString(const Tuple &tuple, std::index_sequence< I... >)
char * formatString(const char *prefix, const char *suffix, size_t numArguments,...)
char * toPrettyCString(const char *p, qsizetype length)
char * toHexRepresentation(const char *ba, qsizetype length)
Returns a pointer to a string that is the string ba represented as a space-separated sequence of hex ...
Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual, const char *expected, const char *file, int line)
Q_TESTLIB_EXPORT char * toPrettyUnicode(QStringView string)
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
Q_CORE_EXPORT char * qstrdup(const char *)
QCborTag
Definition qcborcommon.h:30
QCborSimpleType
Definition qcborcommon.h:23
AudioChannelLayoutTag tag
static QDBusError::ErrorType get(const char *name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const char * typeName
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
[4]
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint first
GLint GLsizei GLsizei GLenum format
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
SSL_CTX int void * arg
#define qPrintable(string)
Definition qstring.h:1531
#define t2
#define QTEST_COMPARE_DECL(KLASS)
QTextStreamManipulator qSetRealNumberPrecision(int precision)
unsigned long ulong
Definition qtypes.h:35
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned short ushort
Definition qtypes.h:33
QByteArray ba
[0]
QFile file
[0]
QTextStream out(stdout)
[7]
QCborValue(QCborTag(2), QByteArray("\x01\0\0\0\0\0\0\0\0", 9))
[0]
QDateTime dateTime
[12]
\inmodule QtCore \inheaderfile QtCborCommon \reentrant
Definition qcborcommon.h:63
static char * format(QCborValue::Type type, const T &t)
static char * format(const QCborArray &a)
static char * innerFormat(QCborValue::Type t, const char *str)
static char * format(const QCborMap &m)
static char * format(const QCborValue &v)
static char * formatTag(QCborTag tag, const QCborValue &taggedValue)
static char * formatSimpleType(QCborSimpleType st)