2014-03-09 14:58:06 -04:00
|
|
|
/*
|
|
|
|
* Copyright 2014 (c) Anna Schumaker.
|
|
|
|
* Test a Database
|
|
|
|
*/
|
2014-06-05 10:19:22 -04:00
|
|
|
#include <core/database.h>
|
2015-01-26 09:40:48 -05:00
|
|
|
#include <core/string.h>
|
2015-08-25 09:27:01 -04:00
|
|
|
#include "test.h"
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-01-04 16:36:19 -05:00
|
|
|
#include <vector>
|
2014-03-09 14:58:06 -04:00
|
|
|
|
|
|
|
|
2015-01-04 16:36:19 -05:00
|
|
|
/*
|
|
|
|
* Derive a DatabaseEntry for storing integerss
|
2014-04-27 17:04:33 -04:00
|
|
|
*/
|
2015-10-13 09:51:12 -04:00
|
|
|
struct int_entry : public DatabaseEntry {
|
|
|
|
unsigned int ie_val;
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
int_entry() : ie_val(0) {};
|
|
|
|
int_entry(unsigned int v) : ie_val(v) {};
|
2014-04-27 17:04:33 -04:00
|
|
|
|
2015-01-04 16:36:19 -05:00
|
|
|
const std::string primary_key() const
|
|
|
|
{
|
2015-10-13 09:51:12 -04:00
|
|
|
gchar *g_val = g_strdup_printf("%u", ie_val);
|
2015-09-01 08:58:34 -04:00
|
|
|
std::string res = g_val;
|
|
|
|
g_free(g_val);
|
|
|
|
return res;
|
2015-01-04 16:36:19 -05:00
|
|
|
}
|
2014-04-27 17:04:33 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
void write(file &f) { file_writef(&f, "%u", ie_val); }
|
|
|
|
void read(file &f) { file_readf(&f, "%u", &ie_val); }
|
2014-04-27 17:04:33 -04:00
|
|
|
};
|
|
|
|
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
static void test_db_entry()
|
2014-04-27 17:04:33 -04:00
|
|
|
{
|
2015-10-13 09:51:12 -04:00
|
|
|
struct int_entry *ent = new struct int_entry(1);
|
|
|
|
struct file f;
|
|
|
|
|
|
|
|
test_equal(ent->index(), 0);
|
|
|
|
test_equal(ent->ie_val, 1);
|
|
|
|
test_equal(ent->primary_key(), "1");
|
|
|
|
|
|
|
|
file_init(&f, "test_db_entry", 0);
|
|
|
|
file_open(&f, OPEN_WRITE);
|
|
|
|
ent->write(f);
|
|
|
|
file_close(&f);
|
|
|
|
delete ent;
|
|
|
|
|
|
|
|
ent = new int_entry();
|
|
|
|
test_equal(ent->ie_val, 0);
|
|
|
|
test_equal(ent->primary_key(), "0");
|
|
|
|
|
|
|
|
file_open(&f, OPEN_READ);
|
|
|
|
ent->read(f);
|
|
|
|
file_close(&f);
|
|
|
|
|
|
|
|
test_equal(ent->ie_val, 1);
|
|
|
|
test_equal(ent->primary_key(), "1");
|
|
|
|
delete ent;
|
2014-04-27 17:04:33 -04:00
|
|
|
}
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
static void test_init()
|
2014-04-27 17:04:33 -04:00
|
|
|
{
|
2015-10-17 10:07:58 -04:00
|
|
|
database<struct int_entry> db("database.db", false);
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
/* Check initial sizes. */
|
2015-10-17 15:12:40 -04:00
|
|
|
test_equal(db_actual_size(&db), 0);
|
2015-10-17 14:59:06 -04:00
|
|
|
test_equal(db.db_size, 0);
|
2014-04-27 17:04:33 -04:00
|
|
|
}
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
static void test_stress(unsigned int N)
|
2014-04-27 17:04:33 -04:00
|
|
|
{
|
2015-10-17 10:07:58 -04:00
|
|
|
database<struct int_entry> db("stress.db", false);
|
|
|
|
database<struct int_entry>::iterator it;
|
2015-10-13 09:51:12 -04:00
|
|
|
std::vector<struct int_entry *> ptrs;
|
|
|
|
struct int_entry *dbe;
|
|
|
|
unsigned int i;
|
|
|
|
gchar *key;
|
|
|
|
|
|
|
|
/* database.insert() */
|
|
|
|
for (i = 0; i < N; i++) {
|
|
|
|
dbe = db.insert(int_entry(i));
|
|
|
|
test_loop_not_equal(dbe, NULL, i);
|
|
|
|
test_loop_equal(db.insert(int_entry(i)), NULL, i);
|
|
|
|
test_loop_equal(dbe->index(), i, i);
|
|
|
|
test_loop_equal(dbe->ie_val, i, i);
|
|
|
|
ptrs.push_back(dbe);
|
2015-08-25 09:27:01 -04:00
|
|
|
} test_loop_passed();
|
|
|
|
|
2015-10-17 14:59:06 -04:00
|
|
|
test_equal(db.db_size, N);
|
2015-10-17 15:12:40 -04:00
|
|
|
test_equal(db_actual_size(&db), N);
|
2015-01-04 16:36:19 -05:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
/* database.at() */
|
|
|
|
for (i = 0; i < N; i++) {
|
|
|
|
dbe = db.at(i);
|
|
|
|
test_loop_not_equal(dbe, NULL, i);
|
|
|
|
test_loop_equal(dbe, ptrs.at(i), i);
|
|
|
|
test_loop_equal(dbe->ie_val, i, i);
|
2015-08-25 09:27:01 -04:00
|
|
|
} test_loop_passed();
|
2015-10-13 09:51:12 -04:00
|
|
|
test_equal(db.at(N), NULL);
|
|
|
|
|
|
|
|
/* database.find() */
|
|
|
|
for (i = 0; i < N; i++) {
|
|
|
|
key = g_strdup_printf("%u", i);
|
|
|
|
dbe = db.find(key);
|
|
|
|
test_loop_not_equal(dbe, NULL, i);
|
|
|
|
test_loop_equal(dbe->primary_key(), key, i);
|
|
|
|
test_loop_equal(dbe, ptrs.at(i), i);
|
|
|
|
test_loop_equal(dbe->ie_val, i, i);
|
|
|
|
g_free(key);
|
|
|
|
} test_loop_passed();
|
|
|
|
key = g_strdup_printf("%u", N);
|
|
|
|
test_equal(db.find(key), NULL);
|
|
|
|
g_free(key);
|
|
|
|
|
|
|
|
/* database.remove(): Even indices only! */
|
|
|
|
for (i = 0; i < N; i += 2) {
|
|
|
|
key = g_strdup_printf("%u", i);
|
|
|
|
db.remove(i);
|
|
|
|
db.remove(i);
|
|
|
|
test_loop_equal(db.at(i), NULL, i);
|
|
|
|
test_loop_equal(db.find(key), NULL, i);
|
|
|
|
g_free(key);
|
|
|
|
} test_loop_passed();
|
|
|
|
db.remove(N);
|
2015-10-17 14:59:06 -04:00
|
|
|
test_equal(db.db_size, N / 2);
|
2015-10-17 15:12:40 -04:00
|
|
|
test_equal(db_actual_size(&db), N);
|
2015-10-13 09:51:12 -04:00
|
|
|
|
|
|
|
/* database.first(), database.next(), database.end() */
|
|
|
|
i = 1;
|
|
|
|
for (it = db.begin(); it != db.end(); it = db.next(it)) {
|
|
|
|
test_loop_not_equal(*it, NULL, i);
|
|
|
|
test_loop_equal(*it, ptrs.at(i), i);
|
|
|
|
test_loop_equal((*it)->ie_val, i, i);
|
|
|
|
i += 2;
|
|
|
|
} test_loop_passed();
|
|
|
|
test_equal(i, N + 1);
|
2014-04-27 17:04:33 -04:00
|
|
|
}
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
static void test_basics() { test_stress(10); }
|
|
|
|
static void test_stress_0() { test_stress(0); }
|
|
|
|
static void test_stress_100K() { test_stress(100000); }
|
2015-01-04 17:56:54 -05:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
static void test_save_load()
|
2014-04-27 17:04:33 -04:00
|
|
|
{
|
2015-10-17 10:07:58 -04:00
|
|
|
database<struct int_entry> db1("save_load.db", true);
|
|
|
|
database<struct int_entry> db2("save_load.db", false);
|
2015-10-13 09:51:12 -04:00
|
|
|
struct int_entry *dbe;
|
|
|
|
const unsigned int N = 10;
|
|
|
|
unsigned int i;
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
/* 10 items should "autosave" when inserted */
|
|
|
|
for (i = 0; i < N; i++)
|
|
|
|
db1.insert(int_entry(i));
|
2014-03-09 14:58:06 -04:00
|
|
|
|
2015-09-17 08:12:25 -04:00
|
|
|
db_load(&db2);
|
2015-10-17 14:59:06 -04:00
|
|
|
test_equal(db2.db_size, N);
|
2015-10-17 15:12:40 -04:00
|
|
|
test_equal(db_actual_size(&db2), N);
|
2015-10-13 09:51:12 -04:00
|
|
|
for (i = 0; i < N; i++) {
|
|
|
|
dbe = db2.at(i);
|
|
|
|
test_loop_not_equal(dbe, NULL, i);
|
|
|
|
test_loop_equal(dbe->ie_val, i, i);
|
2015-08-25 09:27:01 -04:00
|
|
|
} test_loop_passed();
|
2014-04-27 17:04:33 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
/* Removing 5 items, should also trigger autosaving. */
|
|
|
|
for (i = 0; i < N; i += 2)
|
|
|
|
db1.remove(i);
|
2015-01-04 16:36:19 -05:00
|
|
|
|
2015-10-17 10:07:58 -04:00
|
|
|
db2 = database<struct int_entry>("save_load.db", false);
|
2015-09-17 08:12:25 -04:00
|
|
|
db_load(&db2);
|
2015-10-17 14:59:06 -04:00
|
|
|
test_equal(db2.db_size, N / 2);
|
2015-10-13 09:51:12 -04:00
|
|
|
for (i = 1; i < N; i++) {
|
|
|
|
dbe = db2.at(i);
|
|
|
|
if ((i % 2) == 0) {
|
|
|
|
test_loop_equal(dbe, NULL, i);
|
|
|
|
} else {
|
|
|
|
test_loop_not_equal(dbe, NULL, i);
|
|
|
|
test_loop_equal(dbe->ie_val, i, i);
|
|
|
|
}
|
|
|
|
} test_loop_passed();
|
2015-08-25 09:27:01 -04:00
|
|
|
|
2015-10-13 09:51:12 -04:00
|
|
|
/* Test with autosave turned off. */
|
|
|
|
for (i = N; i < (2 * N); i++)
|
|
|
|
db2.insert(int_entry(i));
|
|
|
|
for (i = N; i < (2 * N); i += 2)
|
|
|
|
db2.remove(i);
|
|
|
|
|
2015-10-17 10:07:58 -04:00
|
|
|
db1 = database<struct int_entry>("save_load.db", false);
|
2015-09-17 08:12:25 -04:00
|
|
|
db_load(&db1);
|
2015-10-17 14:59:06 -04:00
|
|
|
test_equal(db1.db_size, N / 2);
|
2015-10-13 09:51:12 -04:00
|
|
|
|
2015-10-18 10:11:24 -04:00
|
|
|
db_save(&db2);
|
2015-10-17 10:07:58 -04:00
|
|
|
db1 = database<struct int_entry>("save_load.db", false);
|
2015-09-17 08:12:25 -04:00
|
|
|
db_load(&db1);
|
2015-10-13 09:51:12 -04:00
|
|
|
|
2015-10-17 14:59:06 -04:00
|
|
|
test_equal(db1.db_size, N);
|
2015-10-17 15:12:40 -04:00
|
|
|
test_equal(db_actual_size(&db1), 2 * N);
|
2015-10-13 09:51:12 -04:00
|
|
|
for (i = 1; i < (2 * N); i++) {
|
|
|
|
dbe = db1.at(i);
|
|
|
|
if ((i % 2) == 0) {
|
|
|
|
test_loop_equal(dbe, NULL, i);
|
|
|
|
} else {
|
|
|
|
test_loop_not_equal(dbe, NULL, i);
|
|
|
|
test_loop_equal(dbe->ie_val, i, i);
|
|
|
|
}
|
|
|
|
} test_loop_passed();
|
|
|
|
}
|
2015-08-25 09:27:01 -04:00
|
|
|
|
|
|
|
DECLARE_UNIT_TESTS(
|
2015-10-13 09:51:12 -04:00
|
|
|
UNIT_TEST("Database Entry", test_db_entry),
|
|
|
|
UNIT_TEST("Database Initialization", test_init),
|
|
|
|
UNIT_TEST("Database Basics", test_basics),
|
|
|
|
UNIT_TEST("Database Stress (n = 0)", test_stress_0),
|
|
|
|
UNIT_TEST("Database Stress (n = 100,000)", test_stress_100K),
|
|
|
|
UNIT_TEST("Database Save and Load", test_save_load),
|
2015-08-25 09:27:01 -04:00
|
|
|
);
|