Files
orca/src/main/macos-press-and-hold-default.defaults-domain.test.ts
T
mirror 34fa2cd5ca
Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
source snapshot 2026-09-02
2026-09-02 02:03:16 +08:00

174 lines
6.7 KiB
TypeScript

import { execFileSync } from 'node:child_process'
import { randomUUID } from 'node:crypto'
import { chmodSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs'
import { homedir, tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { runProcessSync } from '../shared/child-process/run-process'
import {
PRESS_AND_HOLD_KEY,
ensureMacPressAndHoldDefault,
interpretDefaultsRead,
readDomainPressAndHoldPreference,
writeDomainPressAndHoldPreference,
type PressAndHoldHost,
type PressAndHoldRecord
} from './macos-press-and-hold-default'
/**
* Runs against the real `/usr/bin/defaults` on a throwaway Orca-owned domain.
*
* The whole design rests on one claim the mocks cannot make: a domain that has never been written
* is distinguishable from one explicitly set to `false`. Electron's `systemPreferences` cannot tell
* them apart, so if `defaults` could not either, "only write when unset" would be unimplementable.
*
* Every domain used here is a throwaway UUID under Orca's own prefix, deleted along with its plist
* in `afterEach`; the real `com.stablyai.orca` domain is never read or written.
*/
// Why a real Orca-owned domain shape: the ownership guard rejects anything else, so a fake prefix
// would exercise a different branch than production.
const domains: string[] = []
/** Pinned against the real binary below, then reused by the platform-agnostic unit tests. */
const DEFAULTS_MISSING_EXIT_CODE = 1
function throwawayDomain(): string {
const domain = `com.stablyai.orca.defaults-domain-test.${randomUUID()}`
domains.push(domain)
return domain
}
function write(domain: string, value: 'true' | 'false'): void {
execFileSync('/usr/bin/defaults', ['write', domain, PRESS_AND_HOLD_KEY, '-bool', value], {
stdio: 'ignore'
})
}
function rawRead(domain: string): string {
return execFileSync('/usr/bin/defaults', ['read', domain, PRESS_AND_HOLD_KEY], {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore']
}).trim()
}
function hostFor(domain: string, record: PressAndHoldRecord | null = null): PressAndHoldHost {
return {
platform: 'darwin',
resolveBundleIdentifier: () => domain,
readRecord: () => record,
writeRecord: () => undefined,
readDomainPreference: readDomainPressAndHoldPreference,
writeDomainPreference: writeDomainPressAndHoldPreference,
now: () => new Date().toISOString()
}
}
describe.skipIf(process.platform !== 'darwin')(
'press-and-hold against the real defaults binary',
() => {
afterEach(() => {
for (const domain of domains.splice(0)) {
try {
execFileSync('/usr/bin/defaults', ['delete', domain], { stdio: 'ignore' })
} catch {
// The domain may never have been created; nothing to clean up.
}
// Why the file too: `defaults delete` empties the domain but leaves its plist behind, so
// without this every run litters the developer's ~/Library/Preferences.
rmSync(join(homedir(), 'Library', 'Preferences', `${domain}.plist`), { force: true })
}
})
it('tells an unset key apart from an explicit false', () => {
const unset = throwawayDomain()
const explicitlyFalse = throwawayDomain()
write(explicitlyFalse, 'false')
expect(readDomainPressAndHoldPreference(unset)).toBe('unset')
expect(readDomainPressAndHoldPreference(explicitlyFalse)).toBe('set')
expect(rawRead(explicitlyFalse)).toBe('0')
})
it('reports an explicit true as set', () => {
const domain = throwawayDomain()
write(domain, 'true')
expect(readDomainPressAndHoldPreference(domain)).toBe('set')
expect(rawRead(domain)).toBe('1')
})
it('writes false into a previously unset domain', () => {
const domain = throwawayDomain()
expect(ensureMacPressAndHoldDefault(hostFor(domain))).toBe('applied')
expect(rawRead(domain)).toBe('0')
})
it('leaves an explicit value untouched, in either direction', () => {
for (const value of ['true', 'false'] as const) {
const domain = throwawayDomain()
write(domain, value)
expect(ensureMacPressAndHoldDefault(hostFor(domain))).toBe('kept-user-preference')
expect(rawRead(domain)).toBe(value === 'true' ? '1' : '0')
}
})
it('refuses to call a failed probe "unset"', () => {
// Real runs, not hand-built results: a binary that is not there must come back 'unknown'
// through the same path production takes, not be mistaken for "the key does not exist".
const spawnFailure = (): ReturnType<typeof runProcessSync> =>
runProcessSync({
program: '/usr/bin/defaults-does-not-exist',
args: ['read'],
stdio: ['ignore', 'ignore', 'ignore']
})
expect(spawnFailure).toThrow()
expect(interpretDefaultsRead(spawnFailure)).toBe('unknown')
const missingKey = runProcessSync({
program: '/usr/bin/defaults',
args: ['read', throwawayDomain(), PRESS_AND_HOLD_KEY],
stdio: ['ignore', 'ignore', 'ignore']
})
// The one exit code the whole design reads as unset; every other outcome is 'unknown'.
expect(missingKey.code).toBe(DEFAULTS_MISSING_EXIT_CODE)
expect(missingKey.timedOut).toBe(false)
expect(interpretDefaultsRead(() => missingKey)).toBe('unset')
})
// Skipped as root, where the read-only directory below would still be writable.
it.skipIf(process.getuid?.() === 0)('reports a write the binary refused', () => {
// Why a real refusal: `defaults write` exits non-zero instead of throwing, so a caller that
// only caught exceptions would record 'applied' for a value that never reached the plist.
const readOnly = join(mkdtempSync(join(tmpdir(), 'orca-press-hold-ro-')), 'locked')
mkdirSync(readOnly)
chmodSync(readOnly, 0o500)
try {
expect(writeDomainPressAndHoldPreference(join(readOnly, 'domain'), false)).toBe(false)
} finally {
chmodSync(readOnly, 0o700)
rmSync(readOnly, { recursive: true, force: true })
}
})
it('sees the key disappear again after the user deletes it', () => {
const domain = throwawayDomain()
write(domain, 'false')
execFileSync('/usr/bin/defaults', ['delete', domain, PRESS_AND_HOLD_KEY], { stdio: 'ignore' })
expect(readDomainPressAndHoldPreference(domain)).toBe('unset')
// A launch that already decided must not rewrite it, which is what makes the delete stick.
const decided: PressAndHoldRecord = {
version: 1,
decision: 'applied',
domain,
decidedAt: '2026-01-01T00:00:00.000Z'
}
expect(ensureMacPressAndHoldDefault(hostFor(domain, decided))).toBe('already-decided')
expect(readDomainPressAndHoldPreference(domain)).toBe('unset')
})
}
)