Skip to content
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
6 changes: 3 additions & 3 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/JohnSundell/Files", from: "4.0.0"),
.package(url: "https://github.com/nikolainobadi/NnGitKit.git", from: "0.6.0"),
.package(url: "https://github.com/nikolainobadi/NnShellKit.git", branch: "enhance-mock-shell"),
// .package(url: "https://github.com/nikolainobadi/NnShellKit.git", from: "1.0.0"),
.package(url: "https://github.com/nikolainobadi/NnShellKit.git", from: "2.0.0"),
.package(url: "https://github.com/nikolainobadi/NnSwiftDataKit", from: "0.5.0"),
.package(url: "https://github.com/nikolainobadi/SwiftPicker.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"),
Expand Down
7 changes: 4 additions & 3 deletions Tests/NnexKitTests/BinaryArchiverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -362,13 +362,14 @@ private extension BinaryArchiverTests {
let shell: MockShell

if !commandResults.isEmpty {
shell = MockShell(resultMap: commandResults, shouldThrowError: throwError)
shell = throwError ? .init(shouldThrowErrorOnFinal: true) : .init(commands: commandResults.map({ .init(command: $0, output: $1) }))
} else {
shell = MockShell(results: runResults, shouldThrowError: throwError)

shell = .init(results: runResults, shouldThrowErrorOnFinal: throwError)
}

let sut = BinaryArchiver(shell: shell)

return (sut, shell)
}
}
}
28 changes: 14 additions & 14 deletions Tests/NnexKitTests/BinaryCopyUtilityTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ struct BinaryCopyUtilityTests {
extension BinaryCopyUtilityTests {
@Test("Returns original binary when output location is current directory")
func returnsOriginalBinaryForCurrentDirectory() throws {
let shell = MockShell()
let sut = makeSUT(shell: shell)
let (sut, shell) = makeSUT()
let originalBinary = BinaryOutput.single(.init(path: sourcePath))
let outputLocation = BuildOutputLocation.currentDirectory(.universal)

Expand All @@ -41,8 +40,7 @@ extension BinaryCopyUtilityTests {

@Test("Copies single binary to desktop")
func copiesSingleBinaryToDesktop() throws {
let shell = MockShell()
let sut = makeSUT(shell: shell)
let (sut, shell) = makeSUT()
let originalBinary = BinaryOutput.single(.init(path: sourcePath))
let outputLocation = BuildOutputLocation.desktop

Expand All @@ -57,8 +55,7 @@ extension BinaryCopyUtilityTests {

@Test("Copies single binary to custom location")
func copiesSingleBinaryToCustomLocation() throws {
let shell = MockShell()
let sut = makeSUT(shell: shell)
let (sut, shell) = makeSUT()
let originalBinary = BinaryOutput.single(.init(path: sourcePath))
let outputLocation = BuildOutputLocation.custom(customPath)

Expand All @@ -76,8 +73,7 @@ extension BinaryCopyUtilityTests {

@Test("Copies multiple binaries to desktop with architecture suffixes")
func copiesMultipleBinariesToDesktop() throws {
let shell = MockShell()
let sut = makeSUT(shell: shell)
let (sut, shell) = makeSUT()
let armBinary = BinaryInfo(path: "/source/arm64")
let intelBinary = BinaryInfo(path: "/source/x86_64")
let originalBinary = BinaryOutput.multiple([
Expand All @@ -97,8 +93,7 @@ extension BinaryCopyUtilityTests {

@Test("Copies multiple binaries to custom location with architecture suffixes")
func copiesMultipleBinariesToCustomLocation() throws {
let shell = MockShell()
let sut = makeSUT(shell: shell)
let (sut, shell) = makeSUT()
let armBinary = BinaryInfo(path: "/source/arm64")
let intelBinary = BinaryInfo(path: "/source/x86_64")
let originalBinary = BinaryOutput.multiple([
Expand All @@ -121,8 +116,7 @@ extension BinaryCopyUtilityTests {

@Test("Preserves paths with spaces using proper quoting")
func preservesPathsWithSpaces() throws {
let shell = MockShell()
let sut = makeSUT(shell: shell)
let (sut, shell) = makeSUT()
let sourceWithSpaces = "/path with/spaces/binary"
let destinationWithSpaces = "/destination with/spaces"
let originalBinary = BinaryOutput.single(.init(path: sourceWithSpaces))
Expand All @@ -136,8 +130,7 @@ extension BinaryCopyUtilityTests {

@Test("Throws error when shell command fails")
func throwsErrorWhenShellCommandFails() throws {
let shell = MockShell(results: [], shouldThrowError: true)
let sut = makeSUT(shell: shell)
let sut = makeSUT(throwError: true).sut
let originalBinary = BinaryOutput.single(.init(path: sourcePath))
let outputLocation = BuildOutputLocation.desktop

Expand All @@ -153,4 +146,11 @@ private extension BinaryCopyUtilityTests {
func makeSUT(shell: MockShell) -> BinaryCopyUtility {
return BinaryCopyUtility(shell: shell)
}

func makeSUT(throwError: Bool = false) -> (sut: BinaryCopyUtility, shell: MockShell) {
let shell = MockShell(shouldThrowErrorOnFinal: throwError)
let sut = BinaryCopyUtility(shell: shell)

return (sut, shell)
}
}
2 changes: 1 addition & 1 deletion Tests/NnexKitTests/GitHandlerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ extension GitHandlerTests {
// MARK: - SUT
private extension GitHandlerTests {
func makeSUT(runResults: [String] = [], throwError: Bool = false) -> (sut: DefaultGitHandler, shell: MockShell) {
let shell = MockShell(results: runResults, shouldThrowError: throwError)
let shell = MockShell(results: runResults, shouldThrowErrorOnFinal: throwError)
let sut = DefaultGitHandler(shell: shell)

return (sut, shell)
Expand Down
2 changes: 1 addition & 1 deletion Tests/NnexKitTests/ProjectBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ extension ProjectBuilderTests {
private extension ProjectBuilderTests {
func makeSUT(buildType: BuildType = .universal, runResults: [String] = [], throwShellError: Bool = false, testCommand: TestCommand? = nil, skipClean: Bool = false) -> (sut: ProjectBuilder, shell: MockShell) {

let shell = MockShell(results: runResults, shouldThrowError: throwShellError)
let shell = MockShell(results: runResults, shouldThrowErrorOnFinal: throwShellError)
let config = BuildConfig(
projectName: projectName,
projectPath: projectPath,
Expand Down
2 changes: 1 addition & 1 deletion Tests/NnexKitTests/PublishUtilitiesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ extension PublishUtilitiesTests {
let binaryFile = try tempFolder.createFile(named: "testBinary")
try binaryFile.write("fake binary content")

let shell = MockShell(results: [], shouldThrowError: true)
let shell = MockShell(shouldThrowErrorOnFinal: true)
let binaryOutput = BinaryOutput.single(.init(path: binaryFile.path))

#expect(throws: (any Error).self) {
Expand Down
2 changes: 1 addition & 1 deletion Tests/nnexTests/ArchiveTests/ProjectDetectorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ extension ProjectDetectorTests {
// MARK: - SUT
private extension ProjectDetectorTests {
func makeSUT(shellOutputs: [String] = [], shouldThrowShellError: Bool = false) -> DefaultProjectDetector {
let shell = MockShell(results: shellOutputs, shouldThrowError: shouldThrowShellError)
let shell = MockShell(results: shellOutputs, shouldThrowErrorOnFinal: shouldThrowShellError)

return .init(shell: shell)
}
Expand Down
65 changes: 17 additions & 48 deletions Tests/nnexTests/Domain/Execution/BuildExecutionManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ extension BuildExecutionManagerTests {
func successfullyExecutesBuildWithSingleExecutable() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: ["", "", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(selectedItemIndices: [0]) // Select current directory

let sut = makeSUT(shell: shell, picker: picker)
let (sut, shell) = makeSUT(selectedItemIndices: [0])

try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)

Expand All @@ -51,10 +48,7 @@ extension BuildExecutionManagerTests {
func successfullyExecutesBuildWithMultipleExecutables() throws {
try createPackageSwiftWithMultipleExecutables()

let shell = MockShell(results: ["", "", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(selectedItemIndices: [0, 0]) // Select first executable, then current directory

let sut = makeSUT(shell: shell, picker: picker)
let sut = makeSUT(selectedItemIndices: [0, 0]).sut

#expect(throws: Never.self) {
try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)
Expand All @@ -67,10 +61,7 @@ extension BuildExecutionManagerTests {
func executesBuildAndOpensInFinderWhenFlagSet() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: ["", "", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(selectedItemIndices: [0]) // Select current directory

let sut = makeSUT(shell: shell, picker: picker)
let (sut, shell) = makeSUT(selectedItemIndices: [0])

try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: true)

Expand All @@ -82,15 +73,12 @@ extension BuildExecutionManagerTests {
func executesBuildWithCustomOutputLocation() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: ["", "", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(
let (sut, shell) = makeSUT(
selectedItemIndices: [2], // Select custom location
inputResponses: ["/tmp"], // Custom path
permissionResponses: [true] // Confirm path
)

let sut = makeSUT(shell: shell, picker: picker)

try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)

// Verify copy command was executed
Expand All @@ -101,10 +89,7 @@ extension BuildExecutionManagerTests {
func usesDefaultBuildTypeWhenNoneProvided() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: ["", "", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(selectedItemIndices: [0]) // Select current directory

let sut = makeSUT(shell: shell, picker: picker)
let (sut, shell) = makeSUT(selectedItemIndices: [0])

try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)

Expand All @@ -116,10 +101,7 @@ extension BuildExecutionManagerTests {
func skipsCleanWhenCleanFlagFalse() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: ["", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(selectedItemIndices: [0]) // Select current directory

let sut = makeSUT(shell: shell, picker: picker)
let (sut, shell) = makeSUT(selectedItemIndices: [0])

try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: false, openInFinder: false)

Expand All @@ -135,10 +117,7 @@ extension BuildExecutionManagerTests {
func throwsErrorWhenPickerFailsToSelectExecutable() throws {
try createPackageSwiftWithMultipleExecutables()

let shell = MockShell()
let picker = MockPicker(shouldThrowError: true)

let sut = makeSUT(shell: shell, picker: picker)
let sut = makeSUT(throwPickerError: true).sut

#expect(throws: BuildExecutionError.failedToSelectExecutable(reason: "MockPicker error")) {
try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)
Expand All @@ -149,14 +128,11 @@ extension BuildExecutionManagerTests {
func throwsErrorWhenCustomPathIsInvalid() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: ["", "", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(
let (sut, _) = makeSUT(
selectedItemIndices: [2], // Select custom location
inputResponses: ["/nonexistent/path"] // Invalid path
)

let sut = makeSUT(shell: shell, picker: picker)

#expect(throws: BuildExecutionError.invalidCustomPath(path: "/nonexistent/path")) {
try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)
}
Expand All @@ -166,28 +142,20 @@ extension BuildExecutionManagerTests {
func throwsErrorWhenUserCancelsCustomPathConfirmation() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: ["", "", "", "sha256hash /path/to/binary", "sha256hash /path/to/binary"])
let picker = MockPicker(
let (sut, _) = makeSUT(
selectedItemIndices: [2], // Select custom location
inputResponses: ["/tmp"], // Valid path
permissionResponses: [false] // Cancel confirmation
)

let sut = makeSUT(shell: shell, picker: picker)

#expect(throws: BuildExecutionError.buildCancelledByUser) {
try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)
}
}

@Test("Propagates ExecutableNameResolver errors")
func propagatesExecutableNameResolverErrors() throws {
// Don't create Package.swift to trigger missing package error

let shell = MockShell()
let picker = MockPicker()

let sut = makeSUT(shell: shell, picker: picker)
let sut = makeSUT().sut

#expect(throws: ExecutableNameResolverError.missingPackageSwift(path: projectFolder.path)) {
try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)
Expand All @@ -198,10 +166,7 @@ extension BuildExecutionManagerTests {
func propagatesBuildErrorsFromProjectBuilder() throws {
try createPackageSwift(executableName: executableName)

let shell = MockShell(results: [], shouldThrowError: true) // Make shell commands fail
let picker = MockPicker(selectedItemIndices: [0])

let sut = makeSUT(shell: shell, picker: picker)
let sut = makeSUT(selectedItemIndices: [0], throwShellError: true).sut

#expect(throws: (any Error).self) {
try sut.executeBuild(projectPath: projectFolder.path, buildType: .universal, clean: true, openInFinder: false)
Expand All @@ -212,8 +177,12 @@ extension BuildExecutionManagerTests {

// MARK: - Private Methods
private extension BuildExecutionManagerTests {
func makeSUT(shell: MockShell, picker: MockPicker) -> BuildExecutionManager {
return BuildExecutionManager(shell: shell, picker: picker)
func makeSUT(selectedItemIndices: [Int] = [], inputResponses: [String] = [], permissionResponses: [Bool] = [], throwShellError: Bool = false, throwPickerError: Bool = false) -> (sut: BuildExecutionManager, shell: MockShell) {
let shell = MockShell(shouldThrowErrorOnFinal: throwShellError)
let picker = MockPicker(selectedItemIndices: selectedItemIndices, inputResponses: inputResponses, permissionResponses: permissionResponses, shouldThrowError: throwPickerError)
let sut = BuildExecutionManager(shell: shell, picker: picker)

return (sut, shell)
}

func createPackageSwift(executableName: String) throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,7 @@ extension PublishExecutionManagerTests {
func propagatesBuildErrors() throws {
try createPackageSwift()

let factory = MockContextFactory(
shell: MockShell(resultMap: [:], shouldThrowError: true) // Make build fail
)

let factory = MockContextFactory(shell: MockShell(shouldThrowErrorOnFinal: true))
let context = try factory.makeContext()
let existingTap = SwiftDataTap(name: tapName, localPath: tapFolder.path, remotePath: "")
let existingFormula = SwiftDataFormula(
Expand Down
11 changes: 6 additions & 5 deletions Tests/nnexTests/PublishTests/PublishTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,6 @@ extension PublishTests {
#expect(throws: (any Error).self) {
try runCommand(factory, version: .version(versionNumber), message: commitMessage, notes: releaseNotes)
}

withKnownIssue("Determining which shell command fails is currently unreliable") {
#expect(shell.executedCommands.contains { $0.contains("swift test") })
}
}
}

Expand Down Expand Up @@ -325,12 +321,17 @@ private extension PublishTests {
// MARK: - Helpers
private extension PublishTests {
func createMockShell(projectName: String? = nil, projectPath: String? = nil, includeTestCommand: Bool = false, shouldThrowError: Bool = false) -> MockShell {
if shouldThrowError {
return .init(shouldThrowErrorOnFinal: true)
}

let projectPath = projectPath ?? projectFolder.path
let commandResults: [String: String] = [
"shasum -a 256 \"\(projectPath).build/arm64-apple-macosx/release/\(projectName ?? self.projectName)-arm64.tar.gz\"": sha256Output,
"shasum -a 256 \"\(projectPath).build/x86_64-apple-macosx/release/\(projectName ?? self.projectName)-x86_64.tar.gz\"": sha256Output
]
return MockShell(resultMap: commandResults, shouldThrowError: shouldThrowError)

return .init(commands: commandResults.map({ .init(command: $0, output: $1) }))
}

func createTestTapAndFormula(factory: MockContextFactory, formulaPath: String? = nil, testCommand: TestCommand? = nil, extraBuildArgs: [String] = [], projectName: String? = nil, projectFolder: Folder? = nil) throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/nnexTests/Shared/MockContextFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ extension MockContextFactory: ContextFactory {

let newShell: MockShell
if !commandResults.isEmpty {
newShell = MockShell(resultMap: commandResults)
newShell = .init(commands: commandResults.map({ .init(command: $0, output: $1) }))
} else {
newShell = MockShell(results: runResults)
}
Expand Down