Skip to content

v1.1.0 — SPM support and testing framework detection

Choose a tag to compare

@ericodx ericodx released this 06 Apr 11:23
a40aadc

Swift Package Manager projects are now first-class citizens. The tool auto-detects whether the project is Xcode or SPM, resolves the testing framework in use, and runs the full mutation pipeline without requiring a scheme or destination for SPM targets.


What's new

Swift Package Manager support

  • Full mutation testing pipeline for SPM projects — discovery, schematization, sandbox, build, and test execution all work without Xcode
  • Auto-detection of project type: if a Package.swift is present and no scheme/destination is configured, the tool runs in SPM mode
  • ProjectType enum (.xcode(scheme:destination:) or .spm) drives all branching across the pipeline
  • SPM projects use swift build / swift test instead of xcodebuild
  • Shared sandbox with incremental builds for incompatible mutants in SPM mode — avoids a full rebuild per mutant
  • SPMProcessLauncher with aggressive child process cleanup to prevent orphaned test processes

Testing framework detection

  • TestingFramework enum (.xctest or .swiftTesting) with auto-detection by scanning test file imports
  • --testing-framework CLI flag for explicit override
  • XCTest projects are forced to concurrency: 1 to avoid parallel test runner conflicts
  • Testing framework is included in the init template output

Platform-aware timeouts

  • Default timeout split by platform: 120s for Xcode projects, 30s for SPM projects
  • Configurable via --timeout as before

Result parsing

  • TestResultResolver centralises result parsing, delegating to ResultParser (Xcode) or SPMResultParser (SPM)
  • SPMResultParser handles Swift Testing output format and classifies empty output as crash

Build resilience

  • FallbackExecutor extracted for per-file rebuild fallback on build failure — now supports both Xcode and SPM paths
  • BuildError.compilationFailed now carries compiler output for better diagnostics
  • Narrow per-mutant exclusion on schematized build failure instead of excluding entire files

Process management

  • ProcessRequest and ProcessRunner extracted to reduce duplication between Xcode and SPM launchers
  • XcodeProcessLauncher preserves v1.0.0 behaviour; SPMProcessLauncher adds escaped child cleanup
  • InfiniteLoopFilter skips mutations inside while and repeat-while loop bodies that would produce infinite loops

Error reporting

  • LocalizedError conformance on BuildError and SimulatorError for human-readable error messages
  • TextReporter formats total duration as minutes and seconds

Architecture changes

Discovery pipeline — expanded from 4 to 6 stages:

Stage Responsibility
FileDiscoveryStage Collects Swift source files under the configured sources path
ParsingStage Parses source files into ParsedSource values using SwiftSyntax
MutantDiscoveryStage Applies mutation operators to produce mutation points
MutantIndexingStage Assigns unique IDs and indexes mutation points (new)
SchematizationStage Rewrites source files to embed schematizable mutants behind a runtime switch
IncompatibleRewritingStage Produces full-file rewrites for incompatible mutants (new)

Execution layerExecutionDeps consolidates shared dependencies (launcher, cache, reporter, counter) passed between executor and stage types.

ConfigurationRunnerConfiguration now nests BuildOptions, ReportingOptions, and FilterOptions. DetectedProject uses a Kind enum (.xcode or .spm) for project detection results.


Bug fixes

  • Fixed simulator slot leak — slot is now released before parsing results
  • Fixed process group cleanup — kill process group after normal process exit to prevent orphaned children
  • Fixed parent environment merging in SPM test execution
  • Fixed debug print statements left in execution stages
  • Fixed empty SPM output incorrectly classified as test success instead of crash

Internal improvements

  • 43 new test commits covering SPM execution, framework detection, process launchers, fallback paths, and result parsing
  • Unreachable defensive code removed in IncompatibleMutantExecutor and ProjectDetector
  • Force-unwrap for pipeline-guaranteed values in DiscoveryPipeline, SchemataGenerator, and MutationRewriter
  • SPM integration test fixture (CalcLibrary) added for end-to-end validation

Requirements

  • macOS 15+
  • Swift 6.2+
  • Xcode project with a valid scheme and test target, or an SPM package with a test target

Installation

See the Installation Guide for Homebrew, pre-built binary, and build from source instructions.


What's Changed

  • chore: update default configuration values by @ericodx in #42
  • Introduce ProjectType and SPM project detection by @ericodx in #43
  • SPM support — Sandbox and Build by @ericodx in #44
  • SPM support — SimulatorPool bypass by @ericodx in #45
  • SPM support — schematized test execution by @ericodx in #46
  • SPM support — incompatible mutant execution by @ericodx in #47
  • SPM support — SPMResultParser by @ericodx in #48
  • SPM support — fixture, integration tests, and additionalEnvironment API by @ericodx in #49
  • Code and architecture revision by @ericodx in #50
  • Support SPM execution with process lifecycle management by @ericodx in #51
  • feat: split ProcessLauncher by platform, add testingFramework, infinite loop filter and SPM timeout by @ericodx in #52
  • Code cleanup: coverage improvements and dead code removal by @ericodx in #53
  • docs: update documentation for SPM support and testing framework detection by @ericodx in #54

Full Changelog: v1.0.0...v1.1.0