You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/sema/event.test.ts

200 lines
6.3 KiB

/**
* Phase 2 of the codex refactor: intent policy unified through
* `SEMA_FAMILY_POLICY`. The previous valenced/transitional split
* incorrectly forbade intent on transitional families AND required it on
* every valenced family. The tests below pin the post-canon doctrine:
*
* - any family may carry intent unless its policy says otherwise
* - `SEMA_FAMILY_POLICY[family].intentPolicy === 'expected'` is the
* only branch that REQUIRES intent
* - `normalizeSemaEvent` preserves intent on transitional families
* (e.g. `emerge` carrying `'threat'`)
* - `parseSemaEventLabel` accepts every `<family>-<intent>` combination
* including transitional ones
*/
import { describe, expect, it } from 'vitest';
import {
SEMA_EVENT_LABELS,
SEMA_FAMILIES,
isSemaEvent,
isSemaEventLabel,
normalizeSemaEvent,
parseSemaEventLabel,
resolveIntent
} from './event';
import { SEMA_FAMILY_POLICY } from './types';
describe('SEMA_EVENT_LABELS', () => {
it('includes family-only forms for every family', () => {
for (const family of SEMA_FAMILIES) {
expect(SEMA_EVENT_LABELS).toContain(family);
}
});
it('includes family-intent combinations for every family + intent (incl. transitional)', () => {
expect(SEMA_EVENT_LABELS).toContain('emerge-threat');
expect(SEMA_EVENT_LABELS).toContain('shift-fulfill');
expect(SEMA_EVENT_LABELS).toContain('sustain-loss');
expect(SEMA_EVENT_LABELS).toContain('contact-neutral');
});
});
describe('isSemaEventLabel', () => {
it('accepts transitional + intent combinations', () => {
expect(isSemaEventLabel('emerge-threat')).toBe(true);
expect(isSemaEventLabel('shift-fulfill')).toBe(true);
});
it('accepts family-only forms', () => {
expect(isSemaEventLabel('emerge')).toBe(true);
expect(isSemaEventLabel('contact')).toBe(true);
});
it('rejects malformed strings', () => {
expect(isSemaEventLabel('frob')).toBe(false);
expect(isSemaEventLabel('emerge-frob')).toBe(false);
});
});
describe('isSemaEvent — policy-driven', () => {
it('requires intent on `expected` families (commit, signal)', () => {
for (const family of ['commit', 'signal'] as const) {
expect(SEMA_FAMILY_POLICY[family].intentPolicy).toBe('expected');
expect(isSemaEvent({ family })).toBe(false);
expect(isSemaEvent({ family, intent: 'fulfill' })).toBe(true);
}
});
it('allows intent absence on `allowed` families (contact, handle)', () => {
for (const family of ['contact', 'handle'] as const) {
expect(SEMA_FAMILY_POLICY[family].intentPolicy).toBe('allowed');
expect(isSemaEvent({ family })).toBe(true);
expect(isSemaEvent({ family, intent: 'risk' })).toBe(true);
}
});
it('allows intent on `optional` families (emerge, shift, sustain) — the post-canon fix', () => {
for (const family of ['emerge', 'shift', 'sustain'] as const) {
expect(SEMA_FAMILY_POLICY[family].intentPolicy).toBe('optional');
expect(isSemaEvent({ family })).toBe(true);
expect(isSemaEvent({ family, intent: 'threat' })).toBe(true);
}
});
it('accepts intent bindings (fromProp shape) on any policy', () => {
const binding = { fromProp: 'intent', default: 'neutral', supported: ['neutral', 'threat'] } as const;
expect(isSemaEvent({ family: 'commit', intent: binding })).toBe(true);
expect(isSemaEvent({ family: 'emerge', intent: binding })).toBe(true);
});
it('rejects malformed intent values', () => {
expect(isSemaEvent({ family: 'commit', intent: 'frob' })).toBe(false);
expect(isSemaEvent({ family: 'emerge', intent: 42 })).toBe(false);
});
});
describe('parseSemaEventLabel', () => {
it('splits transitional with intent into family + intent', () => {
const parsed = parseSemaEventLabel('emerge-threat');
expect(parsed).toEqual({ family: 'emerge', intent: 'threat' });
});
it('splits valenced with intent into family + intent', () => {
const parsed = parseSemaEventLabel('commit-fulfill');
expect(parsed).toEqual({ family: 'commit', intent: 'fulfill' });
});
it('parses family-only forms', () => {
const parsed = parseSemaEventLabel('emerge');
expect(parsed).toEqual({ family: 'emerge' });
expect('intent' in parsed).toBe(false);
});
});
describe('normalizeSemaEvent — preserves intent on any family', () => {
it('preserves intent on transitional families (emerge with threat)', () => {
const result = normalizeSemaEvent({ family: 'emerge', intent: 'threat' });
expect(result).toEqual({
family: 'emerge',
intent: 'threat',
label: 'emerge-threat'
});
});
it('keeps family-only label when intent is absent', () => {
const result = normalizeSemaEvent({ family: 'contact' });
expect(result).toEqual({
family: 'contact',
intent: null,
label: 'contact'
});
});
it('resolves bindings against props', () => {
const result = normalizeSemaEvent(
{
family: 'emerge',
intent: { fromProp: 'intent', default: 'neutral', supported: ['neutral', 'threat'] }
},
{ intent: 'threat' }
);
expect(result.label).toBe('emerge-threat');
expect(result.intent).toBe('threat');
});
it('falls back to binding default when prop is absent', () => {
const result = normalizeSemaEvent(
{
family: 'commit',
intent: { fromProp: 'intent', default: 'fulfill', supported: ['fulfill', 'threat'] }
},
{}
);
expect(result.label).toBe('commit-fulfill');
});
it('parses string labels symmetrically', () => {
expect(normalizeSemaEvent('emerge-threat')).toEqual({
family: 'emerge',
intent: 'threat',
label: 'emerge-threat'
});
expect(normalizeSemaEvent('emerge')).toEqual({
family: 'emerge',
intent: null,
label: 'emerge'
});
});
});
describe('resolveIntent', () => {
it('returns the literal when intent is already a string', () => {
expect(resolveIntent('threat')).toBe('threat');
});
it('reads `fromProp` value when present and supported', () => {
const intent = resolveIntent(
{ fromProp: 'intent', default: 'neutral', supported: ['neutral', 'risk', 'threat'] },
{ intent: 'risk' }
);
expect(intent).toBe('risk');
});
it('falls back to `default` when prop is missing', () => {
const intent = resolveIntent(
{ fromProp: 'intent', default: 'fulfill', supported: ['fulfill', 'threat'] },
{}
);
expect(intent).toBe('fulfill');
});
it('falls back to first supported when default is unsupported', () => {
const intent = resolveIntent(
{ default: 'loss', supported: ['neutral', 'threat'] } as never,
{}
);
expect(intent).toBe('neutral');
});
});

Powered by TurnKey Linux.