Enhance test coverage by adding new cases for file listing, reading, and ripgrep functionalities. Implement tests for hidden files, depth handling, and path normalization in list_files tests. Expand read_file tests to cover line skipping and reading from empty files. Improve ripgrep tests with various pattern matching scenarios, including regex handling and file pattern exclusions.
This commit is contained in:
1
cli.js
1
cli.js
@@ -2,6 +2,7 @@
|
|||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
import OpenAI from 'openai';
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
|
//npm install tiktoken
|
||||||
//csk-8jftdte6r6vf8fdvp9xkyek5t3jnc6jfhh93d3ewfcwxxvh9
|
//csk-8jftdte6r6vf8fdvp9xkyek5t3jnc6jfhh93d3ewfcwxxvh9
|
||||||
|
|
||||||
import { promises as fs } from "node:fs";
|
import { promises as fs } from "node:fs";
|
||||||
|
|||||||
@@ -124,6 +124,46 @@ function cases() {
|
|||||||
expect: { errorRegex: /Path does not exist:/ }
|
expect: { errorRegex: /Path does not exist:/ }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 7. Hidden excluded when includeHidden=false
|
||||||
|
list.push({
|
||||||
|
name: 'hidden excluded by default',
|
||||||
|
before: { '.hidden': 'h', 'shown.txt': 's' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, dir) || '/', depth: 1, includeHidden: false }),
|
||||||
|
expect: { cwdFromArgs: true, files: [['shown.txt', 'f', 1]] }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 8. Depth 0 shows only top-level entries
|
||||||
|
list.push({
|
||||||
|
name: 'depth 0 top-level only',
|
||||||
|
before: { 'a.txt': 'A', 'sub/b.txt': 'B' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, dir) || '/', depth: 0, includeHidden: false }),
|
||||||
|
expect: { cwdFromArgs: true, files: [['a.txt', 'f', 1], ['sub', 'd', null]] }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 9. Pass hidden file path with includeHidden=false (excluded)
|
||||||
|
list.push({
|
||||||
|
name: 'hidden file path excluded when flag false',
|
||||||
|
before: { '.only.txt': 'x' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, path.join(dir, '.only.txt')), depth: 1, includeHidden: false }),
|
||||||
|
expect: { cwdFromArgs: 'file', files: [] }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 10. Pass hidden file path with includeHidden=true (included)
|
||||||
|
list.push({
|
||||||
|
name: 'hidden file path included when flag true',
|
||||||
|
before: { '.only.txt': 'x' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, path.join(dir, '.only.txt')), depth: 1, includeHidden: true }),
|
||||||
|
expect: { cwdFromArgs: 'file', files: [['.only.txt', 'f', 1]] }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 11. Path normalization outside chroot -> error
|
||||||
|
list.push({
|
||||||
|
name: 'outside chroot error',
|
||||||
|
before: {},
|
||||||
|
args: async () => ({ path: '../../etc', depth: 1, includeHidden: false }),
|
||||||
|
expect: { errorRegex: /Path escapes chroot boundary/ }
|
||||||
|
});
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,38 @@ function cases() {
|
|||||||
expect: { equals: Array.from({ length: 400 }, (_, i) => `L${i + 1}`).join('\n') }
|
expect: { equals: Array.from({ length: 400 }, (_, i) => `L${i + 1}`).join('\n') }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 7. Skip beyond file length -> empty
|
||||||
|
list.push({
|
||||||
|
name: 'skip beyond length returns empty',
|
||||||
|
before: { 's.txt': 'A\nB' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, path.join(dir, 's.txt')), linesToSkip: 10, linesToRead: 5 }),
|
||||||
|
expect: { equals: '' }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 8. Skip to last line and read one
|
||||||
|
list.push({
|
||||||
|
name: 'skip to last line and read one',
|
||||||
|
before: { 't.txt': 'L1\nL2\nL3' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, path.join(dir, 't.txt')), linesToSkip: 2, linesToRead: 1 }),
|
||||||
|
expect: { equals: 'L3' }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 9. Read exactly N lines from middle
|
||||||
|
list.push({
|
||||||
|
name: 'read middle two lines',
|
||||||
|
before: { 'u.txt': 'A\nB\nC\nD' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, path.join(dir, 'u.txt')), linesToSkip: 1, linesToRead: 2 }),
|
||||||
|
expect: { equals: 'B\nC' }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 10. Empty file read -> empty string
|
||||||
|
list.push({
|
||||||
|
name: 'empty file read',
|
||||||
|
before: { 'empty.txt': '' },
|
||||||
|
args: async ({ dir }) => ({ path: path.relative(chrootRoot, path.join(dir, 'empty.txt')), linesToSkip: 0, linesToRead: 100 }),
|
||||||
|
expect: { equals: '' }
|
||||||
|
});
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,66 @@ function cases() {
|
|||||||
expect: { error: /ripgrep error:/ }
|
expect: { error: /ripgrep error:/ }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 7. No line numbers (n_flag false)
|
||||||
|
list.push({
|
||||||
|
name: 'no line numbers',
|
||||||
|
before: { 'a.txt': 'foo\nbar\nfoo' },
|
||||||
|
args: async ({ dir }) => ({ pattern: 'foo', filePattern: path.relative(chrootRoot, path.join(dir, '**')), n_flag: false, i_flag: false }),
|
||||||
|
expect: { equals: [
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '07-no-line-numbers/a.txt'))}:foo`,
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '07-no-line-numbers/a.txt'))}:foo`
|
||||||
|
].join('\n') }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 8. filePattern include-only to exclude .md (tool supports single -g, so include *.txt)
|
||||||
|
list.push({
|
||||||
|
name: 'filePattern include-only excludes md',
|
||||||
|
before: { 'a.txt': 'hit', 'b.md': 'hit' },
|
||||||
|
args: async ({ dir }) => ({ pattern: 'hit', filePattern: path.relative(chrootRoot, path.join(dir, '**/*.txt')), n_flag: true, i_flag: false }),
|
||||||
|
expect: { equals: `${path.relative(chrootRoot, path.join(sandboxRoot, '08-filepattern-negation-excludes-md/a.txt'))}:1:hit` }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 9. Empty filePattern searches all (we'll scope to the case dir by pattern and path shape)
|
||||||
|
list.push({
|
||||||
|
name: 'empty filePattern searches all',
|
||||||
|
before: { 'x.js': 'Hello', 'y.txt': 'Hello' },
|
||||||
|
args: async ({ dir }) => ({ pattern: 'Hello', filePattern: path.relative(chrootRoot, path.join(dir, '**')), n_flag: true, i_flag: false }),
|
||||||
|
expect: { equals: [
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '09-empty-filepattern-searches-all/x.js'))}:1:Hello`,
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '09-empty-filepattern-searches-all/y.txt'))}:1:Hello`
|
||||||
|
].join('\n') }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 10. Anchored regex
|
||||||
|
list.push({
|
||||||
|
name: 'anchored regex',
|
||||||
|
before: { 'a.txt': 'Hello\nHello world\nHello' },
|
||||||
|
args: async ({ dir }) => ({ pattern: '^Hello$', filePattern: path.relative(chrootRoot, path.join(dir, '**')), n_flag: true, i_flag: false }),
|
||||||
|
expect: { equals: [
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '10-anchored-regex/a.txt'))}:1:Hello`,
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '10-anchored-regex/a.txt'))}:3:Hello`
|
||||||
|
].join('\n') }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 11. Special regex characters
|
||||||
|
list.push({
|
||||||
|
name: 'special regex characters',
|
||||||
|
before: { 'a.txt': 'a+b?c\\d and a+b?c\\d' },
|
||||||
|
args: async ({ dir }) => ({ pattern: 'a\\+b\\?c\\\\d', filePattern: path.relative(chrootRoot, path.join(dir, '**')), n_flag: true, i_flag: false }),
|
||||||
|
expect: { equals: `${path.relative(chrootRoot, path.join(sandboxRoot, '11-special-regex-characters/a.txt'))}:1:a+b?c\\d and a+b?c\\d` }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 12. Multiple files across dirs deterministic order
|
||||||
|
list.push({
|
||||||
|
name: 'multi dirs deterministic',
|
||||||
|
before: { 'b/b.txt': 'X', 'a/a.txt': 'X' },
|
||||||
|
args: async ({ dir }) => ({ pattern: '^X$', filePattern: path.relative(chrootRoot, path.join(dir, '**')), n_flag: true, i_flag: false }),
|
||||||
|
expect: { equals: [
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '12-multi-dirs-deterministic/a/a.txt'))}:1:X`,
|
||||||
|
`${path.relative(chrootRoot, path.join(sandboxRoot, '12-multi-dirs-deterministic/b/b.txt'))}:1:X`
|
||||||
|
].join('\n') }
|
||||||
|
});
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user