From d60c90708c73582669af17700d5775f99e3e04fe Mon Sep 17 00:00:00 2001 From: haelyra <49814733+haelyra@users.noreply.github.com> Date: Sun, 11 Oct 2026 15:05:36 -0400 Subject: [PATCH] test: exercise real Python discovery failure controls --- tests/lib/windows-test-env.test.js | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tests/lib/windows-test-env.test.js b/tests/lib/windows-test-env.test.js index 0b6975028..05d0da48f 100644 --- a/tests/lib/windows-test-env.test.js +++ b/tests/lib/windows-test-env.test.js @@ -10,11 +10,24 @@ const assert = require('assert'); const fs = require('fs'); const os = require('os'); const path = require('path'); +const vm = require('vm'); const { test, banner, summary } = require('./helpers/mini-test-runner'); const { spawnSync } = require('child_process'); const { withoutShadowingClaude, toRelativeTarPath, resolvePython } = require('./helpers/windows-test-env'); +/** Load the unchanged helper with controlled process results, keeping its real probe. */ +function loadWithSpawn(spawn) { + const filename = path.join(__dirname, 'helpers', 'windows-test-env.js'); + const module = { exports: {} }; + vm.runInNewContext(fs.readFileSync(filename, 'utf8'), { + module, + require: name => name === 'child_process' ? { spawnSync: spawn } : require(name), + process, + }, { filename }); + return module.exports; +} + banner('windows-test-env helper'); let passed = 0; @@ -76,6 +89,51 @@ try { assert.strictEqual(resolvePython({ platform: 'linux', probe: () => false }), null); })) passed++; else failed++; + if (test('real probe accepts success and preserves Windows launcher arguments', () => { + const calls = []; + const helper = loadWithSpawn((command, args, options) => { + calls.push({ command, args: Array.from(args), options: { ...options } }); + return { status: command === 'py' ? 0 : 9009 }; + }); + const python = helper.resolvePython({ platform: 'win32' }); + assert.strictEqual(python.command, 'py'); + assert.deepStrictEqual(Array.from(python.prefix), ['-3']); + assert.deepStrictEqual(calls.map(call => call.command), ['python', 'py']); + assert.deepStrictEqual(calls[1].args.slice(0, 2), ['-3', '-c']); + assert.deepStrictEqual(calls[1].options, { encoding: 'utf8', timeout: 15000 }); + })) passed++; else failed++; + + if (test('real probe rejects nonzero, missing commands and timed out processes', () => { + for (const result of [ + { status: 1 }, + { status: 9009 }, + { status: null, error: Object.assign(new Error('not found'), { code: 'ENOENT' }) }, + { status: null, error: Object.assign(new Error('timed out'), { code: 'ETIMEDOUT' }) }, + ]) { + const calls = []; + const helper = loadWithSpawn(command => { calls.push(command); return result; }); + assert.strictEqual(helper.resolvePython({ platform: 'win32' }), null); + assert.deepStrictEqual(calls, ['python', 'py', 'python3']); + } + })) passed++; else failed++; + + if (test('real probe code succeeds under known Python 3 and rejects Python 2', () => { + // Select independently so broken discovery cannot silently skip this control. + const known = [['python3'], ['python'], ['py', '-3']].find(([command, ...prefix]) => { + const result = spawnSync(command, [...prefix, '-c', 'import sys; print(sys.version_info[0])'], { encoding: 'utf8', timeout: 15000 }); + return result.status === 0 && result.stdout.trim() === '3'; + }); + assert.ok(known, 'Python 3 is required for the Hermes test workflow'); + for (const [major, expected] of [[3, true], [2, false]]) { + const helper = loadWithSpawn((_command, args, options) => { + const code = args[args.indexOf('-c') + 1]; + const wrapped = `import sys; sys.version_info = (${major}, 0);\n${code}`; + return spawnSync(known[0], [...known.slice(1), '-c', wrapped], options); + }); + assert.strictEqual(helper.resolvePython({ platform: 'win32' }) !== null, expected); + } + })) passed++; else failed++; + if (test('a resolved interpreter actually runs Python 3 here', () => { const python = resolvePython(); if (!python) return;