mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-01 06:22:44 -08:00
refactor: split startup lifecycle and Anki service architecture
This commit is contained in:
@@ -69,7 +69,198 @@ test("parses invisible overlay config and new global shortcuts", () => {
|
||||
|
||||
test("runtime options registry is centralized", () => {
|
||||
const ids = RUNTIME_OPTION_REGISTRY.map((entry) => entry.id);
|
||||
assert.deepEqual(ids, ["anki.autoUpdateNewCards", "anki.kikuFieldGrouping"]);
|
||||
assert.deepEqual(ids, [
|
||||
"anki.autoUpdateNewCards",
|
||||
"anki.nPlusOneMatchMode",
|
||||
"anki.kikuFieldGrouping",
|
||||
]);
|
||||
});
|
||||
|
||||
test("validates ankiConnect n+1 behavior values", () => {
|
||||
const dir = makeTempDir();
|
||||
fs.writeFileSync(
|
||||
path.join(dir, "config.jsonc"),
|
||||
`{
|
||||
"ankiConnect": {
|
||||
"nPlusOne": {
|
||||
"highlightEnabled": "yes",
|
||||
"refreshMinutes": -5
|
||||
}
|
||||
}
|
||||
}`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const service = new ConfigService(dir);
|
||||
const config = service.getConfig();
|
||||
const warnings = service.getWarnings();
|
||||
|
||||
assert.equal(
|
||||
config.ankiConnect.nPlusOne.highlightEnabled,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.highlightEnabled,
|
||||
);
|
||||
assert.equal(
|
||||
config.ankiConnect.nPlusOne.refreshMinutes,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.refreshMinutes,
|
||||
);
|
||||
assert.ok(
|
||||
warnings.some(
|
||||
(warning) => warning.path === "ankiConnect.nPlusOne.highlightEnabled",
|
||||
),
|
||||
);
|
||||
assert.ok(
|
||||
warnings.some(
|
||||
(warning) => warning.path === "ankiConnect.nPlusOne.refreshMinutes",
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts valid ankiConnect n+1 behavior values", () => {
|
||||
const dir = makeTempDir();
|
||||
fs.writeFileSync(
|
||||
path.join(dir, "config.jsonc"),
|
||||
`{
|
||||
"ankiConnect": {
|
||||
"nPlusOne": {
|
||||
"highlightEnabled": true,
|
||||
"refreshMinutes": 120
|
||||
}
|
||||
}
|
||||
}`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const service = new ConfigService(dir);
|
||||
const config = service.getConfig();
|
||||
|
||||
assert.equal(config.ankiConnect.nPlusOne.highlightEnabled, true);
|
||||
assert.equal(config.ankiConnect.nPlusOne.refreshMinutes, 120);
|
||||
});
|
||||
|
||||
test("validates ankiConnect n+1 match mode values", () => {
|
||||
const dir = makeTempDir();
|
||||
fs.writeFileSync(
|
||||
path.join(dir, "config.jsonc"),
|
||||
`{
|
||||
"ankiConnect": {
|
||||
"nPlusOne": {
|
||||
"matchMode": "bad-mode"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const service = new ConfigService(dir);
|
||||
const config = service.getConfig();
|
||||
const warnings = service.getWarnings();
|
||||
|
||||
assert.equal(
|
||||
config.ankiConnect.nPlusOne.matchMode,
|
||||
DEFAULT_CONFIG.ankiConnect.nPlusOne.matchMode,
|
||||
);
|
||||
assert.ok(
|
||||
warnings.some((warning) =>
|
||||
warning.path === "ankiConnect.nPlusOne.matchMode",
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts valid ankiConnect n+1 match mode values", () => {
|
||||
const dir = makeTempDir();
|
||||
fs.writeFileSync(
|
||||
path.join(dir, "config.jsonc"),
|
||||
`{
|
||||
"ankiConnect": {
|
||||
"nPlusOne": {
|
||||
"matchMode": "surface"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const service = new ConfigService(dir);
|
||||
const config = service.getConfig();
|
||||
|
||||
assert.equal(config.ankiConnect.nPlusOne.matchMode, "surface");
|
||||
});
|
||||
|
||||
test("supports legacy ankiConnect.behavior N+1 settings as fallback", () => {
|
||||
const dir = makeTempDir();
|
||||
fs.writeFileSync(
|
||||
path.join(dir, "config.jsonc"),
|
||||
`{
|
||||
"ankiConnect": {
|
||||
"behavior": {
|
||||
"nPlusOneHighlightEnabled": true,
|
||||
"nPlusOneRefreshMinutes": 90,
|
||||
"nPlusOneMatchMode": "surface"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const service = new ConfigService(dir);
|
||||
const config = service.getConfig();
|
||||
const warnings = service.getWarnings();
|
||||
|
||||
assert.equal(config.ankiConnect.nPlusOne.highlightEnabled, true);
|
||||
assert.equal(config.ankiConnect.nPlusOne.refreshMinutes, 90);
|
||||
assert.equal(config.ankiConnect.nPlusOne.matchMode, "surface");
|
||||
assert.ok(
|
||||
warnings.some(
|
||||
(warning) =>
|
||||
warning.path === "ankiConnect.behavior.nPlusOneHighlightEnabled" ||
|
||||
warning.path === "ankiConnect.behavior.nPlusOneRefreshMinutes" ||
|
||||
warning.path === "ankiConnect.behavior.nPlusOneMatchMode",
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts valid ankiConnect n+1 deck list", () => {
|
||||
const dir = makeTempDir();
|
||||
fs.writeFileSync(
|
||||
path.join(dir, "config.jsonc"),
|
||||
`{
|
||||
"ankiConnect": {
|
||||
"nPlusOne": {
|
||||
"decks": ["Deck One", "Deck Two"]
|
||||
}
|
||||
}
|
||||
}`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const service = new ConfigService(dir);
|
||||
const config = service.getConfig();
|
||||
|
||||
assert.deepEqual(config.ankiConnect.nPlusOne.decks, ["Deck One", "Deck Two"]);
|
||||
});
|
||||
|
||||
test("falls back to default when ankiConnect n+1 deck list is invalid", () => {
|
||||
const dir = makeTempDir();
|
||||
fs.writeFileSync(
|
||||
path.join(dir, "config.jsonc"),
|
||||
`{
|
||||
"ankiConnect": {
|
||||
"nPlusOne": {
|
||||
"decks": "not-an-array"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const service = new ConfigService(dir);
|
||||
const config = service.getConfig();
|
||||
const warnings = service.getWarnings();
|
||||
|
||||
assert.deepEqual(config.ankiConnect.nPlusOne.decks, []);
|
||||
assert.ok(
|
||||
warnings.some((warning) => warning.path === "ankiConnect.nPlusOne.decks"),
|
||||
);
|
||||
});
|
||||
|
||||
test("template generator includes known keys", () => {
|
||||
|
||||
Reference in New Issue
Block a user