From 1b34a9a8a030cf24970d59b7425f91b2389c656f Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Wed, 12 Mar 2014 20:23:34 -0400 Subject: [PATCH] index: Update the index design I updated the design and rewrote the unit tests. This creates something more consistent with how I ended up using the index. Signed-off-by: Anna Schumaker --- DESIGN | 60 ++++++++++++++-- include/database.h | 47 +------------ include/filter.h | 6 +- include/index.h | 38 +++++++++++ include/library.h | 8 +-- lib/database.cpp | 64 ----------------- lib/filter.cpp | 15 ++-- lib/index.cpp | 71 +++++++++++++++++++ lib/library.cpp | 8 +-- lib/playlist.cpp | 8 +-- tests/Sconscript | 5 +- tests/index | 45 ++++++++++++ tests/index/Sconscript | 6 -- tests/index/index.cpp | 152 ----------------------------------------- tests/index/index.good | 106 ---------------------------- tests/src/database.cpp | 4 +- tests/src/db_entry.cpp | 4 +- tests/src/index.cpp | 136 ++++++++++++++++++++++++++++++++++++ 18 files changed, 369 insertions(+), 414 deletions(-) create mode 100644 include/index.h create mode 100644 lib/index.cpp create mode 100755 tests/index delete mode 100644 tests/index/Sconscript delete mode 100644 tests/index/index.cpp delete mode 100644 tests/index/index.good create mode 100644 tests/src/index.cpp diff --git a/DESIGN b/DESIGN index 62b2cc6e..d49544ee 100644 --- a/DESIGN +++ b/DESIGN @@ -203,7 +203,7 @@ Database Entry: DatabaseEntry(); virtual void ~DatabaseEntry() = 0; - virtual std::string primary_key() = 0; + virtual const std::string primary_key() = 0; virtual void write(File &) = 0; virtual void read(File &) = 0; @@ -213,7 +213,7 @@ Database Entry: DatabaseEntry :: DatabaseEntry(): Set valid = false. - std::string DatabaseEntry :: primary_key(); + const std::string DatabaseEntry :: primary_key(); This function should return a unique string representing this DatabaseEntry instance, which will be used to prevent duplicates in a database. This string is not expected to @@ -261,7 +261,7 @@ Database: class Database { private: std::vector _db; - std::map _keys; + std::map _keys; unsigned int _size; /* Number of valid rows */ bool _autosave; File _file; @@ -357,22 +357,70 @@ Database: +Index: + An index is a special database used to map a std::string key to + multiple integer values. - IndexEntry: class IndexEntry : public DatabaseEntry { public: + const std::string key; set values; + IndexEntry(const std::string &); + const std::string primary_key(); + void insert(unsigned int); + void remove(unsigned int); + void write(File &); void read(File &); - void print(); - void insert(unsigned int); - void remove(unsigned int); }; File << key << endl; File << values.size() << values[0] << .. << values[N] << endl; +- IndexEntry API: + IndexEntry :: IndexEntry(); + Creat an empty IndexEntry. + + std::string IndexEntry :: primary_key(); + return key; + + void IndexEntry :: insert(unsigned int value); + Add value to the values set. + + void IndexEntry :: remove(unsigned int value); + Remove value from the values set. + + void IndexEntry :: write(File &f); + Write the values set to a file. + + void IndexEntry :: read(File &f); + Read values from a file. + +- Index: + class Index : public Database { + public: + Index(const std::string &, bool); + + void insert(const std::string &, unsigned int); + void remove(const std::string &, unsigned int); + }; + +- Index API: + Index :: Index(const std::string &filepath, bool autosave); + Pass values on to the Database constructor. + + void Index :: insert(const std::string &key, unsigned int value); + Create an IndexEntry for key if one does not exist yet. + Insert value into the IndexEntry corresponding to key. + If autosave is enabled, save(). + + void Index :: remove(const std::string &key, unsigned int value); + Remove value from the IndexEntry corresponding to key. Do not + remove the IndexEntry, even if it is empty. + If autosave is enabled, save(). + Filter: (lib/filter.cpp) diff --git a/include/database.h b/include/database.h index a42bcebc..41dc3a35 100644 --- a/include/database.h +++ b/include/database.h @@ -8,7 +8,6 @@ #include #include -#include #include @@ -17,30 +16,12 @@ public: bool valid; DatabaseEntry(); - virtual std::string primary_key() = 0; + virtual const std::string primary_key() = 0; virtual void write(File &) = 0; virtual void read(File &) = 0; }; -class IndexEntry : public DatabaseEntry { -public: - std::string key; - std::set values; - - IndexEntry(); - IndexEntry(const std::string &, unsigned int); - ~IndexEntry(); - std::string primary_key(); - void write(File &); - void read(File &); -#ifdef CONFIG_TEST - void print(); -#endif /* CONFIG_TEST */ - void insert(unsigned int); - void remove(unsigned int); -}; - template class Database { @@ -51,8 +32,6 @@ private: bool _autosave; File _file; - void autosave(); - public: typedef typename std::vector::iterator iterator; typedef typename std::vector::const_iterator const_iterator; @@ -60,6 +39,7 @@ public: Database(std::string, bool); ~Database(); void save(); + void autosave(); void load(); unsigned int insert(T); @@ -75,29 +55,6 @@ public: iterator find(const std::string &); }; -static inline void index_insert(Database &db, - const std::string &key, - unsigned int val) -{ - Database::iterator it = db.find(key); - if (it == db.end()) { - db.insert(IndexEntry(key, val)); - } else - it->insert(val); -} - -static inline void index_remove(Database &db, - const std::string &key, - unsigned int val) -{ - Database::iterator it = db.find(key); - if (it != db.end()) { - it->remove(val); - if (it->values.size() == 0) - db.remove(it - db.begin()); - } -} - #include "database.hpp" #endif /* OCARINA_DATABASE_H */ diff --git a/include/filter.h b/include/filter.h index a88e4dd1..fd23ac52 100644 --- a/include/filter.h +++ b/include/filter.h @@ -4,7 +4,7 @@ #ifndef OCARINA_FILTER_H #define OCARINA_FILTER_H -#include +#include #include namespace filter { @@ -15,10 +15,6 @@ namespace filter { void print_cache_stats(); -#ifdef CONFIG_TEST - Database &get_index(); -#endif /* CONFIG_TEST */ - }; #endif /* OCARINA_FILTER_H */ diff --git a/include/index.h b/include/index.h new file mode 100644 index 00000000..258d4fd1 --- /dev/null +++ b/include/index.h @@ -0,0 +1,38 @@ +/* + * Copyright 2014 (c) Anna Schumaker. + */ +#ifndef OCARINA_INDEX_H +#define OCARINA_INDEX_H + +#include + +#include +#include + + +class IndexEntry : public DatabaseEntry { +public: + std::string key; + std::set values; + + IndexEntry(); + IndexEntry(const std::string &); + const std::string primary_key(); + void insert(unsigned int); + void remove(unsigned int); + + void write(File &); + void read(File &); +}; + + + +class Index : public Database { +public: + Index(const std::string &, bool); + + void insert(const std::string &, unsigned int); + void remove(const std::string &, unsigned int); +}; + +#endif /* OCARINA_DATABASE_H */ diff --git a/include/library.h b/include/library.h index 36048c0b..e6b81bd5 100644 --- a/include/library.h +++ b/include/library.h @@ -33,7 +33,7 @@ namespace library AGInfo(); AGInfo(DB_Type, TagLib :: Tag *); AGInfo(DB_Type, const std::string &); - std::string primary_key(); + const std::string primary_key(); void read(File &); void write(File &); }; @@ -49,7 +49,7 @@ namespace library Album(); Album(TagLib :: Tag *, unsigned int); Album(const std::string &, unsigned int, unsigned int); - std::string primary_key(); + const std::string primary_key(); void read(File &); void write(File &); }; @@ -63,7 +63,7 @@ namespace library Library(); Library(const std::string &, bool); - std::string primary_key(); + const std::string primary_key(); void read(File &); void write(File &); }; @@ -95,7 +95,7 @@ namespace library unsigned int, const std :: string &); Track(ImportData *, unsigned int, unsigned int, unsigned int, unsigned int); - std::string primary_key(); + const std::string primary_key(); void read(File &); void write(File &); }; diff --git a/lib/database.cpp b/lib/database.cpp index b87cf453..0b1b125d 100644 --- a/lib/database.cpp +++ b/lib/database.cpp @@ -8,67 +8,3 @@ DatabaseEntry :: DatabaseEntry() : valid(false) { } - - - -IndexEntry :: IndexEntry() -{ -} - -IndexEntry :: IndexEntry(const std::string &k, unsigned int v) -{ - key = k; - insert(v); -} - -IndexEntry :: ~IndexEntry() -{ -} - -std::string IndexEntry :: primary_key() -{ - return key; -} - -void IndexEntry :: write(File &f) -{ - std::set::iterator it; - f << key << std::endl << values.size() << " "; - for (it = values.begin(); it != values.end(); it++) - f << *it << " "; -} - -void IndexEntry :: read(File &f) -{ - unsigned int num, val; - - f >> key >> num; - for (unsigned int i = 0; i < num; i++) { - f >> val; - values.insert(val); - } -} - -#ifdef CONFIG_TEST -void IndexEntry :: print() -{ - std::set::iterator it; - :: print("{"); - for (it = values.begin(); it != values.end(); it++) { - if (it != values.begin()) - :: print(" "); - :: print("%d", *it); - } - :: print("}"); -} -#endif /* CONFIG_TEST */ - -void IndexEntry :: insert(unsigned int val) -{ - values.insert(val); -} - -void IndexEntry :: remove(unsigned int val) -{ - values.erase(val); -} diff --git a/lib/filter.cpp b/lib/filter.cpp index d2188dae..2cba8164 100644 --- a/lib/filter.cpp +++ b/lib/filter.cpp @@ -3,14 +3,14 @@ */ #include +#include #include #include #include #include -#include -static Database filter_index("", false); +static Index filter_index("", false); static std::map lowercase_cache; static unsigned int lowercase_cache_hits = 0; @@ -91,7 +91,7 @@ static void add_substrings(const std::string &text, unsigned int track_id) std::string substr; for (unsigned int i = 1; i <= text.size(); i++) { substr = text.substr(0, i); - index_insert(filter_index, substr, track_id); + filter_index.insert(substr, track_id); } } @@ -107,7 +107,7 @@ void filter :: add(const std::string &text, unsigned int track_id) static void find_intersection(std::string &text, std::set &res) { - Database::iterator it = filter_index.find(text); + Index::iterator it = filter_index.find(text); std::set tmp; set_intersection(it->values.begin(), it->values.end(), @@ -157,10 +157,3 @@ void filter :: print_cache_stats() print("Lowercase cache size: %u\n", lowercase_cache.size()); print("Lowercase cache hits: %u\n", lowercase_cache_hits); } - -#ifdef CONFIG_TEST -Database &filter :: get_index() -{ - return filter_index; -} -#endif /* CONFIG_TEST */ diff --git a/lib/index.cpp b/lib/index.cpp new file mode 100644 index 00000000..d1842b0d --- /dev/null +++ b/lib/index.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2014 (c) Anna Schumaker. + */ +#include + + +IndexEntry :: IndexEntry() {} +IndexEntry :: IndexEntry(const std::string &k) + : key(k) +{} + +const std::string IndexEntry :: primary_key() +{ + return key; +} + +void IndexEntry :: insert(unsigned int val) +{ + values.insert(val); +} + +void IndexEntry :: remove(unsigned int val) +{ + values.erase(val); +} + +void IndexEntry :: write(File &f) +{ + std::set::iterator it; + f << key << std::endl << values.size() << " "; + for (it = values.begin(); it != values.end(); it++) + f << *it << " "; +} + +void IndexEntry :: read(File &f) +{ + unsigned int num, val; + + f >> key >> num; + for (unsigned int i = 0; i < num; i++) { + f >> val; + insert(val); + } +} + + + +Index :: Index(const std::string &filepath, bool autosave) + : Database(filepath, autosave) +{} + +void Index :: insert(const std::string &key, unsigned int val) +{ + iterator it = find(key); + if (it == end()) + it = at(Database :: insert(IndexEntry(key))); + + it->insert(val); + autosave(); +} + +void Index :: remove(const std::string &key, unsigned int val) +{ + iterator it = find(key); + + if (it == end()) + return; + + it->remove(val); + autosave(); +} diff --git a/lib/library.cpp b/lib/library.cpp index df89cde1..fe1ecf41 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -60,7 +60,7 @@ library :: AGInfo :: AGInfo(DB_Type type, const std::string &str) throw -E_INVAL; } -std::string library :: AGInfo :: primary_key() +const std::string library :: AGInfo :: primary_key() { return name; } @@ -100,7 +100,7 @@ library :: Album :: Album(const std::string &str, unsigned int yr, unsigned int name_lower = filter :: to_lowercase(name); } -std::string library :: Album :: primary_key() +const std::string library :: Album :: primary_key() { std::stringstream ss; ss << artist_id << "." << name << "." << year; @@ -135,7 +135,7 @@ library :: Library :: Library(const std::string &path, bool is_enabled) { } -std::string library :: Library :: primary_key() +const std::string library :: Library :: primary_key() { return root_path; } @@ -211,7 +211,7 @@ library :: Track :: Track(struct ImportData *data, unsigned int lib, length_str = ss.str(); } -std::string library :: Track :: primary_key() +const std::string library :: Track :: primary_key() { return full_path; } diff --git a/lib/playlist.cpp b/lib/playlist.cpp index 78dd09c0..b6d33487 100644 --- a/lib/playlist.cpp +++ b/lib/playlist.cpp @@ -2,12 +2,12 @@ * Copyright 2013 (c) Anna Schumaker. */ #include -#include #include +#include #include static std::set empty_set; -static Database playlist_db("playlist.db", false); +static Index playlist_db("playlist.db", false); static Playqueue playlist_pq(PQ_ENABLED); static std::string cur_pq; @@ -46,7 +46,7 @@ void playlist :: init() void playlist :: add(const std::string &name, unsigned int track_id) { if ((name == "Banned") || (name == "Favorites")) { - index_insert(playlist_db, name, track_id); + playlist_db.insert(name, track_id); playlist_db.save(); if (name == cur_pq) playlist_pq.add(track_id); @@ -59,7 +59,7 @@ void playlist :: add(const std::string &name, unsigned int track_id) void playlist :: del(const std::string &name, unsigned int track_id) { if ((name == "Banned") || (name == "Favorites")) { - index_remove(playlist_db, name, track_id); + playlist_db.remove(name, track_id); playlist_db.save(); if (name == cur_pq) playlist_pq.del_track(track_id); diff --git a/tests/Sconscript b/tests/Sconscript index f020b880..18fdc894 100644 --- a/tests/Sconscript +++ b/tests/Sconscript @@ -8,9 +8,8 @@ if sys.argv.count("tests") > 0: src = SConscript("src/Sconscript") -tests = [ "version", "file", "db_entry", "database" ] -#scripts = [ "print", "file", "database", "index", "filter", "idle", "playlist", -# "library", "playqueue", "deck", "audio", "gui" ] +tests = [ "version", "file", "db_entry", "database", "index" ] +#scripts = [ "filter", "idle", "playlist", "library", "playqueue", "deck", "audio", "gui" ] prev = None diff --git a/tests/index b/tests/index new file mode 100755 index 00000000..00a01b6d --- /dev/null +++ b/tests/index @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright 2014 (c) Anna Schumaker + +. $(dirname $0)/_functions + +function test_autosave +{ + new_test "Index Test (n = $1, autosave = true)" + src/index.run -a $1 + if [ ! -f $DATA_DIR/index.idx ]; then + echo "ERROR: $DATA_DIR/index.db doesn't exist!" + exit 1 + fi +} + +function test_noautosave +{ + new_test "Index Test (n = $1, autosave = false)" + src/index.run $1 + if [ -f $DATA_DIR/index.idx ]; then + echo "ERROR: $DATA_DIR/index.idx exists!" + exit 1 + fi +} + +function run_test +{ + rm $DATA_DIR/* 2>/dev/null || true + + if [ $1 -lt 1000 ]; then + test_autosave $1 + else + test_noautosave $1 + fi +} + +run_test 10 +echo +run_test 100 +echo +run_test 1000 +echo +run_test 10000 +echo +run_test 100000 diff --git a/tests/index/Sconscript b/tests/index/Sconscript deleted file mode 100644 index e80c209d..00000000 --- a/tests/index/Sconscript +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/python -Import("Test", "CONFIG") - -CONFIG.DATABASE = True - -Test("index", "index.cpp") diff --git a/tests/index/index.cpp b/tests/index/index.cpp deleted file mode 100644 index eaa8a70f..00000000 --- a/tests/index/index.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2013 (c) Anna Schumaker. - */ -#include -#include - -void print_index(Database &index) -{ - std::set::iterator s_it; - std::set::iterator u_it; - - print("=== Printing index ===\n"); - index.print_keys(); - - for (unsigned int i = index.first(); i != index.num_rows(); i = index.next(i)) { - print("index[%s] = ", index[i].primary_key.c_str()); - index[i].print(); - print("\n"); - } - - print("\n"); -} - -void populate_index(Database &index) -{ - std::string key_str; - - for (char key = 'a'; key <= 'z'; key++) { - key_str = key; - for (unsigned int value = 0; value < 10; value++) - index_insert(index, key_str, value); - } -} - -void remove_keys(Database &index) -{ - std::string key_str; - - for (char key = 'a'; key <= 'z'; key+=2) { - key_str = key; - index.remove(index.find_index(key_str)); - if (index.has_key(key_str)) - print("Failed to remove key!\n"); - } -} - -void remove_values(Database &index) -{ - std::string key_str; - unsigned int limit = 0; - - for (char key = 'a'; key <= 'z'; key++) { - key_str = key; - for (unsigned int i = 0; i < limit; i++) - index_remove(index, key_str, i); - limit++; - if (limit == 11) { - limit = 0; - if (index.has_key(key_str)) - print("Failed to remove key!\n"); - } - } -} - -/* - * Test index creation, print key access - */ -void test_0() -{ - print("Test 0\n"); - Database index(""); - - populate_index(index); - print_index(index); -} - -/* - * Test removing keys from an index - */ -void test_1() -{ - print("Test 1\n"); - Database index(""); - - populate_index(index); - remove_keys(index); - print_index(index); -} - -/* - * Test removing values from an index - */ -void test_2() -{ - print("Test 2\n"); - Database index(""); - - populate_index(index); - remove_values(index); - print_index(index); -} - -/* - * Save the database to disk - */ -void test_3() -{ - print("Test 3\n"); - Database index("test.idx"); - - populate_index(index); - remove_values(index); - index.save(); -} - -/* - * Reload the database from disk - */ -void test_4() -{ - print("Test 4\n"); - Database index("test.idx"); - - index.load(); - print_index(index); -} - -/* - * Test access to keys that don't exist - */ -void test_5() -{ - print("Test 5\n"); - Database index(""); - print("index[nokey].size() = "); - try { - print("%u\n", index.find("nokey").values.size()); - } catch (...) { - print("0\n"); - } -} - -int main(int argc, char **argv) -{ - test_0(); - test_1(); - test_2(); - test_3(); - test_4(); - test_5(); - return 0; -} diff --git a/tests/index/index.good b/tests/index/index.good deleted file mode 100644 index d6c4e5fa..00000000 --- a/tests/index/index.good +++ /dev/null @@ -1,106 +0,0 @@ -Test 0 -=== Printing index === -Found keys: a b c d e f g h i j k l m n o p q r s t u v w x y z -index[a] = {0 1 2 3 4 5 6 7 8 9} -index[b] = {0 1 2 3 4 5 6 7 8 9} -index[c] = {0 1 2 3 4 5 6 7 8 9} -index[d] = {0 1 2 3 4 5 6 7 8 9} -index[e] = {0 1 2 3 4 5 6 7 8 9} -index[f] = {0 1 2 3 4 5 6 7 8 9} -index[g] = {0 1 2 3 4 5 6 7 8 9} -index[h] = {0 1 2 3 4 5 6 7 8 9} -index[i] = {0 1 2 3 4 5 6 7 8 9} -index[j] = {0 1 2 3 4 5 6 7 8 9} -index[k] = {0 1 2 3 4 5 6 7 8 9} -index[l] = {0 1 2 3 4 5 6 7 8 9} -index[m] = {0 1 2 3 4 5 6 7 8 9} -index[n] = {0 1 2 3 4 5 6 7 8 9} -index[o] = {0 1 2 3 4 5 6 7 8 9} -index[p] = {0 1 2 3 4 5 6 7 8 9} -index[q] = {0 1 2 3 4 5 6 7 8 9} -index[r] = {0 1 2 3 4 5 6 7 8 9} -index[s] = {0 1 2 3 4 5 6 7 8 9} -index[t] = {0 1 2 3 4 5 6 7 8 9} -index[u] = {0 1 2 3 4 5 6 7 8 9} -index[v] = {0 1 2 3 4 5 6 7 8 9} -index[w] = {0 1 2 3 4 5 6 7 8 9} -index[x] = {0 1 2 3 4 5 6 7 8 9} -index[y] = {0 1 2 3 4 5 6 7 8 9} -index[z] = {0 1 2 3 4 5 6 7 8 9} - -Test 1 -=== Printing index === -Found keys: b d f h j l n p r t v x z -index[b] = {0 1 2 3 4 5 6 7 8 9} -index[d] = {0 1 2 3 4 5 6 7 8 9} -index[f] = {0 1 2 3 4 5 6 7 8 9} -index[h] = {0 1 2 3 4 5 6 7 8 9} -index[j] = {0 1 2 3 4 5 6 7 8 9} -index[l] = {0 1 2 3 4 5 6 7 8 9} -index[n] = {0 1 2 3 4 5 6 7 8 9} -index[p] = {0 1 2 3 4 5 6 7 8 9} -index[r] = {0 1 2 3 4 5 6 7 8 9} -index[t] = {0 1 2 3 4 5 6 7 8 9} -index[v] = {0 1 2 3 4 5 6 7 8 9} -index[x] = {0 1 2 3 4 5 6 7 8 9} -index[z] = {0 1 2 3 4 5 6 7 8 9} - -Test 2 -=== Printing index === -Found keys: a b c d e f g h i j l m n o p q r s t u w x y z -index[a] = {0 1 2 3 4 5 6 7 8 9} -index[b] = {1 2 3 4 5 6 7 8 9} -index[c] = {2 3 4 5 6 7 8 9} -index[d] = {3 4 5 6 7 8 9} -index[e] = {4 5 6 7 8 9} -index[f] = {5 6 7 8 9} -index[g] = {6 7 8 9} -index[h] = {7 8 9} -index[i] = {8 9} -index[j] = {9} -index[l] = {0 1 2 3 4 5 6 7 8 9} -index[m] = {1 2 3 4 5 6 7 8 9} -index[n] = {2 3 4 5 6 7 8 9} -index[o] = {3 4 5 6 7 8 9} -index[p] = {4 5 6 7 8 9} -index[q] = {5 6 7 8 9} -index[r] = {6 7 8 9} -index[s] = {7 8 9} -index[t] = {8 9} -index[u] = {9} -index[w] = {0 1 2 3 4 5 6 7 8 9} -index[x] = {1 2 3 4 5 6 7 8 9} -index[y] = {2 3 4 5 6 7 8 9} -index[z] = {3 4 5 6 7 8 9} - -Test 3 -Test 4 -=== Printing index === -Found keys: a b c d e f g h i j l m n o p q r s t u w x y z -index[a] = {0 1 2 3 4 5 6 7 8 9} -index[b] = {1 2 3 4 5 6 7 8 9} -index[c] = {2 3 4 5 6 7 8 9} -index[d] = {3 4 5 6 7 8 9} -index[e] = {4 5 6 7 8 9} -index[f] = {5 6 7 8 9} -index[g] = {6 7 8 9} -index[h] = {7 8 9} -index[i] = {8 9} -index[j] = {9} -index[l] = {0 1 2 3 4 5 6 7 8 9} -index[m] = {1 2 3 4 5 6 7 8 9} -index[n] = {2 3 4 5 6 7 8 9} -index[o] = {3 4 5 6 7 8 9} -index[p] = {4 5 6 7 8 9} -index[q] = {5 6 7 8 9} -index[r] = {6 7 8 9} -index[s] = {7 8 9} -index[t] = {8 9} -index[u] = {9} -index[w] = {0 1 2 3 4 5 6 7 8 9} -index[x] = {1 2 3 4 5 6 7 8 9} -index[y] = {2 3 4 5 6 7 8 9} -index[z] = {3 4 5 6 7 8 9} - -Test 5 -index[nokey].size() = 0 diff --git a/tests/src/database.cpp b/tests/src/database.cpp index 16c8dc08..ccd72ee1 100644 --- a/tests/src/database.cpp +++ b/tests/src/database.cpp @@ -20,7 +20,7 @@ public: IntEntry(); IntEntry(unsigned int); - std::string primary_key(); + const std::string primary_key(); void write(File &); void read(File &); void print(); @@ -28,7 +28,7 @@ public: IntEntry :: IntEntry() : val(0) {} IntEntry :: IntEntry(unsigned int v) : val(v) {} -std::string IntEntry :: primary_key() +const std::string IntEntry :: primary_key() { std::stringstream ss; ss << val; diff --git a/tests/src/db_entry.cpp b/tests/src/db_entry.cpp index bae0e7a6..f8015dca 100644 --- a/tests/src/db_entry.cpp +++ b/tests/src/db_entry.cpp @@ -19,7 +19,7 @@ public: std::string key; IntEntry(unsigned int, const std::string &); - std::string primary_key(); + const std::string primary_key(); void write(File &); void read(File &); void print(); @@ -31,7 +31,7 @@ IntEntry :: IntEntry(unsigned int i, const std::string &s) key = s; } -std::string IntEntry :: primary_key() +const std::string IntEntry :: primary_key() { return key; } diff --git a/tests/src/index.cpp b/tests/src/index.cpp new file mode 100644 index 00000000..090eb416 --- /dev/null +++ b/tests/src/index.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2014 (c) Anna Schumaker. + * Test a Database + */ + +#include +#include + +#include +#include + + +unsigned int test_num = 0; + +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++; +} + +int main(int argc, char **argv) +{ + bool autosave = false; + unsigned int n; + char c; + + while ((c = getopt(argc, argv, "a")) != -1) { + switch (c) { + case 'a': + autosave = true; + break; + } + } + + n = atoi(argv[optind]); + Index index("index.idx", autosave); + + + /** + * 0: Test inserting when there is no key + */ + index.insert("a", 0); + Index :: iterator it = index.find("a"); + if (it == index.end()) + test_results(false, __LINE__); + if (it->values.size() == 0) + test_results(false, __LINE__); + test_results(*(it->values.begin()) == 0, __LINE__); + + + /** + * 1: Test removing + */ + index.remove("a", 0); + test_results((index.size() == 1) && (index.find("a")->values.size() == 0), __LINE__); + + + /** + * 2: Test adding multiple values + */ + for (c = 'a'; c <= 'z'; c++) { + std::string key = ""; + key += c; + + for (unsigned int i = 0; i < n; i++) + index.insert(key, i); + } + + test_results(index.size() == 26, __LINE__); + + + /** + * 3: Make sure we have multiple values for each key + */ + for (c = 'a'; c <= 'z'; c++) { + std::string key = ""; + key += c; + if (index.find(key)->values.size() != n) + test_results(false, __LINE__); + } + test_results(true, __LINE__); + + + /** + * 4: Test removing multiple values + */ + for (c = 'a'; c <= 'z'; c+=2) { + std::string key = ""; + key += c; + + for (unsigned int i = 0; i < n; i++) + index.remove(key, i); + + if (index.find(key)->values.size() > 0) + test_results(false, __LINE__); + } + + test_results(index.size() == 26, __LINE__); + + + /** + * Everything after this point tests loading from a file + */ + if (autosave == false) + return 0; + + Index index2("index.idx", autosave); + index2.load(); + + + /** + * 5: Load database from file + */ + test_results(index.size() == index2.size(), __LINE__); + + + /** + * 6: Check that everything is the right size + */ + for (c = 'a'; c <= 'z'; c++) { + std::string key = ""; + key += c; + + if (index.find(key)->values.size() != index2.find(key)->values.size()) + test_results(false, __LINE__); + } + test_results(true, __LINE__); + + return 0; +}