import { describe, expect, it } from 'vitest'; import { buildPhysicalDriveProtocol, buildTargetActivation, buildVolumeKeySequence, buildSwipeCycle, chooseCycleDirection, computeSafeViewport, physicalCycleOffsets, roundHalfUp, } from './physical-drive.protocol'; describe('physical-drive.v1 protocol', () => { it('uses round-half-up safe viewport coordinates', () => { expect(roundHalfUp(1.5)).toBe(2); expect(computeSafeViewport({ offsetLeft: 2, offsetTop: 3, width: 390, height: 844 }, { left: 10, right: 12, top: 20, bottom: 22 })).toEqual({ safeX: 12, safeY: 23, width: 368, height: 802, }); expect(() => computeSafeViewport({ offsetLeft: 0, offsetTop: 0, width: 10, height: 10 }, { left: 5, right: 5, top: 0, bottom: 0 })).toThrow(/positive/u); }); it('generates the literal 15-step synchronized touch cycle', () => { const cycle = buildSwipeCycle('forward', { safeX: 0, safeY: 0, width: 100, height: 200 }); expect(cycle.pointer.id).toBe('driveTouch'); expect(cycle.keyboard.id).toBe('driveKeys'); expect(cycle.pointer.actions).toHaveLength(19); expect(cycle.pointer.actions[0]).toEqual({ type: 'pointerMove', duration: 0, origin: 'viewport', x: 50, y: 160 }); expect(cycle.pointer.actions[2]).toEqual({ type: 'pointerMove', duration: 40, origin: 'viewport', x: 50, y: 151 }); expect(cycle.pointer.actions[16]).toEqual({ type: 'pointerMove', duration: 40, origin: 'viewport', x: 50, y: 20 }); expect(cycle.pointer.actions.at(-1)).toEqual({ type: 'pause', duration: 400 }); expect(cycle.keyboard.actions).toEqual([{ type: 'pause', duration: 1_000 }]); }); it('switches direction only at the two-pixel boundaries', () => { expect(chooseCycleDirection('forward', 98, 100)).toBe('reverse'); expect(chooseCycleDirection('forward', 97.99, 100)).toBe('forward'); expect(chooseCycleDirection('reverse', 2, 100)).toBe('forward'); expect(chooseCycleDirection('reverse', 2.01, 100)).toBe('reverse'); }); it('builds exact stable-box activation and synchronized volume input sources', () => { const activation = buildTargetActivation( { left: 10, top: 20, right: 110, bottom: 70 }, { left: 10.5, top: 20.5, right: 110.5, bottom: 70.5 }, { safeX: 0, safeY: 0, width: 100, height: 100 }, ); expect(activation.pointer.actions).toEqual([ { type: 'pointerMove', duration: 0, origin: 'viewport', x: 55, y: 46 }, { type: 'pause', duration: 60 }, { type: 'pointerDown', button: 0 }, { type: 'pause', duration: 60 }, { type: 'pointerUp', button: 0 }, ]); expect(activation.keyboard.actions).toEqual([{ type: 'pause', duration: 120 }]); expect(() => buildTargetActivation( { left: 10, top: 20, right: 110, bottom: 70 }, { left: 11, top: 20, right: 110, bottom: 70 }, { safeX: 0, safeY: 0, width: 100, height: 100 }, )).toThrow(/stable/u); const volume = buildVolumeKeySequence(); expect(volume.keyboard.actions).toEqual([ { type: 'pause', duration: 15_900 }, { type: 'keyDown', value: '\uE004' }, { type: 'pause', duration: 20 }, { type: 'keyUp', value: '\uE004' }, { type: 'pause', duration: 80 }, { type: 'keyDown', value: '\uE012' }, { type: 'pause', duration: 40 }, { type: 'keyUp', value: '\uE012' }, ]); expect(volume.pointer.actions).toEqual([{ type: 'pause', duration: 16_040 }]); }); it('uses every specified cycle except the excluded 389/390-second cycles', () => { const offsets = physicalCycleOffsets(); expect(offsets).toContain(388); expect(offsets).not.toContain(389); expect(offsets).not.toContain(390); expect(offsets).toContain(391); expect(offsets).toContain(509); expect(offsets).not.toContain(510); }); it('preserves normative event order and terminal-Static branches', () => { const protocol = buildPhysicalDriveProtocol(); expect(protocol.version).toBe('physical-drive.v1'); expect(protocol.durationMs).toBe(600_000); expect(protocol.events.filter((event) => event.offsetMs === 390_000).map((event) => event.action)).toEqual([ 'arm-navigation-settlement-barrier', 'navigate-infrastructure', ]); expect(protocol.events.find((event) => event.offsetMs === 391_000)?.assertions).toContain('cancel-exact-pending-navigation-epoch'); expect(protocol.branches.live.find((event) => event.offsetMs === 550_000)?.action).toBe('pause-motion'); expect(protocol.branches.static.find((event) => event.offsetMs === 550_000)?.action).toBe('assert-static-without-input'); expect(protocol.events.at(-1)).toMatchObject({ offsetMs: 600_000, action: 'finish' }); }); });