Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add and test validation of multiple vs. single file urls #1580

Merged
merged 1 commit into from
Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Sources/ApolloCodegenLib/ApolloCodegen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ public class ApolloCodegen {
/// Errors which can happen with code generation
public enum CodegenError: Error, LocalizedError {
case folderDoesNotExist(_ url: URL)
case multipleFilesButNotDirectoryURL(_ url: URL)
case singleFileButNotSwiftFileURL(_ url: URL)

public var errorDescription: String? {
switch self {
case .folderDoesNotExist(let url):
return "Can't run codegen trying to run the command from \(url) because there is no folder there! This should be the folder which, at some depth, contains all your `.graphql` files."
case .multipleFilesButNotDirectoryURL(let url):
return "Codegen is requesting multiple file generation, but the URL passed in (\(url)) is not a directory URL. Please check your URL and try again."
case .singleFileButNotSwiftFileURL(let url):
return "Codegen is requesting single file generation, but the URL passed in (\(url)) is a not a Swift file URL. Please check your URL and try again."
}
}
}
Expand All @@ -35,8 +41,17 @@ public class ApolloCodegen {

switch options.outputFormat {
case .multipleFiles(let folderURL):
/// We have to try to create the folder first because the stuff
/// underlying `isDirectoryURL` only works on actual directories
try FileManager.default.apollo.createFolderIfNeeded(at: folderURL)
guard folderURL.apollo.isDirectoryURL else {
throw CodegenError.multipleFilesButNotDirectoryURL(folderURL)
}
case .singleFile(let fileURL):
guard fileURL.apollo.isSwiftFileURL else {
throw CodegenError.singleFileButNotSwiftFileURL(fileURL)
}

try FileManager.default.apollo.createContainingFolderIfNeeded(for: fileURL)
}

Expand Down
44 changes: 29 additions & 15 deletions Sources/ApolloCodegenLib/FileFinder.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
import Foundation

public struct FileFinder {

#if compiler(>=5.3)
/// Version that works if you're using the 5.3 compiler or above
/// - Parameter filePath: The full file path of the file to find. Defaults to the `#filePath` of the caller.
/// - Returns: The file URL for the parent folder.
public static func findParentFolder(from filePath: StaticString = #filePath) -> URL {
self.findParentFolder(from: filePath.apollo.toString)
}
public static func findParentFolder(from filePath: StaticString = #filePath) -> URL {
self.findParentFolder(from: filePath.apollo.toString)
}

/// The URL of a file at a given path
/// - Parameter filePath: The full file path of the file to find
/// - Returns: The file's URL
public static func fileURL(from filePath: StaticString = #filePath) -> URL {
URL(fileURLWithPath: filePath.apollo.toString)
}
#else
/// Version that works if you're using the 5.2 compiler or below
/// - Parameter file: The full file path of the file to find. Defaults to the `#file` of the caller.
/// - Returns: The file URL for the parent folder.
public static func findParentFolder(from filePath: StaticString = #file) -> URL {
self.findParentFolder(from: filePath.apollo.toString)
}
/// Version that works if you're using the 5.2 compiler or below
/// - Parameter file: The full file path of the file to find. Defaults to the `#file` of the caller.
/// - Returns: The file URL for the parent folder.
public static func findParentFolder(from filePath: StaticString = #file) -> URL {
self.findParentFolder(from: filePath.apollo.toString)
}

/// The URL of a file at a given path
/// - Parameter filePath: The full file path of the file to find
/// - Returns: The file's URL
public static func fileURL(from filePath: StaticString = #file) -> URL {
URL(fileURLWithPath: filePath.apollo.toString)
}
#endif

/// Finds the parent folder from a given file path.
/// - Parameter filePath: The full file path, as a string
/// - Returns: The file URL for the parent folder.
public static func findParentFolder(from filePath: String) -> URL {
let url = URL(fileURLWithPath: filePath)
return url.deletingLastPathComponent()
}
public static func findParentFolder(from filePath: String) -> URL {
let url = URL(fileURLWithPath: filePath)
return url.deletingLastPathComponent()
}
}
19 changes: 19 additions & 0 deletions Sources/ApolloCodegenLib/URL+Apollo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ public enum ApolloURLError: Error, LocalizedError {

extension ApolloExtension where Base == URL {

/// Determines if the URL passed in is a directory URL.
///
/// NOTE: Only works if something at the URL already exists.
///
/// - Returns: True if the URL is a directory URL, false if it isn't.
var isDirectoryURL: Bool {
guard
let resourceValues = try? base.resourceValues(forKeys: [.isDirectoryKey]),
let isDirectory = resourceValues.isDirectory else {
return false
}

return isDirectory
}

var isSwiftFileURL: Bool {
base.pathExtension == "swift"
}

/// - Returns: the URL to the parent folder of the current URL.
public func parentFolderURL() -> URL {
base.deletingLastPathComponent()
Expand Down
48 changes: 48 additions & 0 deletions Tests/ApolloCodegenTests/ApolloCodegenTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,54 @@ class ApolloCodegenTests: XCTestCase {
])
}

func testTryingToUseAFileURLToOutputMultipleFilesFails() {
let scriptFolderURL = CodegenTestHelper.cliFolderURL()
let starWarsFolderURL = CodegenTestHelper.starWarsFolderURL()
let starWarsSchemaFileURL = CodegenTestHelper.starWarsSchemaFileURL()
let outputFolder = CodegenTestHelper.outputFolderURL()
let outputFile = outputFolder.appendingPathComponent("API.swift")

let options = ApolloCodegenOptions(outputFormat: .multipleFiles(inFolderAtURL: outputFile),
urlToSchemaFile: starWarsSchemaFileURL,
downloadTimeout: CodegenTestHelper.timeout)
do {
_ = try ApolloCodegen.run(from: starWarsFolderURL,
with: scriptFolderURL,
options: options)
} catch {
switch error {
case ApolloCodegen.CodegenError.multipleFilesButNotDirectoryURL(let url):
XCTAssertEqual(url, outputFile)
default:
XCTFail("Unexpected error running codegen: \(error.localizedDescription)")

}
}
}

func testTryingToUseAFolderURLToOutputASingleFileFails() {
let scriptFolderURL = CodegenTestHelper.cliFolderURL()
let starWarsFolderURL = CodegenTestHelper.starWarsFolderURL()
let starWarsSchemaFileURL = CodegenTestHelper.starWarsSchemaFileURL()
let outputFolder = CodegenTestHelper.outputFolderURL()

let options = ApolloCodegenOptions(outputFormat: .singleFile(atFileURL: outputFolder),
urlToSchemaFile: starWarsSchemaFileURL,
downloadTimeout: CodegenTestHelper.timeout)
do {
_ = try ApolloCodegen.run(from: starWarsFolderURL,
with: scriptFolderURL,
options: options)
} catch {
switch error {
case ApolloCodegen.CodegenError.singleFileButNotSwiftFileURL(let url):
XCTAssertEqual(url, outputFolder)
default:
XCTFail("Unexpected error running codegen: \(error.localizedDescription)")
}
}
}

func testCodegenWithSingleFileOutputsSingleFile() throws {
let scriptFolderURL = CodegenTestHelper.cliFolderURL()
let starWarsFolderURL = CodegenTestHelper.starWarsFolderURL()
Expand Down
37 changes: 36 additions & 1 deletion Tests/ApolloCodegenTests/URLExtensionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation
import XCTest
import ApolloCodegenLib
@testable import ApolloCodegenLib
import ApolloCore

class URLExtensionsTests: XCTestCase {
Expand Down Expand Up @@ -68,4 +68,39 @@ class URLExtensionsTests: XCTestCase {

XCTAssertEqual(child, expectedFile)
}

func testIsDirectoryForExistingDirectory() {
let parentDirectory = FileFinder.findParentFolder()
XCTAssertTrue(FileManager.default.apollo.folderExists(at: parentDirectory))
XCTAssertTrue(parentDirectory.apollo.isDirectoryURL)
}

func testIsDirectoryForExistingFile() {
let currentFileURL = FileFinder.fileURL()
XCTAssertTrue(FileManager.default.apollo.fileExists(at: currentFileURL))
XCTAssertFalse(currentFileURL.apollo.isDirectoryURL)
}

func testIsSwiftFileForExistingFile() {
let currentFileURL = FileFinder.fileURL()
XCTAssertTrue(FileManager.default.apollo.fileExists(at: currentFileURL))
XCTAssertTrue(currentFileURL.apollo.isSwiftFileURL)
}

func testIsSwiftFileForNonExistentFileWithSingleExtension() {
let currentDirectory = FileFinder.findParentFolder()
let doesntExist = currentDirectory.appendingPathComponent("test.swift")

XCTAssertFalse(FileManager.default.apollo.fileExists(at: doesntExist))
XCTAssertTrue(doesntExist.apollo.isSwiftFileURL)
}

func testIsSwiftFileForNonExistentFileWithMultipleExtensions() {
let currentDirectory = FileFinder.findParentFolder()
let doesntExist = currentDirectory.appendingPathComponent("test.graphql.swift")

XCTAssertFalse(FileManager.default.apollo.fileExists(at: doesntExist))
XCTAssertTrue(doesntExist.apollo.isSwiftFileURL)
}

}