Skip to content

Commit 4cca76f

Browse files
committed
test(daemon): one typed conformance helper for the daemon runtime suites
Extracts the shared exact-owner-unavailable admission mechanics repeated across back/home/app-switcher/focus/viewport/orientation/tv-remote/type/diff runtime test suites into runtime-binding-conformance.ts. Each suite keeps its own expected table (device, unavailable fact, and any owner-specific refusal wording); a new cross-module completeness test checks the shared table against the command registry's runtime-use declarations in both directions, including the newly-registered swipe command.
1 parent fd221b1 commit 4cca76f

11 files changed

Lines changed: 381 additions & 219 deletions
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { test } from 'vitest';
2+
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
3+
4+
const appleDevice = {
5+
id: 'app-switcher-runtime-ios-simulator',
6+
name: 'iPhone',
7+
platform: 'apple',
8+
appleOs: 'ios',
9+
kind: 'simulator',
10+
target: 'mobile',
11+
booted: true,
12+
} as const;
13+
const unavailable = Object.freeze({
14+
available: false,
15+
reason: 'unsupported-device-kind' as const,
16+
hint: 'app-switcher is supported on Apple simulators and physical devices.',
17+
});
18+
19+
test('rejects an unavailable exact-owner fact before binding', async () => {
20+
await expectRefusesUnavailableExactOwnerFact({
21+
command: 'app-switcher',
22+
device: appleDevice,
23+
unavailable,
24+
});
25+
});

src/daemon/__tests__/back-runtime.test.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { activateCompleteRefFrame } from '../ref-frame.ts';
2121
import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts';
2222
import type { GenericPlatformExecutionParams } from '../request-generic-dispatch.ts';
2323
import { resolveBoundBackRuntime } from '../back-runtime.ts';
24+
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
2425
import { createRequestHandler } from './test-device-runtime-gateway.ts';
2526

2627
// File-scoped id, not the widely shared 'ios-simulator' literal: this owner binding's
@@ -125,27 +126,11 @@ test('forwards the requested back mode from the resolved dispatch context', asyn
125126
});
126127

127128
test('rejects an unavailable exact-owner fact before binding', async () => {
128-
const harness = runtimeHarness(unavailable);
129-
130-
const resolved = await resolveBoundBackRuntime({
129+
await expectRefusesUnavailableExactOwnerFact({
130+
command: 'back',
131131
device: appleDevice,
132-
inspectFacts: harness.inspectFacts,
133-
bindDevice: harness.bindDevice,
134-
});
135-
136-
expect(resolved).toEqual({
137-
ok: false,
138-
response: {
139-
ok: false,
140-
error: {
141-
code: 'UNSUPPORTED_OPERATION',
142-
message: 'back is not supported on this device',
143-
hint: unavailable.hint,
144-
},
145-
},
132+
unavailable,
146133
});
147-
expect(harness.inspectFacts).toHaveBeenCalledTimes(1);
148-
expect(harness.bindDevice).not.toHaveBeenCalled();
149134
});
150135

151136
test('request router joins back admission to execution, recording, and ref invalidation', async () => {

src/daemon/__tests__/focus-runtime.test.ts

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { activateCompleteRefFrame } from '../ref-frame.ts';
2121
import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts';
2222
import type { GenericPlatformExecutionParams } from '../request-generic-dispatch.ts';
2323
import { readFocusPoint, resolveBoundFocusRuntime } from '../focus-runtime.ts';
24+
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
2425
import { createRequestHandler } from './test-device-runtime-gateway.ts';
2526

2627
const appleDevice = {
@@ -176,28 +177,11 @@ test('parses coordinates exactly as the retired leaf did', () => {
176177
});
177178

178179
test('rejects an unavailable exact-owner fact before binding', async () => {
179-
const harness = runtimeHarness(unavailable);
180-
181-
const resolved = await resolveBoundFocusRuntime({
180+
await expectRefusesUnavailableExactOwnerFact({
181+
command: 'focus',
182182
device: appleDevice,
183-
positionals: ['40', '90'],
184-
inspectFacts: harness.inspectFacts,
185-
bindDevice: harness.bindDevice,
183+
unavailable,
186184
});
187-
188-
expect(resolved).toEqual({
189-
ok: false,
190-
response: {
191-
ok: false,
192-
error: {
193-
code: 'UNSUPPORTED_OPERATION',
194-
message: 'focus is not supported on this device',
195-
hint: unavailable.hint,
196-
},
197-
},
198-
});
199-
expect(harness.inspectFacts).toHaveBeenCalledTimes(1);
200-
expect(harness.bindDevice).not.toHaveBeenCalled();
201185
});
202186

203187
test('request router joins focus admission to execution, recording, and ref invalidation', async () => {

src/daemon/__tests__/home-runtime.test.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { activateCompleteRefFrame } from '../ref-frame.ts';
2121
import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts';
2222
import type { GenericPlatformExecutionParams } from '../request-generic-dispatch.ts';
2323
import { resolveBoundHomeRuntime } from '../home-runtime.ts';
24+
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
2425
import { createRequestHandler } from './test-device-runtime-gateway.ts';
2526

2627
const macOsDevice = {
@@ -101,22 +102,11 @@ test('resolves one admitted binding and drives one home navigation', async () =>
101102
});
102103

103104
test('rejects an unavailable exact-owner fact before binding (macOS has no springboard home)', async () => {
104-
const harness = runtimeHarness(unavailable);
105-
106-
const resolved = await resolveBoundHomeRuntime({
105+
await expectRefusesUnavailableExactOwnerFact({
106+
command: 'home',
107107
device: macOsDevice,
108-
inspectFacts: harness.inspectFacts,
109-
bindDevice: harness.bindDevice,
110-
});
111-
112-
expect(resolved).toEqual({
113-
ok: false,
114-
response: {
115-
ok: false,
116-
error: { code: 'UNSUPPORTED_OPERATION', message: 'home is not supported on this device' },
117-
},
108+
unavailable,
118109
});
119-
expect(harness.bindDevice).not.toHaveBeenCalled();
120110
});
121111

122112
test('request router joins home admission to execution, recording, and ref invalidation', async () => {

src/daemon/__tests__/orientation-runtime.test.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
readRequestedOrientation,
4747
resolveBoundOrientationRuntime,
4848
} from '../orientation-runtime.ts';
49+
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
4950
import { createRequestHandler } from './test-device-runtime-gateway.ts';
5051
import { androidObservationFixture } from './android-observation-fixture.ts';
5152

@@ -175,26 +176,11 @@ test('rejects an invalid rotation before inspection or binding', async () => {
175176
});
176177

177178
test('rejects an unavailable exact-owner fact before binding', async () => {
178-
const harness = runtimeHarness(unavailable);
179-
180-
const resolved = await resolveBoundOrientationRuntime({
179+
await expectRefusesUnavailableExactOwnerFact({
180+
command: 'orientation',
181181
device: testDevice,
182-
positionals: ['landscape-left'],
183-
inspectFacts: harness.inspectFacts,
184-
bindDevice: harness.bindDevice,
182+
unavailable,
185183
});
186-
187-
expect(resolved).toEqual({
188-
ok: false,
189-
response: {
190-
ok: false,
191-
error: {
192-
code: 'UNSUPPORTED_OPERATION',
193-
message: 'orientation is not supported on this device',
194-
},
195-
},
196-
});
197-
expect(harness.bindDevice).not.toHaveBeenCalled();
198184
});
199185

200186
test('request router joins orientation admission to execution and ref invalidation', async () => {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { expect, test } from 'vitest';
2+
import {
3+
commandDescriptors,
4+
commandRuntimeUseRequirements,
5+
} from '../../core/command-descriptor/registry.ts';
6+
import {
7+
conformedRuntimeBindings,
8+
refusedRuntimeOperation,
9+
refuseUnavailableExactOwnerFact,
10+
type ConformedRuntimeCommand,
11+
} from './runtime-binding-conformance.ts';
12+
13+
/**
14+
* The command registry's `platformExecution` declarations are the production enumeration of
15+
* daemon runtime bindings: every device-runtime descriptor names the uses its route admits, and
16+
* `admitRuntimeOperations` is one seam with no table of its own. The generic and interaction routes
17+
* admit through per-command `src/daemon/<command>-runtime.ts` resolvers, so every single-use
18+
* descriptor on those routes owes the family its conformance entry; the other direction holds any
19+
* entry to a cell its descriptor actually declares.
20+
*/
21+
const CONFORMED_ROUTES = new Set(['generic', 'interaction']);
22+
23+
function singleUseConformedRouteCommands(): string[] {
24+
return commandDescriptors
25+
.filter((descriptor) => {
26+
const route = 'daemon' in descriptor ? descriptor.daemon?.route : undefined;
27+
return route !== undefined && CONFORMED_ROUTES.has(route);
28+
})
29+
.map((descriptor) => descriptor.name)
30+
.filter((command) => commandRuntimeUseRequirements(command)?.length === 1)
31+
.sort();
32+
}
33+
34+
const conformedCommands = Object.keys(conformedRuntimeBindings) as ConformedRuntimeCommand[];
35+
36+
test('every single-use generic or interaction route descriptor has a conformance entry', () => {
37+
const missing = singleUseConformedRouteCommands().filter(
38+
(command) => !conformedCommands.includes(command as ConformedRuntimeCommand),
39+
);
40+
41+
expect(missing).toEqual([]);
42+
});
43+
44+
test('every conformance entry refuses on a cell its registry descriptor declares', () => {
45+
const undeclared = conformedCommands.filter((command) => {
46+
const declared = commandRuntimeUseRequirements(command)?.flat() ?? [];
47+
return !declared.includes(refusedRuntimeOperation(command));
48+
});
49+
50+
expect(undeclared).toEqual([]);
51+
});
52+
53+
const conformanceDevice = {
54+
id: 'runtime-binding-conformance-device',
55+
name: 'Pixel',
56+
platform: 'android',
57+
kind: 'emulator',
58+
target: 'mobile',
59+
booted: true,
60+
} as const;
61+
62+
test.each(conformedCommands)(
63+
'%s refuses its unavailable declared cell before binding',
64+
async (command) => {
65+
const response = await refuseUnavailableExactOwnerFact({
66+
command,
67+
device: conformanceDevice,
68+
unavailable: { available: false, reason: 'owner-capability-missing' },
69+
});
70+
71+
expect(response.error.code).toBe('UNSUPPORTED_OPERATION');
72+
},
73+
);

0 commit comments

Comments
 (0)