diff --git a/Tests/AppTests/PackageCollectionControllerTests.swift b/Tests/AppTests/PackageCollectionControllerTests.swift index 9f416e4c6..7ae7d2f0b 100644 --- a/Tests/AppTests/PackageCollectionControllerTests.swift +++ b/Tests/AppTests/PackageCollectionControllerTests.swift @@ -12,143 +12,161 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + @testable import App import Dependencies import SnapshotTesting -import XCTVapor +import Testing -class PackageCollectionControllerTests: AppTestCase { +@Suite struct PackageCollectionControllerTests { - func test_owner_request() async throws { - try XCTSkipIf(!isRunningInCI && EnvironmentClient.liveValue.collectionSigningPrivateKey() == nil, "Skip test for local user due to unset COLLECTION_SIGNING_PRIVATE_KEY env variable") + @Test( + .disabled( + if: !isRunningInCI() && EnvironmentClient.liveValue.collectionSigningPrivateKey() == nil, + "Skip test for local user due to unset COLLECTION_SIGNING_PRIVATE_KEY env variable" + ) + ) + func owner_request() async throws { try await withDependencies { $0.date.now = .t0 $0.environment.collectionSigningCertificateChain = EnvironmentClient.liveValue.collectionSigningCertificateChain $0.environment.collectionSigningPrivateKey = EnvironmentClient.liveValue.collectionSigningPrivateKey } operation: { - let p = try await savePackage(on: app.db, "https://github.com/foo/1") - do { - let v = try Version(id: UUID(), - package: p, - packageName: "P1-main", - reference: .branch("main"), - toolsVersion: "5.0") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib") - .save(on: app.db) - } - do { - let v = try Version(id: UUID(), - package: p, - latest: .release, - packageName: "P1-tag", - reference: .tag(1, 2, 3), - toolsVersion: "5.1") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) - .save(on: app.db) - try await Build(version: v, - platform: .iOS, - status: .ok, - swiftVersion: .init(5, 6, 0)).save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - try await Repository(package: p, - defaultBranch: "main", - license: .mit, - licenseUrl: "https://foo/mit", - owner: "foo", - summary: "summary 1").create(on: app.db) + try await withApp { app in + let p = try await savePackage(on: app.db, "https://github.com/foo/1") + do { + let v = try Version(id: UUID(), + package: p, + packageName: "P1-main", + reference: .branch("main"), + toolsVersion: "5.0") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib") + .save(on: app.db) + } + do { + let v = try Version(id: UUID(), + package: p, + latest: .release, + packageName: "P1-tag", + reference: .tag(1, 2, 3), + toolsVersion: "5.1") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) + .save(on: app.db) + try await Build(version: v, + platform: .iOS, + status: .ok, + swiftVersion: .init(5, 6, 0)).save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) + } + try await Repository(package: p, + defaultBranch: "main", + license: .mit, + licenseUrl: "https://foo/mit", + owner: "foo", + summary: "summary 1").create(on: app.db) - // MUT - let encoder = self.encoder - try await app.test( - .GET, - "foo/collection.json", - afterResponse: { @MainActor res async throws in - // validation - XCTAssertEqual(res.status, .ok) - let json = try res.content.decode(PackageCollection.self) - assertSnapshot(of: json, as: .json(encoder)) - }) + // MUT + let encoder = self.encoder + try await app.test( + .GET, + "foo/collection.json", + afterResponse: { @MainActor res async throws in + // validation + #expect(res.status == .ok) + let json = try res.content.decode(PackageCollection.self) + assertSnapshot(of: json, as: .json(encoder)) + }) + } } } - func test_custom_request() async throws { - try XCTSkipIf(!isRunningInCI && EnvironmentClient.liveValue.collectionSigningPrivateKey() == nil, "Skip test for local user due to unset COLLECTION_SIGNING_PRIVATE_KEY env variable") + @Test( + .disabled( + if: !isRunningInCI() && EnvironmentClient.liveValue.collectionSigningPrivateKey() == nil, + "Skip test for local user due to unset COLLECTION_SIGNING_PRIVATE_KEY env variable" + ) + ) + func custom_request() async throws { try await withDependencies { $0.date.now = .t0 $0.environment.collectionSigningCertificateChain = EnvironmentClient.liveValue.collectionSigningCertificateChain $0.environment.collectionSigningPrivateKey = EnvironmentClient.liveValue.collectionSigningPrivateKey } operation: { - let p = try await savePackage(on: app.db, "https://github.com/foo/1") - do { - let v = try Version(id: UUID(), - package: p, - packageName: "P1-main", - reference: .branch("main"), - toolsVersion: "5.0") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib") - .save(on: app.db) - } - do { - let v = try Version(id: UUID(), - package: p, - latest: .release, - packageName: "P1-tag", - reference: .tag(1, 2, 3), - toolsVersion: "5.1") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) - .save(on: app.db) - try await Build(version: v, - platform: .iOS, - status: .ok, - swiftVersion: .init(5, 6, 0)).save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - try await Repository(package: p, - defaultBranch: "main", - license: .mit, - licenseUrl: "https://foo/mit", - owner: "foo", - summary: "summary 1").create(on: app.db) - let collection = CustomCollection(id: .id2, .init(key: "custom-collection", - name: "Custom Collection", - url: "https://github.com/foo/bar/list.json")) - try await collection.save(on: app.db) - try await collection.$packages.attach(p, on: app.db) + try await withApp { app in + let p = try await savePackage(on: app.db, "https://github.com/foo/1") + do { + let v = try Version(id: UUID(), + package: p, + packageName: "P1-main", + reference: .branch("main"), + toolsVersion: "5.0") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib") + .save(on: app.db) + } + do { + let v = try Version(id: UUID(), + package: p, + latest: .release, + packageName: "P1-tag", + reference: .tag(1, 2, 3), + toolsVersion: "5.1") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) + .save(on: app.db) + try await Build(version: v, + platform: .iOS, + status: .ok, + swiftVersion: .init(5, 6, 0)).save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) + } + try await Repository(package: p, + defaultBranch: "main", + license: .mit, + licenseUrl: "https://foo/mit", + owner: "foo", + summary: "summary 1").create(on: app.db) + let collection = CustomCollection(id: .id2, .init(key: "custom-collection", + name: "Custom Collection", + url: "https://github.com/foo/bar/list.json")) + try await collection.save(on: app.db) + try await collection.$packages.attach(p, on: app.db) - // MUT - let encoder = self.encoder - try await app.test( - .GET, - "collections/custom-collection/collection.json", - afterResponse: { @MainActor res async throws in - // validation - XCTAssertEqual(res.status, .ok) - let json = try res.content.decode(PackageCollection.self) - assertSnapshot(of: json, as: .json(encoder)) - }) + // MUT + let encoder = self.encoder + try await app.test( + .GET, + "collections/custom-collection/collection.json", + afterResponse: { @MainActor res async throws in + // validation + #expect(res.status == .ok) + let json = try res.content.decode(PackageCollection.self) + assertSnapshot(of: json, as: .json(encoder)) + }) + } } } - func test_nonexisting_404() throws { + @Test func nonexisting_404() async throws { // Ensure a request for a non-existing collection returns a 404 - try withDependencies { + try await withDependencies { $0.environment.dbId = { nil } } operation: { - // MUT - try app.test( - .GET, - "foo/collection.json", - afterResponse: { res in - // validation - XCTAssertEqual(res.status, .notFound) - }) + try await withApp { app in + // MUT + try await app.test( + .GET, + "foo/collection.json", + afterResponse: { res async in + // validation + #expect(res.status == .notFound) + }) + } } } diff --git a/Tests/AppTests/PackageCollectionTests.swift b/Tests/AppTests/PackageCollectionTests.swift index bd70ce93d..efb3ad306 100644 --- a/Tests/AppTests/PackageCollectionTests.swift +++ b/Tests/AppTests/PackageCollectionTests.swift @@ -12,18 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest - @testable import App import Basics import Dependencies import PackageCollectionsSigning import SnapshotTesting +import Testing import Vapor -class PackageCollectionTests: AppTestCase { +@Suite struct PackageCollectionTests { let encoder: JSONEncoder = { let e = JSONEncoder() @@ -35,734 +34,753 @@ class PackageCollectionTests: AppTestCase { typealias VersionResult = PackageCollection.VersionResult typealias VersionResultGroup = PackageCollection.VersionResultGroup - func test_query_filter_urls() async throws { + @Test func query_filter_urls() async throws { // Tests PackageResult.query with the url filter option - // setup - for index in (0..<3) { - let pkg = try await savePackage(on: app.db, "url-\(index)".url) - do { - let v = try Version(package: pkg, - latest: .release, - packageName: "package \(index)", - reference: .tag(1, 2, 3), - toolsVersion: "5.4") - try await v.save(on: app.db) - try await Build(version: v, - buildCommand: "build \(index)", - platform: .iOS, - status: .ok, - swiftVersion: .v1) - .save(on: app.db) - try await Product(version: v, - type: .library(.automatic), - name: "product \(index)") - .save(on: app.db) - try await Target(version: v, name: "target \(index)") + try await withApp { app in + // setup + for index in (0..<3) { + let pkg = try await savePackage(on: app.db, "url-\(index)".url) + do { + let v = try Version(package: pkg, + latest: .release, + packageName: "package \(index)", + reference: .tag(1, 2, 3), + toolsVersion: "5.4") + try await v.save(on: app.db) + try await Build(version: v, + buildCommand: "build \(index)", + platform: .iOS, + status: .ok, + swiftVersion: .v1) + .save(on: app.db) + try await Product(version: v, + type: .library(.automatic), + name: "product \(index)") .save(on: app.db) + try await Target(version: v, name: "target \(index)") + .save(on: app.db) + } + try await Repository(package: pkg, + name: "repo \(index)") + .save(on: app.db) } - try await Repository(package: pkg, - name: "repo \(index)") - .save(on: app.db) - } - // MUT - let res = try await VersionResult.query(on: app.db, filterBy: .urls(["url-1"])) - - // validate selection and all relations being loaded - XCTAssertEqual(res.map(\.version.packageName), ["package 1"]) - XCTAssertEqual(res.flatMap{ $0.builds.map(\.buildCommand) }, - ["build 1"]) - XCTAssertEqual(res.flatMap{ $0.products.map(\.name) }, - ["product 1"]) - XCTAssertEqual(res.flatMap{ $0.targets.map(\.name) }, - ["target 1"]) - XCTAssertEqual(res.map(\.package.url), ["url-1"]) - XCTAssertEqual(res.map(\.repository.name), ["repo 1"]) - // drill into relations of relations - XCTAssertEqual(res.flatMap { $0.version.products.map(\.name) }, ["product 1"]) + // MUT + let res = try await VersionResult.query(on: app.db, filterBy: .urls(["url-1"])) + + // validate selection and all relations being loaded + #expect(res.map(\.version.packageName) == ["package 1"]) + #expect(res.flatMap{ $0.builds.map(\.buildCommand) } == ["build 1"]) + #expect(res.flatMap{ $0.products.map(\.name) } == ["product 1"]) + #expect(res.flatMap{ $0.targets.map(\.name) } == ["target 1"]) + #expect(res.map(\.package.url) == ["url-1"]) + #expect(res.map(\.repository.name) == ["repo 1"]) + // drill into relations of relations + #expect(res.flatMap { $0.version.products.map(\.name) } == ["product 1"]) + } } - func test_query_filter_urls_no_results() async throws { + @Test func query_filter_urls_no_results() async throws { // Tests PackageResult.query without results has safe relationship accessors - // setup - for index in (0..<3) { - let pkg = try await savePackage(on: app.db, "url-\(index)".url) - do { - let v = try Version(package: pkg, - latest: .release, - packageName: "package \(index)", - reference: .tag(1, 2, 3), - toolsVersion: "5.4") - try await v.save(on: app.db) - try await Build(version: v, - buildCommand: "build \(index)", - platform: .iOS, - status: .ok, - swiftVersion: .v1) - .save(on: app.db) - try await Product(version: v, - type: .library(.automatic), - name: "product \(index)") - .save(on: app.db) - try await Target(version: v, name: "target \(index)") + try await withApp { app in + // setup + for index in (0..<3) { + let pkg = try await savePackage(on: app.db, "url-\(index)".url) + do { + let v = try Version(package: pkg, + latest: .release, + packageName: "package \(index)", + reference: .tag(1, 2, 3), + toolsVersion: "5.4") + try await v.save(on: app.db) + try await Build(version: v, + buildCommand: "build \(index)", + platform: .iOS, + status: .ok, + swiftVersion: .v1) + .save(on: app.db) + try await Product(version: v, + type: .library(.automatic), + name: "product \(index)") .save(on: app.db) + try await Target(version: v, name: "target \(index)") + .save(on: app.db) + } + try await Repository(package: pkg, + name: "repo \(index)") + .save(on: app.db) } - try await Repository(package: pkg, - name: "repo \(index)") - .save(on: app.db) - } - // MUT - let res = try await VersionResult.query( - on: app.db, - filterBy: .urls(["non-existant"]) - ) + // MUT + let res = try await VersionResult.query( + on: app.db, + filterBy: .urls(["non-existant"]) + ) - // validate safe access - XCTAssertEqual(res.map(\.version.packageName), []) - XCTAssertEqual(res.flatMap{ $0.builds.map(\.buildCommand) }, []) - XCTAssertEqual(res.flatMap{ $0.products.map(\.name) }, []) - XCTAssertEqual(res.flatMap{ $0.targets.map(\.name) }, []) - XCTAssertEqual(res.map(\.package.url), []) - XCTAssertEqual(res.map(\.repository.name), []) + // validate safe access + #expect(res.map(\.version.packageName) == []) + #expect(res.flatMap{ $0.builds.map(\.buildCommand) } == []) + #expect(res.flatMap{ $0.products.map(\.name) } == []) + #expect(res.flatMap{ $0.targets.map(\.name) } == []) + #expect(res.map(\.package.url) == []) + #expect(res.map(\.repository.name) == []) + } } - func test_query_author() async throws { + @Test func query_author() async throws { // Tests PackageResult.query with the author filter option - // setup - // first package - let owners = ["foo", "foo", "someone else"] - for index in (0..<3) { - let pkg = try await savePackage(on: app.db, "url-\(index)".url) - do { - let v = try Version(package: pkg, - latest: .release, - packageName: "package \(index)", - reference: .tag(1, 2, 3), - toolsVersion: "5.4") - try await v.save(on: app.db) - try await Build(version: v, - buildCommand: "build \(index)", - platform: .iOS, - status: .ok, - swiftVersion: .v1) - .save(on: app.db) - try await Product(version: v, - type: .library(.automatic), - name: "product \(index)") - .save(on: app.db) - try await Target(version: v, name: "target \(index)") + try await withApp { app in + // setup + // first package + let owners = ["foo", "foo", "someone else"] + for index in (0..<3) { + let pkg = try await savePackage(on: app.db, "url-\(index)".url) + do { + let v = try Version(package: pkg, + latest: .release, + packageName: "package \(index)", + reference: .tag(1, 2, 3), + toolsVersion: "5.4") + try await v.save(on: app.db) + try await Build(version: v, + buildCommand: "build \(index)", + platform: .iOS, + status: .ok, + swiftVersion: .v1) .save(on: app.db) + try await Product(version: v, + type: .library(.automatic), + name: "product \(index)") + .save(on: app.db) + try await Target(version: v, name: "target \(index)") + .save(on: app.db) + } + try await Repository(package: pkg, + name: "repo \(index)", + owner: owners[index]) + .save(on: app.db) } - try await Repository(package: pkg, - name: "repo \(index)", - owner: owners[index]) - .save(on: app.db) - } - // MUT - let res = try await VersionResult.query(on: self.app.db, filterBy: .author("foo")) + // MUT + let res = try await VersionResult.query(on: app.db, filterBy: .author("foo")) - // validate selection (relationship loading is tested in test_query_filter_urls) - XCTAssertEqual(res.map(\.version.packageName), - ["package 0", "package 1"]) + // validate selection (relationship loading is tested in test_query_filter_urls) + #expect(res.map(\.version.packageName) == ["package 0", "package 1"]) + } } - func test_query_custom() async throws { + @Test func query_custom() async throws { // Tests PackageResult.query with the custom collection filter option - // setup - let packages = try await (0..<3).mapAsync { index in - let pkg = try await savePackage(on: app.db, "url-\(index)".url) - do { - let v = try Version(package: pkg, - latest: .release, - packageName: "package \(index)", - reference: .tag(1, 2, 3), - toolsVersion: "5.4") - try await v.save(on: app.db) - try await Build(version: v, - buildCommand: "build \(index)", - platform: .iOS, - status: .ok, - swiftVersion: .v1) - .save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "product \(index)") + try await withApp { app in + // setup + let packages = try await (0..<3).mapAsync { index in + let pkg = try await savePackage(on: app.db, "url-\(index)".url) + do { + let v = try Version(package: pkg, + latest: .release, + packageName: "package \(index)", + reference: .tag(1, 2, 3), + toolsVersion: "5.4") + try await v.save(on: app.db) + try await Build(version: v, + buildCommand: "build \(index)", + platform: .iOS, + status: .ok, + swiftVersion: .v1) .save(on: app.db) - try await Target(version: v, name: "target \(index)") + try await Product(version: v, type: .library(.automatic), name: "product \(index)") + .save(on: app.db) + try await Target(version: v, name: "target \(index)") + .save(on: app.db) + } + try await Repository(package: pkg, name: "repo \(index)", owner: "owner") .save(on: app.db) + return pkg } - try await Repository(package: pkg, name: "repo \(index)", owner: "owner") - .save(on: app.db) - return pkg - } - let collection = CustomCollection(id: .id2, .init(key: "list", - name: "List", - url: "https://github.com/foo/bar/list.json")) - try await collection.save(on: app.db) - try await collection.$packages.attach([packages[0], packages[1]], on: app.db) + let collection = CustomCollection(id: .id2, .init(key: "list", + name: "List", + url: "https://github.com/foo/bar/list.json")) + try await collection.save(on: app.db) + try await collection.$packages.attach([packages[0], packages[1]], on: app.db) - // MUT - let res = try await VersionResult.query(on: self.app.db, - filterBy: .customCollection("list")) + // MUT + let res = try await VersionResult.query(on: app.db, + filterBy: .customCollection("list")) - // validate selection (relationship loading is tested in test_query_filter_urls) - XCTAssertEqual(res.map(\.version.packageName), - ["package 0", "package 1"]) + // validate selection (relationship loading is tested in test_query_filter_urls) + #expect(res.map(\.version.packageName) == ["package 0", "package 1"]) + } } - func test_Version_init() async throws { + @Test func Version_init() async throws { // Tests PackageCollection.Version initialisation from App.Version - // setup - let p = Package(url: "1") - try await p.save(on: app.db) - do { - let v = try Version(package: p, - latest: .release, - packageName: "Foo", - publishedAt: Date(timeIntervalSince1970: 0), - reference: .tag(1, 2, 3), - releaseNotes: "Bar", - supportedPlatforms: [.ios("14.0")], - toolsVersion: "5.3") - try await v.save(on: app.db) - try await Repository(package: p).save(on: app.db) - do { - try await Product(version: v, - type: .library(.automatic), - name: "P1", - targets: ["T1"]).save(on: app.db) - try await Product(version: v, - type: .library(.automatic), - name: "P2", - targets: ["T2"]).save(on: app.db) - } - do { - try await Target(version: v, name: "T1").save(on: app.db) - try await Target(version: v, name: "T-2").save(on: app.db) - } + try await withApp { app in + // setup + let p = Package(url: "1") + try await p.save(on: app.db) do { - try await Build(version: v, - platform: .iOS, - status: .ok, - swiftVersion: .v1).save(on: app.db) - try await Build(version: v, - platform: .macosXcodebuild, - status: .ok, - swiftVersion: .v2).save(on: app.db) + let v = try Version(package: p, + latest: .release, + packageName: "Foo", + publishedAt: Date(timeIntervalSince1970: 0), + reference: .tag(1, 2, 3), + releaseNotes: "Bar", + supportedPlatforms: [.ios("14.0")], + toolsVersion: "5.3") + try await v.save(on: app.db) + try await Repository(package: p).save(on: app.db) + do { + try await Product(version: v, + type: .library(.automatic), + name: "P1", + targets: ["T1"]).save(on: app.db) + try await Product(version: v, + type: .library(.automatic), + name: "P2", + targets: ["T2"]).save(on: app.db) + } + do { + try await Target(version: v, name: "T1").save(on: app.db) + try await Target(version: v, name: "T-2").save(on: app.db) + } + do { + try await Build(version: v, + platform: .iOS, + status: .ok, + swiftVersion: .v1).save(on: app.db) + try await Build(version: v, + platform: .macosXcodebuild, + status: .ok, + swiftVersion: .v2).save(on: app.db) + } } - } - let v = try await XCTUnwrapAsync(try await VersionResult.query(on: app.db,filterBy: .urls(["1"])).first?.version) + let v = try await XCTUnwrapAsync(try await VersionResult.query(on: app.db,filterBy: .urls(["1"])).first?.version) - // MUT - let res = try XCTUnwrap( - PackageCollection.Package.Version(version: v, license: .init(name: "MIT", url: "https://foo/mit")) - ) + // MUT + let res = try #require( + PackageCollection.Package.Version(version: v, license: .init(name: "MIT", url: "https://foo/mit")) + ) - // validate the version - XCTAssertEqual(res.version, "1.2.3") - XCTAssertEqual(res.summary, "Bar") - XCTAssertEqual(res.verifiedCompatibility, [ - .init(platform: .init(name: "ios"), swiftVersion: .init("5.8")), - .init(platform: .init(name: "macos"), swiftVersion: .init("5.9")), - ]) - XCTAssertEqual(res.license, .init(name: "MIT", url: URL(string: "https://foo/mit")!)) - XCTAssertEqual(res.createdAt, Date(timeIntervalSince1970: 0)) - - // The spec requires there to be a dictionary keyed by the default tools version. - let manifest = try XCTUnwrap(res.manifests[res.defaultToolsVersion]) - - // Validate the manifest. - XCTAssertEqual(manifest.packageName, "Foo") - XCTAssertEqual( - manifest.products, - [.init(name: "P1", type: .library(.automatic), targets: ["T1"]), - .init(name: "P2", type: .library(.automatic), targets: ["T2"])]) - XCTAssertEqual( - manifest.targets, - [.init(name: "T1", moduleName: "T1"), - .init(name: "T-2", moduleName: "T_2")]) - XCTAssertEqual(manifest.toolsVersion, "5.3") - XCTAssertEqual(manifest.minimumPlatformVersions, [.init(name: "ios", version: "14.0")]) + // validate the version + #expect(res.version == "1.2.3") + #expect(res.summary == "Bar") + #expect(res.verifiedCompatibility == [ + .init(platform: .init(name: "ios"), swiftVersion: .init("5.8")), + .init(platform: .init(name: "macos"), swiftVersion: .init("5.9")), + ]) + #expect(res.license == .init(name: "MIT", url: URL(string: "https://foo/mit")!)) + #expect(res.createdAt == Date(timeIntervalSince1970: 0)) + + // The spec requires there to be a dictionary keyed by the default tools version. + let manifest = try #require(res.manifests[res.defaultToolsVersion]) + + // Validate the manifest. + #expect(manifest.packageName == "Foo") + #expect( + manifest.products == [.init(name: "P1", type: .library(.automatic), targets: ["T1"]), + .init(name: "P2", type: .library(.automatic), targets: ["T2"])]) + #expect( + manifest.targets == [.init(name: "T1", moduleName: "T1"), + .init(name: "T-2", moduleName: "T_2")]) + #expect(manifest.toolsVersion == "5.3") + #expect(manifest.minimumPlatformVersions == [.init(name: "ios", version: "14.0")]) + } } - func test_Package_init() async throws { + @Test func Package_init() async throws { // Tests PackageCollection.Package initialisation from App.Package - // setup - do { - let p = Package(url: "1") - try await p.save(on: app.db) - try await Repository(package: p, - license: .mit, - licenseUrl: "https://foo/mit", - readmeHtmlUrl: "readmeUrl", - summary: "summary") - .save(on: app.db) - let v = try Version(package: p, - latest: .release, - packageName: "Foo", - reference: .tag(1, 2, 3), - toolsVersion: "5.3") - try await v.save(on: app.db) - try await Product(version: v, - type: .library(.automatic), - name: "product").save(on: app.db) - } - let result = try await XCTUnwrapAsync( - try await VersionResult.query(on: app.db, filterBy: .urls(["1"])).first - ) - let group = VersionResultGroup(package: result.package, - repository: result.repository, - versions: [result.version]) + try await withApp { app in + // setup + do { + let p = Package(url: "1") + try await p.save(on: app.db) + try await Repository(package: p, + license: .mit, + licenseUrl: "https://foo/mit", + readmeHtmlUrl: "readmeUrl", + summary: "summary") + .save(on: app.db) + let v = try Version(package: p, + latest: .release, + packageName: "Foo", + reference: .tag(1, 2, 3), + toolsVersion: "5.3") + try await v.save(on: app.db) + try await Product(version: v, + type: .library(.automatic), + name: "product").save(on: app.db) + } + let result = try await XCTUnwrapAsync( + try await VersionResult.query(on: app.db, filterBy: .urls(["1"])).first + ) + let group = VersionResultGroup(package: result.package, + repository: result.repository, + versions: [result.version]) - // MUT - let res = try XCTUnwrap( - PackageCollection.Package(resultGroup: group, - keywords: ["a", "b"]) - ) + // MUT + let res = try #require( + PackageCollection.Package(resultGroup: group, + keywords: ["a", "b"]) + ) - // validate - XCTAssertEqual(res.keywords, ["a", "b"]) - XCTAssertEqual(res.summary, "summary") - XCTAssertEqual(res.readmeURL, "readmeUrl") - XCTAssertEqual(res.license?.name, "MIT") - // version details tested in test_Version_init - // simply assert count here - XCTAssertEqual(res.versions.count, 1) + // validate + #expect(res.keywords == ["a", "b"]) + #expect(res.summary == "summary") + #expect(res.readmeURL == "readmeUrl") + #expect(res.license?.name == "MIT") + // version details tested in test_Version_init + // simply assert count here + #expect(res.versions.count == 1) + } } - func test_groupedByPackage() async throws { - // setup - // 2 packages by the same author (which we select) with two versions - // each. - do { - let p = Package(url: "2") - try await p.save(on: app.db) - try await Repository( - package: p, - owner: "a" - ).save(on: app.db) - try await Version(package: p, latest: .release, packageName: "2a") - .save(on: app.db) - try await Version(package: p, latest: .release, packageName: "2b") - .save(on: app.db) - } - do { - let p = Package(url: "1") - try await p.save(on: app.db) - try await Repository( - package: p, - owner: "a" - ).save(on: app.db) - try await Version(package: p, latest: .release, packageName: "1a") - .save(on: app.db) - try await Version(package: p, latest: .release, packageName: "1b") - .save(on: app.db) - } - let results = try await VersionResult.query(on: app.db, filterBy: .author("a")) + @Test func groupedByPackage() async throws { + try await withApp { app in + // setup + // 2 packages by the same author (which we select) with two versions + // each. + do { + let p = Package(url: "2") + try await p.save(on: app.db) + try await Repository( + package: p, + owner: "a" + ).save(on: app.db) + try await Version(package: p, latest: .release, packageName: "2a") + .save(on: app.db) + try await Version(package: p, latest: .release, packageName: "2b") + .save(on: app.db) + } + do { + let p = Package(url: "1") + try await p.save(on: app.db) + try await Repository( + package: p, + owner: "a" + ).save(on: app.db) + try await Version(package: p, latest: .release, packageName: "1a") + .save(on: app.db) + try await Version(package: p, latest: .release, packageName: "1b") + .save(on: app.db) + } + let results = try await VersionResult.query(on: app.db, filterBy: .author("a")) - // MUT - let res = results.groupedByPackage(sortBy: .url) + // MUT + let res = results.groupedByPackage(sortBy: .url) - // validate - XCTAssertEqual(res.map(\.package.url), ["1", "2"]) - XCTAssertEqual( - res.first - .flatMap { $0.versions.compactMap(\.packageName) }? - .sorted(), - ["1a", "1b"] - ) - XCTAssertEqual( - res.last - .flatMap { $0.versions.compactMap(\.packageName) }? - .sorted(), - ["2a", "2b"] - ) + // validate + #expect(res.map(\.package.url) == ["1", "2"]) + #expect( + res.first + .flatMap { $0.versions.compactMap(\.packageName) }? + .sorted() == ["1a", "1b"] + ) + #expect( + res.last + .flatMap { $0.versions.compactMap(\.packageName) }? + .sorted() == ["2a", "2b"] + ) + } } - func test_groupedByPackage_empty() throws { + @Test func groupedByPackage_empty() throws { // MUT let res = [VersionResult]().groupedByPackage() // validate - XCTAssertTrue(res.isEmpty) + #expect(res.isEmpty) } - func test_generate_from_urls() async throws { + @Test func generate_from_urls() async throws { try await withDependencies { $0.date.now = .init(timeIntervalSince1970: 1610112345) } operation: { - // setup - let pkg = try await savePackage(on: app.db, "1") - do { - let v = try Version(package: pkg, - latest: .release, - packageName: "package", - reference: .tag(1, 2, 3), - toolsVersion: "5.4") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "product") - .save(on: app.db) - } - try await Repository(package: pkg, - license: .mit, - licenseUrl: "https://foo/mit", - summary: "summary").create(on: app.db) + try await withApp { app in + // setup + let pkg = try await savePackage(on: app.db, "1") + do { + let v = try Version(package: pkg, + latest: .release, + packageName: "package", + reference: .tag(1, 2, 3), + toolsVersion: "5.4") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "product") + .save(on: app.db) + } + try await Repository(package: pkg, + license: .mit, + licenseUrl: "https://foo/mit", + summary: "summary").create(on: app.db) - // MUT - let res = try await PackageCollection.generate(db: self.app.db, - filterBy: .urls(["1"]), - authorName: "Foo", - collectionName: "Foo", - keywords: ["key", "word"], - overview: "overview") - - assertSnapshot(of: res, as: .json(encoder)) + // MUT + let res = try await PackageCollection.generate(db: app.db, + filterBy: .urls(["1"]), + authorName: "Foo", + collectionName: "Foo", + keywords: ["key", "word"], + overview: "overview") + + assertSnapshot(of: res, as: .json(encoder)) + } } } - func test_generate_from_urls_noResults() async throws { - // MUT - do { - _ = try await PackageCollection.generate(db: self.app.db, - filterBy: .urls(["1"]), - authorName: "Foo", - collectionName: "Foo", - keywords: ["key", "word"], - overview: "overview") - XCTFail("Expected error") - } catch let error as PackageCollection.Error { - XCTAssertEqual(error, .noResults) - } catch { - XCTFail("Unexpected error: \(error)") + @Test func generate_from_urls_noResults() async throws { + try await withApp { app in + // MUT + do { + _ = try await PackageCollection.generate(db: app.db, + filterBy: .urls(["1"]), + authorName: "Foo", + collectionName: "Foo", + keywords: ["key", "word"], + overview: "overview") + Issue.record("Expected error") + } catch let error as PackageCollection.Error { + #expect(error == .noResults) + } catch { + Issue.record("Unexpected error: \(error)") + } } } - func test_generate_for_owner() async throws { + @Test func generate_for_owner() async throws { try await withDependencies { $0.date.now = .init(timeIntervalSince1970: 1610112345) } operation: { - // setup - // first package - let p1 = try await savePackage(on: app.db, "https://github.com/foo/1") + try await withApp { app in + // setup + // first package + let p1 = try await savePackage(on: app.db, "https://github.com/foo/1") + do { + let v = try Version(id: UUID(), + package: p1, + packageName: "P1-main", + reference: .branch("main"), + toolsVersion: "5.0") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib") + .save(on: app.db) + } + do { + let v = try Version(id: UUID(), + package: p1, + latest: .release, + packageName: "P1-tag", + reference: .tag(2, 0, 0), + toolsVersion: "5.2") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) + .save(on: app.db) + try await Build(version: v, + platform: .iOS, + status: .ok, + swiftVersion: .init(5, 6, 0)).save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) + } + // second package + let p2 = try await savePackage(on: app.db, "https://github.com/foo/2") + do { + let v = try Version(id: UUID(), + package: p2, + packageName: "P2-main", + reference: .branch("main"), + toolsVersion: "5.3") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib") + .save(on: app.db) + } + do { + let v = try Version(id: UUID(), + package: p2, + latest: .release, + packageName: "P2-tag", + reference: .tag(1, 2, 3), + toolsVersion: "5.3") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t2"]) + .save(on: app.db) + try await Target(version: v, name: "t2").save(on: app.db) + } + // unrelated package + _ = try await savePackage(on: app.db, "https://github.com/bar/1") + try await Repository(package: p1, + defaultBranch: "main", + license: .mit, + licenseUrl: "https://foo/mit", + owner: "foo", + summary: "summary 1").create(on: app.db) + try await Repository(package: p2, + defaultBranch: "main", + license: .mit, + licenseUrl: "https://foo/mit", + owner: "foo", + summary: "summary 2").create(on: app.db) + + // MUT + let res = try await PackageCollection.generate(db: app.db, + filterBy: .author("foo"), + authorName: "Foo", + keywords: ["key", "word"]) + + assertSnapshot(of: res, as: .json(encoder)) + } + } + } + + @Test func generate_for_owner_noResults() async throws { + // Ensure we return noResults when no packages are found + try await withApp { app in + // MUT do { + _ = try await PackageCollection.generate(db: app.db, + filterBy: .author("foo"), + authorName: "Foo", + keywords: ["key", "word"]) + Issue.record("Expected error") + } catch let error as PackageCollection.Error { + #expect(error == .noResults) + } catch { + Issue.record("Unexpected error: \(error)") + } + } + } + + @Test func includes_significant_versions_only() async throws { + // Ensure we only export significant versions + // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1147 + try await withApp { app in + // setup + let p = try await savePackage(on: app.db, "https://github.com/foo/1") + try await Repository(package: p, + defaultBranch: "main", + license: .mit, + licenseUrl: "https://foo/mit", + owner: "foo", + summary: "summary").create(on: app.db) + do { // default branch revision let v = try Version(id: UUID(), - package: p1, + package: p, + latest: .defaultBranch, packageName: "P1-main", reference: .branch("main"), toolsVersion: "5.0") try await v.save(on: app.db) try await Product(version: v, type: .library(.automatic), name: "P1Lib") .save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) } - do { + do { // latest release let v = try Version(id: UUID(), - package: p1, + package: p, latest: .release, - packageName: "P1-tag", - reference: .tag(2, 0, 0), - toolsVersion: "5.2") + packageName: "P1-main", + reference: .tag(1, 2, 3), + toolsVersion: "5.0") try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) + try await Product(version: v, type: .library(.automatic), name: "P1Lib") .save(on: app.db) - try await Build(version: v, - platform: .iOS, - status: .ok, - swiftVersion: .init(5, 6, 0)).save(on: app.db) try await Target(version: v, name: "t1").save(on: app.db) } - // second package - let p2 = try await savePackage(on: app.db, "https://github.com/foo/2") - do { + do { // older release let v = try Version(id: UUID(), - package: p2, - packageName: "P2-main", - reference: .branch("main"), - toolsVersion: "5.3") + package: p, + latest: nil, + packageName: "P1-main", + reference: .tag(1, 0, 0), + toolsVersion: "5.0") try await v.save(on: app.db) try await Product(version: v, type: .library(.automatic), name: "P1Lib") .save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) } - do { + do { // latest beta release let v = try Version(id: UUID(), - package: p2, - latest: .release, - packageName: "P2-tag", - reference: .tag(1, 2, 3), - toolsVersion: "5.3") + package: p, + latest: .preRelease, + packageName: "P1-main", + reference: .tag(2, 0, 0, "b1"), + toolsVersion: "5.0") try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t2"]) + try await Product(version: v, type: .library(.automatic), name: "P1Lib") .save(on: app.db) - try await Target(version: v, name: "t2").save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) + } + do { // older beta release + let v = try Version(id: UUID(), + package: p, + latest: nil, + packageName: "P1-main", + reference: .tag(1, 5, 0, "b1"), + toolsVersion: "5.0") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib") + .save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) } - // unrelated package - _ = try await savePackage(on: app.db, "https://github.com/bar/1") - try await Repository(package: p1, - defaultBranch: "main", - license: .mit, - licenseUrl: "https://foo/mit", - owner: "foo", - summary: "summary 1").create(on: app.db) - try await Repository(package: p2, - defaultBranch: "main", - license: .mit, - licenseUrl: "https://foo/mit", - owner: "foo", - summary: "summary 2").create(on: app.db) - - // MUT - let res = try await PackageCollection.generate(db: self.app.db, - filterBy: .author("foo"), - authorName: "Foo", - keywords: ["key", "word"]) - - assertSnapshot(of: res, as: .json(encoder)) - } - } - - func test_generate_for_owner_noResults() async throws { - // Ensure we return noResults when no packages are found - // MUT - do { - _ = try await PackageCollection.generate(db: self.app.db, - filterBy: .author("foo"), - authorName: "Foo", - keywords: ["key", "word"]) - XCTFail("Expected error") - } catch let error as PackageCollection.Error { - XCTAssertEqual(error, .noResults) - } catch { - XCTFail("Unexpected error: \(error)") - } - } - - func test_includes_significant_versions_only() async throws { - // Ensure we only export significant versions - // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1147 - // setup - let p = try await savePackage(on: app.db, "https://github.com/foo/1") - try await Repository(package: p, - defaultBranch: "main", - license: .mit, - licenseUrl: "https://foo/mit", - owner: "foo", - summary: "summary").create(on: app.db) - do { // default branch revision - let v = try Version(id: UUID(), - package: p, - latest: .defaultBranch, - packageName: "P1-main", - reference: .branch("main"), - toolsVersion: "5.0") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib") - .save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - do { // latest release - let v = try Version(id: UUID(), - package: p, - latest: .release, - packageName: "P1-main", - reference: .tag(1, 2, 3), - toolsVersion: "5.0") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib") - .save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - do { // older release - let v = try Version(id: UUID(), - package: p, - latest: nil, - packageName: "P1-main", - reference: .tag(1, 0, 0), - toolsVersion: "5.0") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib") - .save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - do { // latest beta release - let v = try Version(id: UUID(), - package: p, - latest: .preRelease, - packageName: "P1-main", - reference: .tag(2, 0, 0, "b1"), - toolsVersion: "5.0") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib") - .save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - do { // older beta release - let v = try Version(id: UUID(), - package: p, - latest: nil, - packageName: "P1-main", - reference: .tag(1, 5, 0, "b1"), - toolsVersion: "5.0") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib") - .save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - - try await withDependencies { - $0.date.now = .now - } operation: { - // MUT - let res = try await PackageCollection.generate(db: self.app.db, - filterBy: .author("foo"), - authorName: "Foo", - collectionName: "Foo", - keywords: ["key", "word"], - overview: "overview") - // validate - XCTAssertEqual(res.packages.count, 1) - XCTAssertEqual(res.packages.flatMap { $0.versions.map({$0.version}) }, - ["2.0.0-b1", "1.2.3"]) + try await withDependencies { + $0.date.now = .now + } operation: { + // MUT + let res = try await PackageCollection.generate(db: app.db, + filterBy: .author("foo"), + authorName: "Foo", + collectionName: "Foo", + keywords: ["key", "word"], + overview: "overview") + + // validate + #expect(res.packages.count == 1) + #expect(res.packages.flatMap { $0.versions.map({$0.version}) } == ["2.0.0-b1", "1.2.3"]) + } } } - func test_require_products() async throws { + @Test func require_products() async throws { // Ensure we don't include versions without products (by ensuring // init? returns nil, which will be compact mapped away) - let p = Package(url: "1".asGithubUrl.url) - try await p.save(on: app.db) - let v = try Version(package: p, - packageName: "pkg", - reference: .tag(1,2,3), - toolsVersion: "5.3") - try await v.save(on: app.db) - try await v.$builds.load(on: app.db) - try await v.$products.load(on: app.db) - try await v.$targets.load(on: app.db) - XCTAssertNil(PackageCollection.Package.Version(version: v, - license: nil)) + try await withApp { app in + let p = Package(url: "1".asGithubUrl.url) + try await p.save(on: app.db) + let v = try Version(package: p, + packageName: "pkg", + reference: .tag(1,2,3), + toolsVersion: "5.3") + try await v.save(on: app.db) + try await v.$builds.load(on: app.db) + try await v.$products.load(on: app.db) + try await v.$targets.load(on: app.db) + #expect(PackageCollection.Package.Version(version: v, license: nil) == nil) + } } - func test_require_versions() async throws { + @Test func require_versions() async throws { // Ensure we don't include packages without versions (by ensuring // init? returns nil, which will be compact mapped away) - do { // no versions at all - // setup - let pkg = Package(url: "1") - try await pkg.save(on: app.db) - let repo = try Repository(package: pkg) - try await repo.save(on: app.db) - let group = VersionResultGroup(package: pkg, - repository: repo, - versions: []) + try await withApp { app in + do { // no versions at all + // setup + let pkg = Package(url: "1") + try await pkg.save(on: app.db) + let repo = try Repository(package: pkg) + try await repo.save(on: app.db) + let group = VersionResultGroup(package: pkg, + repository: repo, + versions: []) - // MUT - XCTAssertNil(PackageCollection.Package(resultGroup: group, - keywords: nil)) - } - - do { // only invalid versions - // setup - do { - let p = Package(url: "2") - try await p.save(on: app.db) - try await Version(package: p, latest: .release).save(on: app.db) - try await Repository(package: p).save(on: app.db) + // MUT + #expect(PackageCollection.Package(resultGroup: group, keywords: nil) == nil) } - let res = try await XCTUnwrapAsync( - try await VersionResult.query(on: app.db, filterBy: .urls(["2"])).first - ) - let group = VersionResultGroup(package: res.package, - repository: res.repository, - versions: [res.version]) - // MUT - XCTAssertNil(PackageCollection.Package(resultGroup: group, - keywords: nil)) + do { // only invalid versions + // setup + do { + let p = Package(url: "2") + try await p.save(on: app.db) + try await Version(package: p, latest: .release).save(on: app.db) + try await Repository(package: p).save(on: app.db) + } + let res = try await XCTUnwrapAsync( + try await VersionResult.query(on: app.db, filterBy: .urls(["2"])).first + ) + let group = VersionResultGroup(package: res.package, + repository: res.repository, + versions: [res.version]) + + // MUT + #expect(PackageCollection.Package(resultGroup: group, keywords: nil) == nil) + } } } - func test_case_insensitive_owner_matching() async throws { - // setup - let pkg = try await savePackage(on: app.db, "https://github.com/foo/1") - do { - let v = try Version(id: UUID(), - package: pkg, - latest: .release, - packageName: "P1-tag", - reference: .tag(2, 0, 0), - toolsVersion: "5.2") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) - .save(on: app.db) - } - // Owner "Foo" - try await Repository(package: pkg, - defaultBranch: "main", - license: .mit, - licenseUrl: "https://foo/mit", - owner: "Foo", - summary: "summary 1").create(on: app.db) + @Test func case_insensitive_owner_matching() async throws { + try await withApp { app in + // setup + let pkg = try await savePackage(on: app.db, "https://github.com/foo/1") + do { + let v = try Version(id: UUID(), + package: pkg, + latest: .release, + packageName: "P1-tag", + reference: .tag(2, 0, 0), + toolsVersion: "5.2") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) + .save(on: app.db) + } + // Owner "Foo" + try await Repository(package: pkg, + defaultBranch: "main", + license: .mit, + licenseUrl: "https://foo/mit", + owner: "Foo", + summary: "summary 1").create(on: app.db) - try await withDependencies { - $0.date.now = .now - } operation: { - // MUT - let res = try await PackageCollection.generate(db: self.app.db, - // looking for owner "foo" - filterBy: .author("foo"), - collectionName: "collection") + try await withDependencies { + $0.date.now = .now + } operation: { + // MUT + let res = try await PackageCollection.generate(db: app.db, + // looking for owner "foo" + filterBy: .author("foo"), + collectionName: "collection") - // validate - XCTAssertEqual(res.packages.count, 1) + // validate + #expect(res.packages.count == 1) + } } } - func test_generate_ownerName() async throws { + @Test func generate_ownerName() async throws { // Ensure ownerName is used in collectionName and overview - // setup - // first package - let p1 = try await savePackage(on: app.db, "https://github.com/foo/1") - do { - let v = try Version(id: UUID(), - package: p1, - latest: .release, - packageName: "P1-tag", - reference: .tag(2, 0, 0), - toolsVersion: "5.2") - try await v.save(on: app.db) - try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) - .save(on: app.db) - try await Build(version: v, - platform: .iOS, - status: .ok, - swiftVersion: .v2).save(on: app.db) - try await Target(version: v, name: "t1").save(on: app.db) - } - // unrelated package - try await Repository(package: p1, - defaultBranch: "main", - license: .mit, - licenseUrl: "https://foo/mit", - owner: "foo", - ownerName: "Foo Org", - summary: "summary 1").create(on: app.db) - - try await withDependencies { - $0.date.now = .now - } operation: { - // MUT - let res = try await PackageCollection.generate(db: self.app.db, - filterBy: .author("foo"), - authorName: "Foo", - keywords: ["key", "word"]) + try await withApp { app in + // setup + // first package + let p1 = try await savePackage(on: app.db, "https://github.com/foo/1") + do { + let v = try Version(id: UUID(), + package: p1, + latest: .release, + packageName: "P1-tag", + reference: .tag(2, 0, 0), + toolsVersion: "5.2") + try await v.save(on: app.db) + try await Product(version: v, type: .library(.automatic), name: "P1Lib", targets: ["t1"]) + .save(on: app.db) + try await Build(version: v, + platform: .iOS, + status: .ok, + swiftVersion: .v2).save(on: app.db) + try await Target(version: v, name: "t1").save(on: app.db) + } + // unrelated package + try await Repository(package: p1, + defaultBranch: "main", + license: .mit, + licenseUrl: "https://foo/mit", + owner: "foo", + ownerName: "Foo Org", + summary: "summary 1").create(on: app.db) - // validate - XCTAssertEqual(res.name, "Packages by Foo Org") - XCTAssertEqual(res.overview, "A collection of packages authored by Foo Org from the Swift Package Index") + try await withDependencies { + $0.date.now = .now + } operation: { + // MUT + let res = try await PackageCollection.generate(db: app.db, + filterBy: .author("foo"), + authorName: "Foo", + keywords: ["key", "word"]) + + // validate + #expect(res.name == "Packages by Foo Org") + #expect(res.overview == "A collection of packages authored by Foo Org from the Swift Package Index") + } } } - func test_Compatibility() throws { + @Test func Compatibility() throws { // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1215 // setup var builds = [Build]() @@ -783,43 +801,43 @@ class PackageCollectionTests: AppTestCase { // MUT let res = [PackageCollection.Compatibility].init(builds: builds) // validate - XCTAssertEqual(res.count, 3) - XCTAssertEqual(res.map(\.platform).sorted(), - [.init(name: "ios"), .init(name: "ios"), .init(name: "ios")]) - XCTAssertEqual(res.map(\.swiftVersion).sorted(), - [SwiftVersion.v1, .v2, .v3].map { $0.description(droppingZeroes: .patch) }.sorted()) + #expect(res.count == 3) + #expect(res.map(\.platform).sorted() == [.init(name: "ios"), .init(name: "ios"), .init(name: "ios")]) + #expect(res.map(\.swiftVersion).sorted() == [SwiftVersion.v1, .v2, .v3].map { $0.description(droppingZeroes: .patch) }.sorted()) } - func test_authorLabel() async throws { - // setup - let p = Package(url: "1") - try await p.save(on: app.db) - let repositories = try (0..<3).map { - try Repository(package: p, owner: "owner-\($0)") - } + @Test func authorLabel() async throws { + try await withApp { app in + // setup + let p = Package(url: "1") + try await p.save(on: app.db) + let repositories = try (0..<3).map { + try Repository(package: p, owner: "owner-\($0)") + } - // MUT & validate - XCTAssertEqual( - PackageCollection.authorLabel(repositories: []), - nil - ) - XCTAssertEqual( - PackageCollection.authorLabel(repositories: Array(repositories.prefix(1))), - "owner-0" - ) - XCTAssertEqual( - PackageCollection.authorLabel(repositories: Array(repositories.prefix(2))), - "owner-0 and owner-1" - ) - XCTAssertEqual( - PackageCollection.authorLabel(repositories: repositories), - "multiple authors" - ) + // MUT & validate + #expect( + PackageCollection.authorLabel(repositories: []) == nil + ) + #expect( + PackageCollection.authorLabel(repositories: Array(repositories.prefix(1))) == "owner-0" + ) + #expect( + PackageCollection.authorLabel(repositories: Array(repositories.prefix(2))) == "owner-0 and owner-1" + ) + #expect( + PackageCollection.authorLabel(repositories: repositories) == "multiple authors" + ) + } } - func test_sign_collection() async throws { - try XCTSkipIf(!isRunningInCI && EnvironmentClient.liveValue.collectionSigningPrivateKey() == nil, "Skip test for local user due to unset COLLECTION_SIGNING_PRIVATE_KEY env variable") - + @Test( + .disabled( + if: !isRunningInCI() && EnvironmentClient.liveValue.collectionSigningPrivateKey() == nil, + "Skip test for local user due to unset COLLECTION_SIGNING_PRIVATE_KEY env variable" + ) + ) + func sign_collection() async throws { try await withDependencies { $0.environment.collectionSigningCertificateChain = EnvironmentClient.liveValue.collectionSigningCertificateChain $0.environment.collectionSigningPrivateKey = EnvironmentClient.liveValue.collectionSigningPrivateKey @@ -831,27 +849,27 @@ class PackageCollectionTests: AppTestCase { let signedCollection = try await SignedCollection.sign(collection: collection) // validate signed collection content - XCTAssertFalse(signedCollection.signature.signature.isEmpty) + #expect(!signedCollection.signature.signature.isEmpty) assertSnapshot(of: signedCollection, as: .json(encoder)) // validate signature let validated = try await SignedCollection.validate(signedCollection: signedCollection) - XCTAssertTrue(validated) + #expect(validated) } } - func test_sign_collection_revoked_key() async throws { - // Skipping until https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1583#issuecomment-1066592057 - // is resolved - try XCTSkipIf(true) - + @Test( + .disabled("Skipping until issue is resolved"), + .bug("https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1583#issuecomment-1066592057") + ) + func sign_collection_revoked_key() async throws { // setup let collection: PackageCollection = .mock // get cert and key and make sure the inputs are valid (apart from being revoked) // so we don't fail for that reason let revokedUrl = fixtureUrl(for: "revoked.cer") - XCTAssertTrue(Foundation.FileManager.default.fileExists(atPath: revokedUrl.path)) - let revokedKey = try XCTUnwrap(fixtureData(for: "revoked.pem")) + #expect(Foundation.FileManager.default.fileExists(atPath: revokedUrl.path)) + let revokedKey = try #require(try fixtureData(for: "revoked.pem")) await withDependencies { $0.environment.collectionSigningCertificateChain = { @@ -870,11 +888,11 @@ class PackageCollectionTests: AppTestCase { // in this case we need to check the signature // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1583#issuecomment-1048408400 let validated = try await SignedCollection.validate(signedCollection: signedCollection) - XCTAssertFalse(validated) + #expect(!validated) } catch PackageCollectionSigningError.invalidCertChain { // ok } catch { - XCTFail("unexpected signing error: \(error)") + Issue.record("unexpected signing error: \(error)") } } } diff --git a/Tests/AppTests/PackageContributorsTests.swift b/Tests/AppTests/PackageContributorsTests.swift index 8de218a4d..5ecbb0bd2 100644 --- a/Tests/AppTests/PackageContributorsTests.swift +++ b/Tests/AppTests/PackageContributorsTests.swift @@ -12,16 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest - @testable import App import Dependencies +import Testing -class PackageContributorsTests : AppTestCase { +@Suite struct PackageContributorsTests { - func test_packageAuthors_hasAuthors() throws { + @Test func packageAuthors_hasAuthors() throws { let noPackageAuthors = PackageAuthors(authors: [], numberOfContributors: 0) let somePackageAuthors = PackageAuthors(authors: [ @@ -29,11 +28,11 @@ class PackageContributorsTests : AppTestCase { .init(name: "Person Two") ], numberOfContributors: 0) - XCTAssertFalse(noPackageAuthors.hasAuthors) - XCTAssertTrue(somePackageAuthors.hasAuthors) + #expect(!noPackageAuthors.hasAuthors) + #expect(somePackageAuthors.hasAuthors) } - func test_CommitSelector_primaryContributors() throws { + @Test func CommitSelector_primaryContributors() throws { let candidates = [PackageContributors.Contributor(numberOfCommits: 10, name: "Tim"), PackageContributors.Contributor(numberOfCommits: 100, name: "John"), @@ -43,30 +42,30 @@ class PackageContributorsTests : AppTestCase { // MUT let authors = PackageContributors.primaryContributors(candidates: candidates, threshold: 0.6) - XCTAssertEqual(authors.count, 2) - XCTAssertEqual(authors.map(\.name), ["Maria", "Nathalie"] ) + #expect(authors.count == 2) + #expect(authors.map(\.name) == ["Maria", "Nathalie"] ) } - - func test_CommitSelector_primaryContributors_noCandidates() throws { + @Test func CommitSelector_primaryContributors_noCandidates() throws { // MUT let authors = PackageContributors.primaryContributors(candidates: [], threshold: 0.6) - XCTAssertEqual(authors.count, 0) + #expect(authors.count == 0) } - func test_CommitSelector_filter_singleCandidate() throws { + @Test func CommitSelector_filter_singleCandidate() throws { // MUT - let authors = PackageContributors.primaryContributors(candidates: [PackageContributors.Contributor(numberOfCommits: 10, name: "Tim")], - threshold: 0.6) + let authors = PackageContributors + .primaryContributors(candidates: [PackageContributors.Contributor(numberOfCommits: 10, + name: "Tim")], + threshold: 0.6) - XCTAssertEqual(authors.count, 1) - XCTAssertEqual(authors.map(\.name), ["Tim"] ) + #expect(authors.count == 1) + #expect(authors.map(\.name) == ["Tim"] ) } - - func test_PackageContributors_extract() async throws { + @Test func PackageContributors_extract() async throws { try await withDependencies { $0.fileManager.fileExists = { @Sendable _ in true } $0.git.shortlog = { @Sendable _ in @@ -85,19 +84,21 @@ class PackageContributorsTests : AppTestCase { """ } } operation: { - // setup - let pkg = try await savePackage(on: app.db, "1".asGithubUrl.url) - - // MUT - let pkgAuthors = try await PackageContributors.extract(gitCacheDirectoryPath: "", - packageID: pkg.id) - - XCTAssertEqual(pkgAuthors.authors, [Author(name: "Person 1") , - Author(name: "Person 2"), - Author(name: "Person 3"), - Author(name: "Person 4"), - Author(name: "Person 5")]) - XCTAssertEqual(pkgAuthors.numberOfContributors, 6) + try await withApp { app in + // setup + let pkg = try await savePackage(on: app.db, "1".asGithubUrl.url) + + // MUT + let pkgAuthors = try await PackageContributors.extract(gitCacheDirectoryPath: "", + packageID: pkg.id) + + #expect(pkgAuthors.authors == [Author(name: "Person 1") , + Author(name: "Person 2"), + Author(name: "Person 3"), + Author(name: "Person 4"), + Author(name: "Person 5")]) + #expect(pkgAuthors.numberOfContributors == 6) + } } } diff --git a/Tests/AppTests/PackageController+BuildsRoute+BuildInfoTests.swift b/Tests/AppTests/PackageController+BuildsRoute+BuildInfoTests.swift index ed9bebede..5e77febdb 100644 --- a/Tests/AppTests/PackageController+BuildsRoute+BuildInfoTests.swift +++ b/Tests/AppTests/PackageController+BuildsRoute+BuildInfoTests.swift @@ -14,57 +14,57 @@ @testable import App +import Testing import Vapor -import XCTest -class PackageController_BuildsRoute_BuildInfoTests: AppTestCase { +@Suite struct PackageController_BuildsRoute_BuildInfoTests { - func test_buildStatus() throws { + @Test func buildStatus() throws { // Test build status aggregation, in particular see // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/666 // setup // MUT & verification - XCTAssertEqual([mkBuildInfo(.ok), mkBuildInfo(.failed)].compatibility, .compatible) - XCTAssertEqual([mkBuildInfo(.triggered), mkBuildInfo(.triggered)].compatibility, .unknown) - XCTAssertEqual([mkBuildInfo(.failed), mkBuildInfo(.triggered)].compatibility, .unknown) - XCTAssertEqual([mkBuildInfo(.ok), mkBuildInfo(.triggered)].compatibility, .compatible) + #expect([mkBuildInfo(.ok), mkBuildInfo(.failed)].compatibility == .compatible) + #expect([mkBuildInfo(.triggered), mkBuildInfo(.triggered)].compatibility == .unknown) + #expect([mkBuildInfo(.failed), mkBuildInfo(.triggered)].compatibility == .unknown) + #expect([mkBuildInfo(.ok), mkBuildInfo(.triggered)].compatibility == .compatible) } - func test_noneSucceeded() throws { - XCTAssertTrue([mkBuildInfo(.failed), mkBuildInfo(.failed)].noneSucceeded) - XCTAssertFalse([mkBuildInfo(.ok), mkBuildInfo(.failed)].noneSucceeded) + @Test func noneSucceeded() throws { + #expect([mkBuildInfo(.failed), mkBuildInfo(.failed)].noneSucceeded) + #expect(![mkBuildInfo(.ok), mkBuildInfo(.failed)].noneSucceeded) } - func test_anySucceeded() throws { - XCTAssertTrue([mkBuildInfo(.ok), mkBuildInfo(.failed)].anySucceeded) - XCTAssertFalse([mkBuildInfo(.failed), mkBuildInfo(.failed)].anySucceeded) + @Test func anySucceeded() throws { + #expect([mkBuildInfo(.ok), mkBuildInfo(.failed)].anySucceeded) + #expect(![mkBuildInfo(.failed), mkBuildInfo(.failed)].anySucceeded) } - func test_nonePending() throws { - XCTAssertTrue([mkBuildInfo(.ok), mkBuildInfo(.failed)].nonePending) - XCTAssertFalse([mkBuildInfo(.ok), mkBuildInfo(.triggered)].nonePending) + @Test func nonePending() throws { + #expect([mkBuildInfo(.ok), mkBuildInfo(.failed)].nonePending) + #expect(![mkBuildInfo(.ok), mkBuildInfo(.triggered)].nonePending) // timeouts will not be retried - therefore they are not pending - XCTAssertTrue([mkBuildInfo(.ok), mkBuildInfo(.timeout)].nonePending) + #expect([mkBuildInfo(.ok), mkBuildInfo(.timeout)].nonePending) // infrastructure errors _will_ be retried - they are pending - XCTAssertFalse([mkBuildInfo(.ok), mkBuildInfo(.infrastructureError)].nonePending) + #expect(![mkBuildInfo(.ok), mkBuildInfo(.infrastructureError)].nonePending) } - func test_anyPending() throws { - XCTAssertFalse([mkBuildInfo(.ok), mkBuildInfo(.failed)].anyPending) - XCTAssertTrue([mkBuildInfo(.ok), mkBuildInfo(.triggered)].anyPending) + @Test func anyPending() throws { + #expect(![mkBuildInfo(.ok), mkBuildInfo(.failed)].anyPending) + #expect([mkBuildInfo(.ok), mkBuildInfo(.triggered)].anyPending) // timeouts will not be retried - therefore they are not pending - XCTAssertTrue([mkBuildInfo(.ok), mkBuildInfo(.timeout)].nonePending) + #expect([mkBuildInfo(.ok), mkBuildInfo(.timeout)].nonePending) // infrastructure errors _will_ be retried - they are pending - XCTAssertFalse([mkBuildInfo(.ok), mkBuildInfo(.infrastructureError)].nonePending) + #expect(![mkBuildInfo(.ok), mkBuildInfo(.infrastructureError)].nonePending) } - func test_Platform_isCompatible() throws { - XCTAssertTrue(Build.Platform.iOS.isCompatible(with: .iOS)) - XCTAssertFalse(Build.Platform.iOS.isCompatible(with: .macOS)) + @Test func Platform_isCompatible() throws { + #expect(Build.Platform.iOS.isCompatible(with: .iOS)) + #expect(!Build.Platform.iOS.isCompatible(with: .macOS)) - XCTAssertTrue(Build.Platform.macosSpm.isCompatible(with: .macOS)) - XCTAssertTrue(Build.Platform.macosXcodebuild.isCompatible(with: .macOS)) + #expect(Build.Platform.macosSpm.isCompatible(with: .macOS)) + #expect(Build.Platform.macosXcodebuild.isCompatible(with: .macOS)) } } diff --git a/Tests/AppTests/PackageController+BuildsRouteTests.swift b/Tests/AppTests/PackageController+BuildsRouteTests.swift index c3bd18013..9392e182a 100644 --- a/Tests/AppTests/PackageController+BuildsRouteTests.swift +++ b/Tests/AppTests/PackageController+BuildsRouteTests.swift @@ -14,134 +14,139 @@ @testable import App +import Testing import Vapor -import XCTest -class PackageController_BuildsRouteTests: AppTestCase { + +@Suite struct PackageController_BuildsRouteTests { typealias BuildDetails = (id: Build.Id, reference: Reference, platform: Build.Platform, swiftVersion: SwiftVersion, status: Build.Status, docStatus: DocUpload.Status?) - func test_BuildInfo_query() async throws { - // setup - do { - let pkg = try await savePackage(on: app.db, "1".url) - try await Repository(package: pkg, - defaultBranch: "main", - name: "bar", - owner: "foo").save(on: app.db) - let builds: [BuildDetails] = [ - (.id0, .branch("main"), .iOS, .v2, .ok, .ok), - (.id1, .branch("main"), .tvOS, .v1, .failed, nil), - (.id2, .tag(1, 2, 3), .iOS, .v2, .ok, nil), - (.id3, .tag(2, 0, 0, "b1"), .iOS, .v2, .failed, nil), - ] - for b in builds { - let v = try App.Version(package: pkg, - latest: b.reference.kind, - packageName: "p1", - reference: b.reference) - try await v.save(on: app.db) - let build = try Build(id: b.id, version: v, platform: b.platform, status: b.status, swiftVersion: b.swiftVersion) - try await build.save(on: app.db) - if let docStatus = b.docStatus { - let d = DocUpload(id: .init(), status: docStatus) - try await d.attach(to: build, on: app.db) + @Test func BuildInfo_query() async throws { + try await withApp { app in + // setup + do { + let pkg = try await savePackage(on: app.db, "1".url) + try await Repository(package: pkg, + defaultBranch: "main", + name: "bar", + owner: "foo").save(on: app.db) + let builds: [BuildDetails] = [ + (.id0, .branch("main"), .iOS, .v2, .ok, .ok), + (.id1, .branch("main"), .tvOS, .v1, .failed, nil), + (.id2, .tag(1, 2, 3), .iOS, .v2, .ok, nil), + (.id3, .tag(2, 0, 0, "b1"), .iOS, .v2, .failed, nil), + ] + for b in builds { + let v = try App.Version(package: pkg, + latest: b.reference.kind, + packageName: "p1", + reference: b.reference) + try await v.save(on: app.db) + let build = try Build(id: b.id, version: v, platform: b.platform, status: b.status, swiftVersion: b.swiftVersion) + try await build.save(on: app.db) + if let docStatus = b.docStatus { + let d = DocUpload(id: .init(), status: docStatus) + try await d.attach(to: build, on: app.db) + } } } - } - do { // unrelated package and build - let pkg = try await savePackage(on: app.db, "2".url) - try await Repository(package: pkg, - defaultBranch: "main", - name: "bar2", - owner: "foo").save(on: app.db) - let builds: [BuildDetails] = [ - (.id4, .branch("develop"), .iOS, .v4, .ok, nil), - ] - for b in builds { - let v = try App.Version(package: pkg, - latest: b.reference.kind, - packageName: "p1", - reference: b.reference) - try await v.save(on: app.db) - try await Build(id: b.id, version: v, platform: b.platform, status: b.status, swiftVersion: b.swiftVersion) - .save(on: app.db) + do { // unrelated package and build + let pkg = try await savePackage(on: app.db, "2".url) + try await Repository(package: pkg, + defaultBranch: "main", + name: "bar2", + owner: "foo").save(on: app.db) + let builds: [BuildDetails] = [ + (.id4, .branch("develop"), .iOS, .v4, .ok, nil), + ] + for b in builds { + let v = try App.Version(package: pkg, + latest: b.reference.kind, + packageName: "p1", + reference: b.reference) + try await v.save(on: app.db) + try await Build(id: b.id, version: v, platform: b.platform, status: b.status, swiftVersion: b.swiftVersion) + .save(on: app.db) + } } - } - - // MUT - let builds = try await PackageController.BuildsRoute.BuildInfo.query(on: app.db, owner: "foo", repository: "bar") - // validate - XCTAssertEqual( - builds.sorted { $0.buildId.uuidString < $1.buildId.uuidString }, - [ - .init(versionKind: .defaultBranch, reference: .branch("main"), buildId: .id0, swiftVersion: .v2, platform: .iOS, status: .ok, docStatus: .ok), - .init(versionKind: .defaultBranch, reference: .branch("main"), buildId: .id1, swiftVersion: .v1, platform: .tvOS, status: .failed), - .init(versionKind: .release, reference: .tag(1, 2, 3), buildId: .id2, swiftVersion: .v2, platform: .iOS, status: .ok), - .init(versionKind: .preRelease, reference: .tag(2, 0, 0, "b1"), buildId: .id3, swiftVersion: .v2, platform: .iOS, status: .failed), - ].sorted { $0.buildId.uuidString < $1.buildId.uuidString } - ) + // MUT + let builds = try await PackageController.BuildsRoute.BuildInfo.query(on: app.db, owner: "foo", repository: "bar") + + // validate + #expect( + builds.sorted { $0.buildId.uuidString < $1.buildId.uuidString } == [ + .init(versionKind: .defaultBranch, reference: .branch("main"), buildId: .id0, swiftVersion: .v2, platform: .iOS, status: .ok, docStatus: .ok), + .init(versionKind: .defaultBranch, reference: .branch("main"), buildId: .id1, swiftVersion: .v1, platform: .tvOS, status: .failed), + .init(versionKind: .release, reference: .tag(1, 2, 3), buildId: .id2, swiftVersion: .v2, platform: .iOS, status: .ok), + .init(versionKind: .preRelease, reference: .tag(2, 0, 0, "b1"), buildId: .id3, swiftVersion: .v2, platform: .iOS, status: .failed), + ].sorted { $0.buildId.uuidString < $1.buildId.uuidString } + ) + } } - func test_query() async throws { - // setup - let pkg = try await savePackage(on: app.db, "1".url) - try await Repository(package: pkg, - defaultBranch: "main", - forks: 42, - license: .mit, - name: "bar", - owner: "foo", - stars: 17, - summary: "summary").save(on: app.db) - let v = try Version(package: pkg, latest: .defaultBranch, packageName: "pkg", reference: .branch("main")) - try await v.save(on: app.db) - try await Build(id: .id0, version: v, platform: .iOS, status: .ok, swiftVersion: .v1) - .save(on: app.db) - - // MUT - let (pkgInfo, buildInfo) = try await PackageController.BuildsRoute - .query(on: app.db, owner: "foo", repository: "bar") - - // validate - XCTAssertEqual(pkgInfo, .init(packageName: "pkg", - repositoryOwner: "foo", - repositoryName: "bar")) - XCTAssertEqual(buildInfo, [ - .init(versionKind: .defaultBranch, - reference: .branch("main"), - buildId: .id0, - swiftVersion: .v1, - platform: .iOS, - status: .ok) - ]) + @Test func query() async throws { + try await withApp { app in + // setup + let pkg = try await savePackage(on: app.db, "1".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) + let v = try Version(package: pkg, latest: .defaultBranch, packageName: "pkg", reference: .branch("main")) + try await v.save(on: app.db) + try await Build(id: .id0, version: v, platform: .iOS, status: .ok, swiftVersion: .v1) + .save(on: app.db) + + // MUT + let (pkgInfo, buildInfo) = try await PackageController.BuildsRoute + .query(on: app.db, owner: "foo", repository: "bar") + + // validate + #expect(pkgInfo == .init(packageName: "pkg", + repositoryOwner: "foo", + repositoryName: "bar")) + #expect(buildInfo == [ + .init(versionKind: .defaultBranch, + reference: .branch("main"), + buildId: .id0, + swiftVersion: .v1, + platform: .iOS, + status: .ok) + ]) + } } - func test_query_no_builds() async throws { - // setup - let pkg = try await savePackage(on: app.db, "1".url) - try await Repository(package: pkg, - defaultBranch: "main", - forks: 42, - license: .mit, - name: "bar", - owner: "foo", - stars: 17, - summary: "summary").save(on: app.db) - // no builds and also no packageName set - try await Version(package: pkg, latest: .defaultBranch, packageName: nil).save(on: app.db) - - // MUT - let (pkgInfo, buildInfo) = try await PackageController.BuildsRoute - .query(on: app.db, owner: "foo", repository: "bar") - - // validate - XCTAssertEqual(pkgInfo, .init(packageName: nil, - repositoryOwner: "foo", - repositoryName: "bar")) - XCTAssertEqual(buildInfo, []) - + @Test func query_no_builds() async throws { + try await withApp { app in + // setup + let pkg = try await savePackage(on: app.db, "1".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) + // no builds and also no packageName set + try await Version(package: pkg, latest: .defaultBranch, packageName: nil).save(on: app.db) + + // MUT + let (pkgInfo, buildInfo) = try await PackageController.BuildsRoute + .query(on: app.db, owner: "foo", repository: "bar") + + // validate + #expect(pkgInfo == .init(packageName: nil, + repositoryOwner: "foo", + repositoryName: "bar")) + #expect(buildInfo == []) + } } } diff --git a/Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/test_custom_request.1.json b/Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/custom_request.1.json similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/test_custom_request.1.json rename to Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/custom_request.1.json diff --git a/Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/test_owner_request.1.json b/Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/owner_request.1.json similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/test_owner_request.1.json rename to Tests/AppTests/__Snapshots__/PackageCollectionControllerTests/owner_request.1.json diff --git a/Tests/AppTests/__Snapshots__/PackageCollectionTests/test_generate_for_owner.1.json b/Tests/AppTests/__Snapshots__/PackageCollectionTests/generate_for_owner.1.json similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageCollectionTests/test_generate_for_owner.1.json rename to Tests/AppTests/__Snapshots__/PackageCollectionTests/generate_for_owner.1.json diff --git a/Tests/AppTests/__Snapshots__/PackageCollectionTests/test_generate_from_urls.1.json b/Tests/AppTests/__Snapshots__/PackageCollectionTests/generate_from_urls.1.json similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageCollectionTests/test_generate_from_urls.1.json rename to Tests/AppTests/__Snapshots__/PackageCollectionTests/generate_from_urls.1.json diff --git a/Tests/AppTests/__Snapshots__/PackageCollectionTests/test_sign_collection.1.json b/Tests/AppTests/__Snapshots__/PackageCollectionTests/sign_collection.1.json similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageCollectionTests/test_sign_collection.1.json rename to Tests/AppTests/__Snapshots__/PackageCollectionTests/sign_collection.1.json