Skip to content

Commit

Permalink
Fix error thrown on adding framework reference
Browse files Browse the repository at this point in the history
- Replace check `isFile` with `exists` for a filePath in `addFile`
  method defined in PBXProjObjects+Helpers.swift
- Add checks for supported files based on PBXFileReference's
  `fileTypeHash`
- Add some more test cases

Misc:
- Add XCTAssertThrowsSpecificError assert to check if specific error was
  thrown
  • Loading branch information
Alexey Fayzullov committed Feb 12, 2018
1 parent abedbdc commit 88e37ea
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 22 deletions.
Empty file added Fixtures/directory/.gitkeep
Empty file.
Empty file.
Empty file added Fixtures/unsupported.xyz
Empty file.
21 changes: 14 additions & 7 deletions Sources/xcproj/PBXProjObjects+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,14 @@ public extension PBXProj.Objects {
sourceTree: PBXSourceTree = .group,
sourceRoot: Path) throws -> ObjectReference<PBXFileReference> {

guard filePath.isFile else {
throw XCodeProjEditingError.notAFile(path: filePath)
guard filePath.exists else {
throw XCodeProjEditingError.fileNotExists(path: filePath)
}

guard let fileType = PBXFileReference.fileType(path: filePath) else {
throw XCodeProjEditingError.unsupportedFileType(path: filePath)
}

guard let groupReference = groups.first(where: { $0.value == toGroup })?.key else {
throw XCodeProjEditingError.groupNotFound(group: toGroup)
}
Expand Down Expand Up @@ -133,8 +137,8 @@ public extension PBXProj.Objects {
let fileReference = PBXFileReference(
sourceTree: sourceTree,
name: filePath.lastComponent,
explicitFileType: PBXFileReference.fileType(path: filePath),
lastKnownFileType: PBXFileReference.fileType(path: filePath),
explicitFileType: fileType,
lastKnownFileType: fileType,
path: path?.string
)
let reference = generateReference(fileReference, filePath.string)
Expand Down Expand Up @@ -200,13 +204,16 @@ public struct GroupAddingOptions: OptionSet {
}

public enum XCodeProjEditingError: Error, CustomStringConvertible {
case notAFile(path: Path)
case unsupportedFileType(path: Path)
case fileNotExists(path: Path)
case groupNotFound(group: PBXGroup)

public var description: String {
switch self {
case .notAFile(let path):
return "\(path) is not a file path"
case .unsupportedFileType(let path):
return "\(path) is not supported."
case .fileNotExists(let path):
return "\(path) doesn't exist."
case .groupNotFound(let group):
return "Group not found in project: \(group)"
}
Expand Down
13 changes: 13 additions & 0 deletions Tests/xcprojTests/XCTestCase+Assertions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,17 @@ extension XCTestCase {
}
return unwrappedObj
}

typealias EquatableError = Error & Equatable
func XCTAssertThrowsSpecificError<T, E: EquatableError>(_ expression: @autoclosure () throws -> T, _ error: E, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
XCTAssertThrowsError(expression, message, file: file, line: line) { actualError in
let message = "Expected \(error) got \(actualError)"

guard let actualCastedError = actualError as? E else {
XCTFail(message, file: file, line: line)
return
}
XCTAssertEqual(actualCastedError, error, message, file: file, line: line)
}
}
}
102 changes: 87 additions & 15 deletions Tests/xcprojTests/XcodeProjIntegrationSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,34 +138,86 @@ final class XcodeProjIntegrationSpec: XCTestCase {
XCTAssertEqual(project.pbxproj.objects.groups[newGroups[1].reference], newGroups[1].object)
}

func test_add_new_file() throws {
func test_add_new_source_file() throws {
let proj = projectiOS()!.pbxproj
let filePath = fixturesPath() + "newfile.swift"
let iOSGroup = proj.objects.group(named: "iOS", inGroup: proj.rootGroup)!
let file = try proj.objects.addFile(at: filePath, toGroup: iOSGroup.object, sourceRoot: fixturesPath() + "iOS")

let expectedFile = PBXFileReference(sourceTree: .group,
name: "newfile.swift",
explicitFileType: "sourcecode.swift",
lastKnownFileType: "sourcecode.swift",
path: "../../newfile.swift")

XCTAssertEqual(proj.objects.fileReferences[file.reference], file.object)
XCTAssertEqual(file.object.name, "newfile.swift")
XCTAssertEqual(file.object.sourceTree, PBXSourceTree.group)
XCTAssertEqual(file.object.path, "../../newfile.swift")
XCTAssertEqual(file.object, expectedFile)
XCTAssertNotNil(iOSGroup.object.children.index(of: file.reference))

let existingFile = try proj.objects.addFile(at: filePath, toGroup: proj.rootGroup, sourceRoot: fixturesPath() + "iOS")

XCTAssertTrue(file == existingFile)
}

func test_add_not_a_file() throws {
func test_add_new_dynamic_framework() throws {
let proj = projectiOS()!.pbxproj
do {
_ = try proj.objects.addFile(at: fixturesPath() + "iOS/iOS", toGroup: proj.rootGroup, sourceRoot: fixturesPath() + "iOS")
XCTFail("Adding not file path should throw error")
} catch {}

do {
_ = try proj.objects.addFile(at: fixturesPath() + "iOS/iOS/newfile.swift", toGroup: proj.rootGroup, sourceRoot: fixturesPath() + "iOS")
XCTFail("Adding not existing file should throw error")
} catch {}
let filePath = fixturesPath() + "dummy.framework"

let iOSGroup = proj.objects.group(named: "iOS", inGroup: proj.rootGroup)!
let file = try proj.objects.addFile(at: filePath,
toGroup: iOSGroup.object,
sourceRoot: fixtureiOSSourcePath())

let expectedFile = PBXFileReference(sourceTree: .group,
name: "dummy.framework",
explicitFileType: "wrapper.framework",
lastKnownFileType: "wrapper.framework",
path: "../../dummy.framework")


XCTAssertEqual(proj.objects.fileReferences[file.reference], file.object)
XCTAssertEqual(file.object, expectedFile)
XCTAssertNotNil(iOSGroup.object.children.index(of: file.reference))
}

func test_add_existing_file_returns_existing_object() throws {
let proj = projectiOS()!.pbxproj
let filePath = fixturesPath() + "newfile.swift"
let iOSGroup = proj.objects.group(named: "iOS", inGroup: proj.rootGroup)!.object

let file = try proj.objects.addFile(at: filePath, toGroup: iOSGroup, sourceRoot: fixtureiOSSourcePath())
let existingFile = try proj.objects.addFile(at: filePath, toGroup: proj.rootGroup, sourceRoot: fixtureiOSSourcePath())
XCTAssertTrue(file == existingFile)
}

func test_add_unsupported_file_throws() {
let proj = projectiOS()!.pbxproj
let filePath = fixturesPath() + "unsupported.xyz"
XCTAssertThrowsSpecificError(
try proj.objects.addFile(at: filePath, toGroup: proj.rootGroup, sourceRoot: fixtureiOSSourcePath()),
XCodeProjEditingError.unsupportedFileType(path: filePath),
"Adding file reference to unsupported file type should throw an error"
)
}

func test_add_directory_throws() {
let proj = projectiOS()!.pbxproj
let filePath = fixturesPath() + "directory"
XCTAssertThrowsSpecificError(
try proj.objects.addFile(at: filePath, toGroup: proj.rootGroup, sourceRoot: fixtureiOSSourcePath()),
XCodeProjEditingError.unsupportedFileType(path: filePath),
"Adding a directory as a file reference should throw an error"
)
}

func test_add_nonexisting_file_throws() {
let proj = projectiOS()!.pbxproj
let filePath = fixturesPath() + "nonexisting.swift"
XCTAssertThrowsSpecificError(
try proj.objects.addFile(at: filePath, toGroup: proj.rootGroup, sourceRoot: fixtureiOSSourcePath()),
XCodeProjEditingError.fileNotExists(path: filePath),
"Adding a reference to non existing file should throw an error"
)
}

func test_add_new_build_file() throws {
Expand Down Expand Up @@ -255,6 +307,10 @@ final class XcodeProjIntegrationSpec: XCTestCase {
return fixturesPath() + "iOS/Project.xcodeproj"
}

private func fixtureiOSSourcePath() -> Path {
return fixturesPath() + "iOS"
}

private func projectiOS() -> XcodeProj? {
return try? XcodeProj(path: fixtureiOSProjectPath())
}
Expand All @@ -263,3 +319,19 @@ final class XcodeProjIntegrationSpec: XCTestCase {
return try XcodeProj(path: fixtureWithoutWorkspaceProjectPath())
}
}

// This could be code generated (e.g. using sourcery)
extension XCodeProjEditingError: Equatable {
static public func == (lhs: XCodeProjEditingError, rhs: XCodeProjEditingError) -> Bool {
switch (lhs, rhs) {
case (.unsupportedFileType(let path1), .unsupportedFileType(let path2)):
return path1 == path2
case (.fileNotExists(let path1), .fileNotExists(let path2)):
return path1 == path2
case (.groupNotFound(let group1), .groupNotFound(let group2)):
return group1 == group2
default:
return false
}
}
}

0 comments on commit 88e37ea

Please sign in to comment.