Teach QByteArrayView how to parse numbers

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 <thiago.macieira@intel.com>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Edward Welbourne 2021-08-09 18:18:19 +02:00
parent 6db5fd5918
commit 4e9efb0b60
6 changed files with 983 additions and 577 deletions

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the documentation of the Qt Toolkit. ** This file is part of the documentation of the Qt Toolkit.
@ -58,3 +58,24 @@
void fun(QByteArrayView bv); void fun(QByteArrayView bv);
void fun(char ch) { fun(QByteArrayView(&ch, 1)); } void fun(char ch) { fun(QByteArrayView(&ch, 1)); }
//! [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]

View File

@ -3571,6 +3571,11 @@ qlonglong QByteArray::toLongLong(bool *ok, int base) const
return toIntegral_helper<qlonglong>(*this, ok, base); return toIntegral_helper<qlonglong>(*this, ok, base);
} }
qlonglong QByteArrayView::toLongLong(bool *ok, int base) const
{
return toIntegral_helper<qlonglong>(*this, ok, base);
}
/*! /*!
Returns the byte array converted to an \c {unsigned long long} using base \a 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 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<qulonglong>(*this, ok, base); return toIntegral_helper<qulonglong>(*this, ok, base);
} }
qulonglong QByteArrayView::toULongLong(bool *ok, int base) const
{
return toIntegral_helper<qulonglong>(*this, ok, base);
}
/*! /*!
Returns the byte array converted to an \c int using base \a base, which is 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 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<int>(*this, ok, base); return toIntegral_helper<int>(*this, ok, base);
} }
int QByteArrayView::toInt(bool *ok, int base) const
{
return toIntegral_helper<int>(*this, ok, base);
}
/*! /*!
Returns the byte array converted to an \c {unsigned int} using base \a 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 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<uint>(*this, ok, base); return toIntegral_helper<uint>(*this, ok, base);
} }
uint QByteArrayView::toUInt(bool *ok, int base) const
{
return toIntegral_helper<uint>(*this, ok, base);
}
/*! /*!
\since 4.1 \since 4.1
@ -3684,6 +3704,11 @@ long QByteArray::toLong(bool *ok, int base) const
return toIntegral_helper<long>(*this, ok, base); return toIntegral_helper<long>(*this, ok, base);
} }
long QByteArrayView::toLong(bool *ok, int base) const
{
return toIntegral_helper<long>(*this, ok, base);
}
/*! /*!
\since 4.1 \since 4.1
@ -3712,6 +3737,11 @@ ulong QByteArray::toULong(bool *ok, int base) const
return toIntegral_helper<ulong>(*this, ok, base); return toIntegral_helper<ulong>(*this, ok, base);
} }
ulong QByteArrayView::toULong(bool *ok, int base) const
{
return toIntegral_helper<ulong>(*this, ok, base);
}
/*! /*!
Returns the byte array converted to a \c short using base \a base, which is 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 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<short>(*this, ok, base); return toIntegral_helper<short>(*this, ok, base);
} }
short QByteArrayView::toShort(bool *ok, int base) const
{
return toIntegral_helper<short>(*this, ok, base);
}
/*! /*!
Returns the byte array converted to an \c {unsigned short} using base \a 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 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<ushort>(*this, ok, base); return toIntegral_helper<ushort>(*this, ok, base);
} }
ushort QByteArrayView::toUShort(bool *ok, int base) const
{
return toIntegral_helper<ushort>(*this, ok, base);
}
/*! /*!
Returns the byte array converted to a \c double value. 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 double QByteArray::toDouble(bool *ok) const
{
return QByteArrayView(*this).toDouble(ok);
}
double QByteArrayView::toDouble(bool *ok) const
{ {
bool nonNullOk = false; bool nonNullOk = false;
int processed = 0; int processed = 0;
double d = qt_asciiToDouble(constData(), size(), double d = qt_asciiToDouble(data(), size(), nonNullOk, processed, WhitespacesAllowed);
nonNullOk, processed, WhitespacesAllowed);
if (ok) if (ok)
*ok = nonNullOk; *ok = nonNullOk;
return d; return d;
@ -3833,6 +3876,11 @@ float QByteArray::toFloat(bool *ok) const
return QLocaleData::convertDoubleToFloat(toDouble(ok), ok); return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
} }
float QByteArrayView::toFloat(bool *ok) const
{
return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
}
/*! /*!
\since 5.2 \since 5.2

View File

@ -240,8 +240,19 @@ public:
constexpr void chop(qsizetype n) constexpr void chop(qsizetype n)
{ Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; } { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; }
// Defined in qbytearray.cpp:
[[nodiscard]] QByteArrayView trimmed() const noexcept [[nodiscard]] QByteArrayView trimmed() const noexcept
{ return QtPrivate::trimmed(*this); } { 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 [[nodiscard]] bool startsWith(QByteArrayView other) const noexcept
{ return QtPrivate::startsWith(*this, other); } { return QtPrivate::startsWith(*this, other); }

View File

@ -645,6 +645,246 @@
\sa QChar::SpecialCharacter, {QByteArray#Spacing Characters}{Spacing Characters} \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(QByteArrayView bv) const
\fn bool QByteArrayView::startsWith(char ch) const \fn bool QByteArrayView::startsWith(char ch) const

View File

@ -36,7 +36,6 @@
#include <private/qtools_p.h> #include <private/qtools_p.h>
#include "../shared/test_number_shared.h" #include "../shared/test_number_shared.h"
#include <limits>
class tst_QByteArray : public QObject class tst_QByteArray : public QObject
{ {
@ -90,29 +89,12 @@ private slots:
void replace_data(); void replace_data();
void replace(); void replace();
void replaceWithSpecifiedLength(); 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();
void number_double_data(); void number_double_data();
void number_double(); void number_double();
void number_base_data(); void number_base_data();
void number_base(); 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 blockSizeCalculations();
void resizeAfterFromRawData(); 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<QByteArray>("string");
QTest::addColumn<int>("base");
QTest::addColumn<int>("expectednumber");
QTest::addColumn<bool>("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<QByteArray>("string");
QTest::addColumn<int>("base");
QTest::addColumn<uint>("expectednumber");
QTest::addColumn<bool>("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<QByteArray>("string");
QTest::addColumn<double>("expectedNumber");
QTest::addColumn<bool>("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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<long>("result");
QTest::addColumn<bool>("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<long>;
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<qint32>;
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<qlonglong>(Bounds::max()) + 1;
const qlonglong longMinMinusOne = static_cast<qlonglong>(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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<ulong>("result");
QTest::addColumn<bool>("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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<qlonglong>("result");
QTest::addColumn<bool>("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<qlonglong>;
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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<qulonglong>("result");
QTest::addColumn<bool>("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<qulonglong>;
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) static bool checkSize(qsizetype value, qsizetype min)
{ {
return value >= min && value <= std::numeric_limits<qsizetype>::max(); return value >= min && value <= std::numeric_limits<qsizetype>::max();
@ -3056,7 +2484,5 @@ void tst_QByteArray::length_data()
QTest::newRow("with '\\0' no size") << QByteArray("abc\0def") << qsizetype(3); QTest::newRow("with '\\0' no size") << QByteArray("abc\0def") << qsizetype(3);
} }
const char globalChar = '1';
QTEST_MAIN(tst_QByteArray) QTEST_MAIN(tst_QByteArray)
#include "tst_qbytearray.moc" #include "tst_qbytearray.moc"

View File

@ -30,6 +30,8 @@
#include <QByteArrayView> #include <QByteArrayView>
#include <limits>
class tst_QByteArrayApiSymmetry : public QObject class tst_QByteArrayApiSymmetry : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -126,6 +128,41 @@ private slots:
void trimmed_QByteArrayView_data() { trimmed_data(); } void trimmed_QByteArrayView_data() { trimmed_data(); }
void trimmed_QByteArrayView() { trimmed_impl<QByteArrayView>(); } void trimmed_QByteArrayView() { trimmed_impl<QByteArrayView>(); }
void toShort_QByteArray() const { toShort<QByteArray>(); }
void toShort_QByteArrayView() const { toShort<QByteArrayView>(); }
void toUShort_QByteArray() const { toUShort<QByteArray>(); }
void toUShort_QByteArrayView() const { toUShort<QByteArrayView>(); }
void toInt_QByteArray_data() const { toInt_data(); }
void toInt_QByteArrayView_data() const { toInt_data(); }
void toInt_QByteArray() const { toInt<QByteArray>(); }
void toInt_QByteArrayView() const { toInt<QByteArrayView>(); }
void toUInt_QByteArray_data() const { toUInt_data(); }
void toUInt_QByteArrayView_data() const { toUInt_data(); }
void toUInt_QByteArray() const { toUInt<QByteArray>(); }
void toUInt_QByteArrayView() const { toUInt<QByteArrayView>(); }
void toLong_QByteArray_data() const { toLong_data(); }
void toLong_QByteArrayView_data() const { toLong_data(); }
void toLong_QByteArray() const { toLong<QByteArray>(); }
void toLong_QByteArrayView() const { toLong<QByteArrayView>(); }
void toULong_QByteArray_data() const { toULong_data(); }
void toULong_QByteArrayView_data() const { toULong_data(); }
void toULong_QByteArray() const { toULong<QByteArray>(); }
void toULong_QByteArrayView() const { toULong<QByteArrayView>(); }
void toLongLong_QByteArray_data() const { toLongLong_data(); }
void toLongLong_QByteArrayView_data() const { toLongLong_data(); }
void toLongLong_QByteArray() const { toLongLong<QByteArray>(); }
void toLongLong_QByteArrayView() const { toLongLong<QByteArrayView>(); }
void toULongLong_QByteArray_data() const { toULongLong_data(); }
void toULongLong_QByteArrayView_data() const { toULongLong_data(); }
void toULongLong_QByteArray() const { toULongLong<QByteArray>(); }
void toULongLong_QByteArrayView() const { toULongLong<QByteArrayView>(); }
void toFloat_QByteArray() const { toFloat<QByteArray>(); }
void toFloat_QByteArrayView() const { toFloat<QByteArrayView>(); }
void toDouble_QByteArray_data() const { toDouble_data(); }
void toDouble_QByteArrayView_data() const { toDouble_data(); }
void toDouble_QByteArray() const { toDouble<QByteArray>(); }
void toDouble_QByteArrayView() const { toDouble<QByteArrayView>(); }
private: private:
void startsWith_data(); void startsWith_data();
template<typename Haystack, typename Needle> void startsWith_impl(); template<typename Haystack, typename Needle> void startsWith_impl();
@ -164,6 +201,24 @@ private:
void trimmed_data(); void trimmed_data();
template <typename ByteArray> void trimmed_impl(); template <typename ByteArray> void trimmed_impl();
template <typename ByteArray> void toShort() const;
template <typename ByteArray> void toUShort() const;
void toInt_data() const;
template <typename ByteArray> void toInt() const;
void toUInt_data() const;
template <typename ByteArray> void toUInt() const;
void toLong_data() const;
template <typename ByteArray> void toLong() const;
void toULong_data() const;
template <typename ByteArray> void toULong() const;
void toLongLong_data() const;
template <typename ByteArray> void toLongLong() const;
void toULongLong_data() const;
template <typename ByteArray> void toULongLong() const;
template <typename ByteArray> void toFloat() const;
void toDouble_data() const;
template <typename ByteArray> void toDouble() const;
}; };
static const auto empty = QByteArray(""); static const auto empty = QByteArray("");
@ -917,5 +972,610 @@ template <typename ByteArray> void tst_QByteArrayApiSymmetry::trimmed_impl()
} }
} }
template <typename ByteArray> 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 <typename ByteArray> 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<QByteArray>("string");
QTest::addColumn<int>("base");
QTest::addColumn<int>("expectednumber");
QTest::addColumn<bool>("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 <typename ByteArray> 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<QByteArray>("string");
QTest::addColumn<int>("base");
QTest::addColumn<uint>("expectednumber");
QTest::addColumn<bool>("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 <typename ByteArray> 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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<long>("result");
QTest::addColumn<bool>("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<long>;
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<qint32>;
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<qlonglong>(Bounds::max()) + 1;
const qlonglong longMinMinusOne = static_cast<qlonglong>(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 <typename ByteArray> 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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<ulong>("result");
QTest::addColumn<bool>("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 <typename ByteArray> 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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<qlonglong>("result");
QTest::addColumn<bool>("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<qlonglong>;
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 <typename ByteArray> 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<QByteArray>("str");
QTest::addColumn<int>("base");
QTest::addColumn<qulonglong>("result");
QTest::addColumn<bool>("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<qulonglong>;
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 <typename ByteArray> 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 <typename ByteArray> 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<QByteArray>("string");
QTest::addColumn<double>("expectedNumber");
QTest::addColumn<bool>("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 <typename ByteArray> 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) QTEST_APPLESS_MAIN(tst_QByteArrayApiSymmetry)
#include "tst_qbytearrayapisymmetry.moc" #include "tst_qbytearrayapisymmetry.moc"