Skip to content

Commit 6cb1275

Browse files
committed
WIP: Add in path syntax tests
1 parent 28319c6 commit 6cb1275

File tree

2 files changed

+247
-0
lines changed

2 files changed

+247
-0
lines changed

Sources/SystemInternals/Mocking.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ public class MockingDriver {
8181

8282
// A buffer to put `write` bytes into
8383
public var writeBuffer = WriteBuffer()
84+
85+
// Whether we should pretend to be Windows for syntactic operations
86+
// inside FilePath
87+
public var forceWindowsSyntaxForPaths = false
8488
}
8589

8690
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
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

Comments
 (0)