diff --git a/Tests/AppTests/PackageInfoTests.swift b/Tests/AppTests/PackageInfoTests.swift index feaf0fd76..41c8170e4 100644 --- a/Tests/AppTests/PackageInfoTests.swift +++ b/Tests/AppTests/PackageInfoTests.swift @@ -14,46 +14,51 @@ @testable import App -import XCTest +import Testing -class PackageInfoTests: AppTestCase { +@Suite struct PackageInfoTests { - func test_title_package_name() async throws { + @Test func title_package_name() async throws { // Ensure title is populated from package.name() - // setup - let p = try await savePackage(on: app.db, "1") - try await Repository(package: p, name: "repo name", owner: "owner") - .save(on: app.db) - try await Version(package: p, latest: .defaultBranch, packageName: "package name") - .save(on: app.db) - let joined = try await XCTUnwrapAsync(try await Joined3 - .query(on: app.db, version: .defaultBranch) - .first()) - - // MUT - let pkgInfo = PackageInfo(package: joined) - - // validate - XCTAssertEqual(pkgInfo?.title, "package name") + try await withApp { app in + // setup + let p = try await savePackage(on: app.db, "1") + try await Repository(package: p, name: "repo name", owner: "owner") + .save(on: app.db) + try await Version(package: p, latest: .defaultBranch, packageName: "package name") + .save(on: app.db) + let joined = try await XCTUnwrapAsync(try await Joined3 + .query(on: app.db, version: .defaultBranch) + .first()) + + // MUT + let pkgInfo = PackageInfo(package: joined) + + // validate + #expect(pkgInfo?.title == "package name") + } } - func test_title_repo_name() async throws { + @Test func title_repo_name() async throws { // Ensure title is populated from repoName if package.name() is nil - // setup - let p = try await savePackage(on: app.db, "1") - try await Repository(package: p, name: "repo name", owner: "owner") - .save(on: app.db) - try await Version(package: p, latest: .defaultBranch, packageName: nil) - .save(on: app.db) - let joined = try await XCTUnwrapAsync(try await Joined3 - .query(on: app.db, version: .defaultBranch) - .first()) - - // MUT - let pkgInfo = PackageInfo(package: joined) - - // validate - XCTAssertEqual(pkgInfo?.title, "repo name") + try await withApp { app in + // setup + let p = try await savePackage(on: app.db, "1") + try await Repository(package: p, name: "repo name", owner: "owner") + .save(on: app.db) + try await Version(package: p, latest: .defaultBranch, packageName: nil) + .save(on: app.db) + let joined = try await XCTUnwrapAsync(try await Joined3 + .query(on: app.db, version: .defaultBranch) + .first()) + + // MUT + let pkgInfo = PackageInfo(package: joined) + + // validate + #expect(pkgInfo?.title == "repo name") + } } + } diff --git a/Tests/AppTests/PackageReadmeModelTests.swift b/Tests/AppTests/PackageReadmeModelTests.swift index d9a4cbfd8..07483d41a 100644 --- a/Tests/AppTests/PackageReadmeModelTests.swift +++ b/Tests/AppTests/PackageReadmeModelTests.swift @@ -12,16 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + @testable import App import SnapshotTesting import SwiftSoup -import XCTVapor +import Testing -class PackageReadmeModelTests: SnapshotTestCase { +@Suite struct PackageReadmeModelTests { - func test_Element_extractReadme() throws { + @Test func Element_extractReadme() throws { let element = Element.extractReadme("""
@@ -29,22 +31,19 @@ class PackageReadmeModelTests: SnapshotTestCase {
""") - XCTAssertEqual(try element?.html(), "

README content.

") + #expect(try element?.html() == "

README content.

") } - func test_URL_rewriteRelative() throws { + @Test func URL_rewriteRelative() throws { let triple = ("owner", "repo", "main") - XCTAssertEqual(URL(string: "https://example.com")?.rewriteRelative(to: triple, fileType: .raw), nil) - XCTAssertEqual(URL(string: "https://example.com/foo")?.rewriteRelative(to: triple, fileType: .raw), nil) - XCTAssertEqual(URL(string: "/foo")?.rewriteRelative(to: triple, fileType: .raw), - "https://github.com/owner/repo/raw/main/foo") - XCTAssertEqual(URL(string: "/foo")?.rewriteRelative(to: triple, fileType: .blob), - "https://github.com/owner/repo/blob/main/foo") - XCTAssertEqual(URL(string: "/foo/bar?query")?.rewriteRelative(to: triple, fileType: .raw), - "https://github.com/owner/repo/raw/main/foo/bar?query") + #expect(URL(string: "https://example.com")?.rewriteRelative(to: triple, fileType: .raw) == nil) + #expect(URL(string: "https://example.com/foo")?.rewriteRelative(to: triple, fileType: .raw) == nil) + #expect(URL(string: "/foo")?.rewriteRelative(to: triple, fileType: .raw) == "https://github.com/owner/repo/raw/main/foo") + #expect(URL(string: "/foo")?.rewriteRelative(to: triple, fileType: .blob) == "https://github.com/owner/repo/blob/main/foo") + #expect(URL(string: "/foo/bar?query")?.rewriteRelative(to: triple, fileType: .raw) == "https://github.com/owner/repo/raw/main/foo/bar?query") } - func test_Element_rewriteRelativeImages() throws { + @Test func Element_rewriteRelativeImages() throws { // setup let element = Element.extractReadme("""
@@ -64,11 +63,11 @@ class PackageReadmeModelTests: SnapshotTestCase { element?.rewriteRelativeImages(to: ("owner", "repo", "main")) // validate - let html = try XCTUnwrap(try element?.html()) + let html = try #require(try element?.html()) assertSnapshot(of: html, as: .lines) } - func test_Element_rewriteRelativeLinks() throws { + @Test func Element_rewriteRelativeLinks() throws { // setup let element = Element.extractReadme("""
@@ -89,26 +88,26 @@ class PackageReadmeModelTests: SnapshotTestCase { element?.rewriteRelativeLinks(to: ("owner", "repo", "main")) // validate - let html = try XCTUnwrap(try element?.html()) + let html = try #require(try element?.html()) assertSnapshot(of: html, as: .lines) } - func test_URL_initWithPotentiallyUnencodedPath() throws { + @Test func URL_initWithPotentiallyUnencodedPath() throws { // Relative URLs - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "/root/relative/url")).absoluteString, "/root/relative/url") - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "relative/url")).absoluteString, "relative/url") - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "/encoded%20spaces")).absoluteString, "/encoded%20spaces") - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "/unencoded spaces")).absoluteString, "/unencoded%20spaces") - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "/multiple%20%7Bencoded%7D")).absoluteString, "/multiple%20%7Bencoded%7D") - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "/multiple {unencoded}")).absoluteString, "/multiple%20%7Bunencoded%7D") + #expect(try #require(URL(withPotentiallyUnencodedPath: "/root/relative/url")).absoluteString == "/root/relative/url") + #expect(try #require(URL(withPotentiallyUnencodedPath: "relative/url")).absoluteString == "relative/url") + #expect(try #require(URL(withPotentiallyUnencodedPath: "/encoded%20spaces")).absoluteString == "/encoded%20spaces") + #expect(try #require(URL(withPotentiallyUnencodedPath: "/unencoded spaces")).absoluteString == "/unencoded%20spaces") + #expect(try #require(URL(withPotentiallyUnencodedPath: "/multiple%20%7Bencoded%7D")).absoluteString == "/multiple%20%7Bencoded%7D") + #expect(try #require(URL(withPotentiallyUnencodedPath: "/multiple {unencoded}")).absoluteString == "/multiple%20%7Bunencoded%7D") // Absolute URLs - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "https://full.host/and/path")).absoluteString, "https://full.host/and/path") - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "https://full.host/encoded%20spaces")).absoluteString, "https://full.host/encoded%20spaces") - XCTAssertEqual(try XCTUnwrap(URL(withPotentiallyUnencodedPath: "https://full.host/unencoded spaces")).absoluteString, "https://full.host/unencoded%20spaces") + #expect(try #require(URL(withPotentiallyUnencodedPath: "https://full.host/and/path")).absoluteString == "https://full.host/and/path") + #expect(try #require(URL(withPotentiallyUnencodedPath: "https://full.host/encoded%20spaces")).absoluteString == "https://full.host/encoded%20spaces") + #expect(try #require(URL(withPotentiallyUnencodedPath: "https://full.host/unencoded spaces")).absoluteString == "https://full.host/unencoded%20spaces") } - func test_Element_fixInlineAnchors() throws { + @Test func Element_fixInlineAnchors() throws { // setup let element = Element.extractReadme("""
@@ -126,11 +125,11 @@ class PackageReadmeModelTests: SnapshotTestCase { element?.fixInlineAnchors() // validate - let html = try XCTUnwrap(try element?.html()) + let html = try #require(try element?.html()) assertSnapshot(of: html, as: .lines) } - func test_Element_fixProtectedCachedImages() throws { + @Test func Element_fixProtectedCachedImages() throws { // setup let element = Element.extractReadme("""
@@ -150,11 +149,11 @@ class PackageReadmeModelTests: SnapshotTestCase { element?.fixProtectedCachedImages() // validate - let html = try XCTUnwrap(try element?.html()) + let html = try #require(try element?.html()) assertSnapshot(of: html, as: .lines) } - func test_Element_disableTurboOnLinks() throws { + @Test func Element_disableTurboOnLinks() throws { // setup let element = Element.extractReadme("""
@@ -172,7 +171,7 @@ class PackageReadmeModelTests: SnapshotTestCase { element?.disableTurboOnLinks() // validate - let html = try XCTUnwrap(try element?.html()) + let html = try #require(try element?.html()) assertSnapshot(of: html, as: .lines) } } diff --git a/Tests/AppTests/PackageReleasesModelTests.swift b/Tests/AppTests/PackageReleasesModelTests.swift index d91b09b7d..31541aef5 100644 --- a/Tests/AppTests/PackageReleasesModelTests.swift +++ b/Tests/AppTests/PackageReleasesModelTests.swift @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + @testable import App -import XCTVapor import Dependencies +import Testing -class PackageReleasesModelTests: AppTestCase { +@Suite struct PackageReleasesModelTests { - func test_initialise() async throws { + @Test func initialise() async throws { // Setup // Work-around to set the local time zone for time sensitive @@ -36,36 +38,38 @@ class PackageReleasesModelTests: AppTestCase { try await withDependencies { $0.date.now = .spiBirthday } operation: { - let pkg = Package(id: UUID(), url: "1".asGithubUrl.url) - try await pkg.save(on: app.db) - - try await Repository(package: pkg, releases: [ - .mock(description: "Release Notes", descriptionHTML: "Release Notes", - publishedAt: 2, tagName: "1.0.0", url: "some url"), - - .mock(description: nil, descriptionHTML: nil, - publishedAt: 1, tagName: "0.0.1", url: "some url"), - ]).save(on: app.db) - let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) - - - // MUT - let model = try XCTUnwrap(PackageReleases.Model(package: jpr)) - - // Validate - XCTAssertEqual(model.releases, [ - .init(title: "1.0.0", date: "Released 50 years ago on 1 January 1970", - html: "Release Notes", link: "some url"), - - .init(title: "0.0.1", date: "Released 50 years ago on 1 January 1970", - html: nil, link: "some url"), - ]) - // NOTE(heckj): test is sensitive to local time zones, breaks when run at GMT-7 - // resolves as `31 December 1969` + try await withApp { app in + let pkg = Package(id: UUID(), url: "1".asGithubUrl.url) + try await pkg.save(on: app.db) + + try await Repository(package: pkg, releases: [ + .mock(description: "Release Notes", descriptionHTML: "Release Notes", + publishedAt: 2, tagName: "1.0.0", url: "some url"), + + .mock(description: nil, descriptionHTML: nil, + publishedAt: 1, tagName: "0.0.1", url: "some url"), + ]).save(on: app.db) + let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) + + + // MUT + let model = try #require(PackageReleases.Model(package: jpr)) + + // Validate + #expect(model.releases == [ + .init(title: "1.0.0", date: "Released 50 years ago on 1 January 1970", + html: "Release Notes", link: "some url"), + + .init(title: "0.0.1", date: "Released 50 years ago on 1 January 1970", + html: nil, link: "some url"), + ]) + // NOTE(heckj): test is sensitive to local time zones, breaks when run at GMT-7 + // resolves as `31 December 1969` + } } } - func test_dateFormatting() throws { + @Test func dateFormatting() throws { // Work-around to set the local time zone for time sensitive // tests. Sets the explicit default time zone to UTC for the duration @@ -80,15 +84,14 @@ class PackageReleasesModelTests: AppTestCase { let currentDate = Date(timeIntervalSince1970: 500) let targetDate = Date(timeIntervalSince1970: 0) - XCTAssertEqual(PackageReleases.Model.formatDate(targetDate, currentDate: currentDate), - "Released 8 minutes ago on 1 January 1970") + #expect(PackageReleases.Model.formatDate(targetDate, currentDate: currentDate) == "Released 8 minutes ago on 1 January 1970") // NOTE(heckj): test is sensitive to local time zones, breaks when run at GMT-7 // resolves as `31 December 1969` - XCTAssertNil(PackageReleases.Model.formatDate(nil, currentDate: currentDate)) + #expect(PackageReleases.Model.formatDate(nil, currentDate: currentDate) == nil) } - func test_removeDuplicateHeader() throws { + @Test func removeDuplicateHeader() throws { do { // First header is removed if it contains the version (positive case) let descriptionHTML = """ @@ -96,8 +99,7 @@ class PackageReleasesModelTests: AppTestCase {

Second Header for v1.0.0

""" - XCTAssertEqual(PackageReleases.Model.updateDescription(descriptionHTML, replacingTitle: "v1.0.0"), - "

Second Header for v1.0.0

") + #expect(PackageReleases.Model.updateDescription(descriptionHTML, replacingTitle: "v1.0.0") == "

Second Header for v1.0.0

") } do { // First header is *only* removed if it contains the version @@ -106,25 +108,24 @@ class PackageReleasesModelTests: AppTestCase {

Second Header for v1.0.0

""" - XCTAssertEqual(PackageReleases.Model.updateDescription(descriptionHTML, replacingTitle: "v1.0.0"), - "

Header for version 1

\n

Second Header for v1.0.0

") + #expect(PackageReleases.Model.updateDescription(descriptionHTML, replacingTitle: "v1.0.0") == "

Header for version 1

\n

Second Header for v1.0.0

") } do { // Supports all header versions (h1-h6) ["h1", "h2", "h3", "h4", "h5", "h6"].forEach { header in let descriptionHTML = "<\(header)>v1.0.0" - XCTAssertEqual(PackageReleases.Model.updateDescription(descriptionHTML, replacingTitle: "v1.0.0"), "") + #expect(PackageReleases.Model.updateDescription(descriptionHTML, replacingTitle: "v1.0.0") == "") } } } - func test_descriptionIsTrimmed() throws { - XCTAssertEqual(PackageReleases.Model.updateDescription(nil, replacingTitle: ""), nil) - XCTAssertEqual(PackageReleases.Model.updateDescription("", replacingTitle: ""), nil) - XCTAssertEqual(PackageReleases.Model.updateDescription(" ", replacingTitle: ""), nil) - XCTAssertEqual(PackageReleases.Model.updateDescription(""" + @Test func descriptionIsTrimmed() throws { + #expect(PackageReleases.Model.updateDescription(nil, replacingTitle: "") == nil) + #expect(PackageReleases.Model.updateDescription("", replacingTitle: "") == nil) + #expect(PackageReleases.Model.updateDescription(" ", replacingTitle: "") == nil) + #expect(PackageReleases.Model.updateDescription(""" - """, replacingTitle: ""), nil) + """, replacingTitle: "") == nil) } } diff --git a/Tests/AppTests/PackageResultTests.swift b/Tests/AppTests/PackageResultTests.swift index 699c1e610..c5f6d2ec2 100644 --- a/Tests/AppTests/PackageResultTests.swift +++ b/Tests/AppTests/PackageResultTests.swift @@ -12,56 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest - @testable import App import SemanticVersion +import Testing -class PackageResultTests: AppTestCase { +@Suite struct PackageResultTests { typealias PackageResult = PackageController.PackageResult - func test_joined5() async throws { - 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) - try await App.Version(package: pkg, - latest: .defaultBranch, - reference: .branch("main")).save(on: app.db) - try await App.Version(package: pkg, - latest: .release, - reference: .tag(1, 2, 3)).save(on: app.db) - try await App.Version(package: pkg, - latest: .preRelease, - reference: .tag(2, 0, 0, "b1")).save(on: app.db) - - // MUT - let res = try await PackageController.PackageResult - .query(on: app.db, owner: "foo", repository: "bar") - - // validate - XCTAssertEqual(res.model.url, "1") - XCTAssertEqual(res.repository.name, "bar") - XCTAssertEqual(res.defaultBranchVersion.reference, .branch("main")) - XCTAssertEqual(res.releaseVersion?.reference, .tag(1, 2, 3)) - XCTAssertEqual(res.preReleaseVersion?.reference, .tag(2, 0, 0, "b1")) - } - - func test_joined5_no_preRelease() async throws { - do { + @Test func joined5() async throws { + try await withApp { app in let pkg = try await savePackage(on: app.db, "1".url) try await Repository(package: pkg, defaultBranch: "main", forks: 42, license: .mit, - name: "bar1", + name: "bar", owner: "foo", stars: 17, summary: "summary").save(on: app.db) @@ -71,218 +38,264 @@ class PackageResultTests: AppTestCase { try await App.Version(package: pkg, latest: .release, reference: .tag(1, 2, 3)).save(on: app.db) - } - do { - // unrelated package to test join behaviour - let pkg = try await savePackage(on: app.db, "2".url) - try await Repository(package: pkg, - defaultBranch: "main", - forks: 42, - license: .mit, - name: "bar2", - owner: "foo", - stars: 17, - summary: "summary").save(on: app.db) try await App.Version(package: pkg, - latest: .defaultBranch, - reference: .branch("main")).save(on: app.db) - try await App.Version(package: pkg, - latest: .release, - reference: .tag(1, 2, 3)).save(on: app.db) - } - - // MUT - let res = try await PackageController.PackageResult - .query(on: app.db, owner: "foo", repository: "bar1") + latest: .preRelease, + reference: .tag(2, 0, 0, "b1")).save(on: app.db) - // validate - XCTAssertEqual(res.model.url, "1") - XCTAssertEqual(res.repository.name, "bar1") - XCTAssertEqual(res.defaultBranchVersion.reference, .branch("main")) - XCTAssertEqual(res.releaseVersion?.reference, .tag(1, 2, 3)) - } + // MUT + let res = try await PackageController.PackageResult + .query(on: app.db, owner: "foo", repository: "bar") - func test_joined5_defaultBranch_only() async throws { - do { - let pkg = try await savePackage(on: app.db, "1".url) - try await Repository(package: pkg, - defaultBranch: "main", - forks: 42, - license: .mit, - name: "bar1", - owner: "foo", - stars: 17, - summary: "summary").save(on: app.db) - try await App.Version(package: pkg, - latest: .defaultBranch, - reference: .branch("main")).save(on: app.db) - } - do { - // unrelated package to test join behaviour - let pkg = try await savePackage(on: app.db, "2".url) - try await Repository(package: pkg, - defaultBranch: "main", - forks: 42, - license: .mit, - name: "bar2", - owner: "foo", - stars: 17, - summary: "summary").save(on: app.db) - try await App.Version(package: pkg, - latest: .defaultBranch, - reference: .branch("main")).save(on: app.db) - try await App.Version(package: pkg, - latest: .release, - reference: .tag(1, 2, 3)).save(on: app.db) + // validate + #expect(res.model.url == "1") + #expect(res.repository.name == "bar") + #expect(res.defaultBranchVersion.reference == .branch("main")) + #expect(res.releaseVersion?.reference == .tag(1, 2, 3)) + #expect(res.preReleaseVersion?.reference == .tag(2, 0, 0, "b1")) } - - // MUT - let res = try await PackageController.PackageResult - .query(on: app.db, owner: "foo", repository: "bar1") - - // validate - XCTAssertEqual(res.model.url, "1") - XCTAssertEqual(res.repository.name, "bar1") - XCTAssertEqual(res.defaultBranchVersion.reference, .branch("main")) } - func test_query_owner_repository() 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 version = try App.Version(package: pkg, + @Test func joined5_no_preRelease() async throws { + try await withApp { app in + do { + let pkg = try await savePackage(on: app.db, "1".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar1", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) + try await App.Version(package: pkg, latest: .defaultBranch, - packageName: "test package", - reference: .branch("main")) - try await version.save(on: app.db) - - // MUT - let res = try await PackageResult.query(on: app.db, owner: "foo", repository: "bar") - - // validate - XCTAssertEqual(res.package.id, pkg.id) - XCTAssertEqual(res.repository.name, "bar") - } - - func test_query_owner_repository_case_insensitivity() 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 version = try App.Version(package: pkg, + reference: .branch("main")).save(on: app.db) + try await App.Version(package: pkg, + latest: .release, + reference: .tag(1, 2, 3)).save(on: app.db) + } + do { + // unrelated package to test join behaviour + let pkg = try await savePackage(on: app.db, "2".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar2", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) + try await App.Version(package: pkg, latest: .defaultBranch, - packageName: "test package", - reference: .branch("main")) - try await version.save(on: app.db) - - // MUT - let res = try await PackageResult.query(on: app.db, owner: "Foo", repository: "bar") - - // validate - XCTAssertEqual(res.package.id, pkg.id) - } - - func test_activity() async throws { - // setup - let pkg = try await savePackage(on: app.db, "https://github.com/Alamofire/Alamofire") - try await Repository(package: pkg, - lastIssueClosedAt: .t0, - lastPullRequestClosedAt: .t1, - name: "bar", - openIssues: 27, - openPullRequests: 1, - owner: "foo").create(on: app.db) - try await Version(package: pkg, latest: .defaultBranch).save(on: app.db) - let pr = try await PackageResult.query(on: app.db, owner: "foo", repository: "bar") + reference: .branch("main")).save(on: app.db) + try await App.Version(package: pkg, + latest: .release, + reference: .tag(1, 2, 3)).save(on: app.db) + } - // MUT - let res = pr.activity() + // MUT + let res = try await PackageController.PackageResult + .query(on: app.db, owner: "foo", repository: "bar1") - // validate - XCTAssertEqual(res, - .init(openIssuesCount: 27, - openIssuesURL: "https://github.com/Alamofire/Alamofire/issues", - openPullRequestsCount: 1, - openPullRequestsURL: "https://github.com/Alamofire/Alamofire/pulls", - lastIssueClosedAt: .t0, - lastPullRequestClosedAt: .t1)) + // validate + #expect(res.model.url == "1") + #expect(res.repository.name == "bar1") + #expect(res.defaultBranchVersion.reference == .branch("main")) + #expect(res.releaseVersion?.reference == .tag(1, 2, 3)) + } } - func test_canonicalDocumentationTarget() async throws { - // setup - do { - // first package has docs - let pkg = try await savePackage(on: app.db, "1".url) - try await Repository(package: pkg, - defaultBranch: "main", - forks: 42, - license: .mit, - name: "bar1", - owner: "foo", - stars: 17, - summary: "summary").save(on: app.db) + @Test func joined5_defaultBranch_only() async throws { + try await withApp { app in do { + let pkg = try await savePackage(on: app.db, "1".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar1", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) try await App.Version(package: pkg, - docArchives: [.init(name: "foo", title: "Foo")], latest: .defaultBranch, reference: .branch("main")).save(on: app.db) } do { + // unrelated package to test join behaviour + let pkg = try await savePackage(on: app.db, "2".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar2", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) + try await App.Version(package: pkg, + latest: .defaultBranch, + reference: .branch("main")).save(on: app.db) try await App.Version(package: pkg, latest: .release, reference: .tag(1, 2, 3)).save(on: app.db) } - do { - try await App.Version(package: pkg, - latest: .preRelease, - reference: .tag(2, 0, 0, "b1")).save(on: app.db) - } + + // MUT + let res = try await PackageController.PackageResult + .query(on: app.db, owner: "foo", repository: "bar1") + + // validate + #expect(res.model.url == "1") + #expect(res.repository.name == "bar1") + #expect(res.defaultBranchVersion.reference == .branch("main")) } - do { - // second package doesn't have docs - let pkg = try await savePackage(on: app.db, "2".url) + } + + @Test func query_owner_repository() 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: "bar2", + name: "bar", owner: "foo", stars: 17, summary: "summary").save(on: app.db) - try await App.Version(package: pkg, - latest: .defaultBranch, - reference: .branch("main")).save(on: app.db) + let version = try App.Version(package: pkg, + latest: .defaultBranch, + packageName: "test package", + reference: .branch("main")) + try await version.save(on: app.db) + + // MUT + let res = try await PackageResult.query(on: app.db, owner: "foo", repository: "bar") + + // validate + #expect(res.package.id == pkg.id) + #expect(res.repository.name == "bar") } + } + + @Test func query_owner_repository_case_insensitivity() 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 version = try App.Version(package: pkg, + latest: .defaultBranch, + packageName: "test package", + reference: .branch("main")) + try await version.save(on: app.db) - do { // MUT - let res = try await PackageController.PackageResult - .query(on: app.db, owner: "foo", repository: "bar1") + let res = try await PackageResult.query(on: app.db, owner: "Foo", repository: "bar") // validate - XCTAssertEqual(res.canonicalDocumentationTarget(), .internal(docVersion: .reference("main"), archive: "foo")) + #expect(res.package.id == pkg.id) } + } + + @Test func activity() async throws { + try await withApp { app in + // setup + let pkg = try await savePackage(on: app.db, "https://github.com/Alamofire/Alamofire") + try await Repository(package: pkg, + lastIssueClosedAt: .t0, + lastPullRequestClosedAt: .t1, + name: "bar", + openIssues: 27, + openPullRequests: 1, + owner: "foo").create(on: app.db) + try await Version(package: pkg, latest: .defaultBranch).save(on: app.db) + let pr = try await PackageResult.query(on: app.db, owner: "foo", repository: "bar") - do { // MUT - let res = try await PackageController.PackageResult - .query(on: app.db, owner: "foo", repository: "bar2") + let res = pr.activity() // validate - XCTAssertEqual(res.canonicalDocumentationTarget(), nil) + #expect(res == .init(openIssuesCount: 27, + openIssuesURL: "https://github.com/Alamofire/Alamofire/issues", + openPullRequestsCount: 1, + openPullRequestsURL: "https://github.com/Alamofire/Alamofire/pulls", + lastIssueClosedAt: .t0, + lastPullRequestClosedAt: .t1)) + } + } + + @Test func canonicalDocumentationTarget() async throws { + try await withApp { app in + // setup + do { + // first package has docs + let pkg = try await savePackage(on: app.db, "1".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar1", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) + do { + try await App.Version(package: pkg, + docArchives: [.init(name: "foo", title: "Foo")], + latest: .defaultBranch, + reference: .branch("main")).save(on: app.db) + } + do { + try await App.Version(package: pkg, + latest: .release, + reference: .tag(1, 2, 3)).save(on: app.db) + } + do { + try await App.Version(package: pkg, + latest: .preRelease, + reference: .tag(2, 0, 0, "b1")).save(on: app.db) + } + } + do { + // second package doesn't have docs + let pkg = try await savePackage(on: app.db, "2".url) + try await Repository(package: pkg, + defaultBranch: "main", + forks: 42, + license: .mit, + name: "bar2", + owner: "foo", + stars: 17, + summary: "summary").save(on: app.db) + try await App.Version(package: pkg, + latest: .defaultBranch, + reference: .branch("main")).save(on: app.db) + } + + do { + // MUT + let res = try await PackageController.PackageResult + .query(on: app.db, owner: "foo", repository: "bar1") + + // validate + #expect(res.canonicalDocumentationTarget() == .internal(docVersion: .reference("main"), archive: "foo")) + } + + do { + // MUT + let res = try await PackageController.PackageResult + .query(on: app.db, owner: "foo", repository: "bar2") + + // validate + #expect(res.canonicalDocumentationTarget() == nil) + } } } + } diff --git a/Tests/AppTests/PackageTests.swift b/Tests/AppTests/PackageTests.swift index dd18517b9..666466603 100644 --- a/Tests/AppTests/PackageTests.swift +++ b/Tests/AppTests/PackageTests.swift @@ -17,87 +17,84 @@ import Dependencies import Fluent import SQLKit +import Testing import Vapor -import XCTVapor -final class PackageTests: AppTestCase { +@Suite struct PackageTests { - func test_Equatable() throws { - XCTAssertEqual(Package(id: .id0, url: "1".url), - Package(id: .id0, url: "2".url)) - XCTAssertFalse(Package() == Package()) - XCTAssertFalse(Package(id: .id0, url: "1".url) == Package()) + @Test func Equatable() throws { + #expect(Package(id: .id0, url: "1".url) == Package(id: .id0, url: "2".url)) + #expect(Package() != Package()) + #expect(Package(id: .id0, url: "1".url) != Package()) } - func test_Hashable() throws { + @Test func Hashable() throws { let packages: Set = [ Package(id: .id0, url: "1".url), Package(id: .id0, url: "2".url), Package(url: "3".url), Package(url: "4".url) ] - XCTAssertEqual(packages.map { "\($0.id)" }.sorted(), - [UUID.id0.uuidString, "nil", "nil"]) - XCTAssertEqual(packages.map { "\($0.url)" }.sorted(), - ["1", "3", "4"]) + #expect(packages.map { "\($0.id)" }.sorted() == [UUID.id0.uuidString, "nil", "nil"]) + #expect(packages.map { "\($0.url)" }.sorted() == ["1", "3", "4"]) } - func test_cacheDirectoryName() throws { - XCTAssertEqual( - Package(url: "https://github.com/finestructure/Arena").cacheDirectoryName, - "github.com-finestructure-arena") - XCTAssertEqual( - Package(url: "https://github.com/finestructure/Arena.git").cacheDirectoryName, - "github.com-finestructure-arena") - XCTAssertEqual( - Package(url: "http://github.com/finestructure/Arena.git").cacheDirectoryName, - "github.com-finestructure-arena") - XCTAssertEqual( - Package(url: "http://github.com/FINESTRUCTURE/ARENA.GIT").cacheDirectoryName, - "github.com-finestructure-arena") - XCTAssertEqual(Package(url: "foo").cacheDirectoryName, nil) - XCTAssertEqual(Package(url: "http://foo").cacheDirectoryName, nil) - XCTAssertEqual(Package(url: "file://foo").cacheDirectoryName, nil) - XCTAssertEqual(Package(url: "http:///foo/bar").cacheDirectoryName, nil) + @Test func cacheDirectoryName() throws { + #expect( + Package(url: "https://github.com/finestructure/Arena").cacheDirectoryName == "github.com-finestructure-arena") + #expect( + Package(url: "https://github.com/finestructure/Arena.git").cacheDirectoryName == "github.com-finestructure-arena") + #expect( + Package(url: "http://github.com/finestructure/Arena.git").cacheDirectoryName == "github.com-finestructure-arena") + #expect( + Package(url: "http://github.com/FINESTRUCTURE/ARENA.GIT").cacheDirectoryName == "github.com-finestructure-arena") + #expect(Package(url: "foo").cacheDirectoryName == nil) + #expect(Package(url: "http://foo").cacheDirectoryName == nil) + #expect(Package(url: "file://foo").cacheDirectoryName == nil) + #expect(Package(url: "http:///foo/bar").cacheDirectoryName == nil) } - func test_save_status() async throws { - do { // default status - let pkg = Package() // avoid using init with default argument in order to test db default - pkg.url = "1" - try await pkg.save(on: app.db) - let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertEqual(readBack.status, .new) - } - do { // with status - try await Package(url: "2", status: .ok).save(on: app.db) - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).filter(by: "2").first()) - XCTAssertEqual(pkg.status, .ok) + @Test func save_status() async throws { + try await withApp { app in + do { // default status + let pkg = Package() // avoid using init with default argument in order to test db default + pkg.url = "1" + try await pkg.save(on: app.db) + let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(readBack.status == .new) + } + do { // with status + try await Package(url: "2", status: .ok).save(on: app.db) + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).filter(by: "2").first()) + #expect(pkg.status == .ok) + } } } - func test_save_scoreDetails() async throws { + @Test func save_scoreDetails() async throws { try await withDependencies { $0.date.now = .now } operation: { - let pkg = Package(url: "1") - let scoreDetails = Score.Details.mock - pkg.scoreDetails = scoreDetails - try await pkg.save(on: app.db) - let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertEqual(readBack.scoreDetails, scoreDetails) + try await withApp { app in + let pkg = Package(url: "1") + let scoreDetails = Score.Details.mock + pkg.scoreDetails = scoreDetails + try await pkg.save(on: app.db) + let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(readBack.scoreDetails == scoreDetails) + } } } - func test_encode() throws { + @Test func encode() throws { let p = Package(id: UUID(), url: URL(string: "https://github.com/finestructure/Arena")!) p.status = .ok let data = try JSONEncoder().encode(p) - XCTAssertTrue(!data.isEmpty) + #expect(!data.isEmpty) } - func test_decode_date() throws { + @Test func decode_date() throws { let json = """ { "id": "CAFECAFE-CAFE-CAFE-CAFE-CAFECAFECAFE", @@ -112,202 +109,213 @@ final class PackageTests: AppTestCase { let decoder = JSONDecoder() decoder.dateDecodingStrategy = .secondsSince1970 let p = try decoder.decode(Package.self, from: Data(json.utf8)) - XCTAssertEqual(p.id?.uuidString, "CAFECAFE-CAFE-CAFE-CAFE-CAFECAFECAFE") - XCTAssertEqual(p.url, "https://github.com/finestructure/Arena") - XCTAssertEqual(p.status, .ok) - XCTAssertEqual(p.createdAt, Date(timeIntervalSince1970: 0)) - XCTAssertEqual(p.updatedAt, Date(timeIntervalSince1970: 1)) - XCTAssertEqual(p.platformCompatibility, [.iOS, .macOS]) + #expect(p.id?.uuidString == "CAFECAFE-CAFE-CAFE-CAFE-CAFECAFECAFE") + #expect(p.url == "https://github.com/finestructure/Arena") + #expect(p.status == .ok) + #expect(p.createdAt == Date(timeIntervalSince1970: 0)) + #expect(p.updatedAt == Date(timeIntervalSince1970: 1)) + #expect(p.platformCompatibility == [.iOS, .macOS]) } - func test_unique_url() async throws { - try await Package(url: "p1").save(on: app.db) - do { + @Test func unique_url() async throws { + try await withApp { app in try await Package(url: "p1").save(on: app.db) - XCTFail("Expected error") - } catch { } + do { + try await Package(url: "p1").save(on: app.db) + Issue.record("Expected error") + } catch { } + } } - func test_filter_by_url() async throws { - for url in ["https://foo.com/1", "https://foo.com/2"] { - try await Package(url: url.url).save(on: app.db) + @Test func filter_by_url() async throws { + try await withApp { app in + for url in ["https://foo.com/1", "https://foo.com/2"] { + try await Package(url: url.url).save(on: app.db) + } + let res = try await Package.query(on: app.db).filter(by: "https://foo.com/1").all() + #expect(res.map(\.url) == ["https://foo.com/1"]) } - let res = try await Package.query(on: app.db).filter(by: "https://foo.com/1").all() - XCTAssertEqual(res.map(\.url), ["https://foo.com/1"]) } - func test_filter_by_urls() async throws { - for url in ["https://foo.com/1.git", "https://foo.com/2.git", "https://foo.com/a.git", "https://foo.com/A.git"] { - try await Package(url: url.url).save(on: app.db) - } - do { // single match - let res = try await Package.query(on: app.db).filter(by: ["https://foo.com/2.git"]).all() - XCTAssertEqual(res.map(\.url), ["https://foo.com/2.git"]) - } - do { // case insensitive match - let res = try await Package.query(on: app.db).filter(by: ["https://foo.com/2.git", "https://foo.com/a.git"]).all() - XCTAssertEqual( - res.map(\.url), - ["https://foo.com/2.git", "https://foo.com/a.git", "https://foo.com/A.git"] - ) - } - do { // input URLs are normalised - let res = try await Package.query(on: app.db).filter(by: ["http://foo.com/2"]).all() - XCTAssertEqual(res.map(\.url), ["https://foo.com/2.git"]) + @Test func filter_by_urls() async throws { + try await withApp { app in + for url in ["https://foo.com/1.git", "https://foo.com/2.git", "https://foo.com/a.git", "https://foo.com/A.git"] { + try await Package(url: url.url).save(on: app.db) + } + do { // single match + let res = try await Package.query(on: app.db).filter(by: ["https://foo.com/2.git"]).all() + #expect(res.map(\.url) == ["https://foo.com/2.git"]) + } + do { // case insensitive match + let res = try await Package.query(on: app.db).filter(by: ["https://foo.com/2.git", "https://foo.com/a.git"]).all() + #expect( + res.map(\.url) == ["https://foo.com/2.git", "https://foo.com/a.git", "https://foo.com/A.git"] + ) + } + do { // input URLs are normalised + let res = try await Package.query(on: app.db).filter(by: ["http://foo.com/2"]).all() + #expect(res.map(\.url) == ["https://foo.com/2.git"]) + } } } - func test_repository() async throws { - let pkg = try await savePackage(on: app.db, "1") - do { - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).with(\.$repositories).first()) - XCTAssertEqual(pkg.repositories.first, nil) - } - do { - let repo = try Repository(package: pkg) - try await repo.save(on: app.db) - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).with(\.$repositories).first()) - XCTAssertEqual(pkg.repositories.first, repo) + @Test func repository() async throws { + try await withApp { app in + let pkg = try await savePackage(on: app.db, "1") + do { + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).with(\.$repositories).first()) + #expect(pkg.repositories.first == nil) + } + do { + let repo = try Repository(package: pkg) + try await repo.save(on: app.db) + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).with(\.$repositories).first()) + #expect(pkg.repositories.first == repo) + } } } - func test_versions() async throws { - let pkg = try await savePackage(on: app.db, "1") - let versions = [ - try Version(package: pkg, reference: .branch("branch")), - try Version(package: pkg, reference: .branch("default")), - try Version(package: pkg, reference: .tag(.init(1, 2, 3))), - ] - try await versions.create(on: app.db) - do { - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).with(\.$versions).first()) - XCTAssertEqual(pkg.versions.count, 3) + @Test func versions() async throws { + try await withApp { app in + let pkg = try await savePackage(on: app.db, "1") + let versions = [ + try Version(package: pkg, reference: .branch("branch")), + try Version(package: pkg, reference: .branch("default")), + try Version(package: pkg, reference: .tag(.init(1, 2, 3))), + ] + try await versions.create(on: app.db) + do { + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).with(\.$versions).first()) + #expect(pkg.versions.count == 3) + } } } - func test_findBranchVersion() async throws { - // setup - let pkg = try await savePackage(on: app.db, "1") - try await Repository(package: pkg, defaultBranch: "default").create(on: app.db) - let versions = [ - try Version(package: pkg, reference: .branch("branch")), - try Version(package: pkg, commitDate: Date.now.adding(days: -1), - reference: .branch("default")), - try Version(package: pkg, reference: .tag(.init(1, 2, 3))), - try Version(package: pkg, commitDate: Date.now.adding(days: -3), - reference: .tag(.init(2, 1, 0))), - try Version(package: pkg, commitDate: Date.now.adding(days: -2), - reference: .tag(.init(3, 0, 0, "beta"))), - ] - try await versions.create(on: app.db) - - // MUT - let version = Package.findBranchVersion(versions: versions, - branch: "default") - - // validation - XCTAssertEqual(version?.reference, .branch("default")) + @Test func findBranchVersion() async throws { + try await withApp { app in + // setup + let pkg = try await savePackage(on: app.db, "1") + try await Repository(package: pkg, defaultBranch: "default").create(on: app.db) + let versions = [ + try Version(package: pkg, reference: .branch("branch")), + try Version(package: pkg, commitDate: Date.now.adding(days: -1), + reference: .branch("default")), + try Version(package: pkg, reference: .tag(.init(1, 2, 3))), + try Version(package: pkg, commitDate: Date.now.adding(days: -3), + reference: .tag(.init(2, 1, 0))), + try Version(package: pkg, commitDate: Date.now.adding(days: -2), + reference: .tag(.init(3, 0, 0, "beta"))), + ] + try await versions.create(on: app.db) + + // MUT + let version = Package.findBranchVersion(versions: versions, + branch: "default") + + // validation + #expect(version?.reference == .branch("default")) + } } - func test_findRelease() async throws { - // setup - let p = try await savePackage(on: app.db, "1") - let versions: [Version] = [ - try .init(package: p, reference: .tag(2, 0, 0)), - try .init(package: p, reference: .tag(1, 2, 3)), - try .init(package: p, reference: .tag(1, 5, 0)), - try .init(package: p, reference: .tag(2, 0, 0, "b1")), - ] - - // MUT & validation - XCTAssertEqual(Package.findRelease(versions)?.reference, .tag(2, 0, 0)) + @Test func findRelease() async throws { + try await withApp { app in + // setup + let p = try await savePackage(on: app.db, "1") + let versions: [Version] = [ + try .init(package: p, reference: .tag(2, 0, 0)), + try .init(package: p, reference: .tag(1, 2, 3)), + try .init(package: p, reference: .tag(1, 5, 0)), + try .init(package: p, reference: .tag(2, 0, 0, "b1")), + ] + + // MUT & validation + #expect(Package.findRelease(versions)?.reference == .tag(2, 0, 0)) + } } - func test_findPreRelease() async throws { - // setup - let p = try await savePackage(on: app.db, "1") - func t(_ seconds: TimeInterval) -> Date { Date(timeIntervalSince1970: seconds) } - - // MUT & validation - XCTAssertEqual( - Package.findPreRelease([ - try .init(package: p, commitDate: t(2), reference: .tag(3, 0, 0, "b1")), - try .init(package: p, commitDate: t(0), reference: .tag(1, 2, 3)), - try .init(package: p, commitDate: t(1), reference: .tag(2, 0, 0)), - ], - after: .tag(2, 0, 0))?.reference, - .tag(3, 0, 0, "b1") - ) - // ensure a beta doesn't come after its release - XCTAssertEqual( - Package.findPreRelease([ - try .init(package: p, commitDate: t(3), reference: .tag(3, 0, 0)), - try .init(package: p, commitDate: t(2), reference: .tag(3, 0, 0, "b1")), - try .init(package: p, commitDate: t(0), reference: .tag(1, 2, 3)), - try .init(package: p, commitDate: t(1), reference: .tag(2, 0, 0)), - ], - after: .tag(3, 0, 0))?.reference, - nil - ) + @Test func findPreRelease() async throws { + try await withApp { app in + // setup + let p = try await savePackage(on: app.db, "1") + func t(_ seconds: TimeInterval) -> Date { Date(timeIntervalSince1970: seconds) } + + // MUT & validation + #expect( + Package.findPreRelease([ + try .init(package: p, commitDate: t(2), reference: .tag(3, 0, 0, "b1")), + try .init(package: p, commitDate: t(0), reference: .tag(1, 2, 3)), + try .init(package: p, commitDate: t(1), reference: .tag(2, 0, 0)), + ], + after: .tag(2, 0, 0))?.reference == .tag(3, 0, 0, "b1") + ) + // ensure a beta doesn't come after its release + #expect( + Package.findPreRelease([ + try .init(package: p, commitDate: t(3), reference: .tag(3, 0, 0)), + try .init(package: p, commitDate: t(2), reference: .tag(3, 0, 0, "b1")), + try .init(package: p, commitDate: t(0), reference: .tag(1, 2, 3)), + try .init(package: p, commitDate: t(1), reference: .tag(2, 0, 0)), + ], + after: .tag(3, 0, 0))?.reference == nil + ) + } } - func test_findPreRelease_double_digit_build() async throws { + @Test func findPreRelease_double_digit_build() async throws { // Test pre-release sorting of betas with double digit build numbers, // e.g. 2.0.0-b11 should come after 2.0.0-b9 // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/706 - // setup - let p = try await savePackage(on: app.db, "1") - func t(_ seconds: TimeInterval) -> Date { Date(timeIntervalSince1970: seconds) } - - // MUT & validation - XCTAssertEqual( - Package.findPreRelease([ - try .init(package: p, commitDate: t(0), reference: .tag(2, 0, 0, "b9")), - try .init(package: p, commitDate: t(1), reference: .tag(2, 0, 0, "b10")), - try .init(package: p, commitDate: t(2), reference: .tag(2, 0, 0, "b11")), - ], - after: nil)?.reference, - .tag(2, 0, 0, "b11") - ) + try await withApp { app in + // setup + let p = try await savePackage(on: app.db, "1") + func t(_ seconds: TimeInterval) -> Date { Date(timeIntervalSince1970: seconds) } + + // MUT & validation + #expect( + Package.findPreRelease([ + try .init(package: p, commitDate: t(0), reference: .tag(2, 0, 0, "b9")), + try .init(package: p, commitDate: t(1), reference: .tag(2, 0, 0, "b10")), + try .init(package: p, commitDate: t(2), reference: .tag(2, 0, 0, "b11")), + ], + after: nil)?.reference == .tag(2, 0, 0, "b11") + ) + } } - func test_findSignificantReleases_old_beta() async throws { + @Test func findSignificantReleases_old_beta() async throws { // Test to ensure outdated betas aren't picked up as latest versions - // setup - let pkg = Package(id: UUID(), url: "1") - try await pkg.save(on: app.db) - try await Repository(package: pkg, defaultBranch: "main").save(on: app.db) - let versions = [ - try Version(package: pkg, packageName: "foo", reference: .branch("main")), - try Version(package: pkg, packageName: "foo", reference: .tag(2, 0, 0)), - try Version(package: pkg, packageName: "foo", reference: .tag(2, 0, 0, "rc1")) - ] - try await versions.save(on: app.db) - - // MUT - let (release, preRelease, defaultBranch) = Package.findSignificantReleases(versions: versions, branch: "main") - - // validate - XCTAssertEqual(release?.reference, .tag(2, 0, 0)) - XCTAssertEqual(preRelease, nil) - XCTAssertEqual(defaultBranch?.reference, .branch("main")) + try await withApp { app in + // setup + let pkg = Package(id: UUID(), url: "1") + try await pkg.save(on: app.db) + try await Repository(package: pkg, defaultBranch: "main").save(on: app.db) + let versions = [ + try Version(package: pkg, packageName: "foo", reference: .branch("main")), + try Version(package: pkg, packageName: "foo", reference: .tag(2, 0, 0)), + try Version(package: pkg, packageName: "foo", reference: .tag(2, 0, 0, "rc1")) + ] + try await versions.save(on: app.db) + + // MUT + let (release, preRelease, defaultBranch) = Package.findSignificantReleases(versions: versions, branch: "main") + + // validate + #expect(release?.reference == .tag(2, 0, 0)) + #expect(preRelease == nil) + #expect(defaultBranch?.reference == .branch("main")) + } } - func test_versionUrl() throws { - XCTAssertEqual(Package(url: "https://github.com/foo/bar").versionUrl(for: .tag(1, 2, 3)), - "https://github.com/foo/bar/releases/tag/1.2.3") - XCTAssertEqual(Package(url: "https://github.com/foo/bar").versionUrl(for: .branch("main")), - "https://github.com/foo/bar/tree/main") - XCTAssertEqual(Package(url: "https://gitlab.com/foo/bar").versionUrl(for: .tag(1, 2, 3)), - "https://gitlab.com/foo/bar/-/tags/1.2.3") - XCTAssertEqual(Package(url: "https://gitlab.com/foo/bar").versionUrl(for: .branch("main")), - "https://gitlab.com/foo/bar/-/tree/main") + @Test func versionUrl() throws { + #expect(Package(url: "https://github.com/foo/bar").versionUrl(for: .tag(1, 2, 3)) == "https://github.com/foo/bar/releases/tag/1.2.3") + #expect(Package(url: "https://github.com/foo/bar").versionUrl(for: .branch("main")) == "https://github.com/foo/bar/tree/main") + #expect(Package(url: "https://gitlab.com/foo/bar").versionUrl(for: .tag(1, 2, 3)) == "https://gitlab.com/foo/bar/-/tags/1.2.3") + #expect(Package(url: "https://gitlab.com/foo/bar").versionUrl(for: .branch("main")) == "https://gitlab.com/foo/bar/-/tree/main") // ensure .git is stripped off - XCTAssertEqual(Package(url: "https://github.com/foo/bar.git").versionUrl(for: .tag(1, 2, 3)), - "https://github.com/foo/bar/releases/tag/1.2.3") + #expect(Package(url: "https://github.com/foo/bar.git").versionUrl(for: .tag(1, 2, 3)) == "https://github.com/foo/bar/releases/tag/1.2.3") } - func test_isNew() async throws { + @Test func isNew() async throws { let url = "1".asGithubUrl try await withDependencies { $0.date.now = .now @@ -337,131 +345,139 @@ final class PackageTests: AppTestCase { return "" } } operation: { - // setup - let db = app.db - // run reconcile to ingest package - try await reconcile(client: app.client, database: app.db) - try await XCTAssertEqualAsync(try await Package.query(on: db).count(), 1) - - // MUT & validate - do { - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertTrue(pkg.isNew) - } - - // run ingestion to progress package through pipeline - try await Ingestion.ingest(client: app.client, database: app.db, mode: .limit(10)) + try await withApp { app in + // setup + let db = app.db + // run reconcile to ingest package + try await reconcile(client: app.client, database: app.db) + try await XCTAssertEqualAsync(try await Package.query(on: db).count(), 1) + + // MUT & validate + do { + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(pkg.isNew) + } - // MUT & validate - do { - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertTrue(pkg.isNew) - } - - // run analysis to progress package through pipeline - try await Analyze.analyze(client: app.client, database: app.db, mode: .limit(10)) - - // MUT & validate - do { - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertFalse(pkg.isNew) - } - - // run stages again to simulate the cycle... - - try await reconcile(client: app.client, database: app.db) - do { - let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertFalse(pkg.isNew) - } - - try await withDependencies { - $0.date.now = .now.addingTimeInterval(Constants.reIngestionDeadtime) - } operation: { + // run ingestion to progress package through pipeline try await Ingestion.ingest(client: app.client, database: app.db, mode: .limit(10)) + // MUT & validate do { let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertFalse(pkg.isNew) + #expect(pkg.isNew) } + // run analysis to progress package through pipeline try await Analyze.analyze(client: app.client, database: app.db, mode: .limit(10)) + // MUT & validate do { let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertFalse(pkg.isNew) + #expect(!pkg.isNew) + } + + // run stages again to simulate the cycle... + + try await reconcile(client: app.client, database: app.db) + do { + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(!pkg.isNew) + } + + try await withDependencies { + $0.date.now = .now.addingTimeInterval(Constants.reIngestionDeadtime) + } operation: { + try await Ingestion.ingest(client: app.client, database: app.db, mode: .limit(10)) + + do { + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(!pkg.isNew) + } + + try await Analyze.analyze(client: app.client, database: app.db, mode: .limit(10)) + + do { + let pkg = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(!pkg.isNew) + } } } } } - func test_isNew_processingStage_nil() { + @Test func isNew_processingStage_nil() { // ensure a package with processingStage == nil is new // MUT & validate let pkg = Package(url: "1", processingStage: nil) - XCTAssertTrue(pkg.isNew) + #expect(pkg.isNew) } - func test_save_platformCompatibility_save() async throws { - try await Package(url: "1".url, platformCompatibility: [.iOS, .macOS, .iOS]) - .save(on: app.db) - let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertEqual(readBack.platformCompatibility, [.iOS, .macOS]) + @Test func save_platformCompatibility_save() async throws { + try await withApp { app in + try await Package(url: "1".url, platformCompatibility: [.iOS, .macOS, .iOS]) + .save(on: app.db) + let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(readBack.platformCompatibility == [.iOS, .macOS]) + } } - func test_save_platformCompatibility_read_nonunique() async throws { + @Test func save_platformCompatibility_read_nonunique() async throws { // test reading back of a non-unique array (this shouldn't be // occuring but we can't enforce a set at the DDL level so it's // technically possible and we want to ensure it doesn't cause // errors) - try await Package(url: "1".url).save(on: app.db) - try await (app.db as! SQLDatabase).raw( - "update packages set platform_compatibility = '{ios,ios}'" - ).run() - let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) - XCTAssertEqual(readBack.platformCompatibility, [.iOS]) + try await withApp { app in + try await Package(url: "1".url).save(on: app.db) + try await (app.db as! SQLDatabase).raw( + "update packages set platform_compatibility = '{ios,ios}'" + ).run() + let readBack = try await XCTUnwrapAsync(try await Package.query(on: app.db).first()) + #expect(readBack.platformCompatibility == [.iOS]) + } } - func test_updatePlatformCompatibility() async throws { - // setup - let p = try await savePackage(on: app.db, "1") - let v = try Version(package: p, latest: .defaultBranch) - try await v.save(on: app.db) - for platform in Build.Platform.allCases { - // Create a build record for each platform to ensure we can read back - // any mapped build correctly. - // For instance, if macos-spm wasn't mapped to macos in the update statement, - // reading back that package would fail when de-serialising `macos-spm` - // into `Package.PlatformCompatibility`, because it has no such enum - // case. - // We need to test this explicitly, because the raw SQL update statement - // in combination with a plain TEXT[] backing field for - // platform_compatibility prevents us from relying on type safety. - // This test ensures that a newly added case in Build.Platform - // must also be handled in the updatePlatformCompatibility SQL - // statement. - // If it isn't, this test will fail with: - // invalid field: platform_compatibility type: Set error: Unexpected data type: TEXT. Expected jsonb/json - // (which is a bit obscure but means that the content of - // platform_compatibility cannot be de-serialised into - // PlatformCompatibility) - try await Build(version: v, platform: platform, status: .ok, swiftVersion: .v1) - .save(on: app.db) + @Test func updatePlatformCompatibility() async throws { + try await withApp { app in + // setup + let p = try await savePackage(on: app.db, "1") + let v = try Version(package: p, latest: .defaultBranch) + try await v.save(on: app.db) + for platform in Build.Platform.allCases { + // Create a build record for each platform to ensure we can read back + // any mapped build correctly. + // For instance, if macos-spm wasn't mapped to macos in the update statement, + // reading back that package would fail when de-serialising `macos-spm` + // into `Package.PlatformCompatibility`, because it has no such enum + // case. + // We need to test this explicitly, because the raw SQL update statement + // in combination with a plain TEXT[] backing field for + // platform_compatibility prevents us from relying on type safety. + // This test ensures that a newly added case in Build.Platform + // must also be handled in the updatePlatformCompatibility SQL + // statement. + // If it isn't, this test will fail with: + // invalid field: platform_compatibility type: Set error: Unexpected data type: TEXT. Expected jsonb/json + // (which is a bit obscure but means that the content of + // platform_compatibility cannot be de-serialised into + // PlatformCompatibility) + try await Build(version: v, platform: platform, status: .ok, swiftVersion: .v1) + .save(on: app.db) + } + try await savePackage(on: app.db, "2") + + // MUT + try await Package.updatePlatformCompatibility(for: p.requireID(), on: app.db) + + // validate + let p1 = try await XCTUnwrapAsync( + try await Package.query(on: app.db).filter(by: "1".url).first() + ) + #expect(p1.platformCompatibility == [.iOS, .macOS, .linux, .tvOS, .visionOS, .watchOS]) + let p2 = try await XCTUnwrapAsync( + try await Package.query(on: app.db).filter(by: "2".url).first() + ) + #expect(p2.platformCompatibility == []) } - try await savePackage(on: app.db, "2") - - // MUT - try await Package.updatePlatformCompatibility(for: p.requireID(), on: app.db) - - // validate - let p1 = try await XCTUnwrapAsync( - try await Package.query(on: app.db).filter(by: "1".url).first() - ) - XCTAssertEqual(p1.platformCompatibility, [.iOS, .macOS, .linux, .tvOS, .visionOS, .watchOS]) - let p2 = try await XCTUnwrapAsync( - try await Package.query(on: app.db).filter(by: "2".url).first() - ) - XCTAssertEqual(p2.platformCompatibility, []) } } diff --git a/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_disableTurboOnLinks.1.txt b/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_disableTurboOnLinks.1.txt similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_disableTurboOnLinks.1.txt rename to Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_disableTurboOnLinks.1.txt diff --git a/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_fixInlineAnchors.1.txt b/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_fixInlineAnchors.1.txt similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_fixInlineAnchors.1.txt rename to Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_fixInlineAnchors.1.txt diff --git a/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_fixProtectedCachedImages.1.txt b/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_fixProtectedCachedImages.1.txt similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_fixProtectedCachedImages.1.txt rename to Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_fixProtectedCachedImages.1.txt diff --git a/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_rewriteRelativeImages.1.txt b/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_rewriteRelativeImages.1.txt similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_rewriteRelativeImages.1.txt rename to Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_rewriteRelativeImages.1.txt diff --git a/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_rewriteRelativeLinks.1.txt b/Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_rewriteRelativeLinks.1.txt similarity index 100% rename from Tests/AppTests/__Snapshots__/PackageReadmeModelTests/test_Element_rewriteRelativeLinks.1.txt rename to Tests/AppTests/__Snapshots__/PackageReadmeModelTests/Element_rewriteRelativeLinks.1.txt