@@ -17,47 +17,79 @@ import TSCBasic
1717import XCTest
1818
1919final class CompilationDatabaseTests : XCTestCase {
20- func testSplitShellEscapedCommand( ) {
21- func check( _ str: String , _ expected: [ String ] , file: StaticString = #filePath, line: UInt = #line) {
22- XCTAssertEqual ( splitShellEscapedCommand ( str) , expected, file: file, line: line)
23- }
20+ func testSplitShellEscapedCommandBasic( ) {
21+ assertEscapedCommand ( " " , [ ] )
22+ assertEscapedCommand ( " " , [ ] )
23+ assertEscapedCommand ( " a " , [ " a " ] )
24+ assertEscapedCommand ( " abc " , [ " abc " ] )
25+ assertEscapedCommand ( " a😀c " , [ " a😀c " ] )
26+ assertEscapedCommand ( " 😀c " , [ " 😀c " ] )
27+ assertEscapedCommand ( " abc def " , [ " abc " , " def " ] )
28+ assertEscapedCommand ( " abc def " , [ " abc " , " def " ] )
29+ }
30+
31+ func testSplitShellEscapedCommandDoubleQuotes( ) {
32+ assertEscapedCommand ( " \" " , [ " " ] )
33+ assertEscapedCommand ( #""a"# , [ " a " ] )
34+ assertEscapedCommand ( " \" \" " , [ " " ] )
35+ assertEscapedCommand ( #""a""# , [ " a " ] )
36+ assertEscapedCommand ( #""a\"""# , [ #"a""# ] )
37+ assertEscapedCommand ( #""a b c ""# , [ " a b c " ] )
38+ assertEscapedCommand ( #""a " "# , [ " a " ] )
39+ assertEscapedCommand ( #""a " b"# , [ " a " , " b " ] )
40+ assertEscapedCommand ( #""a "b"# , [ " a b " ] )
41+ assertEscapedCommand ( #"a"x ""b"# , [ " ax b " ] , windows: [ #"ax "b"# ] )
42+
43+ assertEscapedCommand ( #""a"bcd"ef""""g""# , [ " abcdefg " ] , windows: [ #"abcdef""g"# ] )
44+ }
45+
46+ func testSplitShellEscapedCommandSingleQuotes( ) {
47+ assertEscapedCommand ( " ' " , [ " " ] , windows: [ " ' " ] )
48+ assertEscapedCommand ( " 'a " , [ " a " ] , windows: [ " 'a " ] )
49+ assertEscapedCommand ( " '' " , [ " " ] , windows: [ " '' " ] )
50+ assertEscapedCommand ( " 'a' " , [ " a " ] , windows: [ " 'a' " ] )
51+ assertEscapedCommand ( #"'a\"'"# , [ #"a\""# ] , windows: [ #"'a"'"# ] )
52+ assertEscapedCommand ( #"'a b c '"# , [ " a b c " ] , windows: [ " 'a " , " b " , " c " , " ' " ] )
53+ assertEscapedCommand ( #"'a ' "# , [ " a " ] , windows: [ " 'a " , " ' " ] )
54+ assertEscapedCommand ( #"'a ' b"# , [ " a " , " b " ] , windows: [ " 'a " , " ' " , " b " ] )
55+ assertEscapedCommand ( #"'a 'b"# , [ " a b " ] , windows: [ " 'a " , " 'b " ] )
56+ assertEscapedCommand ( #"a'x ''b"# , [ " ax b " ] , windows: [ " a'x " , " ''b " ] )
57+ }
2458
25- check ( " " , [ ] )
26- check ( " " , [ ] )
27- check ( " a " , [ " a " ] )
28- check ( " abc " , [ " abc " ] )
29- check ( " a😀c " , [ " a😀c " ] )
30- check ( " 😀c " , [ " 😀c " ] )
31- check ( " abc def " , [ " abc " , " def " ] )
32- check ( " abc def " , [ " abc " , " def " ] )
33-
34- check ( " \" " , [ " " ] )
35- check ( " \" a " , [ " a " ] )
36- check ( " \" \" " , [ " " ] )
37- check ( " \" a \" " , [ " a " ] )
38- check ( " \" a \\ \" \" " , [ " a \" " ] )
39- check ( " \" a b c \" " , [ " a b c " ] )
40- check ( " \" a \" " , [ " a " ] )
41- check ( " \" a \" b " , [ " a " , " b " ] )
42- check ( " \" a \" b " , [ " a b " ] )
43- check ( " a \" x \" \" b " , [ " ax b " ] )
44-
45- check ( " \' " , [ " " ] )
46- check ( " \' a " , [ " a " ] )
47- check ( " \' \' " , [ " " ] )
48- check ( " \' a \' " , [ " a " ] )
49- check ( " \' a \\ \" \' " , [ " a \\ \" " ] )
50- check ( " \' a b c \' " , [ " a b c " ] )
51- check ( " \' a \' " , [ " a " ] )
52- check ( " \' a \' b " , [ " a " , " b " ] )
53- check ( " \' a \' b " , [ " a b " ] )
54- check ( " a \' x \' \' b " , [ " ax b " ] )
55-
56- check ( " a \\ \\ " , [ " a \\ " ] )
57- check ( " \" a \" bcd \" ef \" \" \" \" g \" " , [ " abcdefg " ] )
58- check ( " a' \\ b \" c \" ' " , [ " a \\ b \" c \" " ] )
59+ func testSplitShellEscapedCommandBackslash( ) {
60+ assertEscapedCommand ( #"a\\"# , [ #"a\"# ] , windows: [ #"a\\"# ] )
61+ assertEscapedCommand ( #"a'\b "c"'"# , [ " a \\ b \" c \" " ] , windows: [ #"a'\b"# , #"c'"# ] )
62+
63+ assertEscapedCommand ( #"\""# , [ " \" " ] )
64+ assertEscapedCommand ( #"\\""# , [ #"\"# ] )
65+ assertEscapedCommand ( #"\\\""# , [ #"\""# ] )
66+ assertEscapedCommand ( #"\\ "# , [ #"\"# ] , windows: [ #"\\"# ] )
67+ assertEscapedCommand ( #"\\\ "# , [ #"\ "# ] , windows: [ #"\\\"# ] )
68+ }
69+
70+ func testSplitShellEscapedCommandWindowsCommand( ) {
71+ assertEscapedCommand ( #"C:\swift.exe"# , [ #"C:swift.exe"# ] , windows: [ #"C:\swift.exe"# ] , initialCommandName: true )
72+ assertEscapedCommand (
73+ #"C:\ swift.exe"# ,
74+ [ #"C: swift.exe"# ] ,
75+ windows: [ #"C:\"# , #"swift.exe"# ] ,
76+ initialCommandName: true
77+ )
78+ assertEscapedCommand (
79+ #"C:\ swift.exe"# ,
80+ [ #"C: swift.exe"# ] ,
81+ windows: [ #"C:\"# , #"swift.exe"# ] ,
82+ initialCommandName: false
83+ )
84+ assertEscapedCommand ( #"C:\"swift.exe""# , [ #"C:"swift.exe"# ] , windows: [ #"C:\swift.exe"# ] , initialCommandName: true )
85+ assertEscapedCommand ( #"C:\"swift.exe""# , [ #"C:"swift.exe"# ] , windows: [ #"C:"swift.exe"# ] , initialCommandName: false )
5986 }
6087
88+ func testSplitShellEscapedCommandWindowsTwoDoubleQuotes( ) {
89+ assertEscapedCommand ( #"" test with "" quote""# , [ " test with quote " ] , windows: [ #" test with " quote"# ] )
90+ assertEscapedCommand ( #"" test with "" quote""# , [ " test with quote " ] , windows: [ #" test with " quote"# ] )
91+ }
92+
6193 func testEncodeCompDBCommand( ) throws {
6294 // Requires JSONEncoder.OutputFormatting.sortedKeys
6395 func check( _ cmd: CompilationDatabase . Command , _ expected: String , file: StaticString = #filePath, line: UInt = #line) throws {
@@ -332,3 +364,33 @@ private func checkCompilationDatabaseBuildSystem(_ compdb: ByteString, file: Sta
332364 let buildSystem = CompilationDatabaseBuildSystem ( projectRoot: try AbsolutePath ( validating: " /a " ) , fileSystem: fs)
333365 try block ( buildSystem)
334366}
367+
368+ /// Assert that splitting `str` into its command line components results in `expected`.
369+ ///
370+ /// By default assert that escaping using Unix and Windows rules results in the same split. If `windows` is specified,
371+ /// assert that escaping with Windows rules produces `windows` and escaping using Unix rules results in `expected`.
372+ ///
373+ /// If set `initialCommandName` gets passed to the Windows split function.
374+ private func assertEscapedCommand(
375+ _ str: String ,
376+ _ expected: [ String ] ,
377+ windows: [ String ] ? = nil ,
378+ initialCommandName: Bool = false ,
379+ file: StaticString = #filePath,
380+ line: UInt = #line
381+ ) {
382+ XCTAssertEqual (
383+ splitShellEscapedCommand ( str) ,
384+ expected,
385+ " Splitting Unix command line arguments " ,
386+ file: file,
387+ line: line
388+ )
389+ XCTAssertEqual (
390+ splitWindowsCommandLine ( str, initialCommandName: initialCommandName) ,
391+ windows ?? expected,
392+ " Splitting Windows command line arguments " ,
393+ file: file,
394+ line: line
395+ )
396+ }
0 commit comments