#include #include #include #include #include #include "GridInstanceData.h" /* Unit test code for GridInstanceData.[Ch] * g++ -Wall --std=c++0x -O2 -ggdb GridInstanceDataTest.C GridInstanceData.C */ namespace GridInstanceData { // Returns true of the two numbers are the same. Two finite numbers are // the same if and only if they are equal. If neither number is finite, // they are the same. If one is finite and the other is not, they are not // the same. Basically we're treating NaN just like a normal number, not // like a database NULL. This test does not distinguish between INF, -INF, // and NaN; that's consistent with the rest of the grid. bool sameValue(double x, double y) { if (std::isfinite(x)) if (std::isfinite(y)) return x == y; else return false; else if (std::isfinite(y)) return false; else return true; } // Returns true if they are the same. Returns false and prints a message if // they are different. template < class T > bool compare(typename TransactionList< T >::IList const &list, std::vector< T > const &vector, std::string const &description) { bool same = list.getCount() == vector.size(); if (same) { for (int i = 0; i < vector.size(); i++) if (!sameValue(list.getAt(i),vector[i])) { same = false; break; } } if (!same) { std::cout<<"Error in "< bool compare(TransactionList< T > const &list, std::vector< T > const &committed, std::vector< T > const &inProgress, std::string const &description) { bool s1 = compare(list.committed(), committed, description + " committed"); bool s2 = compare(list.inProgress(), inProgress, description + " in progress"); return s1 && s2; } void testTransactionList() { TransactionList< int > transactionList; compare(transactionList, {}, {}, "empty / initial"); //compare(transactionList, {1, 2}, {}, "fail on purpose"); //compare(transactionList, {}, {3}, "fail on purpose"); transactionList.deleteExcept(5); compare(transactionList, {}, {}, "empty / deleteExcept(5)"); transactionList.deleteExcept(0); compare(transactionList, {}, {}, "empty / deleteExcept(0)"); transactionList.deleteExcept(-5); compare(transactionList, {}, {}, "empty / deleteExcept(-5)"); transactionList.commit(); compare(transactionList, {}, {}, "empty / commit"); transactionList.rollBack(); compare(transactionList, {}, {}, "empty / rollback"); transactionList.append(10); compare(transactionList, {}, {10}, "add 10"); transactionList.append(20); compare(transactionList, {}, {10, 20}, "add 20"); transactionList.append(30); compare(transactionList, {}, {10, 20, 30}, "add 30"); transactionList.deleteExcept(3); compare(transactionList, {}, {10, 20, 30}, "empty / deleteExcept(3)"); transactionList.deleteExcept(2); compare(transactionList, {}, {10, 20}, "empty / deleteExcept(2)"); transactionList.commit(); compare(transactionList, {10, 20}, {10, 20}, "commit"); transactionList.append(31); compare(transactionList, {10, 20}, {10, 20, 31}, "add 31"); transactionList.append(41); compare(transactionList, {10, 20}, {10, 20, 31, 41}, "add 41"); transactionList.deleteExcept(1); compare(transactionList, {10, 20}, {10}, "deleteExcept(1)"); transactionList.commit(); compare(transactionList, {10}, {10}, "commit"); transactionList.deleteExcept(0); compare(transactionList, {10}, {}, "deleteExcept(0)"); transactionList.rollBack(); compare(transactionList, {10}, {10}, "rollback"); transactionList.append(22); compare(transactionList, {10}, {10, 22}, "add 22"); transactionList.append(32); compare(transactionList, {10}, {10, 22, 32}, "add 32"); transactionList.append(42); compare(transactionList, {10}, {10, 22, 32, 42}, "add 42"); transactionList.deleteExcept(3); compare(transactionList, {10}, {10, 22, 32}, "deleteExcept(3)"); transactionList.commit(); compare(transactionList, {10, 22, 32}, {10, 22, 32}, "commit"); transactionList.commit(); compare(transactionList, {10, 22, 32}, {10, 22, 32}, "commit again"); transactionList.deleteExcept(2); compare(transactionList, {10, 22, 32}, {10, 22}, "deleteExcept(2)"); } // This calls each of the standard functions on these inputs, and asserts // that the value we get matches the expected value. void assertListFormulae(Grid const &grid, int firstRow, int lastRow, int column, bool skipBadValues, double expectedSum, double expectedCount, double expectedAverage, double expectedMax, double expectedMin) { const double sum = grid.sum(firstRow, lastRow, column, skipBadValues); const double count = grid.count(firstRow, lastRow, column); const double average = grid.average(firstRow, lastRow, column, skipBadValues); const double max = grid.max(firstRow, lastRow, column, skipBadValues); const double min = grid.min(firstRow, lastRow, column, skipBadValues); assert(sameValue(sum, expectedSum)); assert(sameValue(count, expectedCount)); assert(sameValue(average, expectedAverage)); assert(sameValue(max, expectedMax)); assert(sameValue(min, expectedMin)); } void testGrid() { bool assertionsAreOn = false; assert(assertionsAreOn = true); if (!assertionsAreOn) std::cout<<"Turn assertions on! Test results not valid!"< list; Grid grid(list.committed(), 3); const std::vector< double > cells = { 0, 1 ,70, 1, Grid::invalid(), 60, 2, 2, 50, 3, Grid::invalid(), 40, 4, 4, 30, 5, 5, 20, 6}; for (auto it = cells.begin(); it != cells.end(); it++) list.append(*it); list.commit(); list.deleteExcept(1); compare(list, cells, {0.0}, "testGrid()"); // Invalid list. for (int firstRow = -2; firstRow < 10; firstRow++) for (int column = 0; column < 3; column++) for (int skipBadValues = 0; skipBadValues < 2; skipBadValues++) assertListFormulae(grid, firstRow, firstRow - 2, column, skipBadValues, Grid::invalid(), Grid::invalid(), Grid::invalid(), Grid::invalid(), Grid::invalid()); // Empty list. for (int firstRow = -2; firstRow < 10; firstRow++) for (int column = 0; column < 3; column++) for (int skipBadValues = 0; skipBadValues < 2; skipBadValues++) assertListFormulae(grid, firstRow, firstRow - 1, column, skipBadValues, /* sum */ 0, /* count */ 0, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, /* firstRow */ 0, /* lastRow */ 0, /* column */ 0, /* skipBadVlues */ false, /* sum */ 0, /* count */ 1, /* average */ 0, /* max */ 0, /* min */ 0); assertListFormulae(grid, /* firstRow */ 0, /* lastRow */ 0, /* column */ 1, /* skipBadVlues */ false, /* sum */ 1, /* count */ 1, /* average */ 1, /* max */ 1, /* min */ 1); assertListFormulae(grid, /* firstRow */ 0, /* lastRow */ 0, /* column */ 2, /* skipBadVlues */ false, /* sum */ 70, /* count */ 1, /* average */ 70, /* max */ 70, /* min */ 70); assertListFormulae(grid, /* firstRow */ 1, /* lastRow */ 1, /* column */ 0, /* skipBadVlues */ false, /* sum */ 1, /* count */ 1, /* average */ 1, /* max */ 1, /* min */ 1); assertListFormulae(grid, /* firstRow */ 1, /* lastRow */ 1, /* column */ 1, /* skipBadVlues */ false, /* sum */ Grid::invalid(), /* count */ 0, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, /* firstRow */ 1, /* lastRow */ 1, /* column */ 1, /* skipBadVlues */ true, /* sum */ 0, /* count */ 0, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, /* firstRow */ 1, /* lastRow */ 1, /* column */ 2, /* skipBadVlues */ false, /* sum */ 60, /* count */ 1, /* average */ 60, /* max */ 60, /* min */ 60); // Looking at the first column, so the value is the same as the index. // Look at every combination where the count is at least 1. for (int firstRow = 0; firstRow < 7; firstRow++) for (int lastRow = firstRow; lastRow < 7; lastRow++) { const int count = lastRow - firstRow + 1; const double average = (lastRow + firstRow) / 2.0; const double sum = average * count; const int max = lastRow; const int min = firstRow; assertListFormulae(grid, firstRow, lastRow, 0, false, sum, count, average, max, min); assertListFormulae(grid, firstRow, lastRow, 0, true, sum, count, average, max, min); } // Middle column. Lots of NaN values assertListFormulae(grid, 0, 5, 1, false, /* sum */ Grid::invalid(), /* count */ 4, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, 0, 5, 1, true, /* sum */ 12, /* count */ 4, /* average */ 3, /* max */ 5, /* min */ 1); // Last full row, one partial row, two blank rows off the end. // First column. assertListFormulae(grid, 5, 8, 0, false, /* sum */ Grid::invalid(), /* count */ 2, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, 5, 8, 0, true, /* sum */ 5+6, /* count */ 2, /* average */ (5+6)/2.0, /* max */ 6, /* min */ 5); // Last full row, one partial row, two blank rows off the end. // Second column. assertListFormulae(grid, 5, 8, 1, false, /* sum */ Grid::invalid(), /* count */ 1, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, 5, 8, 1, true, /* sum */ 5, /* count */ 1, /* average */ 5, /* max */ 5, /* min */ 5); // Last full row, one partial row, two blank rows off the end. // Third column. assertListFormulae(grid, 5, 8, 2, false, /* sum */ Grid::invalid(), /* count */ 1, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, 5, 8, 2, true, /* sum */ 20, /* count */ 1, /* average */ 20, /* max */ 20, /* min */ 20); // Top three real rows plus two more above the top. // First column. assertListFormulae(grid, -2, 2, 0, false, /* sum */ Grid::invalid(), /* count */ 3, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, -2, 2, 0, true, /* sum */ 0+1+2, /* count */ 3, /* average */ (0+1+2)/3.0, /* max */ 2, /* min */ 0); // Top three real rows plus two more above the top. // Second column. assertListFormulae(grid, -2, 2, 1, false, /* sum */ Grid::invalid(), /* count */ 2, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, -2, 2, 1, true, /* sum */ 1+2, /* count */ 2, /* average */ (1+2)/2.0, /* max */ 2, /* min */ 1); // Top three real rows plus two more above the top. // Third column. assertListFormulae(grid, -2, 2, 2, false, /* sum */ Grid::invalid(), /* count */ 3, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid, -2, 2, 2, true, /* sum */ 70+60+50, /* count */ 3, /* average */ (70+60+50)/3.0, /* max */ 70, /* min */ 50); // Change things so the last row is complete. The repeat the tests where // we look at the last two rwo real rows plus two empty rows. list.rollBack(); list.append(6); list.append(10); Grid grid1(list.inProgress(), 3); // Exactly the same as before. assertListFormulae(grid1, 5, 8, 0, false, /* sum */ Grid::invalid(), /* count */ 2, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid1, 5, 8, 0, true, /* sum */ 5+6, /* count */ 2, /* average */ (5+6)/2.0, /* max */ 6, /* min */ 5); // Add one new cell. assertListFormulae(grid1, 5, 8, 1, false, /* sum */ Grid::invalid(), /* count */ 2, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid1, 5, 8, 1, true, /* sum */ 5+6, /* count */ 2, /* average */ (5+6)/2.0, /* max */ 6, /* min */ 5); assertListFormulae(grid1, 5, 8, 2, false, /* sum */ Grid::invalid(), /* count */ 2, /* average */ Grid::invalid(), /* max */ Grid::invalid(), /* min */ Grid::invalid()); assertListFormulae(grid1, 5, 8, 2, true, /* sum */ 20+10, /* count */ 2, /* average */ (20+10)/2.0, /* max */ 20, /* min */ 10); // Test getValuesAll() std::vector< double > v; for (int firstRow = -2; firstRow < 10; firstRow++) for (int lastRow = -2; lastRow < 10; lastRow++) { int expectedSize; grid.getValuesAll(v, firstRow, lastRow, 0); if ((firstRow < 0) || (firstRow > 6) || (lastRow < firstRow) || (lastRow > 6)) expectedSize = 0; else expectedSize = lastRow - firstRow + 1; assert(expectedSize == (int)v.size()); grid.getValuesAll(v, firstRow, lastRow, 2); if ((firstRow < 0) || (firstRow > 5) || (lastRow < firstRow) || (lastRow > 5)) expectedSize = 0; else expectedSize = lastRow - firstRow + 1; assert(expectedSize == (int)v.size()); } grid.getValuesAll(v, 3, 4, 1); assert(v.empty()); // column 1, row 3 is NaN. grid.getValuesAll(v, 4, 5, 1); assert(v.size() == 2); assert(v[0] == 4); assert(v[1] == 5); // Test Grid::reference(). for (int i = -5; i < 30; i++) { double expectedValue = Grid::invalid(); if ((i >= 0) && (i < (int)cells.size())) expectedValue = cells[i]; const double value = grid.reference(i / 3, i % 3); assert(sameValue(value, expectedValue)); } } void assertValues(PackableValues const &values, int committedRow, int committedColumn, int inProgressRow, int inProgressColumn, int completedRowCount) { Grid committed = values.committed(); int row = committed.nextRow(); int column = committed.nextCol(); assert(committedRow == row); assert(committedColumn == column); Grid inProgress = values.inProgress(); row = inProgress.nextRow(); column = inProgress.nextCol(); assert(inProgressRow == row); assert(inProgressColumn == column); assert(values.completedRowCount(Use::InProgress) == completedRowCount); } void assertValues(PackableValues const &values, int committedRow, int committedColumn, int inProgressRow, int inProgressColumn) { assertValues(values, committedRow, committedColumn, inProgressRow, inProgressColumn, /* completedRowCount= */ inProgressRow); } void testPackedValues() { PackableValues packedValues(true, 4); assertValues(packedValues, 0, 0, 0, 0); packedValues.store(0); assertValues(packedValues, 0, 0, 0, 1); packedValues.store(1); assertValues(packedValues, 0, 0, 0, 2); packedValues.store(2); assertValues(packedValues, 0, 0, 0, 3); packedValues.store(3); assertValues(packedValues, 0, 0, 1, 0); packedValues.store(4); assertValues(packedValues, 0, 0, 1, 1); packedValues.store(5); assertValues(packedValues, 0, 0, 1, 2); packedValues.commit(); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPacked(5); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPossible(5); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPacked(2); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPossible(2); assertValues(packedValues, 1, 2, 1, 2); // Finally delete something for real packedValues.deleteExceptPacked(1); assertValues(packedValues, 1, 2, 1, 0); packedValues.deleteExceptPacked(1); assertValues(packedValues, 1, 2, 1, 0); packedValues.rollBack(); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPacked(0); assertValues(packedValues, 1, 2, 0, 0); packedValues.deleteExceptPacked(0); assertValues(packedValues, 1, 2, 0, 0); packedValues.rollBack(); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPacked(-1); assertValues(packedValues, 1, 2, 0, 0); packedValues.rollBack(); assertValues(packedValues, 1, 2, 1, 2); // Try again with possible. Results should be identical because I haven't // skiped anything. packedValues.deleteExceptPossible(1); assertValues(packedValues, 1, 2, 1, 0); packedValues.deleteExceptPossible(1); assertValues(packedValues, 1, 2, 1, 0); packedValues.rollBack(); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPossible(0); assertValues(packedValues, 1, 2, 0, 0); packedValues.deleteExceptPossible(0); assertValues(packedValues, 1, 2, 0, 0); packedValues.rollBack(); assertValues(packedValues, 1, 2, 1, 2); packedValues.deleteExceptPossible(-1); assertValues(packedValues, 1, 2, 0, 0); packedValues.rollBack(); assertValues(packedValues, 1, 2, 1, 2); packedValues.store(6); assertValues(packedValues, 1, 2, 1, 3); packedValues.store(7); assertValues(packedValues, 1, 2, 2, 0); packedValues.skipRow(); assertValues(packedValues, 1, 2, 2, 0, 3); packedValues.skipRow(); assertValues(packedValues, 1, 2, 2, 0, 4); // Skip some rows to test packed vs possible. packedValues.deleteExceptPossible(0); assertValues(packedValues, 1, 2, 0, 0); packedValues.skipRow(); // Possible row 0 is missing. packedValues.skipRow(); // Possible row 1 is missing. packedValues.store(0); packedValues.store(0); packedValues.store(0); packedValues.store(0); // Possible row 2 is packed row 0. packedValues.skipRow(); // Possible row 3 is missing. packedValues.store(0); packedValues.store(0); packedValues.store(0); packedValues.store(0); // Possible row 4 is packed row 1. packedValues.store(0); packedValues.store(0); packedValues.store(0); packedValues.store(0); // Possible row 5 is packed row 2. packedValues.skipRow(); // Possible row 6 is missing. packedValues.store(0); packedValues.store(0); packedValues.store(0); packedValues.store(0); // Possible row 7 is packed row 3. packedValues.skipRow(); // Possible row 8 is missing. packedValues.skipRow(); // Possible row 9 is missing. assert(packedValues.packedToPossible(-2, Use::InProgress) == -2); assert(packedValues.packedToPossible(-1, Use::InProgress) == -1); assert(packedValues.packedToPossible(0, Use::InProgress) == 2); assert(packedValues.packedToPossible(1, Use::InProgress) == 4); assert(packedValues.packedToPossible(2, Use::InProgress) == 5); assert(packedValues.packedToPossible(3, Use::InProgress) == 7); // packedToPossible() ignores skipped rows at the end. assert(packedValues.packedToPossible(4, Use::InProgress) == 8); assert(packedValues.packedToPossible(5, Use::InProgress) == 9); packedValues.skipRow(); // Possible row 10 is missing. assert(packedValues.packedToPossible(3, Use::InProgress) == 7); assert(packedValues.packedToPossible(4, Use::InProgress) == 8); assert(packedValues.packedToPossible(5, Use::InProgress) == 9); packedValues.store(0); packedValues.store(0); packedValues.store(0); packedValues.store(0); // Possible row 11 is packed row 4. assert(packedValues.packedToPossible(3, Use::InProgress) == 7); assert(packedValues.packedToPossible(4, Use::InProgress) == 11); assert(packedValues.packedToPossible(5, Use::InProgress) == 12); assert(packedValues.possibleToPacked(-2, Use::InProgress, Round::Down) == -1); assert(packedValues.possibleToPacked(-2, Use::InProgress, Round::Up) == 0); assert(packedValues.possibleToPacked(-2, Use::InProgress, Round::Fail) == NOT_FOUND); assert(packedValues.possibleToPacked(-1, Use::InProgress, Round::Down) == -1); assert(packedValues.possibleToPacked(-1, Use::InProgress, Round::Up) == 0); assert(packedValues.possibleToPacked(-1, Use::InProgress, Round::Fail) == NOT_FOUND); assert(packedValues.possibleToPacked(0, Use::InProgress, Round::Down) == -1); assert(packedValues.possibleToPacked(0, Use::InProgress, Round::Up) == 0); assert(packedValues.possibleToPacked(0, Use::InProgress, Round::Fail) == NOT_FOUND); assert(packedValues.possibleToPacked(1, Use::InProgress, Round::Down) == -1); assert(packedValues.possibleToPacked(1, Use::InProgress, Round::Up) == 0); assert(packedValues.possibleToPacked(1, Use::InProgress, Round::Fail) == NOT_FOUND); assert(packedValues.possibleToPacked(2, Use::InProgress, Round::Down) == 0); assert(packedValues.possibleToPacked(2, Use::InProgress, Round::Up) == 0); assert(packedValues.possibleToPacked(2, Use::InProgress, Round::Fail) == 0); assert(packedValues.possibleToPacked(3, Use::InProgress, Round::Down) == 0); assert(packedValues.possibleToPacked(3, Use::InProgress, Round::Up) == 1); assert(packedValues.possibleToPacked(3, Use::InProgress, Round::Fail) == NOT_FOUND); assert(packedValues.possibleToPacked(4, Use::InProgress, Round::Down) == 1); assert(packedValues.possibleToPacked(4, Use::InProgress, Round::Up) == 1); assert(packedValues.possibleToPacked(4, Use::InProgress, Round::Fail) == 1); assert(packedValues.possibleToPacked(5, Use::InProgress, Round::Down) == 2); assert(packedValues.possibleToPacked(5, Use::InProgress, Round::Up) == 2); assert(packedValues.possibleToPacked(5, Use::InProgress, Round::Fail) == 2); assert(packedValues.possibleToPacked(6, Use::InProgress, Round::Down) == 2); assert(packedValues.possibleToPacked(6, Use::InProgress, Round::Up) == 3); assert(packedValues.possibleToPacked(6, Use::InProgress, Round::Fail) == NOT_FOUND); assert(packedValues.possibleToPacked(7, Use::InProgress, Round::Down) == 3); assert(packedValues.possibleToPacked(7, Use::InProgress, Round::Up) == 3); assert(packedValues.possibleToPacked(7, Use::InProgress, Round::Fail) == 3); assert(packedValues.possibleToPacked(8, Use::InProgress, Round::Down) == 3); assert(packedValues.possibleToPacked(8, Use::InProgress, Round::Up) == 4); assert(packedValues.possibleToPacked(8, Use::InProgress, Round::Fail) == NOT_FOUND); assert(packedValues.possibleToPacked(9, Use::InProgress, Round::Down) == 3); assert(packedValues.possibleToPacked(9, Use::InProgress, Round::Up) == 4); assert(packedValues.possibleToPacked(9, Use::InProgress, Round::Fail) == NOT_FOUND); } }; int main(int, char **) { GridInstanceData::testTransactionList(); GridInstanceData::testGrid(); GridInstanceData::testPackedValues(); }