/* * Copyright 2014 (c) Anna Schumaker. * Test a Database */ #include #include "test.h" #include /*** * * Derive a DatabaseEntry for storing ints * */ class IntEntry : public DatabaseEntry { public: unsigned int val; IntEntry(); IntEntry(unsigned int); const std::string primary_key() const; void write(File &); void read(File &); }; IntEntry :: IntEntry() : val(0) {} IntEntry :: IntEntry(unsigned int v) : val(v) {} const std::string IntEntry :: primary_key() const { std::stringstream ss; ss << val; return ss.str(); } void IntEntry :: write(File &f) { f << val; } void IntEntry :: read(File &f) { f >> val; } static IntEntry *INT_NULL = NULL; /*** * * Struct for passing around arguments to tests * */ struct TestArgs { const unsigned int n; unsigned int size; unsigned int actual; bool autosave; IntEntry *one; IntEntry *three; Database *db; TestArgs(const unsigned int, bool, Database *); }; TestArgs :: TestArgs(const unsigned int _n, bool _asv, Database *_db) : n(_n), size(0), actual(0), autosave(_asv), one(NULL), three(NULL), db(_db) {} /*** * * Run tests with varying database sizes * */ static void test_insertion(struct TestArgs *args) { /* * Initial size should be 0 */ test_equal(args->db->size(), args->size); test_equal(args->db->actual_size(), args->actual); test :: begin(); for (unsigned int i = 0; i < args->n; i++) { IntEntry *it = args->db->insert(IntEntry(i)); check_not_equal(it, INT_NULL); check_equal(it->id, i); check_equal(it->val, i); /* * Pointers should still be valid after more insertions. * These will be checked later */ if (i == 1) args->one = it; if (i == 3) args->three = it; args->size++; args->actual++; } test :: success(); /* * Size should change */ test_equal(args->db->size(), args->size); test_equal(args->db->actual_size(), args->actual); } static void test_insertion2(struct TestArgs *args) { test :: begin(); for (unsigned int i = 0; i < args->n; i++) { IntEntry *it = args->db->insert(IntEntry(i)); check_equal(it, INT_NULL); } test :: success(); /* * Size should not change */ test_equal(args->db->size(), args->size); test_equal(args->db->actual_size(), args->actual); } static void test_removal(struct TestArgs *args) { test :: begin(); for (unsigned int i = 0; i < args->n; i+=2) { args->db->remove(i); args->size--; } test :: success(); /* * Size should change */ test_equal(args->db->size(), args->size); test_equal(args->db->actual_size(), args->actual); /* * Test out-of-bounds removal */ test :: begin(); for (unsigned int i = 0; i < 10; i++) args->db->remove(args->n + i); test :: success(); /* * Size should not change */ test_equal(args->db->size(), args->size); test_equal(args->db->actual_size(), args->actual); } static void test_removal2(struct TestArgs *args) { test :: begin(); for (unsigned int i = 0; i < args->n; i+=2) args->db->remove(i); test :: success(); /* * Size should not change */ test_equal(args->db->size(), args->size); test_equal(args->db->actual_size(), args->actual); } static void test_iterator(struct TestArgs *args) { unsigned int index = 1; Database::iterator it; test :: begin(); for (it = args->db->begin(); it != args->db->end(); it = args->db->next(it)) { check_not_equal((*it), INT_NULL); check_equal((*it)->val, index); check_equal((*it)->id, index); index += 2; }; test :: success(); } static void test_access(struct TestArgs *args) { test :: begin(); for (unsigned int i = 0; i < args->n; i+=2) { IntEntry *it = args->db->at(i); check_equal(it, INT_NULL); } test :: success(); test :: begin(); for (unsigned int i = 1; i < args->n; i+=2) { IntEntry *it = args->db->at(i); check_not_equal(it, INT_NULL); } test :: success(); test :: begin(); for (unsigned int i = 0; i < 10; i++) { IntEntry *it = args->db->at(args->n + i); check_equal(it, INT_NULL); } test :: success(); } static void test_pointers(struct TestArgs *args) { IntEntry *it = args->db->at(1); test_equal(it, args->one); it = args->db->at(3); test_equal(it, args->three); } static void test_insertion3(struct TestArgs *args) { test :: begin(); for (unsigned int i = 0; i < args->n; i+=2) { IntEntry *it = args->db->insert(IntEntry(i)); args->size++; args->actual++; check_equal(it->id, args->n + (i / 2)); } test :: success(); /* * Size should change */ test_equal(args->db->size(), args->size); test_equal(args->db->actual_size(), args->actual); } static void test_autosave(struct TestArgs *args) { Database db2("database.db", args->autosave); db2.load(); if (args->autosave == false) { test_equal(db2.size(), (unsigned)0); test_equal(db2.actual_size(), (unsigned)0); args->db->save(); db2.load(); } test_equal(db2.size(), args->db->size()); test_equal(db2.actual_size(), args->db->actual_size()); Database::iterator it1; Database::iterator it2 = db2.begin(); test :: begin(); for (it1 = args->db->begin(); it1 != args->db->end(); it1++) { if (*it1 == INT_NULL) check_equal(*it2, INT_NULL); else { check_not_equal(*it2, INT_NULL); check_equal((*it1)->id, (*it2)->id); check_equal((*it1)->val, (*it2)->val); } it2++; } test :: success(); } static void db_test(unsigned int n, bool autosave) { test :: rm_data_dir(); std::stringstream ss; ss << " (n = " << n << ")"; const std::string n_str = ss.str(); Database db("database.db", autosave); struct TestArgs args(n, autosave, &db); run_test("Database Insertion Test" + n_str, test_insertion, &args); run_test("Database Second Insertion Test" + n_str, test_insertion2, &args); run_test("Database Removal Test" + n_str, test_removal, &args); run_test("Database Second Removal Test" + n_str, test_removal2, &args); run_test("Database Iterator Test" + n_str, test_iterator, &args); run_test("Database Access Test" + n_str, test_access, &args); run_test("Database Pointer Test" + n_str, test_pointers, &args); run_test("Database Third Insertion Test" + n_str, test_insertion3, &args); run_test("Database Save and Load Test" + n_str, test_autosave, &args); } int main(int argc, char **argv) { db_test(0, true); db_test(10, true); db_test(100, true); db_test(1000, true); db_test(10000, false); db_test(100000, false); return 0; }