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
16 changes: 14 additions & 2 deletions Sources/ContainerizationOCI/Platform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,27 @@ public struct Platform: Sendable, Equatable {
return .init(arch: normalized.arch, os: "linux", variant: normalized.variant)
}

/// The computed description, for example, `linux/arm64/v8`.
/// The computed description, for example, `linux/amd64` or `linux/arm/v7`.
///
/// `arm64`'s only defined variant is `v8`, which `==` and `hash` already treat as
/// equivalent to a `nil` variant. The redundant `v8` is therefore omitted so that
/// two equal arm64 platforms (one with `variant == nil`, one with `"v8"`) describe
/// identically as `linux/arm64`, rather than drifting between `arm64` and
/// `arm64/v8`.
public var description: String {
let architecture = architecture
if let variant = variant {
if let variant, !Self.isRedundantVariant(variant, for: architecture) {
return "\(os)/\(architecture)/\(variant)"
}
return "\(os)/\(architecture)"
}

/// Whether `variant` is the canonical default for `architecture` and can be omitted
/// from the rendered description without losing information.
private static func isRedundantVariant(_ variant: String, for architecture: String) -> Bool {
architecture == "arm64" && variant == "v8"
}

/// The CPU architecture, for example, `amd64` or `arm64`.
public var architecture: String {
Self.normalizeArch(_rawArch).arch
Expand Down
36 changes: 36 additions & 0 deletions Tests/ContainerizationOCITests/OCIPlatformTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,40 @@ struct OCIPlatformTests {
#expect(!matcher(Platform(arch: "arm64", os: "windows", variant: "v8")), "matcher must reject a differing OS")
#expect(matcher(Platform(arch: "arm64", os: "linux", variant: "v8")), "matcher must accept the same OS with an implied v8 variant")
}

// MARK: - description consistency

@Test func arm64_nilAndV8_sameDescription() {
let withoutVariant = Platform(arch: "arm64", os: "linux", variant: nil)
let withV8 = Platform(arch: "arm64", os: "linux", variant: "v8")
#expect(
withoutVariant.description == withV8.description,
"equal arm64 platforms must produce the same description"
)
}

@Test func arm64_descriptionDropsRedundantV8() {
let withV8 = Platform(arch: "arm64", os: "linux", variant: "v8")
#expect(withV8.description == "linux/arm64", "arm64/v8 is canonical arm64, rendered without the redundant variant")
}

@Test func arm64_nilVariantDescription() {
let withoutVariant = Platform(arch: "arm64", os: "linux", variant: nil)
#expect(withoutVariant.description == "linux/arm64")
}

@Test func arm64_fromStringWithV8DescriptionIsCanonical() throws {
let parsed = try Platform(from: "linux/arm64/v8")
#expect(parsed.description == "linux/arm64", "parsing arm64/v8 then describing must yield the canonical short form")
}

@Test func arm_v7_descriptionKeepsVariant() {
let armv7 = Platform(arch: "arm", os: "linux", variant: "v7")
#expect(armv7.description == "linux/arm/v7", "non-redundant variants such as arm/v7 must be preserved")
}

@Test func amd64_descriptionUnaffected() {
let amd64 = Platform(arch: "amd64", os: "linux")
#expect(amd64.description == "linux/amd64")
}
}
Loading