223 lines
4.2 KiB
C++
223 lines
4.2 KiB
C++
/*
|
|
* Copyright 2014 (c) Anna Schumaker.
|
|
* Test a Database
|
|
*/
|
|
|
|
#include <core/database.h>
|
|
#include <tests/test.h>
|
|
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
|
|
/*
|
|
* Derive a DatabaseEntry for storing integerss
|
|
*/
|
|
class IntEntry : public DatabaseEntry {
|
|
public:
|
|
unsigned int val;
|
|
|
|
IntEntry() : val(0) {};
|
|
IntEntry(unsigned int v) : val(v) {};
|
|
|
|
const std::string primary_key() const
|
|
{
|
|
std::stringstream ss;
|
|
ss << val;
|
|
return ss.str();
|
|
}
|
|
|
|
void write(File &f) { f << val; }
|
|
void read(File &f) { f >> val; }
|
|
};
|
|
|
|
|
|
static unsigned int N = 0;
|
|
static bool AUTOSAVE = false;
|
|
static Database<IntEntry> *DB = NULL;
|
|
|
|
|
|
static void test_insertion()
|
|
{
|
|
std::vector<IntEntry *> pointers;
|
|
std::vector<IntEntry *>::iterator p_it;
|
|
|
|
/*
|
|
* Check initial sizes.
|
|
*/
|
|
test_equal(DB->size(), (unsigned)0);
|
|
test_equal(DB->actual_size(), (unsigned)0);
|
|
|
|
test :: begin();
|
|
for (unsigned int i = 0; i < N; i++) {
|
|
IntEntry *it = DB->insert(IntEntry(i));
|
|
check_not_equal(it, (IntEntry *)NULL);
|
|
check_equal(it->index(), i);
|
|
check_equal(it->val, i);
|
|
|
|
pointers.push_back(it);
|
|
|
|
it = DB->insert(IntEntry(i));
|
|
check_equal(it, (IntEntry *)NULL);
|
|
}
|
|
test :: success();
|
|
|
|
/*
|
|
* Size should change
|
|
*/
|
|
test_equal(DB->size(), N);
|
|
test_equal(DB->actual_size(), N);
|
|
|
|
/*
|
|
* Pointers should still be valid
|
|
*/
|
|
test :: begin();
|
|
for (unsigned int i = 0; i < N; i++)
|
|
check_equal(pointers[i], DB->at(i));
|
|
test :: success();
|
|
}
|
|
|
|
static void test_removal()
|
|
{
|
|
test :: begin();
|
|
for (unsigned int i = 0; i < N; i+=2) {
|
|
/*
|
|
* Database size should only decrease once.
|
|
*/
|
|
DB->remove(i);
|
|
DB->remove(i);
|
|
}
|
|
test :: success();
|
|
|
|
/*
|
|
* Size should change
|
|
*/
|
|
test_equal(DB->size(), N / 2);
|
|
test_equal(DB->actual_size(), N);
|
|
|
|
/*
|
|
* Test out-of-bounds removal
|
|
*/
|
|
test :: begin();
|
|
for (unsigned int i = 0; i < 10; i++)
|
|
DB->remove(N + i);
|
|
test :: success();
|
|
|
|
/*
|
|
* Size should not change
|
|
*/
|
|
test_equal(DB->size(), N / 2);
|
|
test_equal(DB->actual_size(), N);
|
|
}
|
|
|
|
static void test_access()
|
|
{
|
|
Database<IntEntry>::iterator it;
|
|
|
|
test :: begin();
|
|
for (unsigned int i = 0; i < N; i+=2)
|
|
check_equal(DB->at(i), (IntEntry *)NULL);
|
|
test :: success();
|
|
|
|
test :: begin();
|
|
it = DB->begin();
|
|
for (unsigned int i = 1; i < N; i+=2) {
|
|
IntEntry *ie = DB->at(i);
|
|
|
|
check_not_equal(ie, (IntEntry *)NULL);
|
|
check_equal(*it, ie);
|
|
check_equal(ie->val, i);
|
|
check_equal(ie->index(), i);
|
|
|
|
it = DB->next(it);
|
|
}
|
|
test :: success();
|
|
|
|
test :: begin();
|
|
for (unsigned int i = 0; i < 10; i++)
|
|
check_equal(DB->at(N + i), (IntEntry *)NULL);
|
|
test :: success();
|
|
}
|
|
|
|
static void test_reinsert()
|
|
{
|
|
test :: begin();
|
|
for (unsigned int i = 0; i < N; i+=2) {
|
|
IntEntry *it = DB->insert(IntEntry(i));
|
|
check_equal(it->index(), N + (i / 2));
|
|
}
|
|
test :: success();
|
|
|
|
/*
|
|
* Size should change
|
|
*/
|
|
test_equal(DB->size(), N);
|
|
test_equal(DB->actual_size(), N + (N / 2));
|
|
}
|
|
|
|
static void test_save_load()
|
|
{
|
|
Database<IntEntry> db2("database.db", false);
|
|
db2.load();
|
|
|
|
if (AUTOSAVE == false) {
|
|
test_equal(db2.size(), (unsigned)0);
|
|
test_equal(db2.actual_size(), (unsigned)0);
|
|
|
|
DB->save();
|
|
db2.load();
|
|
}
|
|
|
|
test_equal(db2.size(), DB->size());
|
|
test_equal(db2.actual_size(), DB->actual_size());
|
|
|
|
Database<IntEntry>::iterator it1;
|
|
Database<IntEntry>::iterator it2 = db2.begin();
|
|
|
|
test :: begin();
|
|
for (it1 = DB->begin(); it1 != DB->end(); it1++) {
|
|
if (*it1 == (IntEntry *)NULL)
|
|
check_equal(*it2, (IntEntry *)NULL);
|
|
else {
|
|
check_not_equal(*it2, (IntEntry *)NULL);
|
|
check_equal((*it1)->index(), (*it2)->index());
|
|
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<IntEntry> db("database.db", autosave);
|
|
|
|
N = n;
|
|
DB = &db;
|
|
AUTOSAVE = autosave;
|
|
|
|
run_test("Database Insertion Test" + n_str, test_insertion);
|
|
run_test("Database Removal Test" + n_str, test_removal);
|
|
run_test("Database Access Test" + n_str, test_access);
|
|
run_test("Database Reinsertion Test" + n_str, test_reinsert);
|
|
run_test("Database Save and Load Test" + n_str, test_save_load);
|
|
}
|
|
|
|
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;
|
|
}
|