2014-03-09 14:58:06 -04:00
|
|
|
/*
|
|
|
|
* Copyright 2014 (c) Anna Schumaker.
|
|
|
|
* Test a Database
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <database.h>
|
|
|
|
#include <print.h>
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int test_num = 0;
|
|
|
|
|
|
|
|
|
|
|
|
class IntEntry : public DatabaseEntry {
|
|
|
|
public:
|
|
|
|
unsigned int val;
|
|
|
|
|
|
|
|
IntEntry();
|
|
|
|
IntEntry(unsigned int);
|
2014-03-25 17:51:37 -04:00
|
|
|
const std::string primary_key() const;
|
2014-03-09 14:58:06 -04:00
|
|
|
void write(File &);
|
|
|
|
void read(File &);
|
|
|
|
void print();
|
|
|
|
};
|
|
|
|
|
|
|
|
IntEntry :: IntEntry() : val(0) {}
|
|
|
|
IntEntry :: IntEntry(unsigned int v) : val(v) {}
|
2014-03-25 17:51:37 -04:00
|
|
|
const std::string IntEntry :: primary_key() const
|
2014-03-09 14:58:06 -04:00
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << val;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntEntry :: write(File &f) { f << val; }
|
|
|
|
void IntEntry :: read(File &f) { f >> val; }
|
|
|
|
void IntEntry :: print() { :: print(primary_key().c_str()); }
|
|
|
|
|
|
|
|
void test_results(bool success, unsigned int line)
|
|
|
|
{
|
|
|
|
print(" %u: ", test_num);
|
|
|
|
if (success)
|
|
|
|
print("Success!\n");
|
|
|
|
else {
|
|
|
|
print("FAILED (%u) =(\n", line);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
test_num++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_size(Database<IntEntry> &db, unsigned int size,
|
|
|
|
unsigned int actual, unsigned int line)
|
|
|
|
{
|
2014-03-23 13:16:22 -04:00
|
|
|
test_results( (db.size() == size) && (db.actual_size() == actual), line );
|
2014-03-09 14:58:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
bool autosave = false;
|
|
|
|
unsigned int n = 0, size = 0, actual = 0;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
while ((c = getopt(argc, argv, "a")) != -1) {
|
|
|
|
switch (c) {
|
|
|
|
case 'a':
|
|
|
|
autosave = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n = atoi(argv[optind]);
|
|
|
|
Database<IntEntry> db("database.db", autosave);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 0: Test initial size
|
|
|
|
*/
|
|
|
|
test_size(db, size, actual, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 1: Test insertion
|
|
|
|
*/
|
2014-03-25 10:57:09 -04:00
|
|
|
IntEntry *one, *three;
|
2014-03-09 14:58:06 -04:00
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
2014-03-25 10:57:09 -04:00
|
|
|
IntEntry *it = db.insert(IntEntry(i));
|
|
|
|
if (it == NULL)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
2014-03-25 10:57:09 -04:00
|
|
|
if (it->id != i)
|
|
|
|
test_results(false, __LINE__);
|
|
|
|
if (it->val != i)
|
|
|
|
test_results(false, __LINE__);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pointers should still be valid after more insertions.
|
|
|
|
* These will be checked later
|
|
|
|
*/
|
|
|
|
if (i == 1)
|
|
|
|
one = it;
|
|
|
|
if (i == 3)
|
|
|
|
three = it;
|
2014-03-09 14:58:06 -04:00
|
|
|
}
|
|
|
|
test_results(true, __LINE__);
|
|
|
|
size += n;
|
|
|
|
actual += n;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 2: Test that size changes
|
|
|
|
*/
|
|
|
|
test_size(db, size, actual, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 3: Test inserting ... again.
|
|
|
|
*/
|
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
2014-03-25 10:57:09 -04:00
|
|
|
IntEntry *it = db.insert(IntEntry(i));
|
2014-04-12 13:48:59 -04:00
|
|
|
if (it != NULL)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
|
|
|
}
|
|
|
|
test_results(true, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 4: Test that size didn't change
|
|
|
|
*/
|
|
|
|
test_size(db, size, actual, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 5: Test that size changes when removing
|
|
|
|
* Also test out-of-bounds removal
|
|
|
|
*
|
|
|
|
* Note: This test removes all even-index entries
|
|
|
|
*/
|
|
|
|
for (unsigned int i = 0; i < n + 10; i+=2) {
|
|
|
|
db.remove(i);
|
2014-03-23 13:16:22 -04:00
|
|
|
if (i < n)
|
|
|
|
size--;
|
2014-03-09 14:58:06 -04:00
|
|
|
}
|
|
|
|
test_size(db, size, actual, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 6: Test that removing again doesn't change anything
|
|
|
|
*/
|
2014-03-25 10:57:09 -04:00
|
|
|
for (unsigned int i = 0; i < n + 10; i+=2)
|
2014-03-09 14:58:06 -04:00
|
|
|
db.remove(i);
|
|
|
|
test_size(db, size, actual, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-03-16 18:32:20 -04:00
|
|
|
* 7: Test iterating and setting ID
|
2014-03-09 14:58:06 -04:00
|
|
|
*/
|
|
|
|
Database<IntEntry>::iterator it;
|
|
|
|
unsigned int index = 1;
|
|
|
|
for (it = db.begin(); it != db.end(); it = db.next(it)) {
|
2014-03-25 10:57:09 -04:00
|
|
|
if ((*it) == NULL)
|
|
|
|
test_results(false, __LINE__);
|
|
|
|
if ((*it)->val != index)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
2014-03-25 10:57:09 -04:00
|
|
|
if ((*it)->id != index)
|
2014-03-16 18:32:20 -04:00
|
|
|
test_results(false, __LINE__);
|
2014-03-09 14:58:06 -04:00
|
|
|
index+=2;
|
|
|
|
};
|
|
|
|
test_results(true, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 8. Test access by id
|
|
|
|
*/
|
|
|
|
for (unsigned int i = 0; i < n + 10; i++) {
|
2014-03-24 19:51:13 -04:00
|
|
|
IntEntry *it = db.at(i);
|
2014-03-25 10:57:09 -04:00
|
|
|
if (i >= n) {
|
|
|
|
if (it != NULL)
|
|
|
|
test_results(false, __LINE__);
|
|
|
|
continue;
|
|
|
|
} else if (i % 2 == 0) {
|
|
|
|
if (it != NULL)
|
|
|
|
test_results(false, __LINE__);
|
|
|
|
} else if (it == NULL)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
2014-03-25 10:57:09 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Remember those pointers we stored earlier?
|
|
|
|
* The should still be valid now.
|
|
|
|
*/
|
|
|
|
if (i == 1 && it != one)
|
|
|
|
test_results(false, __LINE__);
|
|
|
|
if (i == 3 && it != three)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
|
|
|
}
|
|
|
|
test_results(true, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 9. Test inserting once again
|
|
|
|
*/
|
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
2014-04-12 13:48:59 -04:00
|
|
|
IntEntry *it = db.insert(IntEntry(i));
|
2014-03-09 14:58:06 -04:00
|
|
|
if ((i % 2) == 0) {
|
|
|
|
size++;
|
|
|
|
actual++;
|
2014-04-12 13:48:59 -04:00
|
|
|
if (it->id != (n + (i / 2)))
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
|
|
|
} else {
|
2014-04-12 13:48:59 -04:00
|
|
|
if (it != NULL)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
test_results(true, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 10. Test that size changed for every other insert
|
|
|
|
*/
|
|
|
|
test_size(db, size, actual, __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Everything after this point tests loading from a file
|
|
|
|
*/
|
|
|
|
if (autosave == false)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
Database<IntEntry> db2("database.db", autosave);
|
|
|
|
db2.load();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 11. Sizes should match
|
|
|
|
*/
|
|
|
|
test_size(db2, db.size(), db.actual_size(), __LINE__);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 12. Values should match
|
|
|
|
*/
|
|
|
|
Database<IntEntry>::iterator it2 = db2.begin();
|
|
|
|
for (it = db.begin(); it != db.end(); it++) {
|
2014-03-25 10:57:09 -04:00
|
|
|
if ((*it) == NULL && (*it2) != NULL)
|
|
|
|
test_results(false, __LINE__);
|
|
|
|
if ((*it) != NULL && (*it2) == NULL)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
2014-03-25 10:57:09 -04:00
|
|
|
if ((*it) != NULL) {
|
|
|
|
if ((*it)->val != (*it2)->val)
|
2014-03-09 14:58:06 -04:00
|
|
|
test_results(false, __LINE__);
|
2014-03-25 10:57:09 -04:00
|
|
|
if ((*it)->id != (*it2)->id)
|
2014-03-16 18:32:20 -04:00
|
|
|
test_results(false, __LINE__);
|
2014-03-09 14:58:06 -04:00
|
|
|
}
|
|
|
|
it2++;
|
|
|
|
}
|
|
|
|
test_results(true, __LINE__);
|
2014-03-16 18:32:20 -04:00
|
|
|
|
2014-03-09 14:58:06 -04:00
|
|
|
return 0;
|
|
|
|
}
|