Files
proffesor-for-testing__agen…/tests/unit/adapters/ag-ui/json-patch-validation.test.ts
Profa 2253d05618 feat: flatten project structure — archive v2, promote v3 to root
Remove the nested v3/ subdirectory by moving all active source code,
tests, configs, and assets directly to the project root. Archive v2/
(dead code, 847MB) to v2-archive.tar.gz.

Key changes:
- Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/
- Move v3/tsconfig.json, v3/vitest.config.ts to root
- Merge v3/package.json into root package.json (ESM, scripts, deps, exports)
- Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/
- Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes
- Fix all init installer path resolution (3-level-up → 2-level-up)
- Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe"
- Update settings.json ADR/DDD directories to docs/implementation/
- Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks)
- Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces
- Update 15 guidance shards: v3/src/ → src/ path references
- Fix sync interfaces: remove v3/ and v2/ path references
- Fix test path calculations (process.cwd() + '..' no longer needed)
- Fix flaky perf test threshold (500ms → 1000ms for CI environments)
- Fix complexity-analyzer test to match ADR-051 keyword-based eligibility

Build passes, 17,901 tests pass, CLI and MCP bundles verified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:35:41 +00:00

201 lines
7.6 KiB
TypeScript

/**
* JSON Patch Validation and RFC 6902 Compliance Tests
* Split from json-patch.test.ts
*
* Tests for operation validation, patch validation, and RFC 6902 compliance.
*/
import { describe, it, expect } from 'vitest';
import {
validateOperation,
validatePatch,
checkCompliance,
ensureCompliance,
JsonPatchError,
} from '../../../../src/adapters/ag-ui/json-patch.js';
import type { JsonPatchOperation } from '../../../../src/adapters/ag-ui/event-types.js';
describe('Validation', () => {
describe('validateOperation', () => {
it('should validate add operation', () => {
expect(validateOperation({ op: 'add', path: '/foo', value: 1 })).toEqual({ valid: true });
});
it('should validate remove operation', () => {
expect(validateOperation({ op: 'remove', path: '/foo' })).toEqual({ valid: true });
});
it('should validate replace operation', () => {
expect(validateOperation({ op: 'replace', path: '/foo', value: 2 })).toEqual({ valid: true });
});
it('should validate move operation', () => {
expect(validateOperation({ op: 'move', from: '/a', path: '/b' })).toEqual({ valid: true });
});
it('should validate copy operation', () => {
expect(validateOperation({ op: 'copy', from: '/a', path: '/b' })).toEqual({ valid: true });
});
it('should validate test operation', () => {
expect(validateOperation({ op: 'test', path: '/foo', value: 1 })).toEqual({ valid: true });
});
it('should reject invalid operation type', () => {
const result = validateOperation({ op: 'invalid' as 'add', path: '/foo', value: 1 });
expect(result.valid).toBe(false);
expect(result.error).toContain('Invalid operation type');
});
it('should reject add without value', () => {
const result = validateOperation({ op: 'add', path: '/foo' } as JsonPatchOperation);
expect(result.valid).toBe(false);
expect(result.error).toContain('requires a \'value\' field');
});
it('should reject move without from', () => {
const result = validateOperation({ op: 'move', path: '/b' } as JsonPatchOperation);
expect(result.valid).toBe(false);
expect(result.error).toContain('requires a \'from\' path');
});
it('should reject invalid path format', () => {
const result = validateOperation({ op: 'add', path: 'invalid', value: 1 });
expect(result.valid).toBe(false);
expect(result.error).toContain('Invalid JSON Pointer');
});
it('should collect all errors', () => {
const result = validateOperation({ op: 'invalid' as 'add', path: 'bad' } as JsonPatchOperation);
expect(result.valid).toBe(false);
expect(result.errors).toBeDefined();
expect(result.errors!.length).toBeGreaterThan(1);
});
});
describe('validatePatch', () => {
it('should validate empty patch', () => {
expect(validatePatch([])).toEqual({ valid: true });
});
it('should validate valid patch', () => {
const patch: JsonPatchOperation[] = [
{ op: 'add', path: '/foo', value: 1 },
{ op: 'replace', path: '/bar', value: 2 },
];
expect(validatePatch(patch)).toEqual({ valid: true });
});
it('should reject patch with invalid operation', () => {
const patch: JsonPatchOperation[] = [
{ op: 'add', path: '/foo', value: 1 },
{ op: 'invalid' as 'add', path: '/bar', value: 2 },
];
const result = validatePatch(patch);
expect(result.valid).toBe(false);
expect(result.error).toContain('Operation 1');
});
});
});
describe('RFC 6902 Compliance', () => {
describe('checkCompliance', () => {
it('should pass compliant patch', () => {
const patch: JsonPatchOperation[] = [
{ op: 'add', path: '/foo', value: 1 },
{ op: 'remove', path: '/bar' },
{ op: 'replace', path: '/baz', value: 2 },
{ op: 'move', from: '/a', path: '/b' },
{ op: 'copy', from: '/c', path: '/d' },
{ op: 'test', path: '/e', value: 3 },
];
const result = checkCompliance(patch);
expect(result.compliant).toBe(true);
expect(result.issues).toHaveLength(0);
});
it('should detect invalid operation type', () => {
const patch = [{ op: 'invalid', path: '/foo' }] as JsonPatchOperation[];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues[0].type).toBe('invalid_op');
expect(result.issues[0].rfcSection).toBe('4');
});
it('should detect missing path', () => {
const patch = [{ op: 'add', value: 1 }] as unknown as JsonPatchOperation[];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues.some(i => i.type === 'missing_path')).toBe(true);
});
it('should detect invalid path format', () => {
const patch: JsonPatchOperation[] = [{ op: 'add', path: 'invalid', value: 1 }];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues[0].type).toBe('invalid_path');
});
it('should detect missing value for add', () => {
const patch = [{ op: 'add', path: '/foo' }] as JsonPatchOperation[];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues[0].type).toBe('missing_value');
expect(result.issues[0].rfcSection).toBe('4.1');
});
it('should detect missing value for replace', () => {
const patch = [{ op: 'replace', path: '/foo' }] as JsonPatchOperation[];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues[0].rfcSection).toBe('4.3');
});
it('should detect missing from for move', () => {
const patch = [{ op: 'move', path: '/b' }] as JsonPatchOperation[];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues[0].type).toBe('missing_from');
expect(result.issues[0].rfcSection).toBe('4.4');
});
it('should detect missing from for copy', () => {
const patch = [{ op: 'copy', path: '/b' }] as JsonPatchOperation[];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues[0].rfcSection).toBe('4.5');
});
it('should detect invalid from path', () => {
const patch: JsonPatchOperation[] = [{ op: 'move', from: 'invalid', path: '/b' }];
const result = checkCompliance(patch);
expect(result.compliant).toBe(false);
expect(result.issues[0].type).toBe('invalid_from');
});
});
describe('ensureCompliance', () => {
it('should not throw for compliant patch', () => {
const patch: JsonPatchOperation[] = [{ op: 'add', path: '/foo', value: 1 }];
expect(() => ensureCompliance(patch)).not.toThrow();
});
it('should throw JsonPatchError for non-compliant patch', () => {
const patch = [{ op: 'invalid', path: '/foo' }] as JsonPatchOperation[];
expect(() => ensureCompliance(patch)).toThrow(JsonPatchError);
});
it('should include compliance details in error', () => {
const patch = [{ op: 'add', path: 'bad' }] as JsonPatchOperation[];
try {
ensureCompliance(patch);
expect.fail('Should have thrown');
} catch (error) {
expect(error).toBeInstanceOf(JsonPatchError);
expect((error as JsonPatchError).code).toBe('COMPLIANCE_FAILED');
expect((error as JsonPatchError).details?.issues).toBeDefined();
}
});
});
});