// string_pool_test.cc - Don Yang (uguu.org) // // 06/10/11 #include"string_pool.h" #include"util.h" namespace { // Input and output values struct AddInput { // Input value const char *input; // Expected output const char *data; int index; int frequency; }; // Test operations on empty strings static void TestEmpty() { StringPool pool1; CHECK(pool1.strings().empty(), "Initialization failed"); CHECK(pool1.Find("") == NULL, "Found unexpected string"); CHECK(pool1.Add("") != NULL, "Add() failed"); CHECK(pool1.Find("") != NULL, "Find() failed"); CHECK(pool1.strings().size() == 1, "Add() failed"); StringPool pool2; CHECK(pool2.Add("hoge") != NULL, "Add() failed"); CHECK(pool2.Find("") != NULL, "Find() failed"); CHECK(pool1.strings().size() == 1, "Add() failed"); } // Check that adding strings work as expected static void TestAdd() { static const AddInput data[] = { {"", "", 0, 0}, {"hoge", "hoge", 0, 1}, {"", "hoge", 0, 1}, {"piyo", "piyo", 1, 1}, {"piyopiyo", "piyopiyo", 1, 2}, {"piyo", "piyopiyo", 1, 3}, {"hogehoge", "hogehoge", 0, 2}, {"hogepiyo", "hogepiyo", 2, 1}, {"fuga", "fuga", 3, 1}, {NULL, NULL, 0, 0} }; StringPool pool; int errors = 0; // Add items, check expected values after each add for(int i = 0; data[i].input != NULL; i++) { StringPool::Item *item = pool.Add(data[i].input); CHECK(item != NULL, "Add() returned NULL"); if( data[i].data != item->data ) { printf("ERROR: expected[%d].data mismatched: \"%s\" vs \"%s\"\n", i, data[i].data, item->data.c_str()); errors++; } #define CHECK_FIELD(x) \ if( data[i].x != item->x ) \ { \ printf("ERROR: expected[%d]." #x " mismatched: %d vs %d\n", \ i, data[i].x, item->x); \ errors++; \ } CHECK_FIELD(index); CHECK_FIELD(frequency); } CHECK(errors == 0, "Add() failed"); // Try Find() on all queries and check that the index hasn't changed. // Note that there is no such guarantee for empty strings, which // always gets the first index. errors = 0; for(int i = 0; data[i].input != NULL; i++) { const StringPool::Item *item = pool.Find(data[i].input); if( item == NULL ) { printf("ERROR: expected[%d]: not found: \"%s\"\n", i, data[i].input); errors++; continue; } if( *(data[i].input) != '\0' ) CHECK_FIELD(index); #undef CHECK_FIELD } CHECK(errors == 0, "Find() failed"); } // Sorting by frequency works static void TestSort() { StringPool pool; pool.Add("piyo"); pool.Add("piyopiyo"); #define CHECK_INDEX(data, expected_index) \ CHECK(pool.Find(data) != NULL, "Add(" data ") failed"); \ CHECK(pool.Find(data)->index == expected_index, "Add(" data ") failed"); CHECK_INDEX("piyo", 0); pool.Add("hoge"); pool.Add("hogepiyo"); pool.Add("hogepi"); CHECK_INDEX("hoge", 1); pool.Add("hogera"); CHECK_INDEX("hogera", 2); pool.Add("fuga"); CHECK_INDEX("fuga", 3); pool.Sort(); CHECK_INDEX("hoge", 0); CHECK_INDEX("piyo", 1); CHECK_INDEX("fuga", 2); CHECK_INDEX("hogera", 3); } // Test canonicalization static void TestCanonicalize() { StringPool pool; StringPool::Item *a = pool.Add("hogepiyo"); StringPool::Item *b = pool.Add("hoge"); StringPool::Item *c = pool.Add("hoge"); StringPool::Item *d = pool.Add("hogefuga"); StringPool::Item *e = pool.Add("hoge"); CHECK(a == b, "Add1"); CHECK(b == c, "Add2"); CHECK(c != d, "Add3"); CHECK(d == e, "Add4"); pool.Sort(); CHECK(pool.item(0).data == "hogepiyo", "Sort1"); CHECK(pool.item(1).data == "hogefuga", "Sort2"); b = pool.Canonicalize(b, 4); c = pool.Canonicalize(c, 4); e = pool.Canonicalize(e, 4); CHECK(a != b, "Canonicalize1"); CHECK(b == c, "Canonicalize2"); CHECK(c == d, "Canonicalize3"); CHECK(d == e, "Canonicalize3"); pool.Sort(); CHECK(pool.item(0).data == "hogefuga", "Sort3"); CHECK(pool.item(1).data == "hogepiyo", "Sort4"); } } // namespace int main() { TestEmpty(); TestAdd(); TestSort(); TestCanonicalize(); return 0; }