50 lines
2.5 KiB
C++
50 lines
2.5 KiB
C++
// FuzzyMatcher (src/util/fuzzy.h): exactness, ordering, typos, determinism, ceilings.
|
|
#include <cstdio>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "fuzzy.h"
|
|
|
|
using detz::FuzzyMatcher;
|
|
|
|
static int failures = 0;
|
|
#define CHECK(c) do { if (!(c)) { std::printf("FAIL %s:%d %s\n", __FILE__, __LINE__, #c); ++failures; } } while (0)
|
|
|
|
static std::string top(const std::string& q, const std::vector<std::string>& c) {
|
|
long i = FuzzyMatcher::Best(q, c);
|
|
return i < 0 ? "" : c[static_cast<size_t>(i)];
|
|
}
|
|
|
|
int main() {
|
|
const std::vector<std::string> c = {"claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5", "gpt-4o", "gpt-4o-mini",
|
|
"gemini-2.5-pro", "llama3:8b", "opencode", "zen-free", "devplace-free"};
|
|
CHECK(FuzzyMatcher::Score("GPT-4O", "gpt-4o") == 1.0);
|
|
CHECK(FuzzyMatcher::Score("gpt", "gpt-4o") < 1.0);
|
|
CHECK(FuzzyMatcher::Score("", "x") == 0.0 && FuzzyMatcher::Score("x", "") == 0.0);
|
|
CHECK(FuzzyMatcher::Score("zzqq", "claude") == 0.0);
|
|
CHECK(top("opus", c) == "claude-opus-4-5");
|
|
CHECK(top("son", c) == "claude-sonnet-4-5");
|
|
CHECK(top("sonet", c) == "claude-sonnet-4-5"); // dropped letter
|
|
CHECK(top("snonet", c) == "claude-sonnet-4-5"); // transposition
|
|
CHECK(top("opuss", c) == "claude-opus-4-5"); // extra letter
|
|
CHECK(top("4omini", c) == "gpt-4o-mini");
|
|
CHECK(top("g4m", c) == "gpt-4o-mini"); // acronym of word starts
|
|
CHECK(top("OC", c) == "opencode");
|
|
CHECK(top("free", c) == "zen-free"); // shorter id wins the tie
|
|
CHECK(FuzzyMatcher::Score("pro", "gemini-2.5-pro") > FuzzyMatcher::Score("pro", "opencode")); // boundary beats scattered
|
|
CHECK(FuzzyMatcher::Subsequence("fb", "FooBar") > FuzzyMatcher::Subsequence("fb", "fxxxxbxx")); // camelCase
|
|
CHECK(FuzzyMatcher::Typo("ab", "ba") == 0.5); // one swap of two
|
|
CHECK(FuzzyMatcher::Trigram("word", "word") == 1.0);
|
|
CHECK(FuzzyMatcher::Trigram("word", "words") > 0.57 && FuzzyMatcher::Trigram("word", "words") < 0.58); // pg_trgm 4/7
|
|
// Determinism: equal candidates keep list order.
|
|
std::vector<std::string> twin = {"model-a", "model-a"};
|
|
auto r = FuzzyMatcher::Rank("model-a", twin);
|
|
CHECK(r.size() == 2 && r[0].index == 0 && r[1].index == 1);
|
|
// Floor and ceilings never crash.
|
|
CHECK(FuzzyMatcher::Best("zzqq", c, 0.3) == -1);
|
|
CHECK(FuzzyMatcher::Score(std::string(10000, 'a'), std::string(10000, 'a')) == 1.0);
|
|
CHECK(FuzzyMatcher::Score(std::string(500, 'a'), std::string(5000, 'b')) == 0.0);
|
|
std::printf(failures ? "FAILED %d\n" : "fuzzy_test OK\n", failures);
|
|
return failures ? 1 : 0;
|
|
}
|