mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
test: add comprehensive real-world test cases for command pattern parser
- Added extensive test coverage for shell-quote based command parsing - Included edge cases: quotes, escapes, special characters, redirections - Added real-world examples: git, npm, docker, curl, ssh commands - Validated robustness of parser against complex shell command patterns - Ensures reliable command execution across different shell syntaxes
This commit is contained in:
parent
60815f405c
commit
edba73a811
1 changed files with 237 additions and 0 deletions
|
|
@ -117,6 +117,243 @@ describe("extractCommandPatterns", () => {
|
|||
expect(patterns).toEqual(["git", "git add", "git status"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("complex real-world examples", () => {
|
||||
it("should correctly parse unzip with pipe chain", () => {
|
||||
const command = "unzip -l builds/roo-cline-3.21.5-error-boundary-component.vsix|grep map"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
// Should extract individual commands from the chain
|
||||
expect(patterns).toContain("unzip")
|
||||
expect(patterns).toContain("grep")
|
||||
|
||||
// Should not include the full chain
|
||||
expect(patterns).not.toContain(command)
|
||||
|
||||
// Should not include flags or arguments
|
||||
expect(patterns).not.toContain("unzip -l")
|
||||
expect(patterns).not.toContain("grep map")
|
||||
})
|
||||
|
||||
it("should correctly parse git push with multiple arguments", () => {
|
||||
const command = "git push github refactor-use-files-for-history -f"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
// Should extract base command and subcommand
|
||||
expect(patterns).toContain("git")
|
||||
expect(patterns).toContain("git push")
|
||||
|
||||
// Should not include remote, branch, or flags
|
||||
expect(patterns).not.toContain("git push github")
|
||||
expect(patterns).not.toContain("github")
|
||||
expect(patterns).not.toContain("refactor-use-files-for-history")
|
||||
expect(patterns).not.toContain("-f")
|
||||
})
|
||||
|
||||
it("should correctly parse complex build and install chain", () => {
|
||||
const command =
|
||||
"../roo-main/build.sh && code --install-extension builds/roo-cline-3.21.5-error-boundary-component.vsix && code"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
// Should extract script file
|
||||
expect(patterns).toContain("../roo-main/build.sh")
|
||||
|
||||
// Should extract code command (appears twice, but set will dedupe)
|
||||
expect(patterns).toContain("code")
|
||||
|
||||
// Should not include the full chain
|
||||
expect(patterns).not.toContain(command)
|
||||
|
||||
// Should not include flags or arguments
|
||||
expect(patterns).not.toContain("code --install-extension")
|
||||
expect(patterns).not.toContain("--install-extension")
|
||||
expect(patterns).not.toContain("builds/roo-cline-3.21.5-error-boundary-component.vsix")
|
||||
})
|
||||
|
||||
it("should handle npm scripts with arguments", () => {
|
||||
const command = "npm run build -- --watch"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("npm")
|
||||
expect(patterns).toContain("npm run")
|
||||
// Should stop at 'run' to allow any script
|
||||
expect(patterns).not.toContain("npm run build")
|
||||
})
|
||||
|
||||
it("should handle docker commands with subcommands", () => {
|
||||
const command = "docker compose up -d"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("docker")
|
||||
expect(patterns).toContain("docker compose")
|
||||
expect(patterns).not.toContain("docker compose up")
|
||||
expect(patterns).not.toContain("-d")
|
||||
})
|
||||
|
||||
it("should handle kubectl commands", () => {
|
||||
const command = "kubectl get pods -n production"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("kubectl")
|
||||
expect(patterns).toContain("kubectl get")
|
||||
expect(patterns).not.toContain("kubectl get pods")
|
||||
expect(patterns).not.toContain("-n")
|
||||
expect(patterns).not.toContain("production")
|
||||
})
|
||||
|
||||
it("should handle make targets", () => {
|
||||
const command = "make clean && make build"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("make")
|
||||
expect(patterns).toContain("make clean")
|
||||
expect(patterns).toContain("make build")
|
||||
})
|
||||
|
||||
it("should handle python scripts with arguments", () => {
|
||||
const command = "python3 scripts/deploy.py --env production"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("python3")
|
||||
// Should stop after interpreter
|
||||
expect(patterns).not.toContain("scripts/deploy.py")
|
||||
expect(patterns).not.toContain("--env")
|
||||
})
|
||||
|
||||
it("should handle environment variables with commands", () => {
|
||||
const command = "NODE_ENV=test npm test && NODE_ENV=production npm start"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("npm")
|
||||
expect(patterns).toContain("npm test")
|
||||
expect(patterns).toContain("npm start")
|
||||
expect(patterns).not.toContain("NODE_ENV=test")
|
||||
expect(patterns).not.toContain("NODE_ENV=production")
|
||||
})
|
||||
|
||||
it("should handle complex pipe with multiple tools", () => {
|
||||
const command = "ps aux | grep node | awk '{print $2}' | xargs kill -9"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("ps")
|
||||
expect(patterns).toContain("grep")
|
||||
expect(patterns).toContain("awk")
|
||||
expect(patterns).toContain("xargs")
|
||||
// Note: "xargs kill -9" is parsed as a single command where xargs is the command
|
||||
// and "kill -9" are arguments, so kill is not extracted as a separate pattern
|
||||
expect(patterns).not.toContain("kill")
|
||||
expect(patterns).not.toContain("ps aux")
|
||||
expect(patterns).not.toContain("grep node")
|
||||
expect(patterns).not.toContain("kill -9")
|
||||
})
|
||||
|
||||
it("should handle yarn workspaces commands", () => {
|
||||
const command = "yarn workspace @myapp/frontend build"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("yarn")
|
||||
expect(patterns).toContain("yarn workspace")
|
||||
// Should not include the workspace name
|
||||
expect(patterns).not.toContain("@myapp/frontend")
|
||||
expect(patterns).not.toContain("build")
|
||||
})
|
||||
|
||||
it("should handle pnpm commands", () => {
|
||||
const command = "pnpm --filter ./packages/* test"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("pnpm")
|
||||
// Should stop at flags
|
||||
expect(patterns).not.toContain("pnpm --filter")
|
||||
expect(patterns).not.toContain("test")
|
||||
})
|
||||
|
||||
it("should handle curl with complex arguments", () => {
|
||||
const command =
|
||||
"curl -X POST https://api.example.com/data -H 'Content-Type: application/json' -d '{\"key\": \"value\"}'"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("curl")
|
||||
// Should stop at flags
|
||||
expect(patterns).not.toContain("curl -X")
|
||||
expect(patterns).not.toContain("POST")
|
||||
expect(patterns).not.toContain("https://api.example.com/data")
|
||||
})
|
||||
|
||||
it("should handle ssh commands", () => {
|
||||
const command = "ssh user@server.com 'cd /app && npm restart'"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("ssh")
|
||||
// Should not include user@server or remote command
|
||||
expect(patterns).not.toContain("user@server.com")
|
||||
expect(patterns).not.toContain("cd")
|
||||
expect(patterns).not.toContain("npm")
|
||||
})
|
||||
|
||||
it("should handle rsync commands", () => {
|
||||
const command = "rsync -avz --delete ./dist/ user@server:/var/www/html/"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("rsync")
|
||||
// Should stop at flags
|
||||
expect(patterns).not.toContain("rsync -avz")
|
||||
expect(patterns).not.toContain("--delete")
|
||||
})
|
||||
|
||||
it("should handle find with exec", () => {
|
||||
const command = "find . -name '*.log' -exec rm {} \\;"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("find")
|
||||
// Should not include dangerous operations
|
||||
expect(patterns).not.toContain("rm")
|
||||
expect(patterns).not.toContain("-exec")
|
||||
})
|
||||
|
||||
it("should handle systemctl commands", () => {
|
||||
const command = "sudo systemctl restart nginx"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("sudo")
|
||||
// Note: sudo is the command, systemctl is treated as an argument
|
||||
// The parser doesn't have special handling for sudo to extract the actual command
|
||||
expect(patterns).not.toContain("systemctl")
|
||||
expect(patterns).not.toContain("nginx")
|
||||
})
|
||||
|
||||
it("should handle aws cli commands", () => {
|
||||
const command = "aws s3 sync ./build s3://my-bucket --delete"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("aws")
|
||||
// aws is not in special handling, so behavior may vary
|
||||
expect(patterns).not.toContain("--delete")
|
||||
})
|
||||
|
||||
it("should handle multiple redirects", () => {
|
||||
const command = "echo 'test' > file.txt && cat file.txt >> output.log"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("echo")
|
||||
expect(patterns).toContain("cat")
|
||||
expect(patterns).not.toContain("echo 'test'")
|
||||
expect(patterns).not.toContain("file.txt")
|
||||
expect(patterns).not.toContain("output.log")
|
||||
})
|
||||
|
||||
it("should handle background processes", () => {
|
||||
const command = "npm start & npm run worker &"
|
||||
const patterns = extractCommandPatterns(command)
|
||||
|
||||
expect(patterns).toContain("npm")
|
||||
expect(patterns).toContain("npm start")
|
||||
// Note: The & operator is not in the chainOperators list (only &&, ||, ;, |)
|
||||
// So this is parsed as a single command "npm start & npm run worker &"
|
||||
// The parser stops at the first & character when parsing "npm start &..."
|
||||
expect(patterns).not.toContain("npm run")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getPatternDescription", () => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue