From e6866cd00f91dd02fb54942d61fb1586ce0ed5b5 Mon Sep 17 00:00:00 2001 From: Matt McCutchen Date: Wed, 16 Jul 2008 15:59:18 -0400 Subject: [PATCH] Add a bunch more tests to the test suite, some of which require a 32-bit system. These tests, which I mostly wrote a while ago but am just now committing, give me some confidence that the conversion code is actually correct! I couldn't find a practical word-size-independent way to test such things as stringToBigUnsigned("4294967296").toUnsignedLong() , so for now I'm making the test suite specific to systems with short = 16 bits and int = long = 32 bits and hoping that, if it works on those, it will also work on others. --- Makefile | 4 +- testsuite.cc | 168 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 148 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 450681e..aa81d4a 100644 --- a/Makefile +++ b/Makefile @@ -27,14 +27,14 @@ library: $(library-objects) # Conservatively assume that all the objects depend on all the headers. $(library-objects): $(library-headers) -# TESTSUITE +# TESTSUITE (NOTE: Currently expects a 32-bit system) # Compiling the testsuite. testsuite.o: $(library-headers) testsuite: testsuite.o $(library-objects) g++ $^ -o $@ # Extract the expected output from the testsuite source. testsuite.expected: testsuite.cc - sed -nre 's,^.*//([^ ]),\1,p' $< >$@ + nl -ba -p -s: $< | sed -nre 's,^ +([0-9]+):.*//([^ ]),Line \1: \2,p' >$@ # Run the testsuite. .PHONY: test test: testsuite testsuite.expected diff --git a/testsuite.cc b/testsuite.cc index 3796b99..a831fbc 100644 --- a/testsuite.cc +++ b/testsuite.cc @@ -1,6 +1,9 @@ /* Test suite for the library. First, it ``tests'' that all the constructs it * uses compile successfully. Then, its output to stdout is compared to the - * expected output automatically extracted from slash-slash comments below. */ + * expected output automatically extracted from slash-slash comments below. + * + * NOTE: For now, the test suite expects a 32-bit system. On others, some tests + * may fail, and it may be ineffective at catching bugs. TODO: Remedy this. */ #include "BigIntegerLibrary.hh" @@ -8,50 +11,171 @@ #include using namespace std; +// Evaluate expr and print the result or "error" as appropriate. +#define TEST(expr) do {\ + cout << "Line " << __LINE__ << ": ";\ + try {\ + cout << (expr);\ + } catch (const char *err) {\ + cout << "error";\ + }\ + cout << endl;\ +} while (0) + const BigUnsigned &check(const BigUnsigned &x) { unsigned int l = x.getLength(); if (l != 0 && x.getBlock(l-1) == 0) - cout << "Unzapped number!" << endl; + cout << "check: Unzapped number!" << endl; if (l > x.getCapacity()) - cout << "Capacity inconsistent with length!" << endl; + cout << "check: Capacity inconsistent with length!" << endl; return x; } const BigInteger &check(const BigInteger &x) { if (x.getSign() == 0 && !x.getMagnitude().isZero()) - cout << "Sign should not be zero!" << endl; + cout << "check: Sign should not be zero!" << endl; if (x.getSign() != 0 && x.getMagnitude().isZero()) - cout << "Sign should be zero!" << endl; + cout << "check: Sign should be zero!" << endl; check(x.getMagnitude()); return x; } -#define THROWY(x) try {x; cout << "Expected error not thrown!" << endl; } catch (const char *err) {} +short pathologicalShort = ~((unsigned short)(~0) >> 1); +int pathologicalInt = ~((unsigned int)(~0) >> 1); +long pathologicalLong = ~((unsigned long)(~0) >> 1); int main() { try { BigUnsigned z(0), one(1), ten(10); -cout << z << ',' << one << ',' << ten << endl; //0,1,10 +TEST(z); //0 +TEST(1); //1 +TEST(10); //10 // TODO: Comprehensively test the general and special cases of each function. -// Addition -cout << check(BigUnsigned(0) + 0) << endl; //0 -cout << check(BigUnsigned(0) + 1) << endl; //1 -cout << check(BigUnsigned(0xFFFFFFFFU) + 1) << endl; //4294967296 +// Default constructors +TEST(check(BigUnsigned())); //0 +TEST(check(BigInteger())); //0 + +// BigUnsigned conversion limits +TEST(BigUnsigned(0).toUnsignedLong()); //0 +TEST(BigUnsigned(4294967295U).toUnsignedLong()); //4294967295 +TEST(stringToBigUnsigned("4294967296").toUnsignedLong()); //error + +TEST(BigUnsigned(0).toLong()); //0 +TEST(BigUnsigned(2147483647).toLong()); //2147483647 +TEST(BigUnsigned(2147483648U).toLong()); //error + +// int is the same as long on a 32-bit system +TEST(BigUnsigned(0).toUnsignedInt()); //0 +TEST(BigUnsigned(4294967295U).toUnsignedInt()); //4294967295 +TEST(stringToBigUnsigned("4294967296").toUnsignedInt()); //error + +TEST(BigUnsigned(0).toInt()); //0 +TEST(BigUnsigned(2147483647).toInt()); //2147483647 +TEST(BigUnsigned(2147483648U).toInt()); //error + +TEST(BigUnsigned(0).toUnsignedShort()); //0 +TEST(BigUnsigned(65535).toUnsignedShort()); //65535 +TEST(BigUnsigned(65536).toUnsignedShort()); //error + +TEST(BigUnsigned(0).toShort()); //0 +TEST(BigUnsigned(32767).toShort()); //32767 +TEST(BigUnsigned(32768).toShort()); //error + +// BigInteger conversion limits +TEST(BigInteger(-1).toUnsignedLong()); //error +TEST(BigInteger(0).toUnsignedLong()); //0 +TEST(BigInteger(4294967295U).toUnsignedLong()); //4294967295 +TEST(stringToBigInteger("4294967296").toUnsignedLong()); //error + +TEST(stringToBigInteger("-2147483649").toLong()); //error +TEST(stringToBigInteger("-2147483648").toLong()); //-2147483648 +TEST(BigInteger(-2147483647).toLong()); //-2147483647 +TEST(BigInteger(0).toLong()); //0 +TEST(BigInteger(2147483647).toLong()); //2147483647 +TEST(BigInteger(2147483648U).toLong()); //error + +// int is the same as long on a 32-bit system +TEST(BigInteger(-1).toUnsignedInt()); //error +TEST(BigInteger(0).toUnsignedInt()); //0 +TEST(BigInteger(4294967295U).toUnsignedInt()); //4294967295 +TEST(stringToBigInteger("4294967296").toUnsignedInt()); //error + +TEST(stringToBigInteger("-2147483649").toInt()); //error +TEST(stringToBigInteger("-2147483648").toInt()); //-2147483648 +TEST(BigInteger(-2147483647).toInt()); //-2147483647 +TEST(BigInteger(0).toInt()); //0 +TEST(BigInteger(2147483647).toInt()); //2147483647 +TEST(BigInteger(2147483648U).toInt()); //error + +TEST(BigInteger(-1).toUnsignedShort()); //error +TEST(BigInteger(0).toUnsignedShort()); //0 +TEST(BigInteger(65535).toUnsignedShort()); //65535 +TEST(BigInteger(65536).toUnsignedShort()); //error + +TEST(BigInteger(-32769).toShort()); //error +TEST(BigInteger(-32768).toShort()); //-32768 +TEST(BigInteger(-32767).toShort()); //-32767 +TEST(BigInteger(0).toShort()); //0 +TEST(BigInteger(32767).toShort()); //32767 +TEST(BigInteger(32768).toShort()); //error // Negative BigUnsigneds -THROWY(BigUnsigned(-1)); -THROWY(BigUnsigned(5) - BigUnsigned(6)); -cout << check(BigUnsigned(5) - BigUnsigned(5)) << endl; //0 +// ...during construction +TEST(BigUnsigned(short(-1))); //error +TEST(BigUnsigned(pathologicalShort)); //error +TEST(BigUnsigned(-1)); //error +TEST(BigUnsigned(pathologicalInt)); //error +TEST(BigUnsigned(long(-1))); //error +TEST(BigUnsigned(pathologicalLong)); //error +// ...during subtraction +TEST(BigUnsigned(5) - BigUnsigned(6)); //error +TEST(stringToBigUnsigned("314159265358979323") - stringToBigUnsigned("314159265358979324")); //error +TEST(check(BigUnsigned(5) - BigUnsigned(5))); //0 +TEST(check(stringToBigUnsigned("314159265358979323") - stringToBigUnsigned("314159265358979323"))); //0 +TEST(check(stringToBigUnsigned("4294967296") - BigUnsigned(1))); //4294967295 + +// Addition +TEST(check(BigUnsigned(0) + 0)); //0 +TEST(check(BigUnsigned(0) + 1)); //1 +// Ordinary carry +TEST(check(stringToBigUnsigned("8589934591" /* 2^33 - 1*/) + + stringToBigUnsigned("4294967298" /* 2^32 + 2 */))); //12884901889 +// Creation of a new block +TEST(check(BigUnsigned(0xFFFFFFFFU) + 1)); //4294967296 + +// Subtraction +TEST(check(BigUnsigned(1) - 0)); //1 +TEST(check(BigUnsigned(1) - 1)); //0 +TEST(check(BigUnsigned(2) - 1)); //1 +// Ordinary borrow +TEST(check(stringToBigUnsigned("12884901889") + - stringToBigUnsigned("4294967298"))); //8589934591 +// Borrow that removes a block +TEST(check(stringToBigUnsigned("4294967296") - 1)); //4294967295 // Multiplication and division BigUnsigned a = check(BigUnsigned(314159265) * 358979323); -cout << a << ',' << (a / 123) << ',' << (a % 123) << endl; -//112776680263877595,916883579381118,81 -THROWY(BigUnsigned(5) / 0); +TEST(a); //112776680263877595 +TEST(a / 123); //916883579381118 +TEST(a % 123); //81 + +TEST(BigUnsigned(5) / 0); //error + +BigUnsigned p1 = BigUnsigned(3) * 5; +TEST(p1); //15 +/* In this case, we would like g++ to implicitly promote the BigUnsigned to a + * BigInteger, but it seems to prefer converting the -5 to a BigUnsigned, which + * causes an error. If I take out constructors for BigUnsigned from signed + * primitive integers, the BigUnsigned(3) becomes ambiguous, and if I take out + * all the constructors but BigUnsigned(unsigned long), g++ uses that + * constructor and gets a wrong (positive) answer. Thus, I think we'll just + * have to live with this cast. */ +BigInteger p2 = BigInteger(BigUnsigned(3)) * -5; +TEST(p2); //-15 { /* Test that BigInteger division sets the sign to zero. @@ -69,7 +193,7 @@ THROWY(BigUnsigned(5) / 0); * Bug reported by Samuel Larkin. */ BigInteger zero(0), three(3), ans; ans = zero - three; - cout << check(ans).getSign() << endl; //-1 + TEST(check(ans).getSign()); //-1 } { @@ -78,7 +202,7 @@ THROWY(BigUnsigned(5) / 0); * bug when run on such a system.) * Bug reported by Mohand Mezmaz. */ BigInteger f=4; f*=3; - cout<