Files
diegosouzapw--omniroute/tests/unit/model-combo-mappings.test.ts
2026-07-13 13:39:12 +08:00

136 lines
5.2 KiB
TypeScript

/**
* Unit tests for Per-Model Combo Support (#563)
* Tests glob pattern matching and priority ordering.
*/
import { test, describe } from "node:test";
import assert from "node:assert/strict";
// ──────────────────────────────────────────────────────────
// Inline glob-to-regex (same logic as modelComboMappings.ts)
// ──────────────────────────────────────────────────────────
function globToRegex(pattern) {
const escaped = pattern
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
.replace(/\*/g, ".*")
.replace(/\?/g, ".");
return new RegExp(`^${escaped}$`, "i");
}
/**
* Simulate resolveComboForModel logic in-memory.
*/
function resolveFromMappings(modelStr, mappings) {
const enabled = mappings.filter((m) => m.enabled).sort((a, b) => b.priority - a.priority);
for (const mapping of enabled) {
const regex = globToRegex(mapping.pattern);
if (regex.test(modelStr)) {
return mapping.comboName;
}
}
return null;
}
// ──────────────────────────────────────────────────────────
// Test Cases
// ──────────────────────────────────────────────────────────
describe("Model-Combo Mapping: globToRegex", () => {
test("exact match", () => {
const re = globToRegex("claude-sonnet-4");
assert.ok(re.test("claude-sonnet-4"));
assert.ok(!re.test("claude-opus-4"));
});
test("wildcard * matches any characters", () => {
const re = globToRegex("claude-*-opus*");
assert.ok(re.test("claude-sonnet-opus-4"));
assert.ok(re.test("claude-3-opus-20240229"));
assert.ok(!re.test("gpt-4o"));
});
test("wildcard ? matches single character", () => {
const re = globToRegex("gpt-4?");
assert.ok(re.test("gpt-4o"));
assert.ok(re.test("gpt-4t"));
assert.ok(!re.test("gpt-4oo"));
});
test("case-insensitive matching", () => {
const re = globToRegex("Claude-*");
assert.ok(re.test("claude-sonnet-4"));
assert.ok(re.test("CLAUDE-OPUS-4"));
});
test("escapes regex special characters", () => {
const re = globToRegex("model.v2");
assert.ok(re.test("model.v2"));
assert.ok(!re.test("modelXv2")); // . should be literal, not regex .
});
test("pattern with slash (provider/model)", () => {
const re = globToRegex("cc/claude-*");
assert.ok(re.test("cc/claude-opus-4"));
assert.ok(!re.test("gh/claude-opus-4"));
});
});
describe("Model-Combo Mapping: resolveFromMappings", () => {
const mappings = [
{ pattern: "claude-*-opus*", comboName: "frontier-combo", priority: 10, enabled: true },
{ pattern: "claude-sonnet*", comboName: "code-combo", priority: 10, enabled: true },
{ pattern: "gpt-4o*", comboName: "openai-combo", priority: 5, enabled: true },
{ pattern: "gemini-*", comboName: "google-combo", priority: 3, enabled: true },
{ pattern: "disabled-*", comboName: "disabled-combo", priority: 100, enabled: false },
{ pattern: "*", comboName: "catch-all", priority: 0, enabled: true },
];
test("matches opus pattern → frontier-combo", () => {
assert.equal(resolveFromMappings("claude-3-opus-20240229", mappings), "frontier-combo");
});
test("matches sonnet pattern → code-combo", () => {
assert.equal(resolveFromMappings("claude-sonnet-4", mappings), "code-combo");
});
test("matches gpt-4o → openai-combo", () => {
assert.equal(resolveFromMappings("gpt-4o-mini", mappings), "openai-combo");
});
test("matches gemini → google-combo", () => {
assert.equal(resolveFromMappings("gemini-2.5-flash", mappings), "google-combo");
});
test("disabled mappings are skipped", () => {
assert.notEqual(resolveFromMappings("disabled-model", mappings), "disabled-combo");
// Falls through to catch-all instead
assert.equal(resolveFromMappings("disabled-model", mappings), "catch-all");
});
test("unknown model falls to catch-all (* pattern)", () => {
assert.equal(resolveFromMappings("deepseek-chat", mappings), "catch-all");
});
test("no mappings returns null", () => {
assert.equal(resolveFromMappings("any-model", []), null);
});
test("priority ordering: higher priority wins when multiple match", () => {
const overlapping = [
{ pattern: "claude-*", comboName: "generic-claude", priority: 1, enabled: true },
{ pattern: "claude-*-opus*", comboName: "specific-opus", priority: 10, enabled: true },
];
assert.equal(resolveFromMappings("claude-3-opus-4", overlapping), "specific-opus");
});
test("priority ordering: lower priority loses even if listed first", () => {
const overlapping = [
{ pattern: "claude-*-opus*", comboName: "specific-opus", priority: 1, enabled: true },
{ pattern: "claude-*", comboName: "generic-claude", priority: 10, enabled: true },
];
// generic-claude has higher priority (10 > 1), so it wins
assert.equal(resolveFromMappings("claude-3-opus-4", overlapping), "generic-claude");
});
});