|
| 1 | +/* |
| 2 | + This source file is part of the Swift System open source project |
| 3 | + |
| 4 | + Copyright (c) 2020 Apple Inc. and the Swift System project authors |
| 5 | + Licensed under Apache License v2.0 with Runtime Library Exception |
| 6 | + |
| 7 | + See https://swift.org/LICENSE.txt for license information |
| 8 | +*/ |
| 9 | + |
| 10 | +import XCTest |
| 11 | +import SystemPackage |
| 12 | + |
| 13 | + |
| 14 | +struct TestPathSyntax: TestCase { |
| 15 | + var file: StaticString |
| 16 | + var line: UInt |
| 17 | + |
| 18 | + func runAllTests() { |
| 19 | + // ... |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +struct SyntaxTestCase: TestCase { |
| 24 | + // We defer forming the path until `runAllTests()` executes, |
| 25 | + // so that we can switch between unix and windows behavior. |
| 26 | + let pathStr: String |
| 27 | + |
| 28 | + // Whether we want the path to be constructed and syntactically |
| 29 | + // manipulated as though it were a Windows path |
| 30 | + let isWindows: Bool |
| 31 | + |
| 32 | + let absolute: Bool |
| 33 | + |
| 34 | + let root: String? |
| 35 | + let relative: String? |
| 36 | + |
| 37 | + let rootName: String? |
| 38 | + let rootDirectory: String? |
| 39 | + |
| 40 | + let dirname: String |
| 41 | + let basename: String? |
| 42 | + |
| 43 | + let stem: String? |
| 44 | + let `extension`: String? |
| 45 | + |
| 46 | + var file: StaticString |
| 47 | + var line: UInt |
| 48 | +} |
| 49 | + |
| 50 | +extension SyntaxTestCase { |
| 51 | + static func unix( |
| 52 | + _ path: String, |
| 53 | + root: String?, relative: String, |
| 54 | + dirname: String, basename: String?, |
| 55 | + stem: String?, extension: String? = nil, |
| 56 | + file: StaticString = #file, line: UInt = #line |
| 57 | + ) -> SyntaxTestCase { |
| 58 | + SyntaxTestCase( |
| 59 | + pathStr: path, |
| 60 | + isWindows: false, |
| 61 | + absolute: root != nil, |
| 62 | + root: root, relative: relative, |
| 63 | + rootName: nil, rootDirectory: root, |
| 64 | + dirname: dirname, basename: basename, |
| 65 | + stem: stem, extension: `extension`, |
| 66 | + file: file, line: line) |
| 67 | + } |
| 68 | + |
| 69 | + static func windows( |
| 70 | + _ path: String, |
| 71 | + absolute: Bool, |
| 72 | + root: String?, relative: String, |
| 73 | + rootName: String?, rootDirectory: String?, |
| 74 | + dirname: String, basename: String?, |
| 75 | + stem: String?, extension: String? = nil, |
| 76 | + file: StaticString = #file, line: UInt = #line |
| 77 | + ) -> SyntaxTestCase { |
| 78 | + SyntaxTestCase( |
| 79 | + pathStr: path, |
| 80 | + isWindows: true, |
| 81 | + absolute: absolute, |
| 82 | + root: root, relative: relative, |
| 83 | + rootName: rootName, rootDirectory: rootDirectory, |
| 84 | + dirname: dirname, basename: basename, |
| 85 | + stem: stem, extension: `extension`, |
| 86 | + file: file, line: line) |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +import SystemInternals |
| 91 | +private func withWindowsSupport(enabled: Bool, _ f: () -> ()) { |
| 92 | + guard enabled else { return f() } |
| 93 | + MockingDriver.withMockingEnabled { driver in |
| 94 | + driver.forceWindowsSyntaxForPaths = true |
| 95 | + f() |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +extension SyntaxTestCase { |
| 100 | + func runAllTests() { |
| 101 | + withWindowsSupport(enabled: isWindows) { |
| 102 | + let path = FilePath(pathStr) |
| 103 | + expectEqual(pathStr, path.description) |
| 104 | + |
| 105 | +// expectEqual(absolute, path.isAbsolute) |
| 106 | +// expectEqual(!absolute, path.isRelative) |
| 107 | +// |
| 108 | +// expectEqual(root, path.root?.description) |
| 109 | +// expectEqual(relative, path.relativePath.description) |
| 110 | +// |
| 111 | +// expectEqual(rootName, path.rootName) |
| 112 | +// expectEqual(rootDirectory, path.rootDirectory?.description) |
| 113 | +// |
| 114 | +// expectEqual(dirname, path.dirname.description) |
| 115 | +// expectEqual(basename, path.basename?.description) |
| 116 | +// |
| 117 | +// expectEqual(stem, path.stem) |
| 118 | +// expectEqual(`extension`, path.`extension`) |
| 119 | + } |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +// TODO: lexically normalize tests, lexically relative tests, separator normalization, etc. |
| 124 | + |
| 125 | +let unixPaths: Array<SyntaxTestCase> = [ |
| 126 | + .unix( |
| 127 | + "/usr/bin/ls", |
| 128 | + root: "/", relative: "usr/bin/ls", |
| 129 | + dirname: "/usr/bin", basename: "ls", |
| 130 | + stem: "ls"), |
| 131 | + |
| 132 | + .unix( |
| 133 | + "bin/ls", |
| 134 | + root: nil, relative: "bin/ls", |
| 135 | + dirname: "bin", basename: "ls", |
| 136 | + stem: "ls"), |
| 137 | + |
| 138 | + .unix( |
| 139 | + "~/bar.app", |
| 140 | + root: nil, relative: "~/bar.app", |
| 141 | + dirname: "~", basename: "bar.app", |
| 142 | + stem: "bar", extension: "app"), |
| 143 | + |
| 144 | + .unix( |
| 145 | + "/", |
| 146 | + root: "/", relative: "", |
| 147 | + dirname: "/", basename: nil, |
| 148 | + stem: nil, extension: nil), |
| 149 | + |
| 150 | + .unix( |
| 151 | + "/tmp/.", |
| 152 | + root: "/", relative: "tmp/.", |
| 153 | + dirname: "/tmp/.", basename: ".", |
| 154 | + stem: ".", extension: nil), |
| 155 | + |
| 156 | + .unix( |
| 157 | + "/tmp/..", |
| 158 | + root: "/", relative: "tmp/..", |
| 159 | + dirname: "/tmp/..", basename: "..", |
| 160 | + stem: "..", extension: nil), |
| 161 | + |
| 162 | + .unix( |
| 163 | + "/tmp/.hidden", |
| 164 | + root: "/", relative: "tmp/.hidden", |
| 165 | + dirname: "/tmp/.hidden", basename: ".hidden", |
| 166 | + stem: ".hidden", extension: nil), |
| 167 | + |
| 168 | + // Backslash is not a separator, nor a root |
| 169 | + .unix( |
| 170 | + #"\bin\.\ls"#, |
| 171 | + root: nil, relative: #"\bin\.\ls"#, |
| 172 | + dirname: "", basename: #"\bin\.\ls"#, |
| 173 | + stem: #"\bin\"#, extension: #".\ls"#), |
| 174 | +] |
| 175 | + |
| 176 | +let windowsPaths: Array<SyntaxTestCase> = [ |
| 177 | + .windows( |
| 178 | + #"C:\foo\bar.exe"#, |
| 179 | + absolute: true, |
| 180 | + root: #"C:\"#, relative: #"foo\bar.exe"#, |
| 181 | + rootName: "C:", rootDirectory: #"\"#, |
| 182 | + dirname: #"C:\foo"#, basename: "bar.exe", |
| 183 | + stem: "bar", extension: "exe"), |
| 184 | + |
| 185 | + .windows( |
| 186 | + #"C:foo\bar"#, |
| 187 | + absolute: false, |
| 188 | + root: #"C:`"#, relative: #"foo\bar"#, |
| 189 | + rootName: "C:", rootDirectory: nil, |
| 190 | + dirname: #"C:foo"#, basename: "bar", |
| 191 | + stem: "bar"), |
| 192 | + |
| 193 | + .windows( |
| 194 | + #"\foo\bar.exe"#, |
| 195 | + absolute: false, |
| 196 | + root: #"\"#, relative: #"foo\bar"#, |
| 197 | + rootName: nil, rootDirectory: #"\"#, |
| 198 | + dirname: #"\foo"#, basename: "bar", |
| 199 | + stem: "bar", extension: "exe"), |
| 200 | + |
| 201 | + .windows( |
| 202 | + #"foo\bar.exe"#, |
| 203 | + absolute: false, |
| 204 | + root: nil, relative: #"foo\bar"#, |
| 205 | + rootName: nil, rootDirectory: nil, |
| 206 | + dirname: #"foo"#, basename: "bar", |
| 207 | + stem: "bar", extension: "exe"), |
| 208 | + |
| 209 | + .windows( |
| 210 | + #"\\?\device\folder\file.exe"#, |
| 211 | + absolute: true, |
| 212 | + root: #"\\?\device\"#, relative: #"folder\file.exe"#, |
| 213 | + rootName: #"\\?\device"#, rootDirectory: #"\"#, |
| 214 | + dirname: #"\\?\device\folder"#, basename: "file.exe", |
| 215 | + stem: "file", extension: "exe"), |
| 216 | + |
| 217 | + .windows( |
| 218 | + #"\\?\UNC\server\share\folder\file.txt"#, |
| 219 | + absolute: true, |
| 220 | + root: #"\\?\UNC\server\share\`"#, relative: #"folder\file.txt"#, |
| 221 | + rootName: #"\\?\UNC\server\share"#, rootDirectory: #"\"#, |
| 222 | + dirname: #"\\?\UNC\server\share\folder"#, basename: "file.txt", |
| 223 | + stem: "file", extension: ".txt"), |
| 224 | + |
| 225 | + .windows( |
| 226 | + #"\\server\share\folder\file.txt"#, |
| 227 | + absolute: true, |
| 228 | + root: #"\\server\share\`"#, relative: #"folder\file.txt"#, |
| 229 | + rootName: #"\\server\share"#, rootDirectory: #"\"#, |
| 230 | + dirname: #"\\server\share\folder"#, basename: "file.txt", |
| 231 | + stem: "file", extension: ".txt"), |
| 232 | +] |
| 233 | + |
| 234 | +final class FilePathSyntaxTest: XCTestCase { |
| 235 | + func testRootRelative() { |
| 236 | + for test in unixPaths { |
| 237 | + test.runAllTests() |
| 238 | + } |
| 239 | + for test in windowsPaths { |
| 240 | + test.runAllTests() |
| 241 | + } |
| 242 | + } |
| 243 | +} |
0 commit comments