Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions src/utils/format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -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);
}
});

Expand Down
17 changes: 17 additions & 0 deletions tests/acceptance/lib/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown> };
if (repoManifest.overrides) {
const consumerManifestPath = path.join(consumerDir, 'package.json');
const consumerManifest = JSON.parse(
fs.readFileSync(consumerManifestPath, 'utf8'),
) as Record<string, unknown>;
consumerManifest['overrides'] = repoManifest.overrides;
fs.writeFileSync(consumerManifestPath, `${JSON.stringify(consumerManifest, null, 2)}\n`);
}

const registry = await startLocalDependencyRegistry(repoRoot, tempRoot, runner);
try {
await runner.run(
Expand Down
Loading