Compare commits

..

2 Commits

Author SHA1 Message Date
Max Howell
6b52932e7b Merge pull request #27 from mxcl/codecov
More coverage
2019-01-31 16:29:08 -05:00
Max Howell
c456081e65 More coverage 2019-01-31 14:26:09 -05:00
3 changed files with 80 additions and 17 deletions

View File

@@ -1,4 +1,7 @@
import Foundation import Foundation
#if os(Linux)
import Glibc
#endif
public extension Path { public extension Path {
//MARK: File Management //MARK: File Management
@@ -25,6 +28,11 @@ public extension Path {
if overwrite, to.isFile, isFile { if overwrite, to.isFile, isFile {
try FileManager.default.removeItem(at: to.url) try FileManager.default.removeItem(at: to.url)
} }
#if os(Linux) && !swift(>=5.1) // check if fixed
if !overwrite, to.isFile {
throw CocoaError.error(.fileWriteFileExists)
}
#endif
try FileManager.default.copyItem(atPath: string, toPath: to.string) try FileManager.default.copyItem(atPath: string, toPath: to.string)
return to return to
} }
@@ -53,20 +61,16 @@ public extension Path {
@discardableResult @discardableResult
func copy(into: Path, overwrite: Bool = false) throws -> Path { func copy(into: Path, overwrite: Bool = false) throws -> Path {
if !into.exists { if !into.exists {
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true) try FileManager.default.createDirectory(at: into.url, withIntermediateDirectories: true)
} }
let rv = into/basename() let rv = into/basename()
if overwrite, rv.isFile { if overwrite, rv.isFile {
try rv.delete() try rv.delete()
} }
#if os(Linux) #if os(Linux) && !swift(>=5.1) // check if fixed
#if swift(>=5.1)
// check if fixed
#else
if !overwrite, rv.isFile { if !overwrite, rv.isFile {
throw CocoaError.error(.fileWriteFileExists) throw CocoaError.error(.fileWriteFileExists)
} }
#endif
#endif #endif
try FileManager.default.copyItem(at: url, to: rv.url) try FileManager.default.copyItem(at: url, to: rv.url)
return rv return rv
@@ -142,13 +146,26 @@ public extension Path {
} }
/** /**
Creates an empty file at this path. Creates an empty file at this path or if the file exists, updates its modification time.
- Returns: `self` to allow chaining. - Returns: `self` to allow chaining.
*/ */
@inlinable @inlinable
@discardableResult @discardableResult
func touch() throws -> Path { func touch() throws -> Path {
return try "".write(to: self) if !exists {
guard FileManager.default.createFile(atPath: string, contents: nil) else {
throw CocoaError.error(.fileWriteUnknown)
}
} else {
#if os(Linux)
let fd = open(string, O_WRONLY)
defer { close(fd) }
futimens(fd, nil)
#else
try FileManager.default.setAttributes([.modificationDate: Date()], ofItemAtPath: string)
#endif
}
return self
} }
/** /**

View File

@@ -169,6 +169,8 @@ class PathTests: XCTestCase {
try root.foo.touch().copy(to: root.bar) try root.foo.touch().copy(to: root.bar)
XCTAssert(root.foo.isFile) XCTAssert(root.foo.isFile)
XCTAssert(root.bar.isFile) XCTAssert(root.bar.isFile)
XCTAssertThrowsError(try root.foo.copy(to: root.bar))
try root.foo.copy(to: root.bar, overwrite: true)
} }
} }
@@ -182,14 +184,25 @@ class PathTests: XCTestCase {
XCTAssertTrue(bar1.exists) XCTAssertTrue(bar1.exists)
XCTAssertTrue(bar2.exists) XCTAssertTrue(bar2.exists)
} }
// test creates intermediary directories
try bar1.copy(into: root1.create.directories)
// test doesnt replace file if copy into a file
let d = try root1.fuz.touch()
XCTAssertThrowsError(try root1.baz.touch().copy(into: d))
XCTAssert(d.isFile)
XCTAssert(root1.baz.isFile)
} }
} }
func testMoveTo() throws { func testMoveTo() throws {
try Path.mktemp { root in try Path.mktemp { tmpdir in
try root.foo.touch().move(to: root.bar) try tmpdir.foo.touch().move(to: tmpdir.bar)
XCTAssertFalse(root.foo.exists) XCTAssertFalse(tmpdir.foo.exists)
XCTAssert(root.bar.isFile) XCTAssert(tmpdir.bar.isFile)
XCTAssertThrowsError(try tmpdir.foo.touch().move(to: tmpdir.bar))
try tmpdir.foo.move(to: tmpdir.bar, overwrite: true)
} }
} }
@@ -203,6 +216,17 @@ class PathTests: XCTestCase {
XCTAssertFalse(bar1.exists) XCTAssertFalse(bar1.exists)
XCTAssertTrue(bar2.exists) XCTAssertTrue(bar2.exists)
} }
// test creates intermediary directories
try root1.baz.touch().move(into: root1.create.directories)
XCTAssertFalse(root1.baz.exists)
XCTAssert(root1.create.directories.baz.isFile)
// test doesnt replace file if move into a file
let d = try root1.fuz.touch()
XCTAssertThrowsError(try root1.baz.touch().move(into: d))
XCTAssert(d.isFile)
XCTAssert(root1.baz.isFile)
} }
} }
@@ -225,7 +249,7 @@ class PathTests: XCTestCase {
XCTAssertEqual(Path.root.string, "/") XCTAssertEqual(Path.root.string, "/")
XCTAssertEqual(Path.home.string, NSHomeDirectory()) XCTAssertEqual(Path.home.string, NSHomeDirectory())
XCTAssertEqual(Path.documents.string, NSHomeDirectory() + "/Documents") XCTAssertEqual(Path.documents.string, NSHomeDirectory() + "/Documents")
#if os(macOS) #if !os(Linux)
XCTAssertEqual(Path.caches.string, NSHomeDirectory() + "/Library/Caches") XCTAssertEqual(Path.caches.string, NSHomeDirectory() + "/Library/Caches")
XCTAssertEqual(Path.cwd.string, FileManager.default.currentDirectoryPath) XCTAssertEqual(Path.cwd.string, FileManager.default.currentDirectoryPath)
XCTAssertEqual(Path.applicationSupport.string, NSHomeDirectory() + "/Library/Application Support") XCTAssertEqual(Path.applicationSupport.string, NSHomeDirectory() + "/Library/Application Support")
@@ -298,6 +322,9 @@ class PathTests: XCTestCase {
let now2 = Date().timeIntervalSince1970.rounded(.down) let now2 = Date().timeIntervalSince1970.rounded(.down)
XCTAssertNotEqual(now1, now2) XCTAssertNotEqual(now1, now2)
XCTAssertEqual(foo.mtime?.timeIntervalSince1970.rounded(.down), now2) //FIXME flakey XCTAssertEqual(foo.mtime?.timeIntervalSince1970.rounded(.down), now2) //FIXME flakey
XCTAssertNil(tmpdir.void.mtime)
XCTAssertNil(tmpdir.void.ctime)
} }
} }
@@ -334,14 +361,15 @@ class PathTests: XCTestCase {
_ = Bundle.main.sharedFrameworks _ = Bundle.main.sharedFrameworks
} }
func testDataExentsions() throws { func testDataExtensions() throws {
let data = try Data(contentsOf: Path(#file)!) let data = try Data(contentsOf: Path(#file)!)
try Path.mktemp { tmpdir in try Path.mktemp { tmpdir in
_ = try data.write(to: tmpdir.foo) _ = try data.write(to: tmpdir.foo)
_ = try data.write(to: tmpdir.foo, atomically: true)
} }
} }
func testStringExentsions() throws { func testStringExtensions() throws {
let string = try String(contentsOf: Path(#file)!) let string = try String(contentsOf: Path(#file)!)
try Path.mktemp { tmpdir in try Path.mktemp { tmpdir in
_ = try string.write(to: tmpdir.foo) _ = try string.write(to: tmpdir.foo)
@@ -353,4 +381,20 @@ class PathTests: XCTestCase {
_ = try FileHandle(forWritingAt: Path(#file)!) _ = try FileHandle(forWritingAt: Path(#file)!)
_ = try FileHandle(forUpdatingAt: Path(#file)!) _ = try FileHandle(forUpdatingAt: Path(#file)!)
} }
func testSort() {
XCTAssertEqual([Path.root.a, Path.root.c, Path.root.b].sorted(), [Path.root.a, Path.root.b, Path.root.c])
}
func testLock() throws {
#if !os(Linux)
try Path.mktemp { tmpdir in
let bar = try tmpdir.bar.touch()
try bar.lock()
XCTAssertThrowsError(try bar.touch())
try bar.unlock()
try bar.touch()
}
#endif
}
} }

View File

@@ -9,7 +9,7 @@ extension PathTests {
("testConcatenation", testConcatenation), ("testConcatenation", testConcatenation),
("testCopyInto", testCopyInto), ("testCopyInto", testCopyInto),
("testCopyTo", testCopyTo), ("testCopyTo", testCopyTo),
("testDataExentsions", testDataExentsions), ("testDataExtensions", testDataExtensions),
("testDelete", testDelete), ("testDelete", testDelete),
("testDynamicMember", testDynamicMember), ("testDynamicMember", testDynamicMember),
("testEnumeration", testEnumeration), ("testEnumeration", testEnumeration),
@@ -20,6 +20,7 @@ extension PathTests {
("testFilesystemAttributes", testFilesystemAttributes), ("testFilesystemAttributes", testFilesystemAttributes),
("testIsDirectory", testIsDirectory), ("testIsDirectory", testIsDirectory),
("testJoin", testJoin), ("testJoin", testJoin),
("testLock", testLock),
("testMkpathIfExists", testMkpathIfExists), ("testMkpathIfExists", testMkpathIfExists),
("testMktemp", testMktemp), ("testMktemp", testMktemp),
("testMoveInto", testMoveInto), ("testMoveInto", testMoveInto),
@@ -28,8 +29,9 @@ extension PathTests {
("testRelativePathCodable", testRelativePathCodable), ("testRelativePathCodable", testRelativePathCodable),
("testRelativeTo", testRelativeTo), ("testRelativeTo", testRelativeTo),
("testRename", testRename), ("testRename", testRename),
("testSort", testSort),
("testStringConvertibles", testStringConvertibles), ("testStringConvertibles", testStringConvertibles),
("testStringExentsions", testStringExentsions), ("testStringExtensions", testStringExtensions),
("testTimes", testTimes), ("testTimes", testTimes),
] ]
} }