This commit is contained in:
2023-03-10 17:03:57 -05:00
parent c4ac51a1c0
commit 7d69982605
7 changed files with 342 additions and 13 deletions

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "GitVersionTests"
BuildableName = "GitVersionTests"
BlueprintName = "GitVersionTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "swift-git-version"
BuildableName = "swift-git-version"
BlueprintName = "swift-git-version"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "GitVersionTests"
BuildableName = "GitVersionTests"
BlueprintName = "GitVersionTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
viewDebuggingEnabled = "No">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "swift-git-version"
BuildableName = "swift-git-version"
BlueprintName = "swift-git-version"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "swift-git-version"
BuildableName = "swift-git-version"
BlueprintName = "swift-git-version"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -24,8 +24,8 @@ let package = Package(
]
),
.testTarget(
name: "swift-git-versionTests",
dependencies: ["swift-git-version"]
name: "GitVersionTests",
dependencies: ["GitVersion"]
),
]
)

View File

@@ -0,0 +1,157 @@
import Dependencies
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
import XCTestDynamicOverlay
public struct FileClient {
/// Read the file contents from the given `URL` as `Data`.
///
public private(set) var read: (URL) throws -> Data
/// Write `Data` to a file `URL`.
public private(set) var write: (Data, URL) throws -> Void
/// Create a new ``GitVersion/FileClient`` instance.
///
/// This is generally not interacted with directly, instead access as a dependency.
///
///```swift
/// @Dependency(\.fileClient) var fileClient
///```
///
/// - Parameters:
/// - read: Read the file contents.
/// - write: Write the data to a file.
public init(
read: @escaping (URL) throws -> Data,
write: @escaping (Data, URL) throws -> Void
) {
self.read = read
self.write = write
}
/// Read a file at the given path.
///
/// - Parameters:
/// - path: The path to read the file at.
public func read(path: String) throws -> Data {
let url = try url(for: path)
return try self.read(url)
}
/// Read the file as a string.
///
/// - Parameters:
/// - url: The url for the file.
public func readAsString(url: URL) throws -> String {
let data = try read(url)
return String(decoding: data, as: UTF8.self)
}
/// Read the file as a string
///
/// - Parameters:
/// - path: The file path to read.
public func readAsString(path: String) throws -> String {
try self.readAsString(url: url(for: path))
}
/// Read the contents of a file and decode as the decodable type.
///
/// - Parameters:
/// - decodable: The type to decode.
/// - url: The file url.
/// - decoder: The decoder to use.
public func read<D: Decodable>(
_ decodable: D.Type,
from url: URL,
using decoder: JSONDecoder = .init()
) throws -> D {
let data = try read(url)
return try decoder.decode(D.self, from: data)
}
/// Read the contents of a file and decode as the decodable type.
///
/// - Parameters:
/// - decodable: The type to decode.
/// - path: The file path.
/// - decoder: The decoder to use.
public func read<D: Decodable>(
_ decodable: D.Type,
from path: String,
using decoder: JSONDecoder = .init()
) throws -> D {
let data = try read(path: path)
return try decoder.decode(D.self, from: data)
}
/// Write the data to a file at the given path.
///
/// - Parameters:
/// - data: The data to write to the file.
/// - path: The file path.
public func write(data: Data, to path: String) throws {
let url = try url(for: path)
try self.write(data, url)
}
}
extension FileClient: DependencyKey {
/// A ``FileClient`` that does not do anything.
public static let noop = FileClient.init(
read: { _ in Data() },
write: { _, _ in }
)
/// An `unimplemented` ``FileClient``.
public static let testValue = FileClient(
read: unimplemented("\(Self.self).read", placeholder: Data()),
write: unimplemented("\(Self.self).write")
)
/// The live ``FileClient``
public static let liveValue = FileClient(
read: { try Data(contentsOf: $0) },
write: { try $0.write(to: $1, options: .atomic) }
)
}
extension DependencyValues {
/// Access a basic ``FileClient`` that can read / write data to the file system.
///
public var fileClient: FileClient {
get { self[FileClient.self] }
set { self[FileClient.self] = newValue }
}
}
// MARK: - Overrides
extension FileClient {
/// Override the data that get's returned when a `read` operation is called.
///
/// This is useful in a testing context.
///
/// - Parameters:
/// - data: The data to return when a read operation is called.
public mutating func overrideRead(data: Data) {
self.read = { _ in data }
}
}
// MARK: - Private
fileprivate func url(for path: String) throws -> URL {
if #available(macOS 13.0, *) {
return URL(filePath: path)
} else {
// Fallback on earlier versions
return URL(fileURLWithPath: path)
}
}

View File

@@ -1,6 +1,8 @@
import GitVersion
import ShellClient
// An example of using the git version client.
@main
public struct swift_git_version {
public static func main() {

View File

@@ -0,0 +1,39 @@
import XCTest
import GitVersion
import ShellClient
final class GitVersionTests: XCTestCase {
func test_overrides_work() throws {
try withDependencies {
$0.gitVersionClient.override(with: "blob")
} operation: {
@Dependency(\.gitVersionClient) var versionClient
let version = try versionClient.currentVersion()
XCTAssertEqual(version, "blob")
}
}
func test_live() throws {
try withDependencies({
$0.logger.logLevel = .debug
$0.logger = .liveValue
$0.shellClient = .liveValue
$0.gitVersionClient = .liveValue
}, operation: {
@Dependency(\.gitVersionClient) var versionClient
let gitDir = URL(fileURLWithPath: #file)
.deletingLastPathComponent()
.deletingLastPathComponent()
.deletingLastPathComponent()
let version = try versionClient.currentVersion(in: gitDir.absoluteString)
// can't really have a predictable result for the live client.
XCTAssertNotEqual(version, "blob")
})
}
}

View File

@@ -1,11 +0,0 @@
import XCTest
@testable import swift_git_version
final class swift_git_versionTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(swift_git_version().text, "Hello, World!")
}
}