From 4e9efb0b6096c35edc0b98650cf64acb367d5ba8 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 9 Aug 2021 18:18:19 +0200 Subject: [PATCH] Teach QByteArrayView how to parse numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we don't need '\0'-termination on the data, this is possible. Moved QByteArray's tests to tst_QByteArrayApiSymmetry and added some more test-cases. [ChangeLog][QtCore][QByteArrayView] Added numeric parsing methods. Change-Id: Ic0df91ecfe5dbf6f008d344dd0464d7927f32273 Reviewed-by: Thiago Macieira Reviewed-by: MÃ¥rten Nordheim --- .../code/src_corelib_text_qbytearrayview.cpp | 23 +- src/corelib/text/qbytearray.cpp | 52 +- src/corelib/text/qbytearrayview.h | 11 + src/corelib/text/qbytearrayview.qdoc | 240 +++++++ .../text/qbytearray/tst_qbytearray.cpp | 574 --------------- .../tst_qbytearrayapisymmetry.cpp | 660 ++++++++++++++++++ 6 files changed, 983 insertions(+), 577 deletions(-) diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp index d70caa2650..519f609790 100644 --- a/src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_text_qbytearrayview.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -58,3 +58,24 @@ void fun(QByteArrayView bv); void fun(char ch) { fun(QByteArrayView(&ch, 1)); } //! [1] + +//! [2] +QByteArrayView str("FF"); +bool ok; +int hex = str.toInt(&ok, 16); // hex == 255, ok == true +int dec = str.toInt(&ok, 10); // dec == 0, ok == false +//! [2] + +//! [3] +QByteArrayView str("FF"); +bool ok; +long hex = str.toLong(&ok, 16); // hex == 255, ok == true +long dec = str.toLong(&ok, 10); // dec == 0, ok == false +//! [3] + +//! [4] +QByteArrayView string("1234.56 Volt"); +bool ok; +float a = str.toFloat(&ok); // a == 0, ok == false +a = string.first(7).toFloat(&ok); // a == 1234.56, ok == true +//! [4] diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 320f744c4f..a1b0f30d01 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -3571,6 +3571,11 @@ qlonglong QByteArray::toLongLong(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +qlonglong QByteArrayView::toLongLong(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} + /*! Returns the byte array converted to an \c {unsigned long long} using base \a base, which is ten by default. Bases 0 and 2 through 36 are supported, using @@ -3598,6 +3603,11 @@ qulonglong QByteArray::toULongLong(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +qulonglong QByteArrayView::toULongLong(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} + /*! Returns the byte array converted to an \c int using base \a base, which is ten by default. Bases 0 and 2 through 36 are supported, using letters for @@ -3627,6 +3637,11 @@ int QByteArray::toInt(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +int QByteArrayView::toInt(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} + /*! Returns the byte array converted to an \c {unsigned int} using base \a base, which is ten by default. Bases 0 and 2 through 36 are supported, using @@ -3654,6 +3669,11 @@ uint QByteArray::toUInt(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +uint QByteArrayView::toUInt(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} + /*! \since 4.1 @@ -3684,6 +3704,11 @@ long QByteArray::toLong(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +long QByteArrayView::toLong(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} + /*! \since 4.1 @@ -3712,6 +3737,11 @@ ulong QByteArray::toULong(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +ulong QByteArrayView::toULong(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} + /*! Returns the byte array converted to a \c short using base \a base, which is ten by default. Bases 0 and 2 through 36 are supported, using letters for @@ -3739,6 +3769,11 @@ short QByteArray::toShort(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +short QByteArrayView::toShort(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} + /*! Returns the byte array converted to an \c {unsigned short} using base \a base, which is ten by default. Bases 0 and 2 through 36 are supported, using @@ -3766,6 +3801,10 @@ ushort QByteArray::toUShort(bool *ok, int base) const return toIntegral_helper(*this, ok, base); } +ushort QByteArrayView::toUShort(bool *ok, int base) const +{ + return toIntegral_helper(*this, ok, base); +} /*! Returns the byte array converted to a \c double value. @@ -3793,11 +3832,15 @@ ushort QByteArray::toUShort(bool *ok, int base) const */ double QByteArray::toDouble(bool *ok) const +{ + return QByteArrayView(*this).toDouble(ok); +} + +double QByteArrayView::toDouble(bool *ok) const { bool nonNullOk = false; int processed = 0; - double d = qt_asciiToDouble(constData(), size(), - nonNullOk, processed, WhitespacesAllowed); + double d = qt_asciiToDouble(data(), size(), nonNullOk, processed, WhitespacesAllowed); if (ok) *ok = nonNullOk; return d; @@ -3833,6 +3876,11 @@ float QByteArray::toFloat(bool *ok) const return QLocaleData::convertDoubleToFloat(toDouble(ok), ok); } +float QByteArrayView::toFloat(bool *ok) const +{ + return QLocaleData::convertDoubleToFloat(toDouble(ok), ok); +} + /*! \since 5.2 diff --git a/src/corelib/text/qbytearrayview.h b/src/corelib/text/qbytearrayview.h index 1824826437..1cd5b0333e 100644 --- a/src/corelib/text/qbytearrayview.h +++ b/src/corelib/text/qbytearrayview.h @@ -240,8 +240,19 @@ public: constexpr void chop(qsizetype n) { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; } + // Defined in qbytearray.cpp: [[nodiscard]] QByteArrayView trimmed() const noexcept { return QtPrivate::trimmed(*this); } + [[nodiscard]] short toShort(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] ushort toUShort(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] int toInt(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] uint toUInt(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] long toLong(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] ulong toULong(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] qlonglong toLongLong(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] qulonglong toULongLong(bool *ok = nullptr, int base = 10) const; + [[nodiscard]] float toFloat(bool *ok = nullptr) const; + [[nodiscard]] double toDouble(bool *ok = nullptr) const; [[nodiscard]] bool startsWith(QByteArrayView other) const noexcept { return QtPrivate::startsWith(*this, other); } diff --git a/src/corelib/text/qbytearrayview.qdoc b/src/corelib/text/qbytearrayview.qdoc index 5bfd8bdef2..624b056744 100644 --- a/src/corelib/text/qbytearrayview.qdoc +++ b/src/corelib/text/qbytearrayview.qdoc @@ -645,6 +645,246 @@ \sa QChar::SpecialCharacter, {QByteArray#Spacing Characters}{Spacing Characters} */ +/*! + \fn qlonglong QByteArrayView::toLongLong(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to a \c {long long} using base \a + base, which is ten by default. Bases 0 and 2 through 36 are supported, using + letters for digits beyond 9; A is ten, B is eleven and so on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn qulonglong QByteArrayView::toULongLong(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to an \c {unsigned long long} using + base \a base, which is ten by default. Bases 0 and 2 through 36 are + supported, using letters for digits beyond 9; A is ten, B is eleven and so + on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn int QByteArrayView::toInt(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to an \c int using base \a base, + which is ten by default. Bases 0 and 2 through 36 are supported, using + letters for digits beyond 9; A is ten, B is eleven and so on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \snippet code/src_corelib_text_qbytearrayview.cpp 2 + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn uint QByteArrayView::toUInt(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to an \c {unsigned int} using base \a + base, which is ten by default. Bases 0 and 2 through 36 are supported, using + letters for digits beyond 9; A is ten, B is eleven and so on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn long QByteArrayView::toLong(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to a \c long int using base \a base, + which is ten by default. Bases 0 and 2 through 36 are supported, using + letters for digits beyond 9; A is ten, B is eleven and so on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \snippet code/src_corelib_text_qbytearrayview.cpp 3 + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn ulong QByteArrayView::toULong(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to an \c {unsigned long int} using + base \a base, which is ten by default. Bases 0 and 2 through 36 are + supported, using letters for digits beyond 9; A is ten, B is eleven and so + on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn short QByteArrayView::toShort(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to a \c short using base \a base, + which is ten by default. Bases 0 and 2 through 36 are supported, using + letters for digits beyond 9; A is ten, B is eleven and so on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn ushort QByteArrayView::toUShort(bool *ok, int base) const + \since 6.3 + + Returns this byte array view converted to an \c {unsigned short} using base + \a base, which is ten by default. Bases 0 and 2 through 36 are supported, + using letters for digits beyond 9; A is ten, B is eleven and so on. + + If \a base is 0, the base is determined automatically using the following + rules: if the byte array view begins with "0x", the rest of it is read as + hexadecimal (base 16); otherwise, if it begins with "0", the rest of it is + read as octal (base 8); otherwise it is read as decimal. + + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. +*/ + +/*! + \fn double QByteArrayView::toDouble(bool *ok) const + \since 6.3 + + Returns this byte array view converted to a \c double value. + + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \warning The QByteArrayView content may only contain valid numerical + characters which includes the plus/minus sign, the character e used in + scientific notation, and the decimal point. Including the unit or additional + characters leads to a conversion error. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. + + This function ignores leading and trailing spacing characters. +*/ + +/*! + \fn float QByteArrayView::toFloat(bool *ok) const + \since 6.3 + + Returns this byte array view converted to a \c float value. + + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \snippet code/src_corelib_text_qbytearrayview.cpp 4 + + \warning The QByteArrayView content may only contain valid numerical + characters which includes the plus/minus sign, the character e used in + scientific notation, and the decimal point. Including the unit or additional + characters leads to a conversion error. + + \note The conversion of the number is performed in the default C locale, + regardless of the user's locale. Use QLocale to perform locale-aware + conversions between numbers and strings. + + This function ignores leading and trailing whitespace. +*/ + /*! \fn bool QByteArrayView::startsWith(QByteArrayView bv) const \fn bool QByteArrayView::startsWith(char ch) const diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp index ff04eca14d..a4798e77aa 100644 --- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -36,7 +36,6 @@ #include #include "../shared/test_number_shared.h" -#include class tst_QByteArray : public QObject { @@ -90,29 +89,12 @@ private slots: void replace_data(); void replace(); void replaceWithSpecifiedLength(); - void toLong_data(); - void toLong(); - void toULong_data(); - void toULong(); - void toLongLong_data(); - void toLongLong(); - void toULongLong_data(); - void toULongLong(); void number(); void number_double_data(); void number_double(); void number_base_data(); void number_base(); - void toShort(); - void toUShort(); - void toInt_data(); - void toInt(); - void toUInt_data(); - void toUInt(); - void toFloat(); - void toDouble_data(); - void toDouble(); void blockSizeCalculations(); void resizeAfterFromRawData(); @@ -1379,560 +1361,6 @@ void tst_QByteArray::number_base() } } -void tst_QByteArray::toShort() -{ - bool ok = true; // opposite to the next expected result - - QCOMPARE(QByteArray().toShort(&ok), 0); - QVERIFY(!ok); - - QCOMPARE(QByteArray("").toShort(&ok), 0); - QVERIFY(!ok); - - QCOMPARE(QByteArray("12345").toShort(&ok), 12345); - QVERIFY(ok); - - QCOMPARE(QByteArray("-12345").toShort(&ok), -12345); - QVERIFY(ok); - - QCOMPARE(QByteArray("32767").toShort(&ok), 32767); - QVERIFY(ok); - - QCOMPARE(QByteArray("-32768").toShort(&ok), -32768); - QVERIFY(ok); - - QCOMPARE(QByteArray("32768").toShort(&ok), 0); - QVERIFY(!ok); - - QCOMPARE(QByteArray("-32769").toShort(&ok), 0); - QVERIFY(!ok); -} - -void tst_QByteArray::toUShort() -{ - bool ok = true; // opposite to the next expected result - - QCOMPARE(QByteArray().toUShort(&ok), 0); - QVERIFY(!ok); - - QCOMPARE(QByteArray("").toUShort(&ok), 0); - QVERIFY(!ok); - - QCOMPARE(QByteArray("12345").toUShort(&ok), 12345); - QVERIFY(ok); - - QCOMPARE(QByteArray("-12345").toUShort(&ok), 0); - QVERIFY(!ok); - - QCOMPARE(QByteArray("32767").toUShort(&ok), 32767); - QVERIFY(ok); - - QCOMPARE(QByteArray("32768").toUShort(&ok), 32768); - QVERIFY(ok); - - QCOMPARE(QByteArray("65535").toUShort(&ok), 65535); - QVERIFY(ok); - - QCOMPARE(QByteArray("65536").toUShort(&ok), 0); - QVERIFY(!ok); -} - -// defined later -extern const char globalChar; - -void tst_QByteArray::toInt_data() -{ - QTest::addColumn("string"); - QTest::addColumn("base"); - QTest::addColumn("expectednumber"); - QTest::addColumn("expectedok"); - - QTest::newRow("null") << QByteArray() << 10 << 0 << false; - QTest::newRow("empty") << QByteArray("") << 10 << 0 << false; - - QTest::newRow("base 10") << QByteArray("100") << 10 << int(100) << true; - QTest::newRow("base 16-1") << QByteArray("100") << 16 << int(256) << true; - QTest::newRow("base 16-2") << QByteArray("0400") << 16 << int(1024) << true; - QTest::newRow("base 2") << QByteArray("1111") << 2 << int(15) << true; - QTest::newRow("base 8") << QByteArray("100") << 8 << int(64) << true; - QTest::newRow("base 0-1") << QByteArray("0x10") << 0 << int(16) << true; - QTest::newRow("base 0-2") << QByteArray("10") << 0 << int(10) << true; - QTest::newRow("base 0-3") << QByteArray("010") << 0 << int(8) << true; - QTest::newRow("empty") << QByteArray() << 0 << int(0) << false; - - QTest::newRow("leading space") << QByteArray(" 100") << 10 << int(100) << true; - QTest::newRow("trailing space") << QByteArray("100 ") << 10 << int(100) << true; - QTest::newRow("leading junk") << QByteArray("x100") << 10 << int(0) << false; - QTest::newRow("trailing junk") << QByteArray("100x") << 10 << int(0) << false; - - // using fromRawData - QTest::newRow("raw1") << QByteArray::fromRawData("1", 1) << 10 << 1 << true; - QTest::newRow("raw2") << QByteArray::fromRawData("1foo", 1) << 10 << 1 << true; - QTest::newRow("raw3") << QByteArray::fromRawData("12", 1) << 10 << 1 << true; - QTest::newRow("raw4") << QByteArray::fromRawData("123456789", 1) << 10 << 1 << true; - QTest::newRow("raw5") << QByteArray::fromRawData("123456789", 2) << 10 << 12 << true; - - QTest::newRow("raw-static") << QByteArray::fromRawData(&globalChar, 1) << 10 << 1 << true; -} - -void tst_QByteArray::toInt() -{ - QFETCH( QByteArray, string ); - QFETCH( int, base ); - QFETCH( int, expectednumber ); - QFETCH( bool, expectedok ); - - bool ok; - int number = string.toInt(&ok, base); - - QCOMPARE( ok, expectedok ); - QCOMPARE( number, expectednumber ); -} - -void tst_QByteArray::toUInt_data() -{ - QTest::addColumn("string"); - QTest::addColumn("base"); - QTest::addColumn("expectednumber"); - QTest::addColumn("expectedok"); - - QTest::newRow("null") << QByteArray() << 10 << 0u << false; - QTest::newRow("empty") << QByteArray("") << 10 << 0u << false; - - QTest::newRow("negative value") << QByteArray("-50") << 10 << 0u << false; - QTest::newRow("more than MAX_INT") << QByteArray("3234567890") << 10 << 3234567890u << true; - QTest::newRow("2^32 - 1") << QByteArray("4294967295") << 10 << 4294967295u << true; - if (sizeof(int) == 4) - QTest::newRow("2^32") << QByteArray("4294967296") << 10 << 0u << false; -} - -void tst_QByteArray::toUInt() -{ - QFETCH(QByteArray, string); - QFETCH(int, base); - QFETCH(uint, expectednumber); - QFETCH(bool, expectedok); - - bool ok; - const uint number = string.toUInt(&ok, base); - - QCOMPARE(ok, expectedok); - QCOMPARE(number, expectednumber); -} - -void tst_QByteArray::toFloat() -{ - bool ok = true; // opposite to the next expected result - - QCOMPARE(QByteArray().toFloat(&ok), 0.0f); - QVERIFY(!ok); - - QCOMPARE(QByteArray("").toFloat(&ok), 0.0f); - QVERIFY(!ok); - - const QByteArray data("0.000000000931322574615478515625"); - const float expectedValue = 9.31322574615478515625e-10f; - QCOMPARE(data.toFloat(&ok), expectedValue); - QVERIFY(ok); -} - -void tst_QByteArray::toDouble_data() -{ - QTest::addColumn("string"); - QTest::addColumn("expectedNumber"); - QTest::addColumn("expectedOk"); - - QTest::newRow("null") << QByteArray() << 0.0 << false; - QTest::newRow("empty") << QByteArray("") << 0.0 << false; - - QTest::newRow("decimal") << QByteArray("1.2345") << 1.2345 << true; - QTest::newRow("exponent lowercase") << QByteArray("1.2345e+01") << 12.345 << true; - QTest::newRow("exponent uppercase") << QByteArray("1.2345E+02") << 123.45 << true; - QTest::newRow("leading spaces") << QByteArray(" \n\r\t1.2345") << 1.2345 << true; - QTest::newRow("trailing spaces") << QByteArray("1.2345 \n\r\t") << 1.2345 << true; - QTest::newRow("leading junk") << QByteArray("x1.2345") << 0.0 << false; - QTest::newRow("trailing junk") << QByteArray("1.2345x") << 0.0 << false; - QTest::newRow("high precision") << QByteArray("0.000000000931322574615478515625") - << 0.000000000931322574615478515625 << true; - - QTest::newRow("raw, null plus junk") << QByteArray::fromRawData("1.2\0 junk", 9) << 0.0 << false; - QTest::newRow("raw, null-terminator not included") << QByteArray::fromRawData("2.3", 3) << 2.3 << true; -} - -void tst_QByteArray::toDouble() -{ - QFETCH(QByteArray, string); - QFETCH(double, expectedNumber); - QFETCH(bool, expectedOk); - - bool ok; - const double number = string.toDouble(&ok); - - QCOMPARE(ok, expectedOk); - QCOMPARE(number, expectedNumber); -} - -void tst_QByteArray::toLong_data() -{ - QTest::addColumn("str"); - QTest::addColumn("base"); - QTest::addColumn("result"); - QTest::addColumn("ok"); - - QTest::newRow("null") << QByteArray() << 10 << 0L << false; - QTest::newRow("empty") << QByteArray("") << 16 << 0L << false; - QTest::newRow("in range dec") << QByteArray("1608507359") << 10 << 1608507359L << true; - QTest::newRow("in range dec neg") << QByteArray("-1608507359") << 10 << -1608507359L << true; - QTest::newRow("in range hex") << QByteArray("12ABCDEF") << 16 << 0x12ABCDEFL << true; - QTest::newRow("in range hex neg") << QByteArray("-12ABCDEF") << 16 << -0x12ABCDEFL << true; - QTest::newRow("Fibonacci's last int32") << QByteArray("1836311903") << 10 << 1836311903L - << true; - - QTest::newRow("leading spaces") << QByteArray(" \r\n\tABC123") << 16 << 0xABC123L << true; - QTest::newRow("trailing spaces") << QByteArray("1234567\t\r \n") << 10 << 1234567L << true; - QTest::newRow("leading junk") << QByteArray("q12345") << 10 << 0L << false; - QTest::newRow("trailing junk") << QByteArray("abc12345t") << 16 << 0L << false; - - QTest::newRow("dec with base 0") << QByteArray("123") << 0 << 123L << true; - QTest::newRow("neg dec with base 0") << QByteArray("-123") << 0 << -123L << true; - QTest::newRow("hex with base 0") << QByteArray("0x123") << 0 << 0x123L << true; - QTest::newRow("neg hex with base 0") << QByteArray("-0x123") << 0 << -0x123L << true; - QTest::newRow("oct with base 0") << QByteArray("0123") << 0 << 0123L << true; - QTest::newRow("neg oct with base 0") << QByteArray("-0123") << 0 << -0123L << true; - - QTest::newRow("base 3") << QByteArray("12012") << 3 << 140L << true; - QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19L << true; - - using Bounds = std::numeric_limits; - QTest::newRow("long max") << QByteArray::number(Bounds::max()) << 10 << Bounds::max() << true; - QTest::newRow("long min") << QByteArray::number(Bounds::min()) << 10 << Bounds::min() << true; - - using B32 = std::numeric_limits; - QTest::newRow("int32 min bin") << (QByteArray("-1") + QByteArray(31, '0')) << 2 - << long(B32::min()) << true; - QTest::newRow("int32 max bin") << QByteArray(31, '1') << 2 << long(B32::max()) << true; - QTest::newRow("int32 min hex") << QByteArray("-80000000") << 16 << long(B32::min()) << true; - QTest::newRow("int32 max hex") << QByteArray("7fffffff") << 16 << long(B32::max()) << true; - QTest::newRow("int32 min dec") << QByteArray("-2147483648") << 10 << long(B32::min()) << true; - QTest::newRow("int32 max dec") << QByteArray("2147483647") << 10 << long(B32::max()) << true; - - if constexpr (sizeof(long) < sizeof(qlonglong)) { - const qlonglong longMaxPlusOne = static_cast(Bounds::max()) + 1; - const qlonglong longMinMinusOne = static_cast(Bounds::min()) - 1; - QTest::newRow("long max + 1") << QByteArray::number(longMaxPlusOne) << 10 << 0L << false; - QTest::newRow("long min - 1") << QByteArray::number(longMinMinusOne) << 10 << 0L << false; - } -} - -void tst_QByteArray::toLong() -{ - QFETCH(QByteArray, str); - QFETCH(int, base); - QFETCH(long, result); - QFETCH(bool, ok); - - bool b; - QCOMPARE(str.toLong(nullptr, base), result); - QCOMPARE(str.toLong(&b, base), result); - QCOMPARE(b, ok); - if (base == 10) { - // check that by default base is assumed to be 10 - QCOMPARE(str.toLong(&b), result); - QCOMPARE(b, ok); - } -} - -void tst_QByteArray::toULong_data() -{ - QTest::addColumn("str"); - QTest::addColumn("base"); - QTest::addColumn("result"); - QTest::addColumn("ok"); - - ulong LongMaxPlusOne = (ulong)LONG_MAX + 1; - QTest::newRow("LONG_MAX+1") << QString::number(LongMaxPlusOne).toUtf8() << 10 << LongMaxPlusOne << true; - QTest::newRow("null") << QByteArray() << 10 << 0UL << false; - QTest::newRow("empty") << QByteArray("") << 10 << 0UL << false; - QTest::newRow("ulong1") << QByteArray("3234567890") << 10 << 3234567890UL << true; - QTest::newRow("ulong2") << QByteArray("fFFfFfFf") << 16 << 0xFFFFFFFFUL << true; - - QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100UL << true; - QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100UL << true; - QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0UL << false; - QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0UL << false; -} - -void tst_QByteArray::toULong() -{ - QFETCH(QByteArray, str); - QFETCH(int, base); - QFETCH(ulong, result); - QFETCH(bool, ok); - - bool b; - QCOMPARE(str.toULong(0, base), result); - QCOMPARE(str.toULong(&b, base), result); - QCOMPARE(b, ok); -} - -static QByteArray decNext(QByteArray &&big) -{ - // Increments a decimal digit-string (ignoring sign, so decrements if - // negative); only intended for taking a boundary value just out of range, - // so big is never a string of only 9s (that'd be one less than a power of - // ten, which cannot be a power of two, as odd, or one less than one, as the - // power of ten isn't a power of two). - int i = big.size() - 1; - while (big.at(i) == '9') - big[i--] = '0'; - big[i] += 1; - return big; -} - -void tst_QByteArray::toLongLong_data() -{ - QTest::addColumn("str"); - QTest::addColumn("base"); - QTest::addColumn("result"); - QTest::addColumn("ok"); - - QTest::newRow("null") << QByteArray() << 10 << 0LL << false; - QTest::newRow("empty") << QByteArray("") << 10 << 0LL << false; - QTest::newRow("out of base bound") << QByteArray("c") << 10 << 0LL << false; - - QTest::newRow("in range dec") << QByteArray("7679359922672374856") << 10 - << 7679359922672374856LL << true; - QTest::newRow("in range dec neg") << QByteArray("-7679359922672374856") << 10 - << -7679359922672374856LL << true; - QTest::newRow("in range hex") - << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448LL << true; - QTest::newRow("in range hex prefix") - << QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448LL << true; - QTest::newRow("in range hex neg") - << QByteArray("-6A929129A5421448") << 16 << -0x6A929129A5421448LL << true; - QTest::newRow("in range hex prefix neg") - << QByteArray("-0x6A929129A5421448") << 16 << -0x6A929129A5421448LL << true; - QTest::newRow("Fibonacci's last int64") << QByteArray("7540113804746346429") << 10 - << 7540113804746346429LL << true; - - QTest::newRow("leading spaces") << QByteArray(" \r\n\tABCFFFFFFF123") << 16 - << 0xABCFFFFFFF123LL << true; - QTest::newRow("trailing spaces") << QByteArray("9876543210\t\r \n") << 10 - << 9876543210LL << true; - QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0LL << false; - QTest::newRow("space after minus") << QByteArray("- 12") << 10 << 0LL << false; - QTest::newRow("leading junk") << QByteArray("q12345") << 10 << 0LL << false; - QTest::newRow("trailing junk") << QByteArray("abc12345t") << 16 << 0LL << false; - - QTest::newRow("dec with base 0") << QByteArray("9876543210") << 0 << 9876543210LL << true; - QTest::newRow("neg dec with base 0") << QByteArray("-9876543210") << 0 << -9876543210LL << true; - QTest::newRow("hex with base 0") << QByteArray("0x9876543210") << 0 << 0x9876543210LL << true; - QTest::newRow("neg hex with base 0") << QByteArray("-0x9876543210") << 0 << -0x9876543210LL - << true; - QTest::newRow("oct with base 0") << QByteArray("07654321234567") << 0 << 07654321234567LL - << true; - QTest::newRow("neg oct with base 0") << QByteArray("-07654321234567") << 0 << -07654321234567LL - << true; - - QTest::newRow("base 3") << QByteArray("12012") << 3 << 140LL << true; - QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19LL << true; - - // Boundary values, first in every base: - using LL = std::numeric_limits; - for (int b = 0; b <= 36; ++b) { - if (b == 1) // bases 0 and 2 through 36 are allowed - ++b; - QTest::addRow("max base %d", b) - << QByteArray::number(LL::max(), b ? b : 10) << b << LL::max() << true; - QTest::addRow("min base %d", b) - << QByteArray::number(LL::min(), b ? b : 10) << b << LL::min() << true; - } - // Check leading zeros don't hit any buffer-too-big problems: - QTest::newRow("many-0 max dec") - << (QByteArray(512, '0') + QByteArray::number(LL::max())) << 10 << LL::max() << true; - - // Special bases (and let's include some leading space, too !), first decimal: - QTest::newRow("max dec, base 0") << QByteArray::number(LL::max()) << 0 << LL::max() << true; - QTest::newRow("max space dec") - << ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 10 << LL::max() << true; - QTest::newRow("max space dec, base 0") - << ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 0 << LL::max() << true; - QTest::newRow("min dec, base 0") << QByteArray::number(LL::min()) << 0 << LL::min() << true; - QTest::newRow("min space dec") - << ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 10 << LL::min() << true; - QTest::newRow("min space dec, base 0") - << ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 0 << LL::min() << true; - - // Hex with prefix: - QTest::newRow("max 0x base 0") - << ("0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; - QTest::newRow("max +0x base 0") - << ("+0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; - QTest::newRow("max space 0x base 0") - << ("\t\r\n\f\v 0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; - QTest::newRow("max space +0x base 0") - << ("\t\r\n\f\v +0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; - QByteArray big = QByteArray::number(LL::min(), 16); - big.insert(1, "0x"); // after sign - QTest::newRow("min hex prefix") << big << 16 << LL::min() << true; - QTest::newRow("min 0x base 0") << big << 0 << LL::min() << true; - big.prepend("\t\r\n\f\v "); - QTest::newRow("min space hex prefix") << big << 16 << LL::min() << true; - QTest::newRow("min space 0x base 0") << big << 0 << LL::min() << true; - - // Octal with prefix: - QTest::newRow("max octal base 0") - << ('0' + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; - QTest::newRow("max +octal base 0") - << ("+0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; - QTest::newRow("max space octal base 0") - << ("\t\r\n\f\v 0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; - QTest::newRow("max space +octal base 0") - << ("\t\r\n\f\v +0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; - big = QByteArray::number(LL::min(), 8); - big.insert(1, '0'); // after sign - QTest::newRow("min octal prefix") << big << 8 << LL::min() << true; - QTest::newRow("min octal base 0") << big << 0 << LL::min() << true; - big.prepend("\t\r\n\f\v "); - QTest::newRow("min space octal prefix") << big << 8 << LL::min() << true; - QTest::newRow("min space octal base 0") << big << 0 << LL::min() << true; - - // Values *just* out of range: - QTest::newRow("max + 1 dec") << decNext(QByteArray::number(LL::max())) << 10 << 0LL << false; - QTest::newRow("max + 1 dec base 0") - << decNext(QByteArray::number(LL::max())) << 0 << 0LL << false; - QTest::newRow("min - 1 dec") << decNext(QByteArray::number(LL::min())) << 10 << 0LL << false; - QTest::newRow("min - 1 dec base 0") - << decNext(QByteArray::number(LL::min())) << 0 << 0LL << false; - // For hex and octal, we know the last digit of min is 0 and skipping its sign gets max+1: - big = QByteArray::number(LL::min(), 8); - QTest::newRow("max + 1 oct") << big.sliced(1) << 8 << 0LL << false; - big[big.size() - 1] = '1'; - QTest::newRow("min - 1 oct") << big << 8 << 0LL << false; - big.insert(1, '0'); // after minus sign - QTest::newRow("min - 1 octal base 0") << big << 0 << 0LL << false; - big = QByteArray::number(LL::min(), 16); - QTest::newRow("max + 1 hex") << big.sliced(1) << 16 << 0LL << false; - big[big.size() - 1] = '1'; - QTest::newRow("min - 1 hex") << big << 16 << 0LL << false; - big.insert(1, "0x"); // after minus sign - QTest::newRow("min - 1, 0x base 0") << big << 0 << 0LL << false; -} - -void tst_QByteArray::toLongLong() -{ - QFETCH(QByteArray, str); - QFETCH(int, base); - QFETCH(qlonglong, result); - QFETCH(bool, ok); - - bool b; - QCOMPARE(str.toLongLong(nullptr, base), result); - QCOMPARE(str.toLongLong(&b, base), result); - QCOMPARE(b, ok); - if (base == 10) { - QCOMPARE(str.toLongLong(&b), result); - QCOMPARE(b, ok); - } -} - -void tst_QByteArray::toULongLong_data() -{ - QTest::addColumn("str"); - QTest::addColumn("base"); - QTest::addColumn("result"); - QTest::addColumn("ok"); - - QTest::newRow("null") << QByteArray() << 10 << 0ULL << false; - QTest::newRow("empty") << QByteArray("") << 10 << 0ULL << false; - QTest::newRow("out of base bound") << QByteArray("c") << 10 << 0ULL << false; - - QTest::newRow("in range dec") - << QByteArray("7679359922672374856") << 10 << 7679359922672374856ULL << true; - QTest::newRow("in range hex") - << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true; - QTest::newRow("in range hex prefix") - << QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true; - - QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100ULL << true; - QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100ULL << true; - QTest::newRow("leading plus") << QByteArray("+100") << 10 << 100ULL << true; - QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0ULL << false; - QTest::newRow("leading minus") << QByteArray("-100") << 10 << 0ULL << false; - QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0ULL << false; - QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0ULL << false; - - QTest::newRow("dec, base 0") << QByteArray("9876543210") << 0 << 9876543210ULL << true; - QTest::newRow("hex, base 0") << QByteArray("0x9876543210") << 0 << 0x9876543210ULL << true; - QTest::newRow("oct, base 0") << QByteArray("07654321234567") << 0 << 07654321234567ULL << true; - QTest::newRow("base 3") << QByteArray("12012") << 3 << 140ULL << true; - - // Boundary values, first in every base: - using ULL = std::numeric_limits; - for (int b = 0; b <= 36; ++b) { - if (b == 1) // bases 0 and 2 through 36 are allowed - ++b; - QTest::addRow("max base %d", b) - << QByteArray::number(ULL::max(), b ? b : 10) << b << ULL::max() << true; - } - // Check leading zeros don't hit any buffer-too-big problems: - QTest::newRow("many-0 max dec") - << (QByteArray(512, '0') + QByteArray::number(ULL::max())) << 10 << ULL::max() << true; - - // Special bases (and let's include some leading space, too !), first decimal: - QTest::newRow("max dec, base 0") << QByteArray::number(ULL::max()) << 0 << ULL::max() << true; - QTest::newRow("max space dec") - << ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 10 << ULL::max() << true; - QTest::newRow("max space dec, base 0") - << ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 0 << ULL::max() << true; - - // Hex with prefix: - QTest::newRow("max 0x base 0") - << ("0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; - QTest::newRow("max +0x base 0") - << ("+0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; - QTest::newRow("max space 0x base 0") - << ("\t\r\n\f\v 0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; - QTest::newRow("max space +0x base 0") - << ("\t\r\n\f\v +0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; - - // Octal with prefix: - QTest::newRow("max octal base 0") - << ('0' + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; - QTest::newRow("max +octal base 0") - << ("+0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; - QTest::newRow("max space octal base 0") - << ("\t\r\n\f\v 0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; - QTest::newRow("max space +octal base 0") - << ("\t\r\n\f\v +0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; - - // Values *just* out of range: - QTest::newRow("max + 1 dec") << decNext(QByteArray::number(ULL::max())) << 10 << 0ULL << false; - QTest::newRow("max + 1 dec base 0") - << decNext(QByteArray::number(ULL::max())) << 0 << 0ULL << false; - auto big = QByteArray::number(ULL::max(), 8).replace('7', '0'); - // Number of bits is a power of two, so not a multiple of three; so (only) - // first digit of max wasn't 7: - big[0] += 1; - QTest::newRow("max + 1 oct") << big << 8 << 0ULL << false; - // Number of bits is a multiple of four, so every digit of max is 'f'. - big = '1' + QByteArray::number(ULL::max(), 16).replace('f', '0'); - QTest::newRow("max + 1 hex") << big << 16 << 0ULL << false; -} - -void tst_QByteArray::toULongLong() -{ - QFETCH(QByteArray, str); - QFETCH(int, base); - QFETCH(qulonglong, result); - QFETCH(bool, ok); - - bool b; - QCOMPARE(str.toULongLong(0, base), result); - QCOMPARE(str.toULongLong(&b, base), result); - QCOMPARE(b, ok); -} - static bool checkSize(qsizetype value, qsizetype min) { return value >= min && value <= std::numeric_limits::max(); @@ -3056,7 +2484,5 @@ void tst_QByteArray::length_data() QTest::newRow("with '\\0' no size") << QByteArray("abc\0def") << qsizetype(3); } -const char globalChar = '1'; - QTEST_MAIN(tst_QByteArray) #include "tst_qbytearray.moc" diff --git a/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp b/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp index 4d419dd0d3..2feb911af6 100644 --- a/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp +++ b/tests/auto/corelib/text/qbytearrayapisymmetry/tst_qbytearrayapisymmetry.cpp @@ -30,6 +30,8 @@ #include +#include + class tst_QByteArrayApiSymmetry : public QObject { Q_OBJECT @@ -126,6 +128,41 @@ private slots: void trimmed_QByteArrayView_data() { trimmed_data(); } void trimmed_QByteArrayView() { trimmed_impl(); } + void toShort_QByteArray() const { toShort(); } + void toShort_QByteArrayView() const { toShort(); } + void toUShort_QByteArray() const { toUShort(); } + void toUShort_QByteArrayView() const { toUShort(); } + void toInt_QByteArray_data() const { toInt_data(); } + void toInt_QByteArrayView_data() const { toInt_data(); } + void toInt_QByteArray() const { toInt(); } + void toInt_QByteArrayView() const { toInt(); } + void toUInt_QByteArray_data() const { toUInt_data(); } + void toUInt_QByteArrayView_data() const { toUInt_data(); } + void toUInt_QByteArray() const { toUInt(); } + void toUInt_QByteArrayView() const { toUInt(); } + void toLong_QByteArray_data() const { toLong_data(); } + void toLong_QByteArrayView_data() const { toLong_data(); } + void toLong_QByteArray() const { toLong(); } + void toLong_QByteArrayView() const { toLong(); } + void toULong_QByteArray_data() const { toULong_data(); } + void toULong_QByteArrayView_data() const { toULong_data(); } + void toULong_QByteArray() const { toULong(); } + void toULong_QByteArrayView() const { toULong(); } + void toLongLong_QByteArray_data() const { toLongLong_data(); } + void toLongLong_QByteArrayView_data() const { toLongLong_data(); } + void toLongLong_QByteArray() const { toLongLong(); } + void toLongLong_QByteArrayView() const { toLongLong(); } + void toULongLong_QByteArray_data() const { toULongLong_data(); } + void toULongLong_QByteArrayView_data() const { toULongLong_data(); } + void toULongLong_QByteArray() const { toULongLong(); } + void toULongLong_QByteArrayView() const { toULongLong(); } + void toFloat_QByteArray() const { toFloat(); } + void toFloat_QByteArrayView() const { toFloat(); } + void toDouble_QByteArray_data() const { toDouble_data(); } + void toDouble_QByteArrayView_data() const { toDouble_data(); } + void toDouble_QByteArray() const { toDouble(); } + void toDouble_QByteArrayView() const { toDouble(); } + private: void startsWith_data(); template void startsWith_impl(); @@ -164,6 +201,24 @@ private: void trimmed_data(); template void trimmed_impl(); + + template void toShort() const; + template void toUShort() const; + void toInt_data() const; + template void toInt() const; + void toUInt_data() const; + template void toUInt() const; + void toLong_data() const; + template void toLong() const; + void toULong_data() const; + template void toULong() const; + void toLongLong_data() const; + template void toLongLong() const; + void toULongLong_data() const; + template void toULongLong() const; + template void toFloat() const; + void toDouble_data() const; + template void toDouble() const; }; static const auto empty = QByteArray(""); @@ -917,5 +972,610 @@ template void tst_QByteArrayApiSymmetry::trimmed_impl() } } +template void tst_QByteArrayApiSymmetry::toShort() const +{ + bool ok = true; // opposite to the first expected result + + QCOMPARE(ByteArray().toShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("").toShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("12345").toShort(&ok), 12345); + QVERIFY(ok); + + QCOMPARE(ByteArray("-12345").toShort(&ok), -12345); + QVERIFY(ok); + + QCOMPARE(ByteArray("-12345 and a bit", 5).toShort(&ok), -1234); + QVERIFY(ok); + + QCOMPARE(ByteArray("-12345 and a bit").sliced(1, 4).toShort(&ok), 1234); + QVERIFY(ok); + + QCOMPARE(ByteArray("-012345 and a bit", 2).toShort(&ok), 0); + QVERIFY(ok); + + QCOMPARE(ByteArray("-12345 and a bit", 6).toShort(&ok), -12345); + QVERIFY(ok); + + QCOMPARE(ByteArray("-12345 and a bit", 7).toShort(&ok), -12345); + QVERIFY(ok); + + QCOMPARE(ByteArray("12345 and a bit", 10).toShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("32767").toShort(&ok), 32767); + QVERIFY(ok); + + QCOMPARE(ByteArray("-32768").toShort(&ok), -32768); + QVERIFY(ok); + + QCOMPARE(ByteArray("32768").toShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("-32769").toShort(&ok), 0); + QVERIFY(!ok); +} + +template void tst_QByteArrayApiSymmetry::toUShort() const +{ + bool ok = true; // opposite to the first expected result + + QCOMPARE(ByteArray().toUShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("").toUShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("12345").toUShort(&ok), 12345); + QVERIFY(ok); + + QCOMPARE(ByteArray("12345 and a bit", 4).toUShort(&ok), 1234); + QVERIFY(ok); + + QCOMPARE(ByteArray("012345 and a bit").sliced(1, 4).toUShort(&ok), 1234); + QVERIFY(ok); + + QCOMPARE(ByteArray("012345 and a bit", 1).toUShort(&ok), 0); + QVERIFY(ok); + + QCOMPARE(ByteArray("12345 and a bit", 5).toUShort(&ok), 12345); + QVERIFY(ok); + + QCOMPARE(ByteArray("12345 and a bit", 6).toUShort(&ok), 12345); + QVERIFY(ok); + + QCOMPARE(ByteArray("12345 and a bit", 10).toUShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("-12345").toUShort(&ok), 0); + QVERIFY(!ok); + + QCOMPARE(ByteArray("32767").toUShort(&ok), 32767); + QVERIFY(ok); + + QCOMPARE(ByteArray("32768").toUShort(&ok), 32768); + QVERIFY(ok); + + QCOMPARE(ByteArray("65535").toUShort(&ok), 65535); + QVERIFY(ok); + + QCOMPARE(ByteArray("65536").toUShort(&ok), 0); + QVERIFY(!ok); +} + +// defined later +extern const char globalChar; + +void tst_QByteArrayApiSymmetry::toInt_data() const +{ + QTest::addColumn("string"); + QTest::addColumn("base"); + QTest::addColumn("expectednumber"); + QTest::addColumn("expectedok"); + + QTest::newRow("null") << QByteArray() << 10 << 0 << false; + QTest::newRow("empty") << QByteArray("") << 10 << 0 << false; + + QTest::newRow("base 10") << QByteArray("100") << 10 << 100 << true; + QTest::newRow("base 16-1") << QByteArray("100") << 16 << 256 << true; + QTest::newRow("base 16-2") << QByteArray("0400") << 16 << 1024 << true; + QTest::newRow("base 2") << QByteArray("1111") << 2 << 15 << true; + QTest::newRow("base 8") << QByteArray("100") << 8 << 64 << true; + QTest::newRow("base 0-1") << QByteArray("0x10") << 0 << 16 << true; + QTest::newRow("base 0-2") << QByteArray("10") << 0 << 10 << true; + QTest::newRow("base 0-3") << QByteArray("010") << 0 << 8 << true; + QTest::newRow("empty") << QByteArray() << 0 << 0 << false; + + QTest::newRow("leading space") << QByteArray(" 100") << 10 << 100 << true; + QTest::newRow("trailing space") << QByteArray("100 ") << 10 << 100 << true; + QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0 << false; + QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0 << false; + + // using fromRawData + QTest::newRow("raw1") << QByteArray::fromRawData("1", 1) << 10 << 1 << true; + QTest::newRow("raw2") << QByteArray::fromRawData("1foo", 1) << 10 << 1 << true; + QTest::newRow("raw3") << QByteArray::fromRawData("12", 1) << 10 << 1 << true; + QTest::newRow("raw4") << QByteArray::fromRawData("123456789", 1) << 10 << 1 << true; + QTest::newRow("raw5") << QByteArray::fromRawData("123456789", 2) << 10 << 12 << true; + + QTest::newRow("raw-static") << QByteArray::fromRawData(&globalChar, 1) << 10 << 1 << true; +} + +template void tst_QByteArrayApiSymmetry::toInt() const +{ + QFETCH(QByteArray, string); + QFETCH(int, base); + QFETCH(int, expectednumber); + QFETCH(bool, expectedok); + + bool ok; + int number = ByteArray(string).toInt(&ok, base); + + QCOMPARE(ok, expectedok); + QCOMPARE(number, expectednumber); +} + +void tst_QByteArrayApiSymmetry::toUInt_data() const +{ + QTest::addColumn("string"); + QTest::addColumn("base"); + QTest::addColumn("expectednumber"); + QTest::addColumn("expectedok"); + + QTest::newRow("null") << QByteArray() << 10 << 0u << false; + QTest::newRow("empty") << QByteArray("") << 10 << 0u << false; + + QTest::newRow("negative value") << QByteArray("-50") << 10 << 0u << false; + QTest::newRow("more than MAX_INT") << QByteArray("3234567890") << 10 << 3234567890u << true; + QTest::newRow("2^32 - 1") << QByteArray("4294967295") << 10 << 4294967295u << true; + if constexpr (sizeof(int) > 4) + QTest::newRow("2^32") << QByteArray("4294967296") << 10 << (1u << 32) << true; + else + QTest::newRow("2^32") << QByteArray("4294967296") << 10 << 0u << false; +} + +template void tst_QByteArrayApiSymmetry::toUInt() const +{ + QFETCH(QByteArray, string); + QFETCH(int, base); + QFETCH(uint, expectednumber); + QFETCH(bool, expectedok); + + bool ok; + const uint number = ByteArray(string).toUInt(&ok, base); + + QCOMPARE(ok, expectedok); + QCOMPARE(number, expectednumber); +} + +void tst_QByteArrayApiSymmetry::toLong_data() const +{ + QTest::addColumn("str"); + QTest::addColumn("base"); + QTest::addColumn("result"); + QTest::addColumn("ok"); + + QTest::newRow("null") << QByteArray() << 10 << 0L << false; + QTest::newRow("empty") << QByteArray("") << 16 << 0L << false; + QTest::newRow("in range dec") << QByteArray("1608507359") << 10 << 1608507359L << true; + QTest::newRow("in range dec neg") << QByteArray("-1608507359") << 10 << -1608507359L << true; + QTest::newRow("in range hex") << QByteArray("12ABCDEF") << 16 << 0x12ABCDEFL << true; + QTest::newRow("in range hex neg") << QByteArray("-12ABCDEF") << 16 << -0x12ABCDEFL << true; + QTest::newRow("Fibonacci's last int32") + << QByteArray("1836311903") << 10 << 1836311903L << true; + + QTest::newRow("leading spaces") << QByteArray(" \r\n\tABC123") << 16 << 0xABC123L << true; + QTest::newRow("trailing spaces") << QByteArray("1234567\t\r \n") << 10 << 1234567L << true; + QTest::newRow("leading junk") << QByteArray("q12345") << 10 << 0L << false; + QTest::newRow("trailing junk") << QByteArray("abc12345t") << 16 << 0L << false; + + QTest::newRow("dec with base 0") << QByteArray("123") << 0 << 123L << true; + QTest::newRow("neg dec with base 0") << QByteArray("-123") << 0 << -123L << true; + QTest::newRow("hex with base 0") << QByteArray("0x123") << 0 << 0x123L << true; + QTest::newRow("neg hex with base 0") << QByteArray("-0x123") << 0 << -0x123L << true; + QTest::newRow("oct with base 0") << QByteArray("0123") << 0 << 0123L << true; + QTest::newRow("neg oct with base 0") << QByteArray("-0123") << 0 << -0123L << true; + + QTest::newRow("base 3") << QByteArray("12012") << 3 << 140L << true; + QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19L << true; + + using Bounds = std::numeric_limits; + QTest::newRow("long max") << QByteArray::number(Bounds::max()) << 10 << Bounds::max() << true; + QTest::newRow("long min") << QByteArray::number(Bounds::min()) << 10 << Bounds::min() << true; + + using B32 = std::numeric_limits; + QTest::newRow("int32 min bin") + << (QByteArray("-1") + QByteArray(31, '0')) << 2 << long(B32::min()) << true; + QTest::newRow("int32 max bin") << QByteArray(31, '1') << 2 << long(B32::max()) << true; + QTest::newRow("int32 min hex") << QByteArray("-80000000") << 16 << long(B32::min()) << true; + QTest::newRow("int32 max hex") << QByteArray("7fffffff") << 16 << long(B32::max()) << true; + QTest::newRow("int32 min dec") << QByteArray("-2147483648") << 10 << long(B32::min()) << true; + QTest::newRow("int32 max dec") << QByteArray("2147483647") << 10 << long(B32::max()) << true; + + if constexpr (sizeof(long) < sizeof(qlonglong)) { + const qlonglong longMaxPlusOne = static_cast(Bounds::max()) + 1; + const qlonglong longMinMinusOne = static_cast(Bounds::min()) - 1; + QTest::newRow("long max + 1") << QByteArray::number(longMaxPlusOne) << 10 << 0L << false; + QTest::newRow("long min - 1") << QByteArray::number(longMinMinusOne) << 10 << 0L << false; + } +} + +template void tst_QByteArrayApiSymmetry::toLong() const +{ + QFETCH(QByteArray, str); + QFETCH(int, base); + QFETCH(long, result); + QFETCH(bool, ok); + + bool good; + QCOMPARE(ByteArray(str).toLong(nullptr, base), result); + QCOMPARE(ByteArray(str).toLong(&good, base), result); + QCOMPARE(good, ok); + if (base == 10) { + // check that by default base is assumed to be 10 + QCOMPARE(ByteArray(str).toLong(&good), result); + QCOMPARE(good, ok); + } +} + +void tst_QByteArrayApiSymmetry::toULong_data() const +{ + QTest::addColumn("str"); + QTest::addColumn("base"); + QTest::addColumn("result"); + QTest::addColumn("ok"); + + ulong LongMaxPlusOne = (ulong)LONG_MAX + 1; + QTest::newRow("LONG_MAX+1") + << QString::number(LongMaxPlusOne).toUtf8() << 10 << LongMaxPlusOne << true; + QTest::newRow("null") << QByteArray() << 10 << 0UL << false; + QTest::newRow("empty") << QByteArray("") << 10 << 0UL << false; + QTest::newRow("ulong1") << QByteArray("3234567890") << 10 << 3234567890UL << true; + QTest::newRow("ulong2") << QByteArray("fFFfFfFf") << 16 << 0xFFFFFFFFUL << true; + + QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100UL << true; + QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100UL << true; + QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0UL << false; + QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0UL << false; +} + +template void tst_QByteArrayApiSymmetry::toULong() const +{ + QFETCH(QByteArray, str); + QFETCH(int, base); + QFETCH(ulong, result); + QFETCH(bool, ok); + + bool good; + QCOMPARE(ByteArray(str).toULong(0, base), result); + QCOMPARE(ByteArray(str).toULong(&good, base), result); + QCOMPARE(good, ok); +} + +static QByteArray decNext(QByteArray &&big) +{ + // Increments a decimal digit-string (ignoring sign, so decrements if + // negative); only intended for taking a boundary value just out of range, + // so big is never a string of only 9s (that'd be one less than a power of + // ten, which cannot be a power of two, as odd, or one less than one, as the + // power of ten isn't a power of two). + int i = big.size() - 1; + while (big.at(i) == '9') + big[i--] = '0'; + big[i] += 1; + return big; +} + +void tst_QByteArrayApiSymmetry::toLongLong_data() const +{ + QTest::addColumn("str"); + QTest::addColumn("base"); + QTest::addColumn("result"); + QTest::addColumn("ok"); + + QTest::newRow("null") << QByteArray() << 10 << 0LL << false; + QTest::newRow("empty") << QByteArray("") << 10 << 0LL << false; + QTest::newRow("out of base bound") << QByteArray("c") << 10 << 0LL << false; + + QTest::newRow("in range dec") + << QByteArray("7679359922672374856") << 10 << 7679359922672374856LL << true; + QTest::newRow("in range dec neg") + << QByteArray("-7679359922672374856") << 10 << -7679359922672374856LL << true; + QTest::newRow("in range hex") + << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448LL << true; + QTest::newRow("in range hex prefix") + << QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448LL << true; + QTest::newRow("in range hex neg") + << QByteArray("-6A929129A5421448") << 16 << -0x6A929129A5421448LL << true; + QTest::newRow("in range hex prefix neg") + << QByteArray("-0x6A929129A5421448") << 16 << -0x6A929129A5421448LL << true; + QTest::newRow("Fibonacci's last int64") + << QByteArray("7540113804746346429") << 10 << 7540113804746346429LL << true; + + QTest::newRow("leading spaces") + << QByteArray(" \r\n\tABCFFFFFFF123") << 16 << 0xABCFFFFFFF123LL << true; + QTest::newRow("trailing spaces") + << QByteArray("9876543210\t\r \n") << 10 << 9876543210LL << true; + QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0LL << false; + QTest::newRow("space after minus") << QByteArray("- 12") << 10 << 0LL << false; + QTest::newRow("leading junk") << QByteArray("q12345") << 10 << 0LL << false; + QTest::newRow("trailing junk") << QByteArray("abc12345t") << 16 << 0LL << false; + + QTest::newRow("dec with base 0") << QByteArray("9876543210") << 0 << 9876543210LL << true; + QTest::newRow("neg dec with base 0") << QByteArray("-9876543210") << 0 << -9876543210LL << true; + QTest::newRow("hex with base 0") << QByteArray("0x9876543210") << 0 << 0x9876543210LL << true; + QTest::newRow("neg hex with base 0") + << QByteArray("-0x9876543210") << 0 << -0x9876543210LL << true; + QTest::newRow("oct with base 0") + << QByteArray("07654321234567") << 0 << 07654321234567LL << true; + QTest::newRow("neg oct with base 0") + << QByteArray("-07654321234567") << 0 << -07654321234567LL << true; + + QTest::newRow("base 3") << QByteArray("12012") << 3 << 140LL << true; + QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19LL << true; + + // Boundary values, first in every base: + using LL = std::numeric_limits; + for (int b = 0; b <= 36; ++b) { + if (b == 1) // bases 0 and 2 through 36 are allowed + ++b; + QTest::addRow("max base %d", b) + << QByteArray::number(LL::max(), b ? b : 10) << b << LL::max() << true; + QTest::addRow("min base %d", b) + << QByteArray::number(LL::min(), b ? b : 10) << b << LL::min() << true; + } + // Check leading zeros don't hit any buffer-too-big problems: + QTest::newRow("many-0 max dec") + << (QByteArray(512, '0') + QByteArray::number(LL::max())) << 10 << LL::max() << true; + + // Special bases (and let's include some leading space, too !), first decimal: + QTest::newRow("max space dec") + << ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 10 << LL::max() << true; + QTest::newRow("max space dec, base 0") + << ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 0 << LL::max() << true; + QTest::newRow("min space dec") + << ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 10 << LL::min() << true; + QTest::newRow("min space dec, base 0") + << ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 0 << LL::min() << true; + + // Hex with prefix: + QTest::newRow("max 0x base 0") + << ("0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; + QTest::newRow("max +0x base 0") + << ("+0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; + QTest::newRow("max space 0x base 0") + << ("\t\r\n\f\v 0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; + QTest::newRow("max space +0x base 0") + << ("\t\r\n\f\v +0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true; + QByteArray big = QByteArray::number(LL::min(), 16); + big.insert(1, "0x"); // after sign + QTest::newRow("min hex prefix") << big << 16 << LL::min() << true; + QTest::newRow("min 0x base 0") << big << 0 << LL::min() << true; + big.prepend("\t\r\n\f\v "); + QTest::newRow("min space hex prefix") << big << 16 << LL::min() << true; + QTest::newRow("min space 0x base 0") << big << 0 << LL::min() << true; + + // Octal with prefix: + QTest::newRow("max octal base 0") + << ('0' + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; + QTest::newRow("max +octal base 0") + << ("+0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; + QTest::newRow("max space octal base 0") + << ("\t\r\n\f\v 0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; + QTest::newRow("max space +octal base 0") + << ("\t\r\n\f\v +0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true; + big = QByteArray::number(LL::min(), 8); + big.insert(1, '0'); // after sign + QTest::newRow("min octal prefix") << big << 8 << LL::min() << true; + QTest::newRow("min octal base 0") << big << 0 << LL::min() << true; + big.prepend("\t\r\n\f\v "); + QTest::newRow("min space octal prefix") << big << 8 << LL::min() << true; + QTest::newRow("min space octal base 0") << big << 0 << LL::min() << true; + + // Values *just* out of range: + QTest::newRow("max + 1 dec") << decNext(QByteArray::number(LL::max())) << 10 << 0LL << false; + QTest::newRow("max + 1 dec base 0") + << decNext(QByteArray::number(LL::max())) << 0 << 0LL << false; + QTest::newRow("min - 1 dec") << decNext(QByteArray::number(LL::min())) << 10 << 0LL << false; + QTest::newRow("min - 1 dec base 0") + << decNext(QByteArray::number(LL::min())) << 0 << 0LL << false; + // For hex and octal, we know the last digit of min is 0 and skipping its sign gets max+1: + big = QByteArray::number(LL::min(), 8); + QTest::newRow("max + 1 oct") << big.sliced(1) << 8 << 0LL << false; + big[big.size() - 1] = '1'; + QTest::newRow("min - 1 oct") << big << 8 << 0LL << false; + big.insert(1, '0'); // after minus sign + QTest::newRow("min - 1 octal base 0") << big << 0 << 0LL << false; + big = QByteArray::number(LL::min(), 16); + QTest::newRow("max + 1 hex") << big.sliced(1) << 16 << 0LL << false; + big[big.size() - 1] = '1'; + QTest::newRow("min - 1 hex") << big << 16 << 0LL << false; + big.insert(1, "0x"); // after minus sign + QTest::newRow("min - 1, 0x base 0") << big << 0 << 0LL << false; +} + +template void tst_QByteArrayApiSymmetry::toLongLong() const +{ + QFETCH(QByteArray, str); + QFETCH(int, base); + QFETCH(qlonglong, result); + QFETCH(bool, ok); + + bool good; + QCOMPARE(ByteArray(str).toLongLong(nullptr, base), result); + QCOMPARE(ByteArray(str).toLongLong(&good, base), result); + QCOMPARE(good, ok); + if (base == 10) { + QCOMPARE(ByteArray(str).toLongLong(&good), result); + QCOMPARE(good, ok); + } +} + +void tst_QByteArrayApiSymmetry::toULongLong_data() const +{ + QTest::addColumn("str"); + QTest::addColumn("base"); + QTest::addColumn("result"); + QTest::addColumn("ok"); + + QTest::newRow("null") << QByteArray() << 10 << 0ULL << false; + QTest::newRow("empty") << QByteArray("") << 10 << 0ULL << false; + QTest::newRow("out of base bound") << QByteArray("c") << 10 << 0ULL << false; + + QTest::newRow("in range dec") + << QByteArray("7679359922672374856") << 10 << 7679359922672374856ULL << true; + QTest::newRow("in range hex") + << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true; + QTest::newRow("in range hex prefix") + << QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true; + + QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100ULL << true; + QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100ULL << true; + QTest::newRow("leading plus") << QByteArray("+100") << 10 << 100ULL << true; + QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0ULL << false; + QTest::newRow("leading minus") << QByteArray("-100") << 10 << 0ULL << false; + QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0ULL << false; + QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0ULL << false; + + QTest::newRow("dec, base 0") << QByteArray("9876543210") << 0 << 9876543210ULL << true; + QTest::newRow("hex, base 0") << QByteArray("0x9876543210") << 0 << 0x9876543210ULL << true; + QTest::newRow("oct, base 0") << QByteArray("07654321234567") << 0 << 07654321234567ULL << true; + QTest::newRow("base 3") << QByteArray("12012") << 3 << 140ULL << true; + + // Boundary values, first in every base: + using ULL = std::numeric_limits; + for (int b = 0; b <= 36; ++b) { + if (b == 1) // bases 0 and 2 through 36 are allowed + ++b; + QTest::addRow("max base %d", b) + << QByteArray::number(ULL::max(), b ? b : 10) << b << ULL::max() << true; + } + // Check leading zeros don't hit any buffer-too-big problems: + QTest::newRow("many-0 max dec") + << (QByteArray(512, '0') + QByteArray::number(ULL::max())) << 10 << ULL::max() << true; + + // Special bases (and let's include some leading space, too !), first decimal: + QTest::newRow("max space dec") + << ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 10 << ULL::max() << true; + QTest::newRow("max space dec, base 0") + << ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 0 << ULL::max() << true; + + // Hex with prefix: + QTest::newRow("max 0x base 0") + << ("0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; + QTest::newRow("max +0x base 0") + << ("+0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; + QTest::newRow("max space 0x base 0") + << ("\t\r\n\f\v 0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; + QTest::newRow("max space +0x base 0") + << ("\t\r\n\f\v +0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true; + + // Octal with prefix: + QTest::newRow("max octal base 0") + << ('0' + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; + QTest::newRow("max +octal base 0") + << ("+0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; + QTest::newRow("max space octal base 0") + << ("\t\r\n\f\v 0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; + QTest::newRow("max space +octal base 0") + << ("\t\r\n\f\v +0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true; + + // Values *just* out of range: + QTest::newRow("max + 1 dec") << decNext(QByteArray::number(ULL::max())) << 10 << 0ULL << false; + QTest::newRow("max + 1 dec base 0") + << decNext(QByteArray::number(ULL::max())) << 0 << 0ULL << false; + auto big = QByteArray::number(ULL::max(), 8).replace('7', '0'); + // Number of bits is a power of two, so not a multiple of three; so (only) + // first digit of max wasn't 7: + big[0] += 1; + QTest::newRow("max + 1 oct") << big << 8 << 0ULL << false; + // Number of bits is a multiple of four, so every digit of max is 'f'. + big = '1' + QByteArray::number(ULL::max(), 16).replace('f', '0'); + QTest::newRow("max + 1 hex") << big << 16 << 0ULL << false; +} + +template void tst_QByteArrayApiSymmetry::toULongLong() const +{ + QFETCH(QByteArray, str); + QFETCH(int, base); + QFETCH(qulonglong, result); + QFETCH(bool, ok); + + bool good; + QCOMPARE(ByteArray(str).toULongLong(0, base), result); + QCOMPARE(ByteArray(str).toULongLong(&good, base), result); + QCOMPARE(good, ok); +} + +template void tst_QByteArrayApiSymmetry::toFloat() const +{ + bool ok = true; // opposite to the next expected result + + QCOMPARE(ByteArray().toFloat(&ok), 0.0f); + QVERIFY(!ok); + + QCOMPARE(ByteArray("").toFloat(&ok), 0.0f); + QVERIFY(!ok); + + // NB: floats < 1e-6 are zero as far as QCOMPARE() is concerned ! + const char data[] = "0.0000931322574615478515625"; + const float expectedValue = 9.31322574615478515625e-5f; + QCOMPARE(ByteArray(data).toFloat(&ok), expectedValue); + QVERIFY(ok); + QCOMPARE(ByteArray(data, 6).toFloat(&ok), 0.0f); + QVERIFY(ok); + + const char crufty[] = "3.14 and a bit"; + QCOMPARE(ByteArray(crufty).toFloat(&ok), 0.0f); + QVERIFY(!ok); + QCOMPARE(ByteArray(crufty, 4).toFloat(&ok), 3.14f); + QVERIFY(ok); +} + +void tst_QByteArrayApiSymmetry::toDouble_data() const +{ + QTest::addColumn("string"); + QTest::addColumn("expectedNumber"); + QTest::addColumn("expectedOk"); + + QTest::newRow("null") << QByteArray() << 0.0 << false; + QTest::newRow("empty") << QByteArray("") << 0.0 << false; + + QTest::newRow("decimal") << QByteArray("1.2345") << 1.2345 << true; + QTest::newRow("exponent lowercase") << QByteArray("1.2345e+01") << 12.345 << true; + QTest::newRow("exponent uppercase") << QByteArray("1.2345E+02") << 123.45 << true; + QTest::newRow("leading spaces") << QByteArray(" \n\r\t1.2345") << 1.2345 << true; + QTest::newRow("trailing spaces") << QByteArray("1.2345 \n\r\t") << 1.2345 << true; + QTest::newRow("leading junk") << QByteArray("x1.2345") << 0.0 << false; + QTest::newRow("trailing junk") << QByteArray("1.2345x") << 0.0 << false; + QTest::newRow("high precision") + << QByteArray("0.000000000931322574615478515625") << 9.31322574615478515625e-10 << true; + QTest::newRow("exponential") + << QByteArray("9.31322574615478515625e-10") << 9.31322574615478515625e-10 << true; + + QTest::newRow("raw, null plus junk") + << QByteArray::fromRawData("1.2\0 junk", 9) << 0.0 << false; + QTest::newRow("raw, null-terminator excluded") + << QByteArray::fromRawData("2.3", 3) << 2.3 << true; +} + +template void tst_QByteArrayApiSymmetry::toDouble() const +{ + QFETCH(QByteArray, string); + QFETCH(double, expectedNumber); + QFETCH(bool, expectedOk); + + bool ok; + const double number = ByteArray(string).toDouble(&ok); + + QCOMPARE(ok, expectedOk); + QCOMPARE(number, expectedNumber); +} + +const char globalChar = '1'; // Used as staic data for a raw byte array + QTEST_APPLESS_MAIN(tst_QByteArrayApiSymmetry) #include "tst_qbytearrayapisymmetry.moc"