int scrabble_search_test(const char* filename) { long result = errors_counter(); trivial_scrabble_test(); exhaustive_scrabble_test(filename); return errors_counter() - result; }
int exhaustive_scrabble_test(const char* filename) { long result = errors_counter(); // note that dictsize*keys*3 tests are performed size_t DICTSIZE = 10000, KEYS = 10; typedef std::vector<std::string> Dictionary; extern size_t fill_dictionary(const char*, Dictionary&, size_t, size_t = 0); Dictionary dictionary; size_t longest_in_file = fill_dictionary(filename, dictionary, DICTSIZE); std::random_shuffle(dictionary.begin(), dictionary.end()); ScrabbleTst names; Dictionary::iterator dit; for (dit = dictionary.begin(); dit != dictionary.end(); dit += 4) { const std::string& name(*dit); names[name] = name.c_str(); } int skip = dictionary.size() / KEYS; for(dit = dictionary.begin() + skip; dit != dictionary.end(); dit += skip) { std::string name(*dit); std::sort(name.begin(), name.end()); for (int jokercount = 0; jokercount < 3; ++jokercount) { ScrabbleTst::search_results_list matchresults = names.create_search_results(); names.combinatorial_search(name, std::back_inserter(matchresults), jokercount); //if (matchresults.size() == 0) // std::cout << "couldn't find " << name << '\n'; BOOST_CHECK(matchresults.size() != 0); ScrabbleTst matches; ScrabbleTst matchcount; size_t prevsize = 0; for (size_t i = 0; i != matchresults.size(); ++i) { std::string mcopy(matchresults[i].key()); matchcount[mcopy] = mcopy.c_str(); if (matchcount.size() > prevsize) { BOOST_CHECK(check_scrabble_found(name, mcopy, jokercount)); ++prevsize; } else { std::cout << "scrabble found duplicate " << mcopy << "\n"; } std::sort(mcopy.begin(), mcopy.end()); matches[mcopy] = mcopy.c_str(); } // check for duplicates scrabble_findcount += matchresults.size(); scrabble_duplicates += matchresults.size() - matchcount.size(); BOOST_CHECK(matchcount.size() == matchresults.size()); BOOST_CHECK(check_scrabble_missed(names, matches, jokercount)); } } //std::cout << "scrabble duplicate matches " << scrabble_duplicates << " of " << scrabble_findcount << "\n"; return errors_counter() - result; }
int trivial_scrabble_test() { long result = errors_counter(); typedef containers::ternary_tree<std::string, const char*> Tst; Tst names; names["ABCD"] = "ABCD"; names["Abcd"] = "Abcd"; names["ABcd"] = "ABcd"; names["aBCd"] = "aBCd"; names["abc"] = "abc"; names["abcde"] = "abcde"; names["bcd"] = "bcd"; names["abCD"] = "abCD"; names["abCd"] = "abCd"; names["AbcD"] = "AbcD"; names["ABcD"] = "ABcD"; names["aBCD"] = "aBCD"; names["abCDE"] = "abCDE"; names["abCDd"] = "abCDd"; names["abCcd"] = "abCcd"; names["bcdc"] = "bcdc"; names["aab"] = "aab"; Tst::search_results_list matches = names.create_search_results(); typedef Tst::search_results_list::iterator ResultIter; int i = 0; std::string s("abcde"); names.combinatorial_search(s, std::back_inserter(matches)); BOOST_CHECK(matches.size() == 3); matches.clear(); std::random_shuffle(s.begin(), s.end()); names.combinatorial_search(s, std::back_inserter(matches)); BOOST_CHECK(matches.size() == 3); // with wildcards matches.clear(); std::random_shuffle(s.begin(), s.end()); names.combinatorial_search(s, std::back_inserter(matches), 1); BOOST_CHECK(matches.size() == 8); //for (ResultIter rit = matches.begin(); rit != matches.end(); ++rit, ++i) // std::cout << i << ": " << **rit << "\n"; matches.clear(); s.append(s); std::random_shuffle(s.begin(), s.end()); names.combinatorial_search(s, std::back_inserter(matches)); BOOST_CHECK(matches.size() == 5); //for (ResultIter rit = matches.begin(); rit != matches.end(); ++rit, ++i) // std::cout << i << ": " << **rit << "\n"; return errors_counter() - result; }
int check_empty(containers::ternary_tree<std::basic_string<CharT>, DataT>& tst) { typedef containers::ternary_tree<std::basic_string<CharT>, DataT> Tst; long result = errors_counter(); BOOST_CHECK(tst.empty()); BOOST_CHECK(tst.node_count() == 0); BOOST_CHECK(tst.item_count() == 0); Tst::iterator i2(tst.begin()); BOOST_CHECK(i2 == tst.end()); return errors_counter() - result; }
int iteration_quickcheck(Tst& tst, size_t expectcount, CharT* unexpected = 0) { long result = errors_counter(); size_t count = 0; Tst::iterator first = tst.begin(); Tst::iterator last = tst.end(); const char *last_value = 0; while(first != last) { if (first.key() != *first) std::cout << first.key() << " != " << *first << '\n'; BOOST_CHECK(first.key() == *first); last_value = first.value(); if (unexpected) BOOST_CHECK(first.key() != unexpected); ++first; count++; } BOOST_CHECK(first == tst.end()); if (count != expectcount) std::cout << count << " < " << expectcount << '\n'; BOOST_CHECK(count == expectcount); count = 0; first = --tst.end(); Tst::const_reverse_iterator rit = tst.rbegin(); BOOST_CHECK(*first == last_value); last = tst.end(); while(first != last) { if (first.key() != *first) std::cout << first.key() << " != " << *first << '\n'; if (*first != *rit) std::cout << *first << " != " << *rit << '\n'; BOOST_CHECK(first.key() == *first); BOOST_CHECK(*first == *rit); if (unexpected) BOOST_CHECK(first.key() != unexpected); --first; ++rit; count++; } BOOST_CHECK(rit == const_cast<const Tst&>(tst).rend()); if (count != expectcount) std::cout << count << " < " << expectcount << '\n'; return errors_counter() - result; }
inline void report_error( const char* msg, const char* file, int line, const_string func_name, bool is_msg = false ) { ++errors_counter(); std::cerr << file << "(" << line << "): "; if( is_msg ) std::cerr << msg; else std::cerr << "test " << msg << " failed"; if( func_name != "(unknown)" ) std::cerr << " in function: '" << func_name << "'"; std::cerr << std::endl; }
int levenshtein_search_test() { long result = errors_counter(); // Create a tree with known levenshtein count = 100 std::string b0("abcdefjklmn"); int testcount = 3; while ( testcount ) { std::random_shuffle(b0.begin(), b0.end()); int baselen = (int)b0.size(); typedef containers::ternary_tree<std::string, std::string> Tst; Tst names; int L1count = 0, L2count = 0, L3count = 0, L4count = 0; for (int i = 0; i < baselen; i++) { std::string s1(b0); mutate(s1, i); if (names.insert(std::make_pair(s1, s1)).second) L1count++; for (int j = 0; j < (int)s1.size(); j++) { if (j == i) continue; std::string s2(s1); mutate(s2, j); if (names.insert(std::make_pair(s2, s2)).second) L2count++; for (int k = 0; k < (int)s2.size(); k++) { if (abs(k - j) <= 1 || abs(k - i) <= 1) continue; std::string s3(s2); mutate(s3, k); //if (s3.size() < s2.size() && s3.size() == s1.size()) // continue; //if (names.insert(std::make_pair(s3, s3)).second) // L3count++; for (int m = 2; m < (int)s3.size() - 2; m++) { if (abs(m - j) <= 2 || abs(m - i) <= 2 || abs(m - k) <= 2) continue; std::string s4(s3); mutate(s4, m); if (m + 1 >= (int)s4.size()) continue; mutate(s4, m + 1); if (m - 1 < 0) continue; mutate(s4, m - 1); if (m + 2 >= (int)s4.size()) continue; mutate(s4, m + 2); if (m - 2 < 0) continue; mutate(s4, m - 2); if (abs((int)s4.size() - (int)b0.size()) < 2) { s4.insert(rand()%s4.size(), 1, 'Z'); s4.insert(rand()%s4.size(), 1, 'Z'); } if (names.insert(std::make_pair(s4, s4)).second) L4count++; } } } } if (names.size() != L1count + L2count + L3count + L4count) { std::cout << "levenshtein tree name collision, try again"; continue; } Tst::search_results_list results = names.create_search_results(); typedef Tst::search_results_list::iterator ResultsIter; names.levenshtein_search(b0, std::back_inserter(results), 2); if (results.size() != L1count + L2count + L3count) { Tst found; for (ResultsIter rit = results.begin(); rit != results.end(); ++rit) found[**rit] = **rit; BOOST_CHECK(found.size() == L1count + L2count); // + L3count); std::cout << "\nSearch " << b0 //<< ", L-count: " << names.levenshtein_search_count << ", found " << results.size() << " strings"; std::cout << " (" << found.size() << " in " << found.node_count() << " nodes)\n"; if (found.size() != L1count + L2count) { // + L3count) { Tst::iterator fit = found.begin(); for (Tst::iterator nit = names.begin(); nit != names.end(); ++nit) { if (fit != found.end() && *nit == *fit) { std::cout << *nit << "\n"; ++fit; } else std::cout << *nit << " ###\n"; } // std::cout << "full-frontal:\n"; // for (ResultsIter rit = results.begin(); rit != results.end(); ++rit) // std::cout << **rit << "\n"; } } testcount--; } return errors_counter() - result; }
int hamming_search_test(const char* filename) { long result = errors_counter(); typedef containers::ternary_tree<std::string, const char*> Tst; Tst names; names["ABCD"] = "ABCD"; names["Abcd"] = "Abcd"; names["ABcd"] = "ABcd"; names["aBCd"] = "aBCd"; names["abc"] = "abc"; names["abcde"] = "abcde"; names["bcd"] = "bcd"; names["abCD"] = "abCD"; names["abCd"] = "abCd"; names["AbcD"] = "AbcD"; names["ABcD"] = "ABcD"; names["aBCD"] = "aBCD"; names["abCDE"] = "abCDE"; names["abCDd"] = "abCDd"; names["abCcd"] = "abCcd"; names["bcdc"] = "bcdc"; names["aab"] = "aab"; // hamming_search(2): ABcd, AbcD, Abcd, aBCd, abCD, abCd, abc, abcde // levenshtein_search(2): hamming + abCDd, abCcd bcd, bcdc Tst::search_results_list matches = names.create_search_results(); typedef Tst::search_results_list::iterator ResultIter; //names.levenshtein_search_count = 0; names.levenshtein_search("abcd", std::back_inserter(matches), 2); //std::cout << "l-count: " << names.levenshtein_search_count << "\n"; //names.levenshtein_search_count = 0; BOOST_CHECK(matches.size() == 12); if (matches.size() != 12) { // compare with DDJ { Tptr root = 0; for (Tst::iterator it = names.begin(); it != names.end(); ++it) { insertstr = (char*)*it; root = insert2(root, insertstr); } nearsearch(root, "abcd", 2); std::cout << "DDJ nearsearch abcd:\n"; for (int i = 0; i != srchtop; i++) std::cout << srcharr[i] << "\n"; std::cout << "\n"; cleanup2(root); } int i = 0; for (ResultIter rit = matches.begin(); rit != matches.end(); ++rit, ++i) { std::cout << **rit << " = " << (*rit).key(); std::cout /*<< " = " << matches[i].key()*/ << "\n"; } } typedef std::vector<std::string> Dictionary; extern size_t fill_dictionary(const char*, Dictionary&, size_t, size_t = 0); Dictionary dictionary; size_t longest_in_file = fill_dictionary(filename, dictionary, 300); std::random_shuffle(dictionary.begin(), dictionary.end()); names.clear(); Dictionary wildnames; // Add names with mini-variations long zeroes = 0; Dictionary::iterator dit; for (dit = dictionary.begin(); dit != dictionary.end(); ++dit) { const std::string& name(*dit); std::string namecopy(*dit); names[namecopy] = name.c_str(); std::string searchstr(name); for (int i = 0; i < 5; ++i) { int where = rand() % name.size(); // make string with ? at place of changed char if (searchstr[where] == '?') continue; searchstr[where] = '?'; wildnames.push_back(searchstr); char c = (char)rand(); if (!c) zeroes++; namecopy[where] = c; names[namecopy] = name.c_str(); } } for(dit = wildnames.begin(); dit != wildnames.end(); ++dit) { const std::string& name(*dit); for (int diff = 1; diff != 3; ++diff) { Tst::search_results_list matchresults = names.create_search_results(); names.hamming_search(name, std::back_inserter(matchresults), diff); //if (matchresults.size() == 0) // std::cout << "couldn't find " << name << '\n'; //BOOST_CHECK(found == matchresults.size()); for (size_t i = 0; i != matchresults.size(); ++i) BOOST_CHECK(check_hamming_match(matchresults[i].key(), name, diff)); } } return errors_counter() - result; }
int basic_insertion_test() { long result = errors_counter(); typedef containers::ternary_tree<std::basic_string<CharT>, int> Tst; Tst tst; const char* strings[] = { "\0", "aa", "aab", "aac", "add", "aee", "bab" }; widen<CharT> w; // Construction postconditions check_empty(tst); // Standard insert() tst.insert(std::make_pair(w(strings[1]), 1)); tst.insert(std::make_pair(w(strings[5]), 5)); std::pair<std::basic_string<CharT>, int> inval(w(strings[3]), 3); std::pair<Tst::iterator, bool> vr = tst.insert(inval); BOOST_CHECK(vr.first != tst.end()); BOOST_CHECK(vr.second == true); vr = tst.insert(inval); BOOST_CHECK(vr.first != tst.end()); BOOST_CHECK(vr.second == false); BOOST_CHECK((*tst.find(w(strings[1]))) == 1); BOOST_CHECK((*tst.find(w(strings[3]))) == 3); BOOST_CHECK((*tst.find(w(strings[5]))) == 5); BOOST_CHECK(tst.item_count() == 3); BOOST_CHECK(tst.total_key_length() == 3*3-1); // In present version, no reassignment tst.insert(std::make_pair(w(strings[1]), 4)); BOOST_CHECK((*tst.find(w(strings[1]))) == 1); BOOST_CHECK(tst.item_count() == 3); BOOST_CHECK(tst.total_key_length() == 3*3-1); // reference_proxy insert() tst[w(strings[2])] = 2; tst[w(strings[6])] = 6; tst[w(strings[4])] = 4; BOOST_CHECK(tst[w(strings[2])] == 2); BOOST_CHECK(tst[w(strings[4])] == 4); BOOST_CHECK(tst[w(strings[6])] == 6); BOOST_CHECK(tst.item_count() == 6); BOOST_CHECK(tst.total_key_length() == 6*3-1); // Now do reassignment tst[w(strings[1])] = 7; BOOST_CHECK((*tst.find(w(strings[1]))) == 7); //1); tst[w(strings[1])] = 1; // iterator used to check sort order of strings Tst::const_iterator it(tst.begin()); int expect_val = 1; while (it != tst.end()) { Tst::value_type val = *it; // string == "a", "b" etc BOOST_CHECK(expect_val == 1 || it.key().size() == 3); BOOST_CHECK(it.key() == w(strings[expect_val])); // value is 1, 2 etc BOOST_CHECK(val == expect_val++); ++it; } BOOST_CHECK(expect_val == int(tst.item_count() + 1)); // Test clear() postconditions tst.clear(); check_empty(tst); return errors_counter() - result; }