/**
 * RED-GREEN tests for the pack rule validator.
 *
 * @connexum/ai-governance  pack-rule-validator
 */
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { validatePackInput } from './pack-rule-validator.js';
import { CAPABILITY_CLASS } from './capability-classes.js';
const validInput = () => ({
    id: 'co-pack-1',
    version: '1.0.0',
    orgId: 'org-x',
    rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
    isolation: 'none',
});
describe('pack-rule-validator', () => {
    it('valid input passes with ok=true and no errors', () => {
        const r = validatePackInput(validInput());
        assert.equal(r.ok, true);
        assert.equal(r.errors.length, 0);
        assert.equal(r.warnings.length, 0);
    });
    it('missing id is an ERROR', () => {
        const r = validatePackInput({ ...validInput(), id: undefined });
        assert.equal(r.ok, false);
        assert.ok(r.errors.some((e) => e.field === 'id' && e.code === 'MISSING'));
    });
    it('invalid id format is an ERROR', () => {
        const r = validatePackInput({ ...validInput(), id: 'has spaces and !' });
        assert.equal(r.ok, false);
        assert.ok(r.errors.some((e) => e.field === 'id' && e.code === 'INVALID_FORMAT'));
    });
    it('missing version is an ERROR', () => {
        const r = validatePackInput({ ...validInput(), version: undefined });
        assert.ok(r.errors.some((e) => e.field === 'version' && e.code === 'MISSING'));
    });
    it('invalid version is an ERROR', () => {
        const r = validatePackInput({ ...validInput(), version: 'banana' });
        assert.ok(r.errors.some((e) => e.field === 'version' && e.code === 'INVALID_FORMAT'));
    });
    it('missing orgId is an ERROR', () => {
        const r = validatePackInput({ ...validInput(), orgId: '' });
        assert.ok(r.errors.some((e) => e.field === 'orgId' && e.code === 'MISSING'));
    });
    it('invalid isolation is an ERROR', () => {
        const r = validatePackInput({ ...validInput(), isolation: 'super-strict' });
        assert.ok(r.errors.some((e) => e.field === 'isolation' && e.code === 'INVALID_ISOLATION'));
    });
    it('valid isolation values pass', () => {
        for (const iso of ['none', 'sourced-only', 'strict']) {
            const r = validatePackInput({ ...validInput(), isolation: iso });
            assert.equal(r.ok, true, `isolation=${iso} should pass`);
        }
    });
    it('non-array rules is an ERROR', () => {
        const r = validatePackInput({ ...validInput(), rules: 'not an array' });
        assert.ok(r.errors.some((e) => e.field === 'rules' && e.code === 'MISSING'));
    });
    it('empty rules array is a WARN, not an ERROR', () => {
        const r = validatePackInput({ ...validInput(), rules: [] });
        assert.equal(r.ok, true);
        assert.ok(r.warnings.some((w) => w.field === 'rules' && w.code === 'EMPTY_RULE_LIST'));
    });
    it('unknown capability is an ERROR with the allowed list in the message', () => {
        const r = validatePackInput({
            ...validInput(),
            rules: [{ capability: 'capability:nonexistent', action: 'BLOCK' }],
        });
        assert.ok(r.errors.some((e) => e.code === 'UNKNOWN_CAPABILITY'));
        const err = r.errors.find((e) => e.code === 'UNKNOWN_CAPABILITY');
        assert.match(err.message, /Allowed:/);
    });
    it('unknown action is an ERROR', () => {
        const r = validatePackInput({
            ...validInput(),
            rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'EXPLODE' }],
        });
        assert.ok(r.errors.some((e) => e.code === 'UNKNOWN_ACTION'));
    });
    it('duplicate (capability, action) is an ERROR', () => {
        const r = validatePackInput({
            ...validInput(),
            rules: [
                { capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' },
                { capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' },
            ],
        });
        assert.ok(r.errors.some((e) => e.code === 'DUPLICATE_RULE'));
    });
    it('different actions on same capability are NOT duplicates (strictest-wins handles)', () => {
        const r = validatePackInput({
            ...validInput(),
            rules: [
                { capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' },
                { capability: CAPABILITY_CLASS.MCP, action: 'WARN' },
            ],
        });
        assert.equal(r.ok, true);
    });
    it('rule that is not an object is an ERROR', () => {
        const r = validatePackInput({
            ...validInput(),
            rules: ['not-an-object'],
        });
        assert.ok(r.errors.some((e) => e.field === 'rules[0]' && e.code === 'INVALID_FORMAT'));
    });
    it('all 5 valid actions pass', () => {
        for (const action of ['ALLOW', 'LOG', 'WARN', 'REQUIRE_APPROVAL', 'BLOCK']) {
            const r = validatePackInput({
                ...validInput(),
                rules: [{ capability: CAPABILITY_CLASS.MCP, action }],
            });
            assert.equal(r.ok, true, `action=${action} should pass`);
        }
    });
});
//# sourceMappingURL=pack-rule-validator.test.js.map