|
1 | 1 | import assert from 'node:assert/strict'; |
2 | 2 | import { test } from 'vitest'; |
3 | 3 | import { |
| 4 | + describeReplayGestureArityError, |
4 | 5 | gesturePayloadFromPositionals, |
5 | 6 | gesturePayloadToPositionals, |
6 | 7 | normalizePublicGesture, |
@@ -57,6 +58,62 @@ test('gesture recording codec round-trips fling with distance', () => { |
57 | 58 | assert.deepEqual(gesturePayloadFromPositionals(gesturePayloadToPositionals(payload)), payload); |
58 | 59 | }); |
59 | 60 |
|
| 61 | +test('a retired trailing positional reports its migration, not a bare usage line', () => { |
| 62 | + assert.throws(() => swipePayloadFromPositionals(['197', '650', '197', '300', '300']), { |
| 63 | + code: 'INVALID_ARGS', |
| 64 | + message: |
| 65 | + 'swipe accepts 4 arguments: x1 y1 x2 y2. The trailing durationMs positional was removed: use "gesture pan 197 650 0 -350 300" for the same timed drag, or "swipe 197 650 197 300" for a default-duration swipe.', |
| 66 | + }); |
| 67 | + assert.throws(() => gesturePayloadFromPositionals(['fling', 'down', '100', '200', '80', '500']), { |
| 68 | + code: 'INVALID_ARGS', |
| 69 | + message: /trailing durationMs positional was removed: use "gesture fling down 100 200 80"/, |
| 70 | + }); |
| 71 | + assert.throws(() => gesturePayloadFromPositionals(['swipe', 'left', '500']), { |
| 72 | + code: 'INVALID_ARGS', |
| 73 | + message: /trailing durationMs positional was removed: use "gesture swipe left"/, |
| 74 | + }); |
| 75 | + assert.throws(() => gesturePayloadFromPositionals(['rotate', '35', '100', '200', '800']), { |
| 76 | + code: 'INVALID_ARGS', |
| 77 | + message: /trailing velocity positional was removed: use "gesture rotate 35 100 200"/, |
| 78 | + }); |
| 79 | +}); |
| 80 | + |
| 81 | +test('a malformed line is a usage error rather than a migration claim', () => { |
| 82 | + assert.throws(() => swipePayloadFromPositionals(['1', '2', '3', '4', '5', '6']), { |
| 83 | + code: 'INVALID_ARGS', |
| 84 | + message: 'swipe accepts 4 arguments: x1 y1 x2 y2.', |
| 85 | + }); |
| 86 | + assert.throws(() => swipePayloadFromPositionals(['1', '2', '3', '4', '--unknown']), { |
| 87 | + code: 'INVALID_ARGS', |
| 88 | + message: 'swipe accepts 4 arguments: x1 y1 x2 y2.', |
| 89 | + }); |
| 90 | +}); |
| 91 | + |
| 92 | +test('the .ad preflight names the offending line and leaves live syntax alone', () => { |
| 93 | + assert.equal( |
| 94 | + describeReplayGestureArityError('swipe', ['197', '650', '197', '300', '300'], 'line 6'), |
| 95 | + 'swipe accepts 4 arguments: x1 y1 x2 y2 (line 6). The trailing durationMs positional was removed: use "gesture pan 197 650 0 -350 300" for the same timed drag, or "swipe 197 650 197 300" for a default-duration swipe.', |
| 96 | + ); |
| 97 | + assert.equal( |
| 98 | + describeReplayGestureArityError('gesture', ['pan', '110', '443', '48', '0', '500'], 'line 2'), |
| 99 | + undefined, |
| 100 | + ); |
| 101 | + assert.equal(describeReplayGestureArityError('click', ['120', '240'], 'line 2'), undefined); |
| 102 | +}); |
| 103 | + |
| 104 | +test('the .ad preflight defers to dispatch for values it cannot know yet', () => { |
| 105 | + // `${VAR}` tokens resolve after planning, and interpolation never splits a |
| 106 | + // token, so only the argument count is decidable at parse time. |
| 107 | + assert.equal( |
| 108 | + describeReplayGestureArityError('swipe', ['${X1}', '${Y1}', '${X2}', '${Y2}'], 'line 3'), |
| 109 | + undefined, |
| 110 | + ); |
| 111 | + assert.equal( |
| 112 | + describeReplayGestureArityError('gesture', ['${KIND}', '1', '2', '3'], 'line 4'), |
| 113 | + undefined, |
| 114 | + ); |
| 115 | +}); |
| 116 | + |
60 | 117 | test('pinch and rotate syntax rejects a partial origin', () => { |
61 | 118 | assert.throws(() => gesturePayloadFromPositionals(['pinch', '1.5', '100']), { |
62 | 119 | code: 'INVALID_ARGS', |
|
0 commit comments