Skip to content

Commit 8486081

Browse files
committed
swift-package-migrate: Add tests for feature resolution errors
This change also extracts feature resolution into a method and removes a superfluous colon from the 'unsupported feature' error message.
1 parent acbc716 commit 8486081

File tree

2 files changed

+83
-25
lines changed

2 files changed

+83
-25
lines changed

Sources/Commands/PackageCommands/Migrate.swift

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,31 +64,8 @@ extension SwiftPackageCommand {
6464
var options: MigrateOptions
6565

6666
public func run(_ swiftCommandState: SwiftCommandState) async throws {
67-
let toolchain = try swiftCommandState.productsBuildParameters.toolchain
68-
69-
let supportedFeatures = try Dictionary(
70-
uniqueKeysWithValues: toolchain.swiftCompilerSupportedFeatures
71-
.map { ($0.name, $0) }
72-
)
73-
74-
// First, let's validate that all of the features are supported
75-
// by the compiler and are migratable.
76-
77-
var features: [SwiftCompilerFeature] = []
78-
for name in self.options.features {
79-
guard let feature = supportedFeatures[name] else {
80-
let migratableFeatures = supportedFeatures.map(\.value).filter(\.migratable).map(\.name)
81-
throw ValidationError(
82-
"Unsupported feature: \(name). Available features: \(migratableFeatures.joined(separator: ", "))"
83-
)
84-
}
85-
86-
guard feature.migratable else {
87-
throw ValidationError("Feature '\(name)' is not migratable")
88-
}
89-
90-
features.append(feature)
91-
}
67+
// First, validate and resolve the requested feature names.
68+
let features = try self.resolveRequestedFeatures(swiftCommandState)
9269

9370
let buildSystem = try await createBuildSystem(
9471
swiftCommandState,
@@ -188,6 +165,44 @@ extension SwiftPackageCommand {
188165
}
189166
}
190167

168+
/// Resolves the requested feature names.
169+
private func resolveRequestedFeatures(
170+
_ swiftCommandState: SwiftCommandState
171+
) throws -> [SwiftCompilerFeature] {
172+
let toolchain = try swiftCommandState.productsBuildParameters.toolchain
173+
174+
// Query the compiler for supported features.
175+
let supportedFeatures = try toolchain.swiftCompilerSupportedFeatures
176+
177+
var resolvedFeatures: [SwiftCompilerFeature] = []
178+
179+
// Resolve the requested feature names, validating that they are
180+
// supported by the compiler and migratable.
181+
for name in self.options.features {
182+
let feature = supportedFeatures.first { $0.name == name }
183+
184+
guard let feature else {
185+
let migratableCommaSeparatedFeatures = supportedFeatures
186+
.filter(\.migratable)
187+
.map(\.name)
188+
.sorted()
189+
.joined(separator: ", ")
190+
191+
throw ValidationError(
192+
"Unsupported feature '\(name)'. Available features: \(migratableCommaSeparatedFeatures)"
193+
)
194+
}
195+
196+
guard feature.migratable else {
197+
throw ValidationError("Feature '\(name)' is not migratable")
198+
}
199+
200+
resolvedFeatures.append(feature)
201+
}
202+
203+
return resolvedFeatures
204+
}
205+
191206
private func createBuildSystem(
192207
_ swiftCommandState: SwiftCommandState,
193208
targets: OrderedSet<String>,

Tests/CommandsTests/PackageCommandTests.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,6 +2117,49 @@ class PackageCommandTestCase: CommandsBuildProviderTestCase {
21172117
XCTAssertNoMatch(stdout, .contains("--package-path"))
21182118
}
21192119

2120+
func testMigrateCommandNoFeatures() async throws {
2121+
try await XCTAssertThrowsCommandExecutionError(
2122+
await self.execute(["migrate"])
2123+
) { error in
2124+
XCTAssertMatch(
2125+
error.stderr,
2126+
.contains("error: Missing expected argument '--to-feature <to-feature>'")
2127+
)
2128+
}
2129+
}
2130+
2131+
func testMigrateCommandUnknownFeature() async throws {
2132+
try XCTSkipIf(
2133+
!UserToolchain.default.supportesSupportedFeatures,
2134+
"skipping because test environment compiler doesn't support `-print-supported-features`"
2135+
)
2136+
2137+
try await XCTAssertThrowsCommandExecutionError(
2138+
await self.execute(["migrate", "--to-feature", "X"])
2139+
) { error in
2140+
XCTAssertMatch(
2141+
error.stderr,
2142+
.contains("error: Unsupported feature 'X'. Available features:")
2143+
)
2144+
}
2145+
}
2146+
2147+
func testMigrateCommandNonMigratableFeature() async throws {
2148+
try XCTSkipIf(
2149+
!UserToolchain.default.supportesSupportedFeatures,
2150+
"skipping because test environment compiler doesn't support `-print-supported-features`"
2151+
)
2152+
2153+
try await XCTAssertThrowsCommandExecutionError(
2154+
await self.execute(["migrate", "--to-feature", "StrictConcurrency"])
2155+
) { error in
2156+
XCTAssertMatch(
2157+
error.stderr,
2158+
.contains("error: Feature 'StrictConcurrency' is not migratable")
2159+
)
2160+
}
2161+
}
2162+
21202163
func testMigrateCommand() async throws {
21212164
try XCTSkipIf(
21222165
!UserToolchain.default.supportesSupportedFeatures,

0 commit comments

Comments
 (0)