mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-17 21:55:34 +02:00
test(gateguard): pin searches that never saw the target and Unicode line terminators
Each of these is credited on main, reproduced against upstream 2d515e4f:
- rg -t py / -T js / --type-not js, fd -e py, and the Grep tool's
type: "py" credit an Edit of tokenizer.js. Type and extension values
are skipped as plain value flags, so they never filter.
- Glob **/tokenizer.py, rg tokenizer src/*.py, and
git grep tokenizer -- '*.py' credit tokenizer.js. The Glob pattern is
never a filter, and a glob operand scopes as its literal directory.
- Glob **/tokenizer.js, find -name tokenizer.js, rg -g tokenizer.js and
Grep glob: "tokenizer.js" credit tokenizer.js, although each search
could only find the target itself.
- An Edit of "// note<U+2028>foo(1);" to "// note<U+2028>foo(2);" passes
as comment-only, although JavaScript ends the comment at U+2028 and
foo(2) runs.
Scenario 21-bypass-filter-forms adds ten must-deny steps and four
controls. Four hook controls that asserted exact-name lookups still
credit (find -name widget.py, Grep glob widget.py, Get-ChildItem
-Filter widget.py) now assert the lookup is denied; each keeps its
original purpose, that the exclusion parser leaves a positive include
alone, through a wildcard include (widget.*).
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -5669,14 +5669,25 @@ function runTests() {
|
||||
['Grep widget glob *.{py,js} (braces are one glob)', 'Grep', { pattern: 'widget', glob: '*.{py,js}', path: creditRoot }],
|
||||
['Grep widget glob !node_modules/**', 'Grep', { pattern: 'widget', glob: '!node_modules/**', path: creditRoot }],
|
||||
['grep --exclude-dir=node_modules widget', 'Bash', { command: 'grep -r --exclude-dir=node_modules widget .' }],
|
||||
['find -name widget.py', 'Bash', { command: 'find . -name widget.py' }],
|
||||
['Grep TODO glob widget.py (positive glob names the stem)', 'Grep', { pattern: 'TODO', glob: 'widget.py', path: creditRoot }]
|
||||
["find -name 'widget.*'", 'Bash', { command: "find . -name 'widget.*'" }],
|
||||
['Grep TODO glob widget.* (positive glob names the stem)', 'Grep', { pattern: 'TODO', glob: 'widget.*', path: creditRoot }]
|
||||
];
|
||||
for (const [label, name, input] of exclusionCredited) {
|
||||
gateCase(`control still credits (${label})`, () => {
|
||||
assertCredited(creditEdit(exclusionTarget, exclusionTurn(name, input)), label);
|
||||
});
|
||||
}
|
||||
// A search confined to the target's own file name read the target rather than searched for it.
|
||||
const lookupDenied = [
|
||||
['find -name widget.py', 'Bash', { command: 'find . -name widget.py' }],
|
||||
['Grep TODO glob widget.py', 'Grep', { pattern: 'TODO', glob: 'widget.py', path: creditRoot }]
|
||||
];
|
||||
for (const [label, name, input] of lookupDenied) {
|
||||
gateCase(`a lookup of the target by its own name never credits it (${label})`, () => {
|
||||
assertNotCredited(creditEdit(exclusionTarget, exclusionTurn(name, input)), label);
|
||||
assert.ok(!readState().fact_force_credited, `${label}: nothing credited`);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Bracket classes in filter globs match exactly ---
|
||||
const bracketCases = [
|
||||
@@ -5780,10 +5791,10 @@ function runTests() {
|
||||
});
|
||||
}
|
||||
const psCredited = [
|
||||
'Get-ChildItem -Path src -Recurse -Filter widget.py',
|
||||
'Get-ChildItem -Recurse -Filt:widget.py',
|
||||
'Get-ChildItem -Path src -Recurse -Filter widget.*',
|
||||
'Get-ChildItem -Recurse -Filt:widget.*',
|
||||
'Get-ChildItem -Recurse -Include a.md, widget.py',
|
||||
'Get-ChildItem -Recurse -Exclude a.md, b.md -Filter widget.py',
|
||||
'Get-ChildItem -Recurse -Exclude a.md, b.md -Filter widget.*',
|
||||
'Select-String -Pattern widget -Path src/* -Exclude a.md'
|
||||
];
|
||||
for (const command of psCredited) {
|
||||
@@ -5791,6 +5802,11 @@ function runTests() {
|
||||
assertCredited(creditEdit(exclusionTarget, exclusionTurn('PowerShell', { command })), command);
|
||||
});
|
||||
}
|
||||
for (const command of ['Get-ChildItem -Path src -Recurse -Filter widget.py', 'Get-ChildItem -Recurse -Filt:widget.py']) {
|
||||
gateCase(`a PowerShell lookup of the target by its own name never credits it (${command})`, () => {
|
||||
assertNotCredited(creditEdit(exclusionTarget, exclusionTurn('PowerShell', { command })), command);
|
||||
});
|
||||
}
|
||||
gateCase('PowerShell include lists spread across tokens still filter the target', () => {
|
||||
const command = 'Get-ChildItem -Recurse -Include a.md, widget.md';
|
||||
assertNotCredited(creditEdit(exclusionTarget, exclusionTurn('PowerShell', { command })), command);
|
||||
|
||||
@@ -35,6 +35,16 @@ test('a comment-only change to C-family code is trivial', () => {
|
||||
assert.strictEqual(isTrivialEdit('a(); // x', 'a(); // y', JS), true);
|
||||
});
|
||||
|
||||
test('a Unicode line terminator makes an edit non-trivial', () => {
|
||||
// JavaScript ends a line comment at U+2028 and U+2029, and C# also at U+0085.
|
||||
for (const sep of ['\u2028', '\u2029', '\u0085']) {
|
||||
const code = sep.codePointAt(0).toString(16);
|
||||
assert.strictEqual(isTrivialEdit(`// note${sep}foo(1);`, `// note${sep}foo(2);`, JS), false, `U+${code} ends the comment`);
|
||||
assert.strictEqual(isTrivialEdit(`a(); // x${sep}y`, `a(); // z${sep}y`, JS), false, `U+${code} anywhere`);
|
||||
assert.strictEqual(isTrivialEdit(`x = 1 # a${sep}b`, `x = 1 # c${sep}b`, PY), false, `U+${code} in any language`);
|
||||
}
|
||||
});
|
||||
|
||||
test('comment markers inside a string are code', () => {
|
||||
assert.strictEqual(isTrivialEdit('const s = "a // b";', 'const s = "a // c";', JS), false);
|
||||
assert.strictEqual(isTrivialEdit("const s = 'x /* y */ z';", "const s = 'x /* q */ z';", JS), false);
|
||||
|
||||
@@ -157,6 +157,80 @@ test('stripped test stems keep the generic, length, word-boundary and scope rule
|
||||
assert.strictEqual(miss && miss.reason, 'generic-stem');
|
||||
});
|
||||
|
||||
const filterScan = searches => ({ turnId: null, searches, batchIds: new Map(), newestMessageId: null, shellCommands: [], reads: [] });
|
||||
const filterSearch = (name, input) => ({ name, input, callsAgo: 1, messageId: 'msg_1' });
|
||||
const label = ([name, input]) => `${name} ${JSON.stringify(input)}`;
|
||||
|
||||
test('a type, extension or path pattern that misses the target stops its stem from crediting', () => {
|
||||
const { findCreditingSearch, findClosestMiss } = loadHook();
|
||||
const data = { cwd: root };
|
||||
const target = `${root}/src/parser/tokenizer.js`;
|
||||
const missing = [
|
||||
['Bash', { command: 'rg -t py tokenizer src' }],
|
||||
['Bash', { command: 'rg -T js tokenizer src' }],
|
||||
['Bash', { command: 'rg --type-not js tokenizer src' }],
|
||||
['Bash', { command: 'fd -e py tokenizer src' }],
|
||||
['Grep', { pattern: 'tokenizer', type: 'py' }],
|
||||
['Glob', { pattern: '**/tokenizer.py' }],
|
||||
['Bash', { command: 'rg tokenizer src/*.py' }],
|
||||
['Bash', { command: 'grep -rn tokenizer src/**/*.py' }],
|
||||
['Bash', { command: "git grep tokenizer -- '*.py'" }],
|
||||
['Bash', { command: "git ls-files '*tokenizer.py'" }]
|
||||
];
|
||||
for (const search of missing) {
|
||||
const scan = filterScan([filterSearch(...search)]);
|
||||
assert.strictEqual(findCreditingSearch(scan, target, false, data), null, label(search));
|
||||
assert.strictEqual((findClosestMiss(scan, target, false, data) || {}).reason, 'excluded', label(search));
|
||||
}
|
||||
const covering = [
|
||||
['Bash', { command: 'rg -t js tokenizer src' }],
|
||||
['Bash', { command: 'fd -e js tokenizer src' }],
|
||||
['Grep', { pattern: 'tokenizer', type: 'js' }],
|
||||
['Glob', { pattern: '**/tokenizer*' }],
|
||||
['Glob', { pattern: 'src/**/*tokenizer*' }],
|
||||
['Bash', { command: 'rg tokenizer src/*' }],
|
||||
['Bash', { command: 'rg tokenizer lib/*.py src' }],
|
||||
['Bash', { command: "git grep tokenizer -- '*.js'" }],
|
||||
['Bash', { command: "git grep tokenizer -- 'src/*.js'" }]
|
||||
];
|
||||
for (const search of covering) {
|
||||
assert.ok(findCreditingSearch(filterScan([filterSearch(...search)]), target, false, data), label(search));
|
||||
}
|
||||
});
|
||||
|
||||
test('a search confined to the target file name is a lookup, not a search', () => {
|
||||
const { findCreditingSearch, findClosestMiss } = loadHook();
|
||||
const data = { cwd: root };
|
||||
const target = `${root}/src/parser/tokenizer.js`;
|
||||
const lookups = [
|
||||
['Glob', { pattern: '**/tokenizer.js' }],
|
||||
['Glob', { pattern: 'src/**/tokenizer.js' }],
|
||||
['Grep', { pattern: 'tokenizer', glob: 'tokenizer.js' }],
|
||||
['Grep', { pattern: 'tokenizer', glob: '**/tokenizer.js' }],
|
||||
['Bash', { command: 'find src -name tokenizer.js' }],
|
||||
['Bash', { command: 'rg -g tokenizer.js tokenizer src' }],
|
||||
['Bash', { command: 'rg --files -g tokenizer.js src' }],
|
||||
['Bash', { command: 'rg tokenizer src/**/tokenizer.js' }]
|
||||
];
|
||||
for (const search of lookups) {
|
||||
const scan = filterScan([filterSearch(...search)]);
|
||||
assert.strictEqual(findCreditingSearch(scan, target, false, data), null, label(search));
|
||||
assert.strictEqual((findClosestMiss(scan, target, false, data) || {}).reason, 'lookup', label(search));
|
||||
}
|
||||
const searches = [
|
||||
['Glob', { pattern: '**/tokenizer.*' }],
|
||||
['Bash', { command: "find src -name 'tokenizer.*'" }],
|
||||
['Bash', { command: "rg -g tokenizer.js -g '*.ts' tokenizer src" }]
|
||||
];
|
||||
for (const search of searches) {
|
||||
assert.ok(findCreditingSearch(filterScan([filterSearch(...search)]), target, false, data), label(search));
|
||||
}
|
||||
const testTarget = `${root}/tests/parser/tokenizer.test.js`;
|
||||
const lookupOfModule = filterScan([filterSearch('Glob', { pattern: '**/tokenizer.js' })]);
|
||||
assert.strictEqual(findCreditingSearch(lookupOfModule, testTarget, false, data), null, 'a Glob of the module never listed its test');
|
||||
assert.strictEqual((findClosestMiss(lookupOfModule, testTarget, false, data) || {}).reason, 'excluded');
|
||||
});
|
||||
|
||||
fs.rmSync(transcriptDir, { recursive: true, force: true });
|
||||
|
||||
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
||||
|
||||
@@ -86,5 +86,45 @@ test('PowerShell -Exclude binds from an unambiguous prefix', () => {
|
||||
assert.deepStrictEqual(filter.globs, ['a.py', 'widget.py']);
|
||||
});
|
||||
|
||||
const admitted = (item, rel) => filtersAdmitTarget(item, ctxFor(rel), null) && admits(item, rel);
|
||||
|
||||
test('rg -t/--type selects ripgrep type globs instead of being skipped', () => {
|
||||
for (const args of [['-t', 'py'], ['-tpy'], ['--type', 'py'], ['--type=py'], ['-it', 'py']]) {
|
||||
const item = rgItem([...args, 'tokenizer', 'src']);
|
||||
assert.strictEqual(admitted(item, 'src/tokenizer.js'), false, args.join(' '));
|
||||
assert.strictEqual(admitted(item, 'src/tokenizer.pyi'), true, args.join(' '));
|
||||
}
|
||||
assert.strictEqual(admitted(rgItem(['-t', 'js', 'x']), 'src/tokenizer.mjs'), true);
|
||||
assert.strictEqual(admitted(rgItem(['-t', 'py', '-t', 'js', 'x']), 'src/tokenizer.js'), true, 'types are alternatives');
|
||||
});
|
||||
|
||||
test('rg -T/--type-not excludes the type globs', () => {
|
||||
for (const args of [['-T', 'js'], ['-Tjs'], ['--type-not', 'js'], ['--type-not=js']]) {
|
||||
assert.strictEqual(admitted(rgItem([...args, 'x']), 'src/tokenizer.js'), false, args.join(' '));
|
||||
assert.strictEqual(admitted(rgItem([...args, 'x']), 'src/tokenizer.py'), true, args.join(' '));
|
||||
}
|
||||
});
|
||||
|
||||
test('unknown or redefined rg types are unreadable filters', () => {
|
||||
for (const args of [['-t', 'nosuchtype'], ['-T', 'nosuchtype'], ['--type-add', 'web:*.js', '-t', 'web'], ['--type-clear', 'js']]) {
|
||||
assert.strictEqual(admitted(rgItem([...args, 'x']), 'src/tokenizer.js'), false, args.join(' '));
|
||||
}
|
||||
});
|
||||
|
||||
test('fd -e/--extension is an include', () => {
|
||||
const fdItem = args => ({ ...shellSearchFilters('fd', args), scopes: [['.']], pathIncludes: false });
|
||||
for (const args of [['-e', 'py'], ['-epy'], ['--extension', 'py'], ['--extension=.py']]) {
|
||||
assert.strictEqual(admitted(fdItem([...args, 'tokenizer', 'src']), 'src/tokenizer.js'), false, args.join(' '));
|
||||
assert.strictEqual(admitted(fdItem([...args, 'tokenizer', 'src']), 'src/tokenizer.py'), true, args.join(' '));
|
||||
}
|
||||
});
|
||||
|
||||
test('the Grep tool type parameter is an include, and an unknown type is unreadable', () => {
|
||||
const grepItem = (glob, type) => ({ ...grepToolFilters(glob, type), scopes: [['.']], pathIncludes: true });
|
||||
assert.strictEqual(admitted(grepItem(undefined, 'py'), 'src/tokenizer.js'), false);
|
||||
assert.strictEqual(admitted(grepItem(undefined, 'py'), 'src/tokenizer.py'), true);
|
||||
assert.strictEqual(admitted(grepItem(undefined, 'nosuchtype'), 'src/tokenizer.js'), false);
|
||||
});
|
||||
|
||||
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
|
||||
Reference in New Issue
Block a user