This commit is contained in:
NotExpectedYet committed 2026-09-26 05:35:29 +01:00
commit 0964819cdc
34 files changed
+7912

No files matched your search

+97
View File
@@ -0,0 +1,97 @@
import { strict as assert } from 'node:assert'
import { test } from 'node:test'
import { Config, SETTING_KEYS, validateSettings } from '../index.js'
/**
* The load-time contract.
*
* `apply` never runs when Cordis rejects a plugin's `Config`, so these are the
* only failures a plugin cannot report from inside itself — the profile simply
* refuses to boot. The rest of the suite calls `apply` directly and would never
* notice, which is exactly why this file exists separately.
*/
test('Config is a Standard Schema, which is what Cordis requires', () => {
assert.ok(Config !== undefined, 'Config must be exported')
assert.ok(Config['~standard'] !== undefined, 'Config must implement the Standard Schema interface')
})
test('Config fills every field from an empty input, so apply can rely on defaults', () => {
const filled = Config({})
for (const key of SETTING_KEYS) {
assert.ok(key in filled, `${key} has no default and would be undefined in apply`)
}
assert.equal(filled.embeddingApiBase, 'http://127.0.0.1:11434')
assert.equal(filled.embeddingDimensions, 768)
assert.equal(filled.syncBudgetMs, 20_000)
assert.deepEqual(filled.exclude, [])
assert.deepEqual(filled.extensions, [])
})
test('Config keeps an explicit value and fills the rest', () => {
const filled = Config({ embeddingApiBase: 'http://10.50.1.2:11434', embeddingConcurrency: 8 })
assert.equal(filled.embeddingApiBase, 'http://10.50.1.2:11434')
assert.equal(filled.embeddingConcurrency, 8)
assert.equal(filled.embeddingBatchSize, 16)
assert.equal(filled.embeddingTimeoutMs, 30_000)
assert.equal(filled.embeddingKeepAlive, '5m')
// The per-excerpt cap equals the chunk cap, so chunks arrive whole.
assert.equal(filled.excerptLines, 80)
assert.equal(filled.totalExcerptLines, 400)
assert.equal(filled.maxChunkLines, 80)
})
test('a wrongly typed value fails loudly at load rather than silently in apply', () => {
assert.throws(() => Config({ embeddingDimensions: 'seven hundred' }))
assert.throws(() => Config({ exclude: 'src/generated/' }))
assert.throws(() => Config({ embeddingApiBase: { host: 'localhost' } }))
})
test('every declared setting is a real schema key, so none is dead config', () => {
const filled = Config({})
for (const key of SETTING_KEYS) {
assert.ok(Object.hasOwn(filled, key), `${key} is listed in SETTING_KEYS but is not in the schema`)
}
// And the reverse: no schema field is missing from the documented list, or
// `configure` would reject a setting the schema happily accepts.
for (const key of Object.keys(filled)) {
assert.ok(SETTING_KEYS.includes(key), `${key} is in the schema but not in SETTING_KEYS`)
}
})
/** The defaults plus an override, as the settings provider would resolve them. */
function settingsWith(patch) {
return { ...Config({}), ...patch }
}
test('validateSettings accepts the defaults', () => {
assert.doesNotThrow(() => validateSettings(Config({})))
})
test('validateSettings rejects an endpoint that is not a URL', () => {
// A bare host:port parses successfully — `localhost:` is read as the scheme —
// so it is the protocol check that actually catches the common mistake.
assert.throws(() => validateSettings(settingsWith({ embeddingApiBase: 'localhost:11434' })), /must be http or https/)
assert.throws(() => validateSettings(settingsWith({ embeddingApiBase: '' })), /not a URL/)
assert.doesNotThrow(() => validateSettings(settingsWith({ embeddingApiBase: 'http://10.50.1.2:11434' })))
})
test('validateSettings rejects a non-http protocol', () => {
assert.throws(() => validateSettings(settingsWith({ embeddingApiBase: 'file:///tmp/socket' })), /must be http or https/)
})
test('validateSettings rejects values that would break the pipeline', () => {
assert.throws(() => validateSettings(settingsWith({ embeddingDimensions: 0 })), /positive number/)
assert.throws(() => validateSettings(settingsWith({ embeddingConcurrency: 0 })), /at least 1/)
assert.throws(() => validateSettings(settingsWith({ excerptLines: 0 })), /at least 1/)
assert.throws(() => validateSettings(settingsWith({ syncBudgetMs: -1 })), /cannot be negative/)
})
test('validateSettings rejects cross-field contradictions the schema cannot see', () => {
assert.throws(() => validateSettings(settingsWith({ defaultLimit: 50, maxLimit: 10 })), /cannot exceed maxLimit/)
assert.throws(() => validateSettings(settingsWith({ chunkLines: 100, maxChunkLines: 80 })), /below chunkLines/)
// An overlap at or above the cap means a split never advances.
assert.throws(() => validateSettings(settingsWith({ chunkLines: 10, maxChunkLines: 10, overlapLines: 10 })), /never advances/)
assert.throws(() => validateSettings(settingsWith({ minSimilarity: 1.5 })), /between 0 and 1/)
})