Skip to content

Commit 93c182a

Browse files
committed
move test to its own file
1 parent ab10bc2 commit 93c182a

File tree

2 files changed

+128
-128
lines changed

2 files changed

+128
-128
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// kilocode_change new file
2+
3+
// npx vitest src/utils/__tests__/command-validation-quote-protection.spec.ts
4+
5+
import {
6+
protectNewlinesInQuotes,
7+
NEWLINE_PLACEHOLDER,
8+
CARRIAGE_RETURN_PLACEHOLDER,
9+
} from "../command-validation-quote-protection"
10+
11+
describe("protectNewlinesInQuotes", () => {
12+
const newlinePlaceholder = NEWLINE_PLACEHOLDER
13+
const crPlaceholder = CARRIAGE_RETURN_PLACEHOLDER
14+
15+
describe("basic quote handling", () => {
16+
it("protects newlines in double quotes", () => {
17+
const input = 'echo "hello\nworld"'
18+
const expected = `echo "hello${newlinePlaceholder}world"`
19+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
20+
})
21+
22+
it("protects newlines in single quotes", () => {
23+
const input = "echo 'hello\nworld'"
24+
const expected = `echo 'hello${newlinePlaceholder}world'`
25+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
26+
})
27+
28+
it("does not protect newlines outside quotes", () => {
29+
const input = "echo hello\necho world"
30+
const expected = "echo hello\necho world"
31+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
32+
})
33+
})
34+
35+
describe("quote concatenation", () => {
36+
it("handles quote concatenation where content between quotes is NOT quoted", () => {
37+
// In bash: echo '"'A'"' prints "A" (A is not quoted)
38+
const input = `echo '"'A\n'"'`
39+
// The newline after A is NOT inside quotes, so it should NOT be protected
40+
const expected = `echo '"'A\n'"'`
41+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
42+
})
43+
44+
it("handles alternating quotes correctly", () => {
45+
// echo "hello"world"test" -> hello is quoted, world is not, test is quoted
46+
const input = `echo "hello\n"world\n"test\n"`
47+
const expected = `echo "hello${newlinePlaceholder}"world\n"test${newlinePlaceholder}"`
48+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
49+
})
50+
51+
it("handles single quote after double quote", () => {
52+
const input = `echo "hello"'world\n'`
53+
const expected = `echo "hello"'world${newlinePlaceholder}'`
54+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
55+
})
56+
57+
it("handles double quote after single quote", () => {
58+
const input = `echo 'hello'"world\n"`
59+
const expected = `echo 'hello'"world${newlinePlaceholder}"`
60+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
61+
})
62+
})
63+
64+
describe("escaped quotes", () => {
65+
it("handles escaped double quotes in double-quoted strings", () => {
66+
const input = 'echo "hello\\"world\n"'
67+
const expected = `echo "hello\\"world${newlinePlaceholder}"`
68+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
69+
})
70+
71+
it("does not treat backslash as escape in single quotes", () => {
72+
// In single quotes, backslash is literal (except for \' in some shells)
73+
const input = "echo 'hello\\'world\n'"
74+
// The \\ is literal, the ' ends the quote, so world\n is outside quotes
75+
const expected = "echo 'hello\\'world\n'"
76+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
77+
})
78+
})
79+
80+
describe("edge cases", () => {
81+
it("handles unclosed quotes", () => {
82+
const input = 'echo "unclosed\n'
83+
const expected = `echo "unclosed${newlinePlaceholder}`
84+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
85+
})
86+
87+
it("handles empty string", () => {
88+
expect(protectNewlinesInQuotes("", newlinePlaceholder, crPlaceholder)).toBe("")
89+
})
90+
91+
it("handles string with no quotes", () => {
92+
const input = "echo hello\nworld"
93+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(input)
94+
})
95+
96+
it("handles multiple newlines in quotes", () => {
97+
const input = 'echo "line1\nline2\nline3"'
98+
const expected = `echo "line1${newlinePlaceholder}line2${newlinePlaceholder}line3"`
99+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
100+
})
101+
102+
it("handles carriage returns", () => {
103+
const input = 'echo "hello\rworld"'
104+
const expected = `echo "hello${crPlaceholder}world"`
105+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
106+
})
107+
108+
it("handles CRLF", () => {
109+
const input = 'echo "hello\r\nworld"'
110+
const expected = `echo "hello${crPlaceholder}${newlinePlaceholder}world"`
111+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
112+
})
113+
})
114+
115+
describe("real-world git commit examples", () => {
116+
it("protects newlines in git commit message", () => {
117+
const input = `git commit -m "feat: title\n\n- point a\n- point b"`
118+
const expected = `git commit -m "feat: title${newlinePlaceholder}${newlinePlaceholder}- point a${newlinePlaceholder}- point b"`
119+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
120+
})
121+
122+
it("handles complex git command with multiple quoted sections", () => {
123+
const input = `git add . && git commit -m "feat: title\n\n- point a" && echo "done\n"`
124+
const expected = `git add . && git commit -m "feat: title${newlinePlaceholder}${newlinePlaceholder}- point a" && echo "done${newlinePlaceholder}"`
125+
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
126+
})
127+
})
128+
})

webview-ui/src/utils/__tests__/command-validation.spec.ts

Lines changed: 0 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -13,134 +13,6 @@ import {
1313
createCommandValidator,
1414
containsDangerousSubstitution,
1515
} from "../command-validation"
16-
// kilocode_change start
17-
import {
18-
protectNewlinesInQuotes,
19-
NEWLINE_PLACEHOLDER,
20-
CARRIAGE_RETURN_PLACEHOLDER,
21-
} from "../command-validation-quote-protection"
22-
// kilocode_change end
23-
24-
// kilocode_change start
25-
describe("protectNewlinesInQuotes", () => {
26-
const newlinePlaceholder = NEWLINE_PLACEHOLDER
27-
const crPlaceholder = CARRIAGE_RETURN_PLACEHOLDER
28-
29-
describe("basic quote handling", () => {
30-
it("protects newlines in double quotes", () => {
31-
const input = 'echo "hello\nworld"'
32-
const expected = `echo "hello${newlinePlaceholder}world"`
33-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
34-
})
35-
36-
it("protects newlines in single quotes", () => {
37-
const input = "echo 'hello\nworld'"
38-
const expected = `echo 'hello${newlinePlaceholder}world'`
39-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
40-
})
41-
42-
it("does not protect newlines outside quotes", () => {
43-
const input = "echo hello\necho world"
44-
const expected = "echo hello\necho world"
45-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
46-
})
47-
})
48-
49-
describe("quote concatenation", () => {
50-
it("handles quote concatenation where content between quotes is NOT quoted", () => {
51-
// In bash: echo '"'A'"' prints "A" (A is not quoted)
52-
const input = `echo '"'A\n'"'`
53-
// The newline after A is NOT inside quotes, so it should NOT be protected
54-
const expected = `echo '"'A\n'"'`
55-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
56-
})
57-
58-
it("handles alternating quotes correctly", () => {
59-
// echo "hello"world"test" -> hello is quoted, world is not, test is quoted
60-
const input = `echo "hello\n"world\n"test\n"`
61-
const expected = `echo "hello${newlinePlaceholder}"world\n"test${newlinePlaceholder}"`
62-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
63-
})
64-
65-
it("handles single quote after double quote", () => {
66-
const input = `echo "hello"'world\n'`
67-
const expected = `echo "hello"'world${newlinePlaceholder}'`
68-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
69-
})
70-
71-
it("handles double quote after single quote", () => {
72-
const input = `echo 'hello'"world\n"`
73-
const expected = `echo 'hello'"world${newlinePlaceholder}"`
74-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
75-
})
76-
})
77-
78-
describe("escaped quotes", () => {
79-
it("handles escaped double quotes in double-quoted strings", () => {
80-
const input = 'echo "hello\\"world\n"'
81-
const expected = `echo "hello\\"world${newlinePlaceholder}"`
82-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
83-
})
84-
85-
it("does not treat backslash as escape in single quotes", () => {
86-
// In single quotes, backslash is literal (except for \' in some shells)
87-
const input = "echo 'hello\\'world\n'"
88-
// The \\ is literal, the ' ends the quote, so world\n is outside quotes
89-
const expected = "echo 'hello\\'world\n'"
90-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
91-
})
92-
})
93-
94-
describe("edge cases", () => {
95-
it("handles unclosed quotes", () => {
96-
const input = 'echo "unclosed\n'
97-
const expected = `echo "unclosed${newlinePlaceholder}`
98-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
99-
})
100-
101-
it("handles empty string", () => {
102-
expect(protectNewlinesInQuotes("", newlinePlaceholder, crPlaceholder)).toBe("")
103-
})
104-
105-
it("handles string with no quotes", () => {
106-
const input = "echo hello\nworld"
107-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(input)
108-
})
109-
110-
it("handles multiple newlines in quotes", () => {
111-
const input = 'echo "line1\nline2\nline3"'
112-
const expected = `echo "line1${newlinePlaceholder}line2${newlinePlaceholder}line3"`
113-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
114-
})
115-
116-
it("handles carriage returns", () => {
117-
const input = 'echo "hello\rworld"'
118-
const expected = `echo "hello${crPlaceholder}world"`
119-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
120-
})
121-
122-
it("handles CRLF", () => {
123-
const input = 'echo "hello\r\nworld"'
124-
const expected = `echo "hello${crPlaceholder}${newlinePlaceholder}world"`
125-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
126-
})
127-
})
128-
129-
describe("real-world git commit examples", () => {
130-
it("protects newlines in git commit message", () => {
131-
const input = `git commit -m "feat: title\n\n- point a\n- point b"`
132-
const expected = `git commit -m "feat: title${newlinePlaceholder}${newlinePlaceholder}- point a${newlinePlaceholder}- point b"`
133-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
134-
})
135-
136-
it("handles complex git command with multiple quoted sections", () => {
137-
const input = `git add . && git commit -m "feat: title\n\n- point a" && echo "done\n"`
138-
const expected = `git add . && git commit -m "feat: title${newlinePlaceholder}${newlinePlaceholder}- point a" && echo "done${newlinePlaceholder}"`
139-
expect(protectNewlinesInQuotes(input, newlinePlaceholder, crPlaceholder)).toBe(expected)
140-
})
141-
})
142-
})
143-
// kilocode_change end
14416

14517
describe("Command Validation", () => {
14618
describe("parseCommand", () => {

0 commit comments

Comments
 (0)