import { describe, it, expect } from 'vitest';
import {
PREDICATES,
evalPredicates,
getPredicateNames,
isValidPredicate,
} from '../predicate-registry.ts';
import type { PredicateContext } from '../predicate-types.ts';
import type { ResolvedRuntimeConfig } from '../../utils/config-store.ts';
function createDefaultConfig(
overrides: Partial<ResolvedRuntimeConfig> = {},
): ResolvedRuntimeConfig {
return {
debug: false,
enabledWorkflows: [],
experimentalWorkflowDiscovery: false,
disableSessionDefaults: false,
disableXcodeAutoSync: false,
uiDebuggerGuardMode: 'error',
incrementalBuildsEnabled: false,
dapRequestTimeoutMs: 30000,
dapLogEvents: false,
launchJsonWaitMs: 8000,
debuggerBackend: 'dap',
...overrides,
};
}
function createContext(overrides: Partial<PredicateContext> = {}): PredicateContext {
return {
runtime: 'mcp',
config: createDefaultConfig(),
runningUnderXcode: false,
xcodeToolsActive: false,
xcodeToolsAvailable: false,
...overrides,
};
}
describe('predicate-registry', () => {
describe('PREDICATES', () => {
describe('debugEnabled', () => {
it('should return true when debug is enabled', () => {
const ctx = createContext({
config: createDefaultConfig({ debug: true }),
});
expect(PREDICATES.debugEnabled(ctx)).toBe(true);
});
it('should return false when debug is disabled', () => {
const ctx = createContext({
config: createDefaultConfig({ debug: false }),
});
expect(PREDICATES.debugEnabled(ctx)).toBe(false);
});
});
describe('experimentalWorkflowDiscoveryEnabled', () => {
it('should return true when experimental workflow discovery is enabled', () => {
const ctx = createContext({
config: createDefaultConfig({ experimentalWorkflowDiscovery: true }),
});
expect(PREDICATES.experimentalWorkflowDiscoveryEnabled(ctx)).toBe(true);
});
it('should return false when experimental workflow discovery is disabled', () => {
const ctx = createContext({
config: createDefaultConfig({ debug: false }),
});
expect(PREDICATES.experimentalWorkflowDiscoveryEnabled(ctx)).toBe(false);
});
});
describe('runningUnderXcodeAgent', () => {
it('should return true when running under Xcode', () => {
const ctx = createContext({ runningUnderXcode: true });
expect(PREDICATES.runningUnderXcodeAgent(ctx)).toBe(true);
});
it('should return false when not running under Xcode', () => {
const ctx = createContext({ runningUnderXcode: false });
expect(PREDICATES.runningUnderXcodeAgent(ctx)).toBe(false);
});
});
describe('requiresXcodeTools', () => {
it('should return true when Xcode tools are active', () => {
const ctx = createContext({ xcodeToolsActive: true });
expect(PREDICATES.requiresXcodeTools(ctx)).toBe(true);
});
it('should return false when Xcode tools are not active', () => {
const ctx = createContext({ xcodeToolsActive: false });
expect(PREDICATES.requiresXcodeTools(ctx)).toBe(false);
});
});
describe('xcodeToolsAvailable', () => {
it('should return true when Xcode tools bridge is available', () => {
const ctx = createContext({ xcodeToolsAvailable: true });
expect(PREDICATES.xcodeToolsAvailable(ctx)).toBe(true);
});
it('should return false when Xcode tools bridge is not available', () => {
const ctx = createContext({ xcodeToolsAvailable: false });
expect(PREDICATES.xcodeToolsAvailable(ctx)).toBe(false);
});
});
describe('hideWhenXcodeAgentMode', () => {
it('should return true when not running under Xcode', () => {
const ctx = createContext({ runningUnderXcode: false });
expect(PREDICATES.hideWhenXcodeAgentMode(ctx)).toBe(true);
});
it('should return false when running under Xcode', () => {
const ctx = createContext({ runningUnderXcode: true });
expect(PREDICATES.hideWhenXcodeAgentMode(ctx)).toBe(false);
});
});
describe('xcodeAutoSyncDisabled', () => {
it('should return true when running under Xcode AND auto-sync is disabled', () => {
const ctx = createContext({
runningUnderXcode: true,
config: createDefaultConfig({ disableXcodeAutoSync: true }),
});
expect(PREDICATES.xcodeAutoSyncDisabled(ctx)).toBe(true);
});
it('should return false when running under Xcode but auto-sync is enabled', () => {
const ctx = createContext({
runningUnderXcode: true,
config: createDefaultConfig({ disableXcodeAutoSync: false }),
});
expect(PREDICATES.xcodeAutoSyncDisabled(ctx)).toBe(false);
});
it('should return false when not running under Xcode even if auto-sync is disabled', () => {
const ctx = createContext({
runningUnderXcode: false,
config: createDefaultConfig({ disableXcodeAutoSync: true }),
});
expect(PREDICATES.xcodeAutoSyncDisabled(ctx)).toBe(false);
});
it('should return false when not running under Xcode and auto-sync is enabled', () => {
const ctx = createContext({
runningUnderXcode: false,
config: createDefaultConfig({ disableXcodeAutoSync: false }),
});
expect(PREDICATES.xcodeAutoSyncDisabled(ctx)).toBe(false);
});
});
describe('always', () => {
it('should always return true', () => {
const ctx = createContext();
expect(PREDICATES.always(ctx)).toBe(true);
});
});
describe('never', () => {
it('should always return false', () => {
const ctx = createContext();
expect(PREDICATES.never(ctx)).toBe(false);
});
});
});
describe('evalPredicates', () => {
it('should return true for empty predicate list', () => {
const ctx = createContext();
expect(evalPredicates([], ctx)).toBe(true);
});
it('should return true for undefined predicate list', () => {
const ctx = createContext();
expect(evalPredicates(undefined, ctx)).toBe(true);
});
it('should return true when all predicates pass', () => {
const ctx = createContext({
config: createDefaultConfig({ debug: true, experimentalWorkflowDiscovery: true }),
});
expect(evalPredicates(['debugEnabled', 'experimentalWorkflowDiscoveryEnabled'], ctx)).toBe(
true,
);
});
it('should return false when any predicate fails', () => {
const ctx = createContext({
config: createDefaultConfig({ debug: true }),
});
expect(evalPredicates(['debugEnabled', 'experimentalWorkflowDiscoveryEnabled'], ctx)).toBe(
false,
);
});
it('should throw for unknown predicate', () => {
const ctx = createContext();
expect(() => evalPredicates(['unknownPredicate'], ctx)).toThrow(
"Unknown predicate 'unknownPredicate'",
);
});
});
describe('getPredicateNames', () => {
it('should return all predicate names', () => {
const names = getPredicateNames();
expect(names).toContain('debugEnabled');
expect(names).toContain('experimentalWorkflowDiscoveryEnabled');
expect(names).toContain('runningUnderXcodeAgent');
expect(names).toContain('requiresXcodeTools');
expect(names).toContain('xcodeToolsAvailable');
expect(names).toContain('hideWhenXcodeAgentMode');
expect(names).toContain('xcodeAutoSyncDisabled');
expect(names).toContain('always');
expect(names).toContain('never');
});
});
describe('isValidPredicate', () => {
it('should return true for valid predicates', () => {
expect(isValidPredicate('debugEnabled')).toBe(true);
expect(isValidPredicate('hideWhenXcodeAgentMode')).toBe(true);
});
it('should return false for invalid predicates', () => {
expect(isValidPredicate('unknownPredicate')).toBe(false);
expect(isValidPredicate('')).toBe(false);
});
});
});