mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-20 17:01:24 -07:00
test: cut low-value tests, rewrite the rest around behavior, parallelize lanes (#285)
This commit is contained in:
1 parent
4b6842d034
commit
b48083ddd8
368 files changed
+18045
-60331
No files matched your search
+889
-1373
File diff suppressed because it is too large.
Load diff
@@ -1,26 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import test from 'node:test';
|
||||
|
||||
const source = readFileSync('scripts/compare-yomitan-api.ts', 'utf8');
|
||||
|
||||
test('creates the configured Yomitan user-data directory before Electron uses it', () => {
|
||||
const setPathIndex = source.indexOf(
|
||||
"electronModule.app.setPath('userData', options.yomitanUserDataPath)",
|
||||
);
|
||||
assert.notEqual(setPathIndex, -1);
|
||||
|
||||
const mkdirIndex = source.lastIndexOf(
|
||||
'fs.mkdirSync(options.yomitanUserDataPath, { recursive: true })',
|
||||
setPathIndex,
|
||||
);
|
||||
assert.ok(mkdirIndex > -1, 'must create the user-data directory');
|
||||
assert.ok(mkdirIndex < setPathIndex, 'must create the directory before app.setPath');
|
||||
});
|
||||
|
||||
test('lets output drain by using exitCode in the top-level completion handlers', () => {
|
||||
const completionHandlers = source.slice(source.lastIndexOf('\nmain()'));
|
||||
assert.match(completionHandlers, /process\.exitCode = process\.exitCode \?\? 0/);
|
||||
assert.match(completionHandlers, /process\.exitCode = 1/);
|
||||
assert.doesNotMatch(completionHandlers, /process\.exit\(/);
|
||||
});
|
||||
@@ -21,6 +21,7 @@ const requiredDocs = [
|
||||
'docs/workflow/README.md',
|
||||
'docs/workflow/agent-skills.md',
|
||||
'docs/workflow/planning.md',
|
||||
'docs/workflow/testing.md',
|
||||
'docs/workflow/verification.md',
|
||||
] as const;
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import test from 'node:test';
|
||||
|
||||
const source = readFileSync('scripts/get-mpv-window-macos.swift', 'utf8');
|
||||
|
||||
test('minimized Accessibility windows are validated by PID and socket before reporting minimized', () => {
|
||||
const minimizedAssignmentIndex = source.indexOf('foundMinimizedTargetWindow = true');
|
||||
assert.notEqual(minimizedAssignmentIndex, -1);
|
||||
|
||||
const loopStartIndex = source.lastIndexOf('for window in windows', minimizedAssignmentIndex);
|
||||
assert.notEqual(loopStartIndex, -1);
|
||||
|
||||
const pidExtractionIndex = source.indexOf(
|
||||
'AXUIElementGetPid(window, &windowPid)',
|
||||
loopStartIndex,
|
||||
);
|
||||
const appPidMatchIndex = source.indexOf('windowPid != app.processIdentifier', loopStartIndex);
|
||||
const socketCheckIndex = source.indexOf('if !windowHasTargetSocket(windowPid)', loopStartIndex);
|
||||
|
||||
assert.ok(
|
||||
pidExtractionIndex > loopStartIndex && pidExtractionIndex < minimizedAssignmentIndex,
|
||||
'window PID must be extracted before accepting a minimized window',
|
||||
);
|
||||
assert.ok(
|
||||
appPidMatchIndex > pidExtractionIndex && appPidMatchIndex < minimizedAssignmentIndex,
|
||||
'window PID must match the owning app before accepting a minimized window',
|
||||
);
|
||||
assert.ok(
|
||||
socketCheckIndex > appPidMatchIndex && socketCheckIndex < minimizedAssignmentIndex,
|
||||
'target socket must be validated before accepting a minimized window',
|
||||
);
|
||||
});
|
||||
|
||||
test('focused mpv window follows the frontmost mpv app signal', () => {
|
||||
const focusHelperIndex = source.indexOf('private func isFocusedMpvWindow');
|
||||
assert.notEqual(focusHelperIndex, -1);
|
||||
|
||||
const nextFunctionIndex = source.indexOf('\nprivate func ', focusHelperIndex + 1);
|
||||
const focusHelperBody = source.slice(focusHelperIndex, nextFunctionIndex);
|
||||
|
||||
assert.ok(
|
||||
focusHelperBody.includes('frontmost.pid == ownerPid'),
|
||||
'matching frontmost PID should mark the mpv window focused',
|
||||
);
|
||||
assert.ok(
|
||||
focusHelperBody.includes('frontmost.isMpv && windowHasTargetSocket(ownerPid)'),
|
||||
'frontmost mpv app should mark the target mpv window focused even when PIDs differ',
|
||||
);
|
||||
assert.ok(
|
||||
source.includes('focused: isFocusedMpvWindow(ownerPid: windowPid, frontmost: frontmost)'),
|
||||
'Accessibility path should use the shared focused mpv helper',
|
||||
);
|
||||
assert.ok(
|
||||
source.includes('focused: isFocusedMpvWindow(ownerPid: ownerPid, frontmost: frontmost)'),
|
||||
'CoreGraphics path should use the shared focused mpv helper',
|
||||
);
|
||||
});
|
||||
|
||||
test('frontmost mpv app emits active state when geometry lookup misses', () => {
|
||||
assert.ok(
|
||||
/case\s+\.active:/.test(source),
|
||||
'helper should expose an active state without window geometry',
|
||||
);
|
||||
assert.ok(
|
||||
source.includes('if windowHasTargetSocket(frontmost.pid)'),
|
||||
'active state should still accept a matching target socket when available',
|
||||
);
|
||||
assert.ok(
|
||||
source.includes('return targetMpvSocketPath != nil'),
|
||||
'active state should preserve frontmost mpv even if command-line socket detection fails',
|
||||
);
|
||||
assert.ok(
|
||||
source.includes('return .active'),
|
||||
'lookup should preserve active mpv state after geometry lookup misses',
|
||||
);
|
||||
assert.ok(source.includes('print("active")'), 'active state should be printed for the tracker');
|
||||
});
|
||||
|
||||
test('frontmost non-mpv app emits inactive state when geometry lookup misses', () => {
|
||||
assert.ok(
|
||||
/case\s+\.inactive:/.test(source),
|
||||
'helper should expose an inactive state without window geometry',
|
||||
);
|
||||
assert.ok(
|
||||
source.includes('if frontmost != nil'),
|
||||
'helper should distinguish a known non-mpv frontmost app from an unknown miss',
|
||||
);
|
||||
assert.ok(source.includes('return .inactive'), 'known non-mpv focus should return inactive');
|
||||
assert.ok(
|
||||
source.includes('print("inactive")'),
|
||||
'inactive state should be printed for the tracker',
|
||||
);
|
||||
});
|
||||
@@ -1,45 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
|
||||
function createWorkspace(name: string): string {
|
||||
const baseDir = path.join(process.cwd(), '.tmp', 'get-frequency-typecheck-test');
|
||||
fs.mkdirSync(baseDir, { recursive: true });
|
||||
return fs.mkdtempSync(path.join(baseDir, `${name}-`));
|
||||
}
|
||||
|
||||
test('scripts/get_frequency.ts typechecks in isolation', () => {
|
||||
const workspace = createWorkspace('isolated-script');
|
||||
const tsconfigPath = path.join(workspace, 'tsconfig.json');
|
||||
|
||||
fs.writeFileSync(
|
||||
tsconfigPath,
|
||||
JSON.stringify(
|
||||
{
|
||||
extends: '../../../tsconfig.typecheck.json',
|
||||
include: ['../../../scripts/get_frequency.ts'],
|
||||
exclude: [],
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
try {
|
||||
const result = spawnSync('bunx', ['tsc', '--noEmit', '-p', tsconfigPath], {
|
||||
cwd: process.cwd(),
|
||||
encoding: 'utf8',
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
result.status,
|
||||
0,
|
||||
`expected scripts/get_frequency.ts to typecheck\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`,
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(workspace, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
@@ -39,24 +39,6 @@ describe('Bun corresponding-source manifest', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('pins the source to the revision reported by the distributed binary', async () => {
|
||||
const manifest = parseSourceManifest(
|
||||
JSON.parse(
|
||||
await fs.readFile(path.join(projectRoot, 'build/bun-source-manifest.json'), 'utf8'),
|
||||
),
|
||||
);
|
||||
|
||||
expect(manifest.version).toBe('1.3.5');
|
||||
expect(manifest.bunRevision).toBe('1e86cebd74a5723e818b5c0555276b646bcf0e4c');
|
||||
expect(manifest.releaseTagCommit).toBe('fa5a5bbe556a4bda5bde77b4013aa6c3bb4ec9ab');
|
||||
expect(manifest.sources.find((source) => source.name === 'WebKit')?.revision).toBe(
|
||||
'6d0f3aac0b817cc01a846b3754b21271adedac12',
|
||||
);
|
||||
expect(manifest.sources.find((source) => source.name === 'tinycc')?.revision).toBe(
|
||||
'29985a3b59898861442fa3b43f663fc1af2591d7',
|
||||
);
|
||||
});
|
||||
|
||||
test('parses commit and tag registrations from Bun CMake', () => {
|
||||
const registrations = parseRegisteredRepositories(`
|
||||
register_repository(
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
test('build:syncui bundles the sandboxed preload and keeps Electron external', () => {
|
||||
const packageJson = JSON.parse(
|
||||
fs.readFileSync(path.join(import.meta.dir, '..', 'package.json'), 'utf8'),
|
||||
) as { scripts: Record<string, string> };
|
||||
const command = packageJson.scripts['build:syncui'] ?? '';
|
||||
|
||||
assert.match(command, /src\/preload-syncui\.ts/);
|
||||
assert.match(command, /--bundle/);
|
||||
assert.match(command, /--external:electron/);
|
||||
assert.match(command, /--outfile=dist\/preload-syncui\.js/);
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import test from 'node:test';
|
||||
|
||||
const source = readFileSync('scripts/prepare-build-assets.mjs', 'utf8');
|
||||
|
||||
test('macOS helper build creates dist scripts directory before swiftc output', () => {
|
||||
const buildFunctionIndex = source.indexOf('function buildMacosHelper()');
|
||||
assert.notEqual(buildFunctionIndex, -1);
|
||||
|
||||
const swiftcIndex = source.indexOf("'swiftc'", buildFunctionIndex);
|
||||
assert.notEqual(swiftcIndex, -1);
|
||||
|
||||
const ensureDirIndex = source.lastIndexOf('ensureDir(scriptsOutputDir)', swiftcIndex);
|
||||
|
||||
assert.ok(
|
||||
ensureDirIndex > buildFunctionIndex,
|
||||
'buildMacosHelper must create dist/scripts before swiftc writes the helper binary',
|
||||
);
|
||||
});
|
||||
|
||||
// Regression guard for #213: an untargeted swiftc stamps the build machine's OS
|
||||
// version as the helper's minimum, so released builds refuse to load on older macOS.
|
||||
test('macOS helper is compiled with an explicit deployment target', () => {
|
||||
assert.match(source, /-target/);
|
||||
assert.match(source, /apple-macos\$\{MACOS_HELPER_DEPLOYMENT_TARGET\}/);
|
||||
});
|
||||
@@ -75,7 +75,7 @@ test('resolveCoverageDir keeps coverage output inside the repository', () => {
|
||||
assert.throws(() => resolveCoverageDir(repoRoot, ['--coverage-dir', '/tmp/escape']));
|
||||
});
|
||||
|
||||
test('runCoverageLane returns a failure when a discovered test fails', () => {
|
||||
test('runCoverageLane returns a failure when a discovered test fails', async () => {
|
||||
const repoRoot = mkdtempSync(join(tmpdir(), 'subminer-coverage-failure-'));
|
||||
try {
|
||||
mkdirSync(join(repoRoot, 'src'));
|
||||
@@ -93,10 +93,10 @@ test('runCoverageLane returns a failure when a discovered test fails', () => {
|
||||
);
|
||||
|
||||
assert.notEqual(
|
||||
runCoverageLane({
|
||||
await runCoverageLane({
|
||||
repoRootDir: repoRoot,
|
||||
argv: ['bun-src-full', '--coverage-dir', 'coverage/test-src'],
|
||||
stdio: 'pipe',
|
||||
quiet: true,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { availableParallelism } from 'node:os';
|
||||
import { isAbsolute, join, relative, resolve } from 'node:path';
|
||||
import { collectLaneFiles } from './test-lanes';
|
||||
|
||||
@@ -201,9 +202,40 @@ export function mergeLcovReports(reports: string[]): string {
|
||||
return chunks.length > 0 ? `${chunks.join('\n')}\n` : '';
|
||||
}
|
||||
|
||||
export function runCoverageLane(
|
||||
options: { repoRootDir?: string; argv?: string[]; stdio?: 'inherit' | 'pipe' } = {},
|
||||
): number {
|
||||
type ShardResult = { status: number; output: string; lcov: string | null };
|
||||
|
||||
// Runs one test file under coverage into its own shard directory, buffering
|
||||
// output so parallel shards do not interleave on the terminal.
|
||||
function runShard(repoRootDir: string, file: string, shardDir: string): Promise<ShardResult> {
|
||||
return new Promise((resolveShard) => {
|
||||
const child = spawn(
|
||||
'bun',
|
||||
['test', '--coverage', '--coverage-reporter=lcov', '--coverage-dir', shardDir, `./${file}`],
|
||||
{ cwd: repoRootDir },
|
||||
);
|
||||
let output = '';
|
||||
child.stdout.on('data', (chunk) => (output += chunk));
|
||||
child.stderr.on('data', (chunk) => (output += chunk));
|
||||
child.on('error', (error) => resolveShard({ status: 1, output: String(error), lcov: null }));
|
||||
child.on('close', (code) => {
|
||||
const lcovPath = join(shardDir, 'lcov.info');
|
||||
const lcov = existsSync(lcovPath) ? readFileSync(lcovPath, 'utf8') : null;
|
||||
resolveShard({ status: code ?? 1, output, lcov });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function parseJobsArg(argv: string[]): number {
|
||||
const index = argv.indexOf('--jobs');
|
||||
if (index === -1) return availableParallelism();
|
||||
return Math.max(1, Number(argv[index + 1]) || 1);
|
||||
}
|
||||
|
||||
// Shards run in parallel (one per CPU unless --jobs N). The first failing shard
|
||||
// stops scheduling new shards and its exit status becomes the lane result.
|
||||
export async function runCoverageLane(
|
||||
options: { repoRootDir?: string; argv?: string[]; quiet?: boolean } = {},
|
||||
): Promise<number> {
|
||||
const repoRootDir = options.repoRootDir ?? repoRoot;
|
||||
const argv = options.argv ?? process.argv.slice(2);
|
||||
const laneName = argv[0];
|
||||
@@ -225,40 +257,44 @@ export function runCoverageLane(
|
||||
process.stderr.write(`${error instanceof Error ? error.message : error}\n`);
|
||||
return 1;
|
||||
}
|
||||
const reports: string[] = [];
|
||||
|
||||
const reports: Array<string | null> = new Array(files.length).fill(null);
|
||||
const failures: Array<{ file: string; result: ShardResult }> = [];
|
||||
let nextIndex = 0;
|
||||
|
||||
const worker = async (): Promise<void> => {
|
||||
while (failures.length === 0 && nextIndex < files.length) {
|
||||
const index = nextIndex++;
|
||||
const file = files[index]!;
|
||||
const shardDir = join(shardRoot, String(index + 1).padStart(3, '0'));
|
||||
const result = await runShard(repoRootDir, file, shardDir);
|
||||
if (result.status !== 0) {
|
||||
failures.push({ file, result });
|
||||
return;
|
||||
}
|
||||
if (result.lcov === null && !options.quiet) {
|
||||
process.stdout.write(`Skipping empty coverage shard for ${file}\n`);
|
||||
}
|
||||
reports[index] = result.lcov;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
for (const [index, file] of files.entries()) {
|
||||
const shardDir = join(shardRoot, `${String(index + 1).padStart(3, '0')}`);
|
||||
const result = spawnSync(
|
||||
'bun',
|
||||
['test', '--coverage', '--coverage-reporter=lcov', '--coverage-dir', shardDir, `./${file}`],
|
||||
{
|
||||
cwd: repoRootDir,
|
||||
stdio: options.stdio ?? 'inherit',
|
||||
},
|
||||
);
|
||||
const jobs = Math.min(parseJobsArg(argv), files.length);
|
||||
await Promise.all(Array.from({ length: jobs }, worker));
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
const [failure] = failures;
|
||||
if (failure !== undefined) {
|
||||
const { file, result } = failure;
|
||||
if (!options.quiet) {
|
||||
process.stderr.write(`${result.output}\nCoverage shard failed: ${file}\n`);
|
||||
}
|
||||
if ((result.status ?? 1) !== 0) {
|
||||
return result.status ?? 1;
|
||||
}
|
||||
|
||||
const lcovPath = join(shardDir, 'lcov.info');
|
||||
if (!existsSync(lcovPath)) {
|
||||
process.stdout.write(`Skipping empty coverage shard for ${file}\n`);
|
||||
continue;
|
||||
}
|
||||
|
||||
reports.push(readFileSync(lcovPath, 'utf8'));
|
||||
return result.status;
|
||||
}
|
||||
|
||||
writeFileSync(join(coverageDir, 'lcov.info'), mergeLcovReports(reports), 'utf8');
|
||||
process.stdout.write(
|
||||
`Merged LCOV written to ${relative(repoRootDir, join(coverageDir, 'lcov.info'))}\n`,
|
||||
);
|
||||
const lcovPath = join(coverageDir, 'lcov.info');
|
||||
writeFileSync(lcovPath, mergeLcovReports(reports.filter((r) => r !== null)), 'utf8');
|
||||
process.stdout.write(`Merged LCOV written to ${relative(repoRootDir, lcovPath)}\n`);
|
||||
return 0;
|
||||
} finally {
|
||||
rmSync(shardRoot, { recursive: true, force: true });
|
||||
@@ -267,5 +303,5 @@ export function runCoverageLane(
|
||||
|
||||
// @ts-ignore Bun entrypoint detection; TS config for scripts still targets CommonJS.
|
||||
if (import.meta.main) {
|
||||
process.exit(runCoverageLane());
|
||||
runCoverageLane().then((status) => process.exit(status));
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { resolve } from 'node:path';
|
||||
import { availableParallelism } from 'node:os';
|
||||
import { spawn, spawnSync } from 'node:child_process';
|
||||
import { collectLaneFiles } from './test-lanes.ts';
|
||||
|
||||
@@ -7,6 +8,8 @@ import { collectLaneFiles } from './test-lanes.ts';
|
||||
// test file so a hanging test or leaked global in one file cannot poison the
|
||||
// rest of the lane. Use --single-process for the old all-in-one-process mode.
|
||||
//
|
||||
// Files run in parallel, one worker per CPU by default; --jobs 1 runs serially.
|
||||
//
|
||||
// Usage: bun scripts/run-test-lane.mjs <lane> [--jobs N] [--timeout-secs N] [--single-process]
|
||||
|
||||
const repoRoot = resolve(fileURLToPath(new URL('..', import.meta.url)));
|
||||
@@ -34,7 +37,12 @@ for (const signal of ['SIGINT', 'SIGTERM']) {
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const options = { lane: undefined, jobs: 1, timeoutSecs: 300, singleProcess: false };
|
||||
const options = {
|
||||
lane: undefined,
|
||||
jobs: availableParallelism(),
|
||||
timeoutSecs: 300,
|
||||
singleProcess: false,
|
||||
};
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
if (arg === '--jobs') {
|
||||
|
||||
@@ -61,15 +61,6 @@ test('normalizeTarget maps each supported electron-builder target without using
|
||||
assert.throws(() => normalizeTarget('linux', 0), /Unsupported Bun runtime target architecture/);
|
||||
});
|
||||
|
||||
test('resolveArtifact chooses baseline x64 builds and standard arm64 builds', () => {
|
||||
const config = runtimeConfig();
|
||||
assert.equal(resolveArtifact(config, 'linux', 'x64').file, 'bun-linux-x64-baseline.zip');
|
||||
assert.equal(resolveArtifact(config, 'darwin', 'x64').file, 'bun-darwin-x64-baseline.zip');
|
||||
assert.equal(resolveArtifact(config, 'win32', 'x64').file, 'bun-windows-x64-baseline.zip');
|
||||
assert.equal(resolveArtifact(config, 'linux', 'arm64').file, 'bun-linux-aarch64.zip');
|
||||
assert.equal(resolveArtifact(config, 'darwin', 'arm64').file, 'bun-darwin-aarch64.zip');
|
||||
});
|
||||
|
||||
test('tracked runtime manifest covers every supported target at the packageManager version', async () => {
|
||||
const config = await loadRuntimeConfig();
|
||||
assert.equal(config.version, '1.3.5');
|
||||
|
||||
Reference in new issue
Block a user