Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f43feb4
Consolidate TestCase execution and preserve diagnostics
kudit Jul 26, 2026
c6c86f1
Add reusable Swift Testing module adapter
kudit Jul 26, 2026
69e9f64
Fix test execution availability and exclusivity
kudit Jul 27, 2026
a262414
Keep testing product manifest changes focused
kudit Jul 27, 2026
3b5666d
Fold execution mode conformance into its declaration
kudit Jul 27, 2026
49bff8a
Fix test infrastructure availability
kudit Jul 27, 2026
5a8f751
Add source-based debug formatting conveniences
kudit Jul 27, 2026
ce3fa40
Move debug formatting helpers into Debug.swift
kudit Jul 27, 2026
60b7b9e
Consolidate debug message and formatting APIs
kudit Jul 27, 2026
04e75c7
Simplified code duplication
kudit Jul 28, 2026
23b6f56
Included expanded support for lastPathComponent
kudit Jul 28, 2026
60ed6cf
Improve lastPathComponent for cross-platform compatibility
kudit Jul 28, 2026
a55ac76
Enhance CONTRIBUTING.md with collaborative coding workflow
kudit Jul 28, 2026
cd96617
Exercise ModuleTestEntry through Swift Testing
kudit Jul 28, 2026
d6b97ca
Update CHANGELOG with testing requirements
kudit Jul 28, 2026
e03065f
Serialize debug tests and restore settings safely
kudit Jul 29, 2026
c9bfda2
Remove duplicated grouped module test bridge
kudit Jul 29, 2026
fd1bf22
Document v1.19.0 test infrastructure changes
kudit Jul 29, 2026
6f6a24e
Restore changelog history before focused update
kudit Jul 29, 2026
6f9ec99
Updated module requirements
kudit Jul 29, 2026
a5ba797
Discover module tests without global registration
kudit Jul 29, 2026
61e59ba
Set package version to 1.18.3
kudit Jul 29, 2026
d82e8c0
Set Compatibility version to 1.18.3
kudit Jul 29, 2026
7935f7a
Revert "Set Compatibility version to 1.18.3"
kudit Jul 29, 2026
c891def
fixed version surfaces
kudit Jul 29, 2026
b79fcb6
added compatibility testing library
kudit Jul 29, 2026
2b15418
Remove duplicate module graph traversal
kudit Jul 29, 2026
53628d6
Use concrete Compatibility test catalog
kudit Jul 29, 2026
ae7c4ee
fixed @available checks for macOS 12
kudit Jul 29, 2026
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 CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

# TODO:
Testing required before release:

- Confirm `Compatibility Module Test Entries` displays each reusable `TestCase` separately.
- Confirm the new entries execute successfully and preserve readable module, section, and test names.
- Confirm the serialized debug tests restore `Compatibility.settings` even when an expectation throws.
- Run SwiftPM and supported-platform validation before tagging the release.

## v1.18.3 2026-07-28
Added the reusable `Compatibility Testing Library` product and `ModuleTestEntry` adapter so each module `TestCase` appears as an individually named Swift Testing result.
Unified `TestCase.execute()` and live test execution through one lifecycle implementation with explicit parallel and serialized execution modes.
Added source-aware test failures, labeled debug-format context, and source-context debugging conveniences while preserving existing debug-format call sites.
Made debug tests run exclusively and restore process-global debug settings with `defer`, including when an expectation throws.
Expanded contributor guidance for short, staged, maintainer-reviewed coding workflows.

## v1.18.2 2026-07-23
Fixed Swift Package Index build errors and warnings across SwiftUI and WebAssembly targets.
Replaced conditional SwiftUI `Group` wrappers with direct `@ViewBuilder` results and concrete text-selection types.
Expand Down
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ PROMPT for updating Module packages:
Review this Swift package for adoption of the Module APIs introduced in github.com/kudit/Compatibility v1.16.0 or later. Inspect the package’s existing architecture and preserve its public behavior and platform compatibility. Add or update its Compatibility dependency if necessary. Apply an appropriate Module conformance, including its version, direct Compatibility dependency, module dependencies, immediately available moduleInfo, ordered TestCase sections, and opt-in open-source repository metadata when applicable. Register the package from its highest-level module or document how an application should register it through Application.track(including:). Add complete inline DocC comments to the relevant public APIs so generated documentation can discover them. Do not create a .docc catalog, separate documentation articles, or another documentation folder. Preserve existing comments unless they are missing, unclear, or inaccurate. Put reusable tests in the module's TestCase collections so they run both in the in-app test UI and through the Swift Testing bridge; retain target-specific tests only where infrastructure requires them. Follow this package’s existing CONTRIBUTING.md, changelog, versioning, formatting, availability, and compatibility conventions. Avoid unrelated reformatting and whitespace-only changes. Before changing version numbers, compare the current changelog version with the latest committed Git version. If the active working-tree changelog is already ahead of Git, do not choose another version; synchronize that active version across every package manifest, Xcode project, public source constant, test fixture or suite heading, README or documentation display, and other hard-coded version surface. Please check that all deprecations (that can) have appropriate renamed clauses for easy fixits.


## Collaborative coding workflow

When working interactively with a maintainer, generally (this shouldn't be meant to override thread instructions but are here as a default):
- Work in small, reviewable stages rather than delivering a large implementation all at once.
- Present one immediate decision or action at a time and pause for maintainer feedback unless instructed to do a batch.
- Explain design choices briefly and answer questions before continuing implementation.
- Preserve and review the maintainer's local edits before adding further changes.
- Let the maintainer build, edit, commit, and push between stages when practical.
- After each pushed maintainer change, review the latest commit before proposing or applying the next change.
- Keep pull requests in draft until the implementation is compiled, exercised by real tests, and fully reviewed.
- Avoid unrelated cleanup, broad reformatting, and speculative changes that make the diff harder to reason about.


## Version and changelog rules

- Keep changelog entries in `## vX.X.X YYYY-MM-DD` format, with short line-separated notes under the current version.
Expand Down
11 changes: 9 additions & 2 deletions Development/Compatibility.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
B5209EE32C431CF800FBA30B /* CompatibilityDemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5209EE22C431CF800FBA30B /* CompatibilityDemoView.swift */; };
B5209EE42C431CF800FBA30B /* CompatibilityDemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5209EE22C431CF800FBA30B /* CompatibilityDemoView.swift */; };
B52C8E0F2C38CA76008EBD2D /* MyApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E5FC3A2C3860EC004F2009 /* MyApp.swift */; };
B52DEB233019BA54003291D0 /* Compatibility Testing Library in Frameworks */ = {isa = PBXBuildFile; productRef = B52DEB223019BA54003291D0 /* Compatibility Testing Library */; };
B569253B2E8715550045FFC6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B5E5FC822C3863B9004F2009 /* Assets.xcassets */; };
B579D4A52C46FF1A009A037A /* Compatibility Library in Frameworks */ = {isa = PBXBuildFile; productRef = B579D4A42C46FF1A009A037A /* Compatibility Library */; };
B58B5C452C38F98800689837 /* (null) in Sources */ = {isa = PBXBuildFile; };
Expand Down Expand Up @@ -91,6 +92,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B52DEB233019BA54003291D0 /* Compatibility Testing Library in Frameworks */,
B594CFB72DB0BACA001E8658 /* Compatibility Library in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -227,6 +229,7 @@
name = CompatibilityTests;
packageProductDependencies = (
B594CFB62DB0BACA001E8658 /* Compatibility Library */,
B52DEB223019BA54003291D0 /* Compatibility Testing Library */,
);
productName = CompatibilityTests;
productReference = B594CFA92DB0B838001E8658 /* CompatibilityTests.xctest */;
Expand Down Expand Up @@ -488,7 +491,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1.18.2;
MARKETING_VERSION = 1.18.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -559,7 +562,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 1.18.2;
MARKETING_VERSION = 1.18.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "";
Expand Down Expand Up @@ -814,6 +817,10 @@
package = B52C8E0D2C3886E6008EBD2D /* XCLocalSwiftPackageReference ".." */;
productName = "Compatibility Library";
};
B52DEB223019BA54003291D0 /* Compatibility Testing Library */ = {
isa = XCSwiftPackageProductDependency;
productName = "Compatibility Testing Library";
};
B579D4A42C46FF1A009A037A /* Compatibility Library */ = {
isa = XCSwiftPackageProductDependency;
package = B52C8E0D2C3886E6008EBD2D /* XCLocalSwiftPackageReference ".." */;
Expand Down
23 changes: 3 additions & 20 deletions Development/CompatibilityTests/CompatibilityTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -446,25 +446,8 @@ struct CompatibilityTests {
}
}

/// Runs every public module section through the same TestCase values used by the live UI.
@Test(
"Compatibility Module Tests",
arguments: await MainActor.run { Compatibility.tests.keys.elements }
)
@MainActor
@available(iOS 13, macOS 12, tvOS 13, watchOS 6, *)
func moduleTests(section: String) async throws {
// Compatibility.tests is the authoritative package-wide test collection.
let tests = Compatibility.tests[section] ?? []
try await withThrowingTaskGroup(of: Void.self) { group in
for test in tests {
// Each case is independently isolated by TestCase, so long-running rows can overlap.
group.addTask {
try await test.execute()
}
}
try await group.waitForAll()
}
}
// Reusable module tests now live in ModuleTestEntryTests.swift. That adapter creates one
// Swift Testing argument per TestCase, so keeping the former section-based bridge here would
// execute the same Compatibility tests twice and hide individual test names beneath a section.
}
#endif
31 changes: 31 additions & 0 deletions Development/CompatibilityTests/ModuleTestEntryTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// ModuleTestEntryTests.swift
// CompatibilityTests
//
// Exercises the reusable CompatibilityTesting adapter through Swift Testing.
//

#if compiler(>=5.9) && canImport(Compatibility) && canImport(CompatibilityTesting) && canImport(Testing)
import Compatibility
import CompatibilityTesting
import Testing

@Suite("Compatibility Module Test Entries")
struct ModuleTestEntryTests {
/// Presents every reusable Compatibility `TestCase` as its own named Swift Testing argument.
@Test(
"Compatibility Module Test",
arguments: await MainActor.run {
ModuleTestEntry.entries(
for: Compatibility.self,
tests: Compatibility.tests
)
}
)
@MainActor
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
func moduleTest(entry: ModuleTestEntry) async throws {
try await entry.execute()
}
}
#endif
19 changes: 16 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// This file is automatically generated.
// Do not edit it by hand because the contents will be replaced.

let version = "1.18.2"
let version = "1.18.3"
let packageLibraryName = "Compatibility"

#if canImport(PackageDescription)
Expand All @@ -31,7 +31,8 @@ var targets = [
dependencies: [
// .product(name: "Compatibility Library", package: "compatibility"), // apparently needs to be lowercase. Also note this is "Compatibility Library" not "Compatibility"
],
path: "Sources"
path: "Sources",
exclude: ["CompatibilityTesting"]
// If resources need to be included in the module, include here
// ,resources: [ // unfortuantely cannot be conditionally compiled based on Swift version since the tool seems to be run on latest version.
// Resource.process("Resources"),
Expand Down Expand Up @@ -129,21 +130,33 @@ targets += [
// on macOS still discover them, so maintainers can build the CLI and run tests.
#if !SwiftPlaygrounds && !canImport(PlaygroundSupport)
products += [
.library(
name: "Compatibility Testing Library",
targets: ["CompatibilityTesting"]
),
.executable(
name: "compatibilityCLI",
targets: ["compatibilityCLI"]
),
]

targets += [
.target(
name: "CompatibilityTesting",
dependencies: [.init(stringLiteral: packageLibraryName)],
path: "Sources/CompatibilityTesting"
),
.executableTarget(
name: "compatibilityCLI",
dependencies: [.init(stringLiteral: packageLibraryName)],
path: "Development/compatibilityCLI"
),
.testTarget(
name: "\(packageLibraryName)Tests",
dependencies: [.init(stringLiteral: packageLibraryName)],// have to use init since normally would be assignable by string literal but we're not using a string literal
dependencies: [
.init(stringLiteral: packageLibraryName),
"CompatibilityTesting",
],// have to use init since normally would be assignable by string literal but we're not using a string literal
path: "Development/CompatibilityTests",
// The Xcode project consumes this test plan directly, while SwiftPM has no
// declaration for it and otherwise warns that the file is unhandled.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Compatibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

public enum Compatibility: Module {
/// The version of the Compatibility Library since cannot get directly from Package.swift.
public static let version: Version = "1.18.2"
public static let version: Version = "1.18.3"

/// Public source repository for Compatibility so support reports can direct developers to its source and issue history.
///
Expand Down
89 changes: 89 additions & 0 deletions Sources/CompatibilityTesting/ModuleTestEntry.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#if compiler(>=5.9) && canImport(Testing)
import Compatibility
import Testing

/// One reusable Compatibility `TestCase` presented as an individual Swift Testing argument.
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
public struct ModuleTestEntry: Sendable, Identifiable {
public let moduleIdentifier: String
public let moduleName: String
public let section: String
public let testTitle: String
public let index: Int

private let testCase: TestCase

public var id: String {
"\(moduleIdentifier)/\(section)/\(index)"
}

@MainActor
init(module: Module.Type, section: String, index: Int, testCase: TestCase) {
self.moduleIdentifier = module.moduleIdentifier
self.moduleName = module.moduleName
self.section = section
self.testTitle = testCase.title
self.index = index
self.testCase = testCase
}

/// Executes the original shared test and propagates its detailed error into Swift Testing and Xcode.
@MainActor
public func execute() async throws {
try await testCase.execute()
}
}

@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
extension ModuleTestEntry: CustomTestStringConvertible {
public var testDescription: String {
"\(moduleName) › \(section) › \(testTitle)"
}
}

@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
extension ModuleTestEntry: CustomTestArgumentEncodable {
public func encodeTestArgument(to encoder: some Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(id)
}
}

@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
public extension ModuleTestEntry {
/// Flattens an explicitly supplied module test catalog into individually named test arguments.
///
/// The caller supplies the concrete module's `tests` value so Swift does not fall back to a
/// protocol-extension default when a downstream package has an overly restrictive availability
/// annotation. Dependency traversal remains the responsibility of Compatibility's existing
/// `Build` registration graph rather than being duplicated in the testing adapter.
@MainActor
static func entries(
for module: Module.Type,
tests: OrderedDictionary<String, [TestCase]>
) -> [ModuleTestEntry] {
tests.flatMap { section, tests in
tests.enumerated().map { index, testCase in
ModuleTestEntry(
module: module,
section: section,
index: index,
testCase: testCase
)
}
}
}

/// Flattens each supplied module's protocol-visible catalog.
///
/// This convenience remains useful once conforming modules expose `tests` at the same
/// availability as the `Module` requirement. Call ``entries(for:tests:)`` while migrating an
/// older conformer whose test catalog has a stricter availability annotation.
@MainActor
static func entries(including modules: Module.Type...) -> [ModuleTestEntry] {
modules.flatMap { module in
entries(for: module, tests: module.tests)
}
}
}
#endif
2 changes: 1 addition & 1 deletion Sources/Core/Build.swift
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ public extension Build.Environment {
case .designedForiPad:
return .purple
case .macCatalyst:
if #available(iOS 15.0, macCatalyst 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *) {
if #available(iOS 15, macCatalyst 15, tvOS 15, macOS 12, watchOS 8, *) {
return .teal
} else {
return .purple
Expand Down
2 changes: 1 addition & 1 deletion Sources/Core/CloudStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public enum CloudStatus: CustomStringConvertible, Sendable, CaseIterable, Symbol
}

#if compiler(>=5.9)
@available(iOS 13, macOS 12, tvOS 13, watchOS 6, *)
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
public extension CloudStatus {
/// Shared enum behavior tests available to both the in-app test UI and Swift Testing bridge.
@MainActor
Expand Down
Loading