diff --git a/src/utils/format.test.ts b/src/utils/format.test.ts index 141daa5..0cf822d 100644 --- a/src/utils/format.test.ts +++ b/src/utils/format.test.ts @@ -690,14 +690,27 @@ describe('maskUrlUserinfoInText', () => { ); }); - it('stays linear when many short authorities follow a distant @', () => { - // A backward lastIndexOf for the authority's @ made this quadratic. - const hostile = `@${' http:x/'.repeat(50_000)}`; + // A baseline run at 1/10 the size sets the bound instead of a fixed + // millisecond budget, so this holds on any machine while still failing on + // quadratic behavior: linear scaling gives ~10x the baseline, quadratic + // gives ~100x, and 40x is the dividing line with slack for noise. The + // floor keeps a near-zero baseline from making the bound vacuous. + function expectLinearScaling(buildInput: (repeat: number) => string, fullRepeat: number): void { + const t0 = Date.now(); + maskUrlUserinfoInText(buildInput(fullRepeat / 10)); + const baseline = Date.now() - t0; + const floor = Math.max(baseline, 10); + const start = Date.now(); + maskUrlUserinfoInText(buildInput(fullRepeat)); + const fullDuration = Date.now() - start; - maskUrlUserinfoInText(hostile); + expect(fullDuration).toBeLessThan(40 * floor); + } - expect(Date.now() - start).toBeLessThan(500); + it('stays linear when many short authorities follow a distant @', () => { + // A backward lastIndexOf for the authority's @ made this quadratic. + expectLinearScaling((repeat) => `@${' http:x/'.repeat(repeat)}`, 50_000); }); it('stays linear on terminator-free scheme repeats and unclosed brackets', () => { @@ -707,11 +720,7 @@ describe('maskUrlUserinfoInText', () => { // its `]`. Past MAX_AUTHORITY_SPAN the adjudicator now fails closed // instead of parsing unbounded candidates. for (const unit of ['https:\\\\u:p@', 'https:\\\\u:p@!', 'https://u:p@[/']) { - const start = Date.now(); - - maskUrlUserinfoInText(unit.repeat(20_000)); - - expect(Date.now() - start).toBeLessThan(1_000); + expectLinearScaling((repeat) => unit.repeat(repeat), 20_000); } }); diff --git a/tests/acceptance/lib/pack.ts b/tests/acceptance/lib/pack.ts index 74d663b..76a4710 100644 --- a/tests/acceptance/lib/pack.ts +++ b/tests/acceptance/lib/pack.ts @@ -100,6 +100,23 @@ export async function packAndInstall( env: { ...process.env, npm_config_cache: npmCache }, }); + // The stub registry serves only the versions pinned in the repo lock, and + // npm overrides do not propagate to dependents, so a bare consumer resolves + // ranges the lock has overridden away (filelist -> minimatch@^5) and the + // install 404s. Mirror the root overrides into the consumer manifest so its + // resolution stays inside what the stub can serve. + const repoManifest = JSON.parse( + fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'), + ) as { overrides?: Record }; + if (repoManifest.overrides) { + const consumerManifestPath = path.join(consumerDir, 'package.json'); + const consumerManifest = JSON.parse( + fs.readFileSync(consumerManifestPath, 'utf8'), + ) as Record; + consumerManifest['overrides'] = repoManifest.overrides; + fs.writeFileSync(consumerManifestPath, `${JSON.stringify(consumerManifest, null, 2)}\n`); + } + const registry = await startLocalDependencyRegistry(repoRoot, tempRoot, runner); try { await runner.run(