summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp')
-rw-r--r--tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp154
1 files changed, 145 insertions, 9 deletions
diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
index 8232ca8fba..03300c6dbe 100644
--- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
+++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
@@ -223,11 +223,20 @@ void tst_QNumeric::floatDistance_double()
void tst_QNumeric::addOverflow_data()
{
QTest::addColumn<int>("size");
+
+ // for unsigned, all sizes are supported
QTest::newRow("quint8") << 8;
QTest::newRow("quint16") << 16;
QTest::newRow("quint32") << 32;
QTest::newRow("quint64") << 64;
QTest::newRow("ulong") << 48; // it's either 32- or 64-bit, so on average it's 48 :-)
+
+ // for signed, we can't guarantee 64-bit
+ QTest::newRow("qint8") << -8;
+ QTest::newRow("qint16") << -16;
+ QTest::newRow("qint32") << -32;
+ if (sizeof(void *) == sizeof(qint64))
+ QTest::newRow("qint64") << -64;
}
// Note: in release mode, all the tests may be statically determined and only the calls
@@ -238,6 +247,7 @@ template <typename Int> static void addOverflow_template()
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling in release mode");
#else
const Int max = std::numeric_limits<Int>::max();
+ const Int min = std::numeric_limits<Int>::min();
Int r;
// basic values
@@ -248,15 +258,50 @@ template <typename Int> static void addOverflow_template()
QCOMPARE(add_overflow(Int(0), Int(1), &r), false);
QCOMPARE(r, Int(1));
+ QCOMPARE(sub_overflow(Int(0), Int(0), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(sub_overflow(Int(1), Int(0), &r), false);
+ QCOMPARE(r, Int(1));
+ QCOMPARE(sub_overflow(Int(1), Int(1), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(sub_overflow(Int(0), Int(1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-1));
+
// half-way through max
QCOMPARE(add_overflow(Int(max/2), Int(max/2), &r), false);
QCOMPARE(r, Int(max / 2 * 2));
+ QCOMPARE(sub_overflow(Int(max/2), Int(max/2), &r), false);
+ QCOMPARE(r, Int(0));
QCOMPARE(add_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), false);
QCOMPARE(r, Int(max / 2 * 2));
+ QCOMPARE(sub_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-2));
QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(Int(max/2 + 1), Int(max/2), &r), false);
+ QCOMPARE(r, Int(1));
QCOMPARE(add_overflow(Int(max/2), Int(max/2 + 1), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(Int(max/2), Int(max/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-1));
+
+ QCOMPARE(add_overflow(Int(min/2), Int(min/2), &r), false);
+ QCOMPARE(r, Int(min / 2 * 2));
+ QCOMPARE(sub_overflow(Int(min/2), Int(min/2), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(add_overflow(Int(min/2 - 1), Int(min/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(min / 2 * 2));
+ QCOMPARE(sub_overflow(Int(min/2 - 1), Int(min/2 + 1), &r), false);
+ QCOMPARE(r, Int(-2));
+ QCOMPARE(sub_overflow(Int(min/2 + 1), Int(min/2), &r), false);
+ QCOMPARE(r, Int(1));
+ QCOMPARE(sub_overflow(Int(min/2), Int(min/2 + 1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-1));
// more than half
QCOMPARE(add_overflow(Int(max/4 * 3), Int(max/4), &r), false);
@@ -265,19 +310,55 @@ template <typename Int> static void addOverflow_template()
// max
QCOMPARE(add_overflow(max, Int(0), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(max, Int(0), &r), false);
+ QCOMPARE(r, max);
QCOMPARE(add_overflow(Int(0), max, &r), false);
QCOMPARE(r, max);
+ QCOMPARE(sub_overflow(Int(0), max, &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-max));
+
+ QCOMPARE(add_overflow(min, Int(0), &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(sub_overflow(min, Int(0), &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(add_overflow(Int(0), min, &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(sub_overflow(Int(0), Int(min+1), &r), !min);
+ if (min)
+ QCOMPARE(r, Int(-(min+1)));
// 64-bit issues
if (max > std::numeric_limits<uint>::max()) {
QCOMPARE(add_overflow(Int(std::numeric_limits<uint>::max()), Int(std::numeric_limits<uint>::max()), &r), false);
QCOMPARE(r, Int(2 * Int(std::numeric_limits<uint>::max())));
+ QCOMPARE(sub_overflow(Int(std::numeric_limits<uint>::max()), Int(std::numeric_limits<uint>::max()), &r), false);
+ QCOMPARE(r, Int(0));
+ }
+ if (min && min < -Int(std::numeric_limits<uint>::max())) {
+ QCOMPARE(add_overflow(Int(-Int(std::numeric_limits<uint>::max())), Int(-Int(std::numeric_limits<uint>::max())), &r), false);
+ QCOMPARE(r, Int(-2 * Int(std::numeric_limits<uint>::max())));
+ QCOMPARE(sub_overflow(Int(-Int(std::numeric_limits<uint>::max())), Int(-Int(std::numeric_limits<uint>::max())), &r), false);
+ QCOMPARE(r, Int(0));
}
- // overflows
+ // overflows past max
QCOMPARE(add_overflow(max, Int(1), &r), true);
QCOMPARE(add_overflow(Int(1), max, &r), true);
QCOMPARE(add_overflow(Int(max/2 + 1), Int(max/2 + 1), &r), true);
+ if (!min) {
+ QCOMPARE(sub_overflow(Int(-max), Int(-2), &r), true);
+ QCOMPARE(sub_overflow(Int(max/2 - 1), Int(max/2 + 1), &r), true);
+ }
+
+ // overflows past min (in case of min == 0, repeats some tests above)
+ if (min) {
+ QCOMPARE(sub_overflow(min, Int(1), &r), true);
+ QCOMPARE(sub_overflow(Int(1), min, &r), true);
+ QCOMPARE(sub_overflow(Int(min/2 - 1), Int(-Int(min/2)), &r), true);
+ QCOMPARE(add_overflow(min, Int(-1), &r), true);
+ QCOMPARE(add_overflow(Int(-1), min, &r), true);
+ }
#endif
}
@@ -294,6 +375,15 @@ void tst_QNumeric::addOverflow()
addOverflow_template<ulong>(); // not really 48-bit
if (size == 64)
addOverflow_template<quint64>();
+
+ if (size == -8)
+ addOverflow_template<qint8>();
+ if (size == -16)
+ addOverflow_template<qint16>();
+ if (size == -32)
+ addOverflow_template<qint32>();
+ if (size == -64)
+ addOverflow_template<qint64>();
}
void tst_QNumeric::mulOverflow_data()
@@ -309,7 +399,13 @@ template <typename Int> static void mulOverflow_template()
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling");
#else
const Int max = std::numeric_limits<Int>::max();
- const Int middle = Int(max >> (sizeof(Int) * CHAR_BIT / 2));
+ const Int min = std::numeric_limits<Int>::min();
+
+ // for unsigned (even number of significant bits): mid2 = mid1 - 1
+ // for signed (odd number of significant bits): mid2 = mid1 / 2 - 1
+ const Int mid1 = Int(Int(1) << sizeof(Int) * CHAR_BIT / 2);
+ const Int mid2 = (std::numeric_limits<Int>::digits % 2 ? mid1 / 2 : mid1) - 1;
+
Int r;
// basic multiplications
@@ -323,6 +419,10 @@ template <typename Int> static void mulOverflow_template()
QCOMPARE(r, Int(0));
QCOMPARE(mul_overflow(Int(0), max, &r), false);
QCOMPARE(r, Int(0));
+ QCOMPARE(mul_overflow(min, Int(0), &r), false);
+ QCOMPARE(r, Int(0));
+ QCOMPARE(mul_overflow(Int(0), min, &r), false);
+ QCOMPARE(r, Int(0));
QCOMPARE(mul_overflow(Int(1), Int(1), &r), false);
QCOMPARE(r, Int(1));
@@ -330,23 +430,45 @@ template <typename Int> static void mulOverflow_template()
QCOMPARE(r, max);
QCOMPARE(mul_overflow(max, Int(1), &r), false);
QCOMPARE(r, max);
+ QCOMPARE(mul_overflow(Int(1), min, &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(mul_overflow(min, Int(1), &r), false);
+ QCOMPARE(r, min);
// almost max
- QCOMPARE(mul_overflow(middle, middle, &r), false);
- QCOMPARE(r, Int(max - 2 * middle));
- QCOMPARE(mul_overflow(Int(middle + 1), middle, &r), false);
- QCOMPARE(r, Int(middle << (sizeof(Int) * CHAR_BIT / 2)));
- QCOMPARE(mul_overflow(middle, Int(middle + 1), &r), false);
- QCOMPARE(r, Int(middle << (sizeof(Int) * CHAR_BIT / 2)));
+ QCOMPARE(mul_overflow(mid1, mid2, &r), false);
+ QCOMPARE(r, Int(max - mid1 + 1));
QCOMPARE(mul_overflow(Int(max / 2), Int(2), &r), false);
QCOMPARE(r, Int(max & ~Int(1)));
QCOMPARE(mul_overflow(Int(max / 4), Int(4), &r), false);
QCOMPARE(r, Int(max & ~Int(3)));
+ if (min) {
+ QCOMPARE(mul_overflow(Int(-mid1), mid2, &r), false);
+ QCOMPARE(r, Int(-max + mid1 - 1));
+ QCOMPARE(mul_overflow(Int(-max / 2), Int(2), &r), false);
+ QCOMPARE(r, Int(-max + 1));
+ QCOMPARE(mul_overflow(Int(-max / 4), Int(4), &r), false);
+ QCOMPARE(r, Int(-max + 3));
+
+ QCOMPARE(mul_overflow(Int(-mid1), Int(mid2 + 1), &r), false);
+ QCOMPARE(r, min);
+ QCOMPARE(mul_overflow(mid1, Int(-mid2 - 1), &r), false);
+ QCOMPARE(r, min);
+ }
// overflows
QCOMPARE(mul_overflow(max, Int(2), &r), true);
QCOMPARE(mul_overflow(Int(max / 2), Int(3), &r), true);
- QCOMPARE(mul_overflow(Int(middle + 1), Int(middle + 1), &r), true);
+ QCOMPARE(mul_overflow(mid1, Int(mid2 + 1), &r), true);
+ QCOMPARE(mul_overflow(Int(max / 2 + 2), Int(2), &r), true);
+ QCOMPARE(mul_overflow(Int(1ULL << (std::numeric_limits<Int>::digits - 1)), Int(2), &r), true);
+
+ if (min) {
+ QCOMPARE(mul_overflow(min, Int(2), &r), true);
+ QCOMPARE(mul_overflow(Int(min / 2), Int(3), &r), true);
+ QCOMPARE(mul_overflow(Int(min / 2 - 1), Int(2), &r), true);
+ QCOMPARE(mul_overflow(Int(min + min/2), Int(2), &r), true);
+ }
#endif
}
@@ -373,6 +495,20 @@ void tst_QNumeric::mulOverflow()
MulOverflowDispatch<ulong>()(); // not really 48-bit
if (size == 64)
MulOverflowDispatch<quint64>()();
+
+ if (size == -8)
+ MulOverflowDispatch<qint8>()();
+ if (size == -16)
+ MulOverflowDispatch<qint16>()();
+ if (size == -32)
+ MulOverflowDispatch<qint32>()();
+ if (size == -64) {
+#if QT_POINTER_SIZE == 8
+ MulOverflowDispatch<qint64>()();
+#else
+ QFAIL("128-bit multiplication not supported on this platform");
+#endif
+ }
}
void tst_QNumeric::signedOverflow()