ocarina/tests/database.cpp

306 lines
6.3 KiB
C++

/*
* Copyright 2014 (c) Anna Schumaker.
* Test a Database
*/
#include <core/database.h>
#include "test.h"
#include <sstream>
/***
*
* 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<IntEntry> *db;
TestArgs(const unsigned int, bool, Database<IntEntry> *);
};
TestArgs :: TestArgs(const unsigned int _n, bool _asv, Database<IntEntry> *_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<IntEntry>::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<IntEntry> 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<IntEntry>::iterator it1;
Database<IntEntry>::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<IntEntry> 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;
}