Files
hermes-agent/apps/desktop/electron/source-python.test.ts
hermes-seaeye[bot] aae6c2044e fmt(js): npm run fix on merge (#123390)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-26 03:39:27 +00:00

73 lines
3.1 KiB
TypeScript

import assert from 'node:assert/strict'
import path from 'node:path'
import { test } from 'vitest'
import { createSourcePythonBackend } from './source-backend'
import { resolveSourcePython } from './source-python'
const ROOT: string = path.join(path.sep, 'checkout')
/** A checkout reporting exactly `present` (root-relative) as existing files. */
function checkout(present: string[] = [], exists: boolean = true) {
const files = new Set(present.map(entry => path.join(ROOT, entry)))
return { root: ROOT, fileExists: (candidate: string): boolean => exists && files.has(candidate) }
}
test('a checkout with no virtualenv resolves to no interpreter, never a PATH Python', (): void => {
const { root, fileExists } = checkout()
// The invariant: "this root has no runtime" must reach callers as null.
// Answering with a PATH Python runs an install's update probe and its backend
// under an interpreter nothing selected — it can import the checkout while
// lacking its selected dependencies (updater/checkout-source.ts).
assert.equal(resolveSourcePython(root, { fileExists, isWindows: false }), null)
assert.equal(resolveSourcePython(root, { fileExists, isWindows: true }), null)
})
test('a virtualenv-less checkout yields no source backend, so the ladder moves on', (): void => {
const { root, fileExists } = checkout()
const python: string | null = resolveSourcePython(root, { fileExists, isWindows: false })
assert.equal(createSourcePythonBackend(root, python, ['serve']), null)
})
test('the checkout virtualenv is preferred over the flat venv, on both layouts', (): void => {
const venv: string = path.join('venv', 'bin', 'python')
const dotVenv: string = path.join('.venv', 'bin', 'python')
const windows: string = path.join('.venv', 'Scripts', 'python.exe')
assert.equal(
resolveSourcePython(ROOT, { fileExists: checkout([venv, dotVenv]).fileExists, isWindows: false }),
path.join(ROOT, dotVenv)
)
assert.equal(
resolveSourcePython(ROOT, { fileExists: checkout([venv]).fileExists, isWindows: false }),
path.join(ROOT, venv)
)
assert.equal(
resolveSourcePython(ROOT, { fileExists: checkout([windows]).fileExists, isWindows: true }),
path.join(ROOT, windows)
)
})
test('an explicit developer interpreter wins, and is only honoured when it exists', (): void => {
const preferred: string = path.join(path.sep, 'opt', 'hermes', 'bin', 'python')
const aged: string = path.join(ROOT, 'venv', 'bin', 'python')
const { root, fileExists } = checkout(['venv/bin/python'], true)
const withPreferred = (candidate: string): boolean => candidate === preferred || fileExists(candidate)
assert.equal(
resolveSourcePython(root, { override: preferred, fileExists: withPreferred, isWindows: false }),
preferred
)
// An override naming a file that is gone does not resurrect a PATH Python;
// it falls through to the checkout, then to null.
assert.equal(resolveSourcePython(root, { override: preferred, fileExists, isWindows: false }), aged)
assert.equal(
resolveSourcePython(ROOT, { override: preferred, fileExists: checkout().fileExists, isWindows: false }),
null
)
})