diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2021-08-27 14:58:57 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2021-08-30 17:46:00 +0200 |
commit | 5644af6f8a800a1516360a42ba4c1a8dc61fc516 (patch) | |
tree | 0fb11871c40c7f389f95bc227699fdcda8b7889a /tests | |
parent | 522ca997d3baab1b88f454bbeea9f357d3969dff (diff) |
Replace FreeBSD's strtou?ll() with std::from_chars()-based strntou?ll()
Remove third-party code in favor of STL. Implement (for now)
strtou?ll() as inlines on strntou?ll() calling strlen() for the size
parameter. (This is not entirely safe, as a string lacking
'\0'-termination but with at least some non-matching text after the
numeric portion would formerly be parsed just fine, but would now
produce a crash. However, strtou?ll() are internal and callers should
be ensuring '\0'-termination.)
Task-number: QTBUG-74286
Change-Id: I0c8ca7d4f6110367e93b4c0164854a82c5a545e1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp | 199 | ||||
-rw-r--r-- | tests/auto/corelib/text/qlocale/tst_qlocale.cpp | 3 | ||||
-rw-r--r-- | tests/auto/corelib/text/qstring/tst_qstring.cpp | 76 |
3 files changed, 258 insertions, 20 deletions
diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp index 3b7e0efb00..ff04eca14d 100644 --- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -36,6 +36,7 @@ #include <private/qtools_p.h> #include "../shared/test_number_shared.h" +#include <limits> class tst_QByteArray : public QObject { @@ -1674,6 +1675,20 @@ void tst_QByteArray::toULong() 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"); @@ -1689,10 +1704,14 @@ void tst_QByteArray::toLongLong_data() << 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 neg") << QByteArray("-6A929129A5421448") << 16 - << -0x6A929129A5421448LL << 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; @@ -1700,6 +1719,8 @@ void tst_QByteArray::toLongLong_data() << 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; @@ -1716,13 +1737,86 @@ void tst_QByteArray::toLongLong_data() QTest::newRow("base 3") << QByteArray("12012") << 3 << 140LL << true; QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19LL << true; - QTest::newRow("max dec") << QByteArray("9223372036854775807") << 10 << 9223372036854775807LL - << true; - QTest::newRow("mix hex") << QByteArray("-7FFFFFFFFFFFFFFF") << 16 << -0x7FFFFFFFFFFFFFFFLL - << true; - - QTest::newRow("max + 1 dec") << QByteArray("9223372036854775808") << 10 << 0LL << false; - QTest::newRow("min - 1 hex") << QByteArray("-8000000000000001") << 16 << 0LL << false; + // 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() @@ -1749,14 +1843,81 @@ void tst_QByteArray::toULongLong_data() QTest::addColumn<qulonglong>("result"); QTest::addColumn<bool>("ok"); - QTest::newRow("null") << QByteArray() << 10 << (qulonglong)0 << false; - QTest::newRow("empty") << QByteArray("") << 10 << (qulonglong)0 << false; - QTest::newRow("out of base bound") << QByteArray("c") << 10 << (qulonglong)0 << false; - - QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << qulonglong(100) << true; - QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << qulonglong(100) << true; - QTest::newRow("leading junk") << QByteArray("x100") << 10 << qulonglong(0) << false; - QTest::newRow("trailing junk") << QByteArray("100x") << 10 << qulonglong(0) << false; + 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() diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 89cb46163a..631ca9ff0a 100644 --- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -1319,6 +1319,9 @@ void tst_QLocale::long_long_conversion_data() QTest::newRow("C 12345,67") << QString("C") << "12345,67" << false << (qlonglong) 0; QTest::newRow("C 123456,7") << QString("C") << "123456,7" << false << (qlonglong) 0; QTest::newRow("C 1,234,567") << QString("C") << "1,234,567" << true << (qlonglong) 1234567; + using LL = std::numeric_limits<qlonglong>; + QTest::newRow("C LLONG_MIN") << QString("C") << QString::number(LL::min()) << true << LL::min(); + QTest::newRow("C LLONG_MAX") << QString("C") << QString::number(LL::max()) << true << LL::max(); QTest::newRow("de_DE 1") << QString("de_DE") << "1" << true << (qlonglong) 1; QTest::newRow("de_DE 1.") << QString("de_DE") << "1." << false << (qlonglong) 0; diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index c2a7b93c7d..a377834025 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -3897,7 +3897,7 @@ void tst_QString::toLong() void tst_QString::toULongLong() { QString str; - bool ok; + bool ok = true; QCOMPARE(str.toULongLong(), Q_UINT64_C(0)); QCOMPARE(str.toULongLong(&ok), Q_UINT64_C(0)); @@ -3917,6 +3917,15 @@ void tst_QString::toULongLong() QCOMPARE( str.toULongLong( 0 ), Q_UINT64_C(0) ); QCOMPARE( str.toULongLong( &ok ), Q_UINT64_C(0) ); QVERIFY( !ok ); + + // Check limits round-trip in every base: + using ULL = std::numeric_limits<qulonglong>; + for (int b = 0; b <= 36; ++b) { + if (b == 1) // 0 and 2 through 36 are valid bases + ++b; + QCOMPARE(QString::number(ULL::max(), b ? b : 10).toULongLong(&ok, b), ULL::max()); + QVERIFY(ok); + } } void tst_QString::toLongLong() @@ -3969,6 +3978,71 @@ void tst_QString::toLongLong() } } } + + // Check bounds. + // First in every base, with no prefix: + using LL = std::numeric_limits<qlonglong>; + for (int b = 0; b <= 36; ++b) { + if (b == 1) // 0 and 2 through 36 are valid bases + ++b; + QCOMPARE(QString::number(LL::max(), b ? b : 10).toLongLong(&ok, b), LL::max()); + QVERIFY(ok); + QCOMPARE(QString::number(LL::min(), b ? b : 10).toLongLong(&ok, b), LL::min()); + QVERIFY(ok); + } + + // Then in base 16 or 0 with 0x prefix: + auto big = QString::number(LL::min(), 16); + big.insert(1, u"0x"); // after the minus sign + big.prepend(u"\t\r\n\f\v "); + QCOMPARE(big.toLongLong(&ok, 16), LL::min()); + QVERIFY(ok); + QCOMPARE(big.toLongLong(&ok, 0), LL::min()); + QVERIFY(ok); + big = QString::number(LL::max(), 16); + big.prepend(u"\t\r\n\f\v 0x"); + QCOMPARE(big.toLongLong(&ok, 16), LL::max()); + QVERIFY(ok); + QCOMPARE(big.toLongLong(&ok, 0), LL::max()); + QVERIFY(ok); + big.insert(6, u'+'); + QCOMPARE(big.toLongLong(&ok, 16), LL::max()); + QVERIFY(ok); + QCOMPARE(big.toLongLong(&ok, 0), LL::max()); + QVERIFY(ok); + + // Next octal: + big = QString::number(LL::min(), 8); + big.insert(1, u'0'); // after the minus sign + big.prepend(u"\t\r\n\f\v "); + QCOMPARE(big.toLongLong(&ok, 8), LL::min()); + QVERIFY(ok); + QCOMPARE(big.toLongLong(&ok, 0), LL::min()); + QVERIFY(ok); + big = QString::number(LL::max(), 8); + big.prepend(u"\t\r\n\f\v 0"); + QCOMPARE(big.toLongLong(&ok, 8), LL::max()); + QVERIFY(ok); + QCOMPARE(big.toLongLong(&ok, 0), LL::max()); + QVERIFY(ok); + big.insert(6, u'+'); + QCOMPARE(big.toLongLong(&ok, 8), LL::max()); + QVERIFY(ok); + QCOMPARE(big.toLongLong(&ok, 0), LL::max()); + QVERIFY(ok); + + // Finally decimal for base 0: + big = QString::number(LL::min(), 10); + big.prepend(u"\t\r\n\f\v "); + QCOMPARE(big.toLongLong(&ok, 0), LL::min()); + QVERIFY(ok); + big = QString::number(LL::max(), 10); + big.prepend(u"\t\r\n\f\v "); + QCOMPARE(big.toLongLong(&ok, 0), LL::max()); + QVERIFY(ok); + big.insert(6, u'+'); + QCOMPARE(big.toLongLong(&ok, 0), LL::max()); + QVERIFY(ok); } //////////////////////////////////////////////////////////////////////////// |