diff --git a/Sources/SwiftSDKGenerator/PlatformModels/LinuxDistribution.swift b/Sources/SwiftSDKGenerator/PlatformModels/LinuxDistribution.swift index c82835b..8eef83e 100644 --- a/Sources/SwiftSDKGenerator/PlatformModels/LinuxDistribution.swift +++ b/Sources/SwiftSDKGenerator/PlatformModels/LinuxDistribution.swift @@ -21,24 +21,24 @@ public enum LinuxDistribution: Hashable, Sendable { case ubi9 } - public enum Ubuntu: String, Sendable { + public enum Ubuntu: String, Sendable, Equatable, CaseIterable { case focal case jammy case noble init(version: String) throws { switch version { - case "20.04": - self = .focal - case "22.04": - self = .jammy - case "24.04": - self = .noble + case "20.04": self = .focal + case "22.04": self = .jammy + case "24.04": self = .noble default: - throw GeneratorError.unknownLinuxDistribution( - name: LinuxDistribution.Name.ubuntu.rawValue, - version: version - ) + guard let versionType = Self(rawValue: version) else { + throw GeneratorError.unknownLinuxDistribution( + name: LinuxDistribution.Name.ubuntu.rawValue, + version: version + ) + } + self = versionType } } @@ -59,6 +59,7 @@ public enum LinuxDistribution: Hashable, Sendable { "linux-libc-dev", "zlib1g", "zlib1g-dev", + "libicu-dev", "libcurl4-openssl-dev", ] } @@ -69,28 +70,25 @@ public enum LinuxDistribution: Hashable, Sendable { return commonPackages + [ "libgcc-10-dev", "libicu66", - "libicu-dev", "libstdc++-10-dev", ] case .jammy: return commonPackages + [ "libgcc-12-dev", "libicu70", - "libicu-dev", "libstdc++-12-dev", ] case .noble: return commonPackages + [ "libgcc-13-dev", "libicu74", - "libicu-dev", "libstdc++-13-dev", ] } } } - public enum Debian: String, Sendable { + public enum Debian: String, Sendable, Equatable, CaseIterable { case bullseye case bookworm case trixie @@ -101,10 +99,13 @@ public enum LinuxDistribution: Hashable, Sendable { case "12": self = .bookworm case "13": self = .trixie default: - throw GeneratorError.unknownLinuxDistribution( - name: LinuxDistribution.Name.debian.rawValue, - version: version - ) + guard let versionType = Self(rawValue: version) else { + throw GeneratorError.unknownLinuxDistribution( + name: LinuxDistribution.Name.debian.rawValue, + version: version + ) + } + self = versionType } } @@ -125,6 +126,7 @@ public enum LinuxDistribution: Hashable, Sendable { "linux-libc-dev", "zlib1g", "zlib1g-dev", + "libicu-dev", "libcurl4-openssl-dev", ] } @@ -135,21 +137,18 @@ public enum LinuxDistribution: Hashable, Sendable { return commonPackages + [ "libgcc-10-dev", "libicu67", - "libicu-dev", "libstdc++-10-dev", ] case .bookworm: return commonPackages + [ "libgcc-12-dev", "libicu72", - "libicu-dev", "libstdc++-12-dev", ] case .trixie: return commonPackages + [ "libgcc-14-dev", "libicu76", - "libicu-dev", "libstdc++-14-dev", ] } diff --git a/Tests/SwiftSDKGeneratorTests/PlatformModels/LinuxDistributionTests.swift b/Tests/SwiftSDKGeneratorTests/PlatformModels/LinuxDistributionTests.swift new file mode 100644 index 0000000..b07f46f --- /dev/null +++ b/Tests/SwiftSDKGeneratorTests/PlatformModels/LinuxDistributionTests.swift @@ -0,0 +1,195 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2022-2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#if canImport(Testing) + import Testing + @testable import SwiftSDKGenerator + + struct LinuxDistributionTests { + struct UbuntuTests { + @Test(arguments: [ + ("20.04", LinuxDistribution.Ubuntu.focal), + ("focal", LinuxDistribution.Ubuntu.focal), + + ("22.04", LinuxDistribution.Ubuntu.jammy), + ("jammy", LinuxDistribution.Ubuntu.jammy), + + ("24.04", LinuxDistribution.Ubuntu.noble), + ("noble", LinuxDistribution.Ubuntu.noble), + ]) + func validVersionStrings(versionString: String, expectedVersion: LinuxDistribution.Ubuntu) throws { + let version = try LinuxDistribution.Ubuntu(version: versionString) + #expect(version == expectedVersion) + } + + @Test(arguments: [ + "18.04", + "bionic", + "unknown", + "invalid", + ]) func invalidVersionStrings(versionString: String) throws { + #expect(throws: GeneratorError.self) { + let _ = try LinuxDistribution.Ubuntu(version: versionString) + } + } + + @Test(arguments: [ + (LinuxDistribution.Ubuntu.focal, "20.04"), + (LinuxDistribution.Ubuntu.jammy, "22.04"), + (LinuxDistribution.Ubuntu.noble, "24.04"), + ]) + func versionProperty(ubuntuVersion: LinuxDistribution.Ubuntu, expectedVersionString: String) { + #expect(ubuntuVersion.version == expectedVersionString) + } + + @Test(arguments: LinuxDistribution.Ubuntu.allCases) + func requiredPackages(ubuntuVersion: LinuxDistribution.Ubuntu) { + let commonPackages = [ + "libc6", + "libc6-dev", + "libgcc-s1", + "libstdc++6", + "linux-libc-dev", + "zlib1g", + "zlib1g-dev", + "libicu-dev", + "libcurl4-openssl-dev", + ] + + let requiredPackages = ubuntuVersion.requiredPackages + #expect(requiredPackages.starts(with: commonPackages)) + + // Some required packages that change versions between Ubuntu versions + #expect(requiredPackages.contains(where: { $0.matches(regex: "libgcc-\\d{2}-dev") })) + #expect(requiredPackages.contains(where: { $0.matches(regex: "libicu\\d{2}") })) + #expect(requiredPackages.contains(where: { $0.matches(regex: "libstdc\\+\\+-\\d{2}-dev") })) + } + } + + struct DebianTests { + @Test(arguments: [ + ("11", LinuxDistribution.Debian.bullseye), + ("bullseye", LinuxDistribution.Debian.bullseye), + + ("12", LinuxDistribution.Debian.bookworm), + ("bookworm", LinuxDistribution.Debian.bookworm), + + ("13", LinuxDistribution.Debian.trixie), + ("trixie", LinuxDistribution.Debian.trixie), + ]) + func validVersionStrings(versionString: String, expectedVersion: LinuxDistribution.Debian) throws { + let version = try LinuxDistribution.Debian(version: versionString) + #expect(version == expectedVersion) + } + + @Test(arguments: [ + "9", + "sid", + "unknown", + "invalid", + ]) func invalidVersionStrings(versionString: String) throws { + #expect(throws: GeneratorError.self) { + let _ = try LinuxDistribution.Debian(version: versionString) + } + } + + @Test(arguments: [ + (LinuxDistribution.Debian.bullseye, "11"), + (LinuxDistribution.Debian.bookworm, "12"), + (LinuxDistribution.Debian.trixie, "13"), + ]) + func versionProperty(debianVersion: LinuxDistribution.Debian, expectedVersionString: String) { + #expect(debianVersion.version == expectedVersionString) + } + + @Test(arguments: LinuxDistribution.Debian.allCases) + func requiredPackages(debianVersion: LinuxDistribution.Debian) { + let commonPackages = [ + "libc6", + "libc6-dev", + "libgcc-s1", + "libstdc++6", + "linux-libc-dev", + "zlib1g", + "zlib1g-dev", + "libicu-dev", + "libcurl4-openssl-dev", + ] + + let requiredPackages = debianVersion.requiredPackages + #expect(requiredPackages.starts(with: commonPackages)) + + // Some required packages that change versions between Debian versions + #expect(requiredPackages.contains(where: { $0.matches(regex: "libgcc-\\d{2}-dev") })) + #expect(requiredPackages.contains(where: { $0.matches(regex: "libicu\\d{2}") })) + #expect(requiredPackages.contains(where: { $0.matches(regex: "libstdc\\+\\+-\\d{2}-dev") })) + } + } + + @Test(arguments: [ + (LinuxDistribution.Name.rhel, "ubi9", "ubi9", "rhel-ubi9"), + (LinuxDistribution.Name.ubuntu, "22.04", "jammy", "jammy"), + (LinuxDistribution.Name.debian, "12", "bookworm", "bookworm"), + ]) + func distributionProperties( + name: LinuxDistribution.Name, + version: String, + expectedRelease: String, + expectedImageSuffix: String + ) throws { + let distribution = try LinuxDistribution(name: name, version: version) + + #expect(distribution.name == name) + #expect(distribution.release == expectedRelease) + #expect(distribution.swiftDockerImageSuffix == expectedImageSuffix) + #expect(distribution.description.isEmpty == false) + } + + @Test(arguments: [ + ("rhel", LinuxDistribution.Name.rhel), + ("ubuntu", LinuxDistribution.Name.ubuntu), + ("debian", LinuxDistribution.Name.debian), + ]) func validDistributionNames(nameString: String, expectedName: LinuxDistribution.Name) throws { + let name = try LinuxDistribution.Name(nameString: nameString) + #expect(name == expectedName) + } + + @Test(arguments: [ + "amazonlinux", + "fedora", + "opensuse", + ]) func invalidDistributionNames(name: String) throws { + #expect(throws: GeneratorError.self) { + let _ = try LinuxDistribution.Name(nameString: name) + } + } + + @Test(arguments: [ + (LinuxDistribution.Name.rhel, "ubi8"), + (LinuxDistribution.Name.ubuntu, "18.04"), + (LinuxDistribution.Name.debian, "9"), + ]) func invalidDistributionVersions( + name: LinuxDistribution.Name, + version: String + ) throws { + #expect(throws: GeneratorError.self) { + let _ = try LinuxDistribution(name: name, version: version) + } + } + } + + extension String { + func matches(regex: String) -> Bool { + return self.range(of: regex, options: .regularExpression) != nil + } + } +#endif