Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/daemon/__tests__/app-switcher-runtime.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { test } from 'vitest';
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';

const appleDevice = {
id: 'app-switcher-runtime-ios-simulator',
name: 'iPhone',
platform: 'apple',
appleOs: 'ios',
kind: 'simulator',
target: 'mobile',
booted: true,
} as const;
const unavailable = Object.freeze({
available: false,
reason: 'unsupported-device-kind' as const,
hint: 'app-switcher is supported on Apple simulators and physical devices.',
});

test('rejects an unavailable exact-owner fact before binding', async () => {
await expectRefusesUnavailableExactOwnerFact({
command: 'app-switcher',
device: appleDevice,
unavailable,
});
});
23 changes: 4 additions & 19 deletions src/daemon/__tests__/back-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { activateCompleteRefFrame } from '../ref-frame.ts';
import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts';
import type { GenericPlatformExecutionParams } from '../request-generic-dispatch.ts';
import { resolveBoundBackRuntime } from '../back-runtime.ts';
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
import { createRequestHandler } from './test-device-runtime-gateway.ts';

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

test('rejects an unavailable exact-owner fact before binding', async () => {
const harness = runtimeHarness(unavailable);

const resolved = await resolveBoundBackRuntime({
await expectRefusesUnavailableExactOwnerFact({
command: 'back',
device: appleDevice,
inspectFacts: harness.inspectFacts,
bindDevice: harness.bindDevice,
});

expect(resolved).toEqual({
ok: false,
response: {
ok: false,
error: {
code: 'UNSUPPORTED_OPERATION',
message: 'back is not supported on this device',
hint: unavailable.hint,
},
},
unavailable,
});
expect(harness.inspectFacts).toHaveBeenCalledTimes(1);
expect(harness.bindDevice).not.toHaveBeenCalled();
});

test('request router joins back admission to execution, recording, and ref invalidation', async () => {
Expand Down
24 changes: 4 additions & 20 deletions src/daemon/__tests__/focus-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { activateCompleteRefFrame } from '../ref-frame.ts';
import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts';
import type { GenericPlatformExecutionParams } from '../request-generic-dispatch.ts';
import { readFocusPoint, resolveBoundFocusRuntime } from '../focus-runtime.ts';
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
import { createRequestHandler } from './test-device-runtime-gateway.ts';

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

test('rejects an unavailable exact-owner fact before binding', async () => {
const harness = runtimeHarness(unavailable);

const resolved = await resolveBoundFocusRuntime({
await expectRefusesUnavailableExactOwnerFact({
command: 'focus',
device: appleDevice,
positionals: ['40', '90'],
inspectFacts: harness.inspectFacts,
bindDevice: harness.bindDevice,
unavailable,
});

expect(resolved).toEqual({
ok: false,
response: {
ok: false,
error: {
code: 'UNSUPPORTED_OPERATION',
message: 'focus is not supported on this device',
hint: unavailable.hint,
},
},
});
expect(harness.inspectFacts).toHaveBeenCalledTimes(1);
expect(harness.bindDevice).not.toHaveBeenCalled();
});

test('request router joins focus admission to execution, recording, and ref invalidation', async () => {
Expand Down
18 changes: 4 additions & 14 deletions src/daemon/__tests__/home-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { activateCompleteRefFrame } from '../ref-frame.ts';
import type { BindDeviceRuntime, InspectDeviceRuntimeFacts } from '../request-runtime-binding.ts';
import type { GenericPlatformExecutionParams } from '../request-generic-dispatch.ts';
import { resolveBoundHomeRuntime } from '../home-runtime.ts';
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
import { createRequestHandler } from './test-device-runtime-gateway.ts';

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

test('rejects an unavailable exact-owner fact before binding (macOS has no springboard home)', async () => {
const harness = runtimeHarness(unavailable);

const resolved = await resolveBoundHomeRuntime({
await expectRefusesUnavailableExactOwnerFact({
command: 'home',
device: macOsDevice,
inspectFacts: harness.inspectFacts,
bindDevice: harness.bindDevice,
});

expect(resolved).toEqual({
ok: false,
response: {
ok: false,
error: { code: 'UNSUPPORTED_OPERATION', message: 'home is not supported on this device' },
},
unavailable,
});
expect(harness.bindDevice).not.toHaveBeenCalled();
});

test('request router joins home admission to execution, recording, and ref invalidation', async () => {
Expand Down
22 changes: 4 additions & 18 deletions src/daemon/__tests__/orientation-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
readRequestedOrientation,
resolveBoundOrientationRuntime,
} from '../orientation-runtime.ts';
import { expectRefusesUnavailableExactOwnerFact } from './runtime-binding-conformance.ts';
import { createRequestHandler } from './test-device-runtime-gateway.ts';
import { androidObservationFixture } from './android-observation-fixture.ts';

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

test('rejects an unavailable exact-owner fact before binding', async () => {
const harness = runtimeHarness(unavailable);

const resolved = await resolveBoundOrientationRuntime({
await expectRefusesUnavailableExactOwnerFact({
command: 'orientation',
device: testDevice,
positionals: ['landscape-left'],
inspectFacts: harness.inspectFacts,
bindDevice: harness.bindDevice,
unavailable,
});

expect(resolved).toEqual({
ok: false,
response: {
ok: false,
error: {
code: 'UNSUPPORTED_OPERATION',
message: 'orientation is not supported on this device',
},
},
});
expect(harness.bindDevice).not.toHaveBeenCalled();
});

test('request router joins orientation admission to execution and ref invalidation', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { expect, test } from 'vitest';
import {
commandDescriptors,
commandRuntimeUseRequirements,
} from '../../core/command-descriptor/registry.ts';
import {
conformedRuntimeBindings,
refusedRuntimeOperation,
refuseUnavailableExactOwnerFact,
type ConformedRuntimeCommand,
} from './runtime-binding-conformance.ts';

/**
* The command registry's `platformExecution` declarations are the production enumeration of
* daemon runtime bindings: every device-runtime descriptor names the uses its route admits, and
* `admitRuntimeOperations` is one seam with no table of its own. The generic and interaction routes
* admit through per-command `src/daemon/<command>-runtime.ts` resolvers, so every single-use
* descriptor on those routes owes the family its conformance entry; the other direction holds any
* entry to a cell its descriptor actually declares.
*/
const CONFORMED_ROUTES = new Set(['generic', 'interaction']);

function singleUseConformedRouteCommands(): string[] {
return commandDescriptors
.filter((descriptor) => {
const route = 'daemon' in descriptor ? descriptor.daemon?.route : undefined;
return route !== undefined && CONFORMED_ROUTES.has(route);
})
.map((descriptor) => descriptor.name)
.filter((command) => commandRuntimeUseRequirements(command)?.length === 1)
.sort();
}

const conformedCommands = Object.keys(conformedRuntimeBindings) as ConformedRuntimeCommand[];

test('every single-use generic or interaction route descriptor has a conformance entry', () => {
const missing = singleUseConformedRouteCommands().filter(
(command) => !conformedCommands.includes(command as ConformedRuntimeCommand),
);

expect(missing).toEqual([]);
});

test('every conformance entry refuses on a cell its registry descriptor declares', () => {
const undeclared = conformedCommands.filter((command) => {
const declared = commandRuntimeUseRequirements(command)?.flat() ?? [];
return !declared.includes(refusedRuntimeOperation(command));
});

expect(undeclared).toEqual([]);
});

const conformanceDevice = {
id: 'runtime-binding-conformance-device',
name: 'Pixel',
platform: 'android',
kind: 'emulator',
target: 'mobile',
booted: true,
} as const;

test.each(conformedCommands)(
'%s refuses its unavailable declared cell before binding',
async (command) => {
const response = await refuseUnavailableExactOwnerFact({
command,
device: conformanceDevice,
unavailable: { available: false, reason: 'owner-capability-missing' },
});

expect(response.error.code).toBe('UNSUPPORTED_OPERATION');
},
);
Loading
Loading