import { describe, expect, it } from 'vitest'; import { validateCourseAgentAnchor, validateCoursePackageDescriptor, } from '../src/index.js'; const SHA = 'a'.repeat(64); describe('course package descriptor', () => { it('accepts immutable unique-course metadata without a product version', () => { const descriptor = { schemaVersion: 1, kind: 'makelore-course-package', courseId: 'course_python_basics', contentHash: SHA, archiveSha256: 'b'.repeat(64), archiveBytes: 1024, formatVersion: 1, minPlayerVersion: '0.1.0', title: 'Python 零基础入门', sceneCount: 10, capabilities: { sceneKinds: ['slide', 'interactive', 'quiz'], hasAudio: false, hasWhiteboard: false, hasAgent: true, }, createdAt: '2026-08-16T00:00:00.000Z', }; expect(validateCoursePackageDescriptor(descriptor)).toEqual({ ok: true, value: descriptor, errors: [], }); expect(descriptor).not.toHaveProperty('version'); }); it('rejects malformed hashes and zero-byte archives', () => { const result = validateCoursePackageDescriptor({ schemaVersion: 1, kind: 'makelore-course-package', courseId: 'course_1', contentHash: 'bad', archiveSha256: SHA, archiveBytes: 0, formatVersion: 1, minPlayerVersion: '0.1.0', title: 'Course', sceneCount: 1, capabilities: { sceneKinds: ['slide'], hasAudio: false, hasWhiteboard: false, hasAgent: false, }, createdAt: '2026-08-16T00:00:00.000Z', }); expect(result.ok).toBe(false); expect(result.errors).toContain('contentHash must be a SHA-256 hex string'); expect(result.errors).toContain('archiveBytes must be a positive integer'); }); }); describe('agent anchor', () => { it('binds an Agent request to an exact course and playback position', () => { expect( validateCourseAgentAnchor({ courseId: 'course_python_basics', contentHash: SHA, sceneOrder: 2, actionIndex: 1, positionMs: 3200, }).ok, ).toBe(true); }); });