From 59798c80c559f27cfb7e9f62ddf8a4d7f217faf6 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:18:38 +0100 Subject: [PATCH 01/15] Convert ShellOutCommandExtensionTests --- .../ShellOutCommandExtensionTests.swift | 85 ++++++++----------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/Tests/AppTests/ShellOutCommandExtensionTests.swift b/Tests/AppTests/ShellOutCommandExtensionTests.swift index 6066372f4..1968932f9 100644 --- a/Tests/AppTests/ShellOutCommandExtensionTests.swift +++ b/Tests/AppTests/ShellOutCommandExtensionTests.swift @@ -14,88 +14,75 @@ @testable import App -import XCTest import ShellOut +import Testing -class ShellOutCommandExtensionTests: XCTestCase { +@Suite struct ShellOutCommandExtensionTests { - func test_gitClean() throws { - XCTAssertEqual(ShellOutCommand.gitClean.description, "git clean -fdx") + @Test func gitClean() throws { + #expect(ShellOutCommand.gitClean.description == "git clean -fdx") } - func test_gitCommitCount() throws { - XCTAssertEqual(ShellOutCommand.gitCommitCount.description, "git rev-list --count HEAD") + @Test func gitCommitCount() throws { + #expect(ShellOutCommand.gitCommitCount.description == "git rev-list --count HEAD") } - func test_gitFetch() throws { - XCTAssertEqual(ShellOutCommand.gitFetchAndPruneTags.description, "git fetch --tags --prune-tags --prune") + @Test func gitFetch() throws { + #expect(ShellOutCommand.gitFetchAndPruneTags.description == "git fetch --tags --prune-tags --prune") } - func test_gitFirstCommitDate() throws { - XCTAssertEqual(ShellOutCommand.gitFirstCommitDate.description, - #"git log --max-parents=0 -n1 --format=format:"%ct""#) + @Test func gitFirstCommitDate() throws { + #expect(ShellOutCommand.gitFirstCommitDate.description == #"git log --max-parents=0 -n1 --format=format:"%ct""#) } - func test_gitLastCommitDate() throws { - XCTAssertEqual(ShellOutCommand.gitLastCommitDate.description, - #"git log -n1 --format=format:"%ct""#) + @Test func gitLastCommitDate() throws { + #expect(ShellOutCommand.gitLastCommitDate.description == #"git log -n1 --format=format:"%ct""#) } - func test_gitReset() throws { - XCTAssertEqual(ShellOutCommand.gitReset(hard: true).description, - "git reset --hard") - XCTAssertEqual(ShellOutCommand.gitReset(hard: false).description, - "git reset") + @Test func gitReset() throws { + #expect(ShellOutCommand.gitReset(hard: true).description == "git reset --hard") + #expect(ShellOutCommand.gitReset(hard: false).description == "git reset") } - func test_gitReset_branch() throws { - XCTAssertEqual(ShellOutCommand.gitReset(to: "foo", hard: true).description, - "git reset origin/foo --hard") - XCTAssertEqual(ShellOutCommand.gitReset(to: "foo", hard: false).description, - "git reset origin/foo") + @Test func gitReset_branch() throws { + #expect(ShellOutCommand.gitReset(to: "foo", hard: true).description == "git reset origin/foo --hard") + #expect(ShellOutCommand.gitReset(to: "foo", hard: false).description == "git reset origin/foo") } - func test_gitRevisionInfo() throws { + @Test func gitRevisionInfo() throws { let dash = "-" - XCTAssertEqual( + #expect( ShellOutCommand - .gitRevisionInfo(reference: .tag(1, 2, 3), separator: dash).description, - #"git log -n1 --format=tformat:"%H\#(dash)%ct" 1.2.3"# + .gitRevisionInfo(reference: .tag(1, 2, 3), separator: dash).description == #"git log -n1 --format=tformat:"%H\#(dash)%ct" 1.2.3"# ) - XCTAssertEqual( + #expect( ShellOutCommand - .gitRevisionInfo(reference: .branch("foo"), separator: dash).description, - #"git log -n1 --format=tformat:"%H\#(dash)%ct" foo"# + .gitRevisionInfo(reference: .branch("foo"), separator: dash).description == #"git log -n1 --format=tformat:"%H\#(dash)%ct" foo"# ) - XCTAssertEqual( + #expect( ShellOutCommand - .gitRevisionInfo(reference: .branch("ba\nd"), separator: dash).description, - "git log -n1 --format=tformat:\"%H\(dash)%ct\" 'ba\nd'" + .gitRevisionInfo(reference: .branch("ba\nd"), separator: dash).description == "git log -n1 --format=tformat:\"%H\(dash)%ct\" 'ba\nd'" ) } - func test_gitShowDate() throws { - XCTAssertEqual(ShellOutCommand.gitShowDate("abc").description, - #"git show -s --format=%ct abc"#) + @Test func gitShowDate() throws { + #expect(ShellOutCommand.gitShowDate("abc").description == #"git show -s --format=%ct abc"#) } - func test_gitListTags() throws { - XCTAssertEqual(ShellOutCommand.gitListTags.description, "git tag") + @Test func gitListTags() throws { + #expect(ShellOutCommand.gitListTags.description == "git tag") } - func test_quoting() throws { - XCTAssertEqual( - ShellOutCommand.gitReset(to: "foo ; rm *", hard: false).description, - "git reset origin/'foo ; rm *'" + @Test func quoting() throws { + #expect( + ShellOutCommand.gitReset(to: "foo ; rm *", hard: false).description == "git reset origin/'foo ; rm *'" ) - XCTAssertEqual( - ShellOutCommand.gitRevisionInfo(reference: .branch("foo ; rm *")).description, - #"git log -n1 --format=tformat:"%H-%ct" 'foo ; rm *'"# + #expect( + ShellOutCommand.gitRevisionInfo(reference: .branch("foo ; rm *")).description == #"git log -n1 --format=tformat:"%H-%ct" 'foo ; rm *'"# ) - XCTAssertEqual( - ShellOutCommand.gitShowDate("foo ; rm *").description, - #"git show -s --format=%ct 'foo ; rm *'"# + #expect( + ShellOutCommand.gitShowDate("foo ; rm *").description == #"git show -s --format=%ct 'foo ; rm *'"# ) } From 473749b8f641e03d4a38ffc1df7a2bc31c332643 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:19:38 +0100 Subject: [PATCH 02/15] Convert SignificantBuildsTests --- Tests/AppTests/SignificantBuildsTests.swift | 36 ++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Tests/AppTests/SignificantBuildsTests.swift b/Tests/AppTests/SignificantBuildsTests.swift index eccb277f8..92f308633 100644 --- a/Tests/AppTests/SignificantBuildsTests.swift +++ b/Tests/AppTests/SignificantBuildsTests.swift @@ -14,12 +14,12 @@ @testable import App -import XCTest +import Testing -class SignificantBuildsTests: XCTestCase { +@Suite struct SignificantBuildsTests { - func test_swiftVersionCompatibility() throws { + @Test func swiftVersionCompatibility() throws { // setup let sb = SignificantBuilds(buildInfo: [ (.v3, .linux, .ok), @@ -28,13 +28,13 @@ class SignificantBuildsTests: XCTestCase { ]) // MUT - let res = try XCTUnwrap(sb.swiftVersionCompatibility().values) + let res = try #require(sb.swiftVersionCompatibility().values) // validate - XCTAssertEqual(res.sorted(), [.v2, .v3]) + #expect(res.sorted() == [.v2, .v3]) } - func test_swiftVersionCompatibility_allPending() throws { + @Test func swiftVersionCompatibility_allPending() throws { // setup let sb = SignificantBuilds(buildInfo: [ (.v3, .linux, .triggered), @@ -46,10 +46,10 @@ class SignificantBuildsTests: XCTestCase { let res = sb.swiftVersionCompatibility() // validate - XCTAssertEqual(res, .pending) + #expect(res == .pending) } - func test_swiftVersionCompatibility_partialPending() throws { + @Test func swiftVersionCompatibility_partialPending() throws { // setup let sb = SignificantBuilds(buildInfo: [ (.v3, .linux, .ok), @@ -58,13 +58,13 @@ class SignificantBuildsTests: XCTestCase { ]) // MUT - let res = try XCTUnwrap(sb.swiftVersionCompatibility().values) + let res = try #require(sb.swiftVersionCompatibility().values) // validate - XCTAssertEqual(res.sorted(), [ .v3 ]) + #expect(res.sorted() == [ .v3 ]) } - func test_platformCompatibility() throws { + @Test func platformCompatibility() throws { // setup let sb = SignificantBuilds(buildInfo: [ (.v3, .linux, .ok), @@ -73,13 +73,13 @@ class SignificantBuildsTests: XCTestCase { ]) // MUT - let res = try XCTUnwrap(sb.platformCompatibility().values) + let res = try #require(sb.platformCompatibility().values) // validate - XCTAssertEqual(res.sorted(), [.macosSpm, .linux]) + #expect(res.sorted() == [.macosSpm, .linux]) } - func test_platformCompatibility_allPending() throws { + @Test func platformCompatibility_allPending() throws { // setup let sb = SignificantBuilds(buildInfo: [ (.v3, .linux, .triggered), @@ -91,10 +91,10 @@ class SignificantBuildsTests: XCTestCase { let res = sb.platformCompatibility() // validate - XCTAssertEqual(res, .pending) + #expect(res == .pending) } - func test_platformCompatibility_partialPending() throws { + @Test func platformCompatibility_partialPending() throws { // setup let sb = SignificantBuilds(buildInfo: [ (.v3, .linux, .ok), @@ -103,10 +103,10 @@ class SignificantBuildsTests: XCTestCase { ]) // MUT - let res = try XCTUnwrap(sb.platformCompatibility().values) + let res = try #require(sb.platformCompatibility().values) // validate - XCTAssertEqual(res.sorted(), [ .linux ]) + #expect(res.sorted() == [ .linux ]) } } From 593c2c40b1fd0fbe158de0f94f8141cfb4cfb413 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:31:30 +0100 Subject: [PATCH 03/15] Convert SitemapTests --- Tests/AppTests/SitemapTests.swift | 296 +++++++++--------- ...s.1.xml => siteMapForPackage_noDocs.1.xml} | 0 ...1.xml => siteMapForPackage_withDocs.1.xml} | 0 ..._siteMapIndex.1.xml => siteMapIndex.1.xml} | 0 ...icPages.1.xml => siteMapStaticPages.1.xml} | 0 5 files changed, 145 insertions(+), 151 deletions(-) rename Tests/AppTests/__Snapshots__/SitemapTests/{test_siteMapForPackage_noDocs.1.xml => siteMapForPackage_noDocs.1.xml} (100%) rename Tests/AppTests/__Snapshots__/SitemapTests/{test_siteMapForPackage_withDocs.1.xml => siteMapForPackage_withDocs.1.xml} (100%) rename Tests/AppTests/__Snapshots__/SitemapTests/{test_siteMapIndex.1.xml => siteMapIndex.1.xml} (100%) rename Tests/AppTests/__Snapshots__/SitemapTests/{test_siteMapStaticPages.1.xml => siteMapStaticPages.1.xml} (100%) diff --git a/Tests/AppTests/SitemapTests.swift b/Tests/AppTests/SitemapTests.swift index 1f7d1ebbe..d05857553 100644 --- a/Tests/AppTests/SitemapTests.swift +++ b/Tests/AppTests/SitemapTests.swift @@ -15,129 +15,117 @@ @testable import App import Dependencies +import DependenciesTestSupport import SnapshotTesting -import XCTVapor +import Testing +import Vapor @preconcurrency import Plot -class SitemapTests: SnapshotTestCase { +@Suite struct SitemapTests { - @MainActor - func test_siteMapIndex() async throws { - // Setup - let packages = (0..<3).map { Package(url: "\($0)".url) } - try await packages.save(on: app.db) - try await packages.map { try Repository(package: $0, defaultBranch: "default", - lastCommitDate: .t0, name: $0.url, - owner: "foo") }.save(on: app.db) - try await packages.map { try Version(package: $0, packageName: "foo", - reference: .branch("default")) }.save(on: app.db) - try await Search.refresh(on: app.db) + @Test(.dependency(\.date.now, .t0)) + func siteMapIndex() async throws { + try await withApp { app in + // Setup + let packages = (0..<3).map { Package(url: "\($0)".url) } + try await packages.save(on: app.db) + try await packages.map { try Repository(package: $0, defaultBranch: "default", + lastCommitDate: .t0, name: $0.url, + owner: "foo") }.save(on: app.db) + try await packages.map { try Version(package: $0, packageName: "foo", + reference: .branch("default")) }.save(on: app.db) + try await Search.refresh(on: app.db) - let req = Request(application: app, on: app.eventLoopGroup.next()) + let req = Request(application: app, on: app.eventLoopGroup.next()) - // MUT - let siteMapIndex = try await SiteMapController.index(req: req) + // MUT + let siteMapIndex = try await SiteMapController.index(req: req) - // Validation - assertSnapshot(of: siteMapIndex.render(indentedBy: .spaces(2)), - as: .init(pathExtension: "xml", diffing: .lines)) + // Validation + assertSnapshot(of: siteMapIndex.render(indentedBy: .spaces(2)), + as: .init(pathExtension: "xml", diffing: .lines)) + } } - func test_siteMapIndex_prod() async throws { + @Test func siteMapIndex_prod() async throws { // Ensure sitemap routing is configured in prod try await withDependencies { + $0.date.now = .t0 $0.environment.current = { .production } $0.httpClient.postPlausibleEvent = App.HTTPClient.noop } operation: { - // We also need to set up a new app that's configured for production, - // because app.test is not affected by @Dependency overrides. - let prodApp = try await setup(.production) - try await App.run { + try await withApp(environment: .production) { app in // MUT - try await prodApp.test(.GET, "/sitemap.xml") { res async in + try await app.test(.GET, "/sitemap.xml") { res async in // Validation - XCTAssertEqual(res.status, .ok) + #expect(res.status == .ok) } - } defer: { - try await prodApp.asyncShutdown() } } } - func test_siteMapIndex_dev() async throws { + @Test func siteMapIndex_dev() async throws { // Ensure we don't serve sitemaps in dev try await withDependencies { $0.environment.dbId = { nil } } operation: { - let devApp = try await setup(.development) - - try await App.run { + try await withApp(environment: .development) { app in // MUT - try await devApp.test(.GET, "/sitemap.xml") { res async in + try await app.test(.GET, "/sitemap.xml") { res async in // Validation - XCTAssertEqual(res.status, .notFound) + #expect(res.status == .notFound) } - } defer: { - try await devApp.asyncShutdown() } } } - @MainActor - func test_siteMapStaticPages() async throws { - let req = Request(application: app, on: app.eventLoopGroup.next()) + @Test func siteMapStaticPages() async throws { + try await withApp { app in + let req = Request(application: app, on: app.eventLoopGroup.next()) - // MUT - let siteMap = try await SiteMapController.staticPages(req: req) + // MUT + let siteMap = try await SiteMapController.staticPages(req: req) - // Validation - assertSnapshot(of: siteMap.render(indentedBy: .spaces(2)), - as: .init(pathExtension: "xml", diffing: .lines)) + // Validation + assertSnapshot(of: siteMap.render(indentedBy: .spaces(2)), + as: .init(pathExtension: "xml", diffing: .lines)) + } } - func test_siteMapStaticPages_prod() async throws { + @Test func siteMapStaticPages_prod() async throws { // Ensure sitemap routing is configured in prod try await withDependencies { $0.environment.current = { .production } $0.httpClient.postPlausibleEvent = App.HTTPClient.noop } operation: { - // We also need to set up a new app that's configured for production, - // because app.test is not affected by @Dependency overrides. - let prodApp = try await setup(.production) - try await App.run { + try await withApp(environment: .production) { app in // MUT - try await prodApp.test(.GET, "/sitemap-static-pages.xml") { res async in + try await app.test(.GET, "/sitemap-static-pages.xml") { res async in // Validation - XCTAssertEqual(res.status, .ok) + #expect(res.status == .ok) } - } defer: { - try await prodApp.asyncShutdown() } } } - func test_siteMapStaticPages_dev() async throws { + @Test func siteMapStaticPages_dev() async throws { // Ensure we don't serve sitemaps in dev try await withDependencies { $0.environment.dbId = { nil } } operation: { - let devApp = try await setup(.development) - - try await App.run { + try await withApp(environment: .development) { app in // MUT - try await devApp.test(.GET, "/sitemap-static-pages.xml") { res async in + try await app.test(.GET, "/sitemap-static-pages.xml") { res async in // Validation - XCTAssertEqual(res.status, .notFound) + #expect(res.status == .notFound) } - } defer: { - try await devApp.asyncShutdown() } } } - func test_linkablePathUrls() async throws { + @Test func linkablePathUrls() async throws { try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } $0.environment.siteURL = { "https://spi.com" } @@ -151,34 +139,36 @@ class SitemapTests: SnapshotTestCase { """) } } operation: { - // setup - let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) - try await package.save(on: app.db) - try await Repository(package: package, defaultBranch: "default", - lastCommitDate: Date.now, - name: "Repo0", owner: "Owner").save(on: app.db) - try await Version(package: package, - commit: "123456", - commitDate: .t0, - docArchives: [.init(name: "t1", title: "T1")], - latest: .defaultBranch, - packageName: "SomePackage", - reference: .branch("default"), - spiManifest: .init(builder: .init(configs: [.init(documentationTargets: ["t1", "t2"])]))).save(on: app.db) - let packageResult = try await PackageController.PackageResult - .query(on: app.db, owner: "owner", repository: "repo0") + try await withApp { app in + // setup + let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) + try await package.save(on: app.db) + try await Repository(package: package, defaultBranch: "default", + lastCommitDate: Date.now, + name: "Repo0", owner: "Owner").save(on: app.db) + try await Version(package: package, + commit: "123456", + commitDate: .t0, + docArchives: [.init(name: "t1", title: "T1")], + latest: .defaultBranch, + packageName: "SomePackage", + reference: .branch("default"), + spiManifest: .init(builder: .init(configs: [.init(documentationTargets: ["t1", "t2"])]))).save(on: app.db) + let packageResult = try await PackageController.PackageResult + .query(on: app.db, owner: "owner", repository: "repo0") - // MUT - let urls = await PackageController.linkablePathUrls(client: app.client, packageResult: packageResult) + // MUT + let urls = await PackageController.linkablePathUrls(client: app.client, packageResult: packageResult) - XCTAssertEqual(urls, [ - "https://spi.com/Owner/Repo0/default/documentation/foo/bar/1", - "https://spi.com/Owner/Repo0/default/documentation/foo/bar/2" - ]) + #expect(urls == [ + "https://spi.com/Owner/Repo0/default/documentation/foo/bar/1", + "https://spi.com/Owner/Repo0/default/documentation/foo/bar/2" + ]) + } } } - func test_linkablePathUrls_reference_pathEncoded() async throws { + @Test func linkablePathUrls_reference_pathEncoded() async throws { // Ensure branch names with / are properly "path encoded" // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/2462 try await withDependencies { @@ -194,84 +184,88 @@ class SitemapTests: SnapshotTestCase { """) } } operation: { + try await withApp { app in + // setup + let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) + try await package.save(on: app.db) + try await Repository(package: package, defaultBranch: "a/b", + lastCommitDate: Date.now, + name: "Repo0", owner: "Owner").save(on: app.db) + try await Version(package: package, + commit: "123456", + commitDate: .t0, + docArchives: [.init(name: "t1", title: "T1")], + latest: .defaultBranch, + packageName: "SomePackage", + reference: .branch("a/b"), + spiManifest: .init(builder: .init(configs: [.init(documentationTargets: ["t1", "t2"])]))).save(on: app.db) + let packageResult = try await PackageController.PackageResult + .query(on: app.db, owner: "owner", repository: "repo0") + + // MUT + let urls = await PackageController.linkablePathUrls(client: app.client, packageResult: packageResult) + + #expect(urls == [ + "https://spi.com/Owner/Repo0/a-b/documentation/foo/bar/1", + "https://spi.com/Owner/Repo0/a-b/documentation/foo/bar/2" + ]) + } + } + } + + @Test func siteMapForPackage_noDocs() async throws { + try await withApp { app in // setup let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) try await package.save(on: app.db) - try await Repository(package: package, defaultBranch: "a/b", - lastCommitDate: Date.now, + try await Repository(package: package, defaultBranch: "default", + lastCommitDate: .t0, name: "Repo0", owner: "Owner").save(on: app.db) - try await Version(package: package, - commit: "123456", - commitDate: .t0, - docArchives: [.init(name: "t1", title: "T1")], - latest: .defaultBranch, - packageName: "SomePackage", - reference: .branch("a/b"), - spiManifest: .init(builder: .init(configs: [.init(documentationTargets: ["t1", "t2"])]))).save(on: app.db) + try await Version(package: package, latest: .defaultBranch, packageName: "SomePackage", + reference: .branch("default")).save(on: app.db) let packageResult = try await PackageController.PackageResult .query(on: app.db, owner: "owner", repository: "repo0") - - // MUT - let urls = await PackageController.linkablePathUrls(client: app.client, packageResult: packageResult) - - XCTAssertEqual(urls, [ - "https://spi.com/Owner/Repo0/a-b/documentation/foo/bar/1", - "https://spi.com/Owner/Repo0/a-b/documentation/foo/bar/2" - ]) - } - } - - @MainActor - func test_siteMapForPackage_noDocs() async throws { - // setup - let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) - try await package.save(on: app.db) - try await Repository(package: package, defaultBranch: "default", - lastCommitDate: .t0, - name: "Repo0", owner: "Owner").save(on: app.db) - try await Version(package: package, latest: .defaultBranch, packageName: "SomePackage", - reference: .branch("default")).save(on: app.db) - let packageResult = try await PackageController.PackageResult - .query(on: app.db, owner: "owner", repository: "repo0") - // MUT - let sitemap = try await SiteMapController.package(owner: packageResult.repository.owner, - repository: packageResult.repository.name, - lastActivityAt: packageResult.repository.lastActivityAt, - linkablePathUrls: []) - let xml = sitemap.render(indentedBy: .spaces(2)) + // MUT + let sitemap = try await SiteMapController.package(owner: packageResult.repository.owner, + repository: packageResult.repository.name, + lastActivityAt: packageResult.repository.lastActivityAt, + linkablePathUrls: []) + let xml = sitemap.render(indentedBy: .spaces(2)) - // Validation - assertSnapshot(of: xml, as: .init(pathExtension: "xml", diffing: .lines)) + // Validation + assertSnapshot(of: xml, as: .init(pathExtension: "xml", diffing: .lines)) + } } - @MainActor - func test_siteMapForPackage_withDocs() async throws { - // setup - let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) - try await package.save(on: app.db) - try await Repository(package: package, defaultBranch: "default", - lastCommitDate: .t0, - name: "Repo0", owner: "Owner").save(on: app.db) - try await Version(package: package, latest: .defaultBranch, packageName: "SomePackage", - reference: .branch("default")).save(on: app.db) - let packageResult = try await PackageController.PackageResult - .query(on: app.db, owner: "owner", repository: "repo0") - let linkablePathUrls = [ - "/documentation/semanticversion/semanticversion/minor", - "/documentation/semanticversion/semanticversion/_(_:_:)-4ftn7", - "/documentation/semanticversion/semanticversion/'...(_:)-40b95" - ] + @Test func siteMapForPackage_withDocs() async throws { + try await withApp { app in + // setup + let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) + try await package.save(on: app.db) + try await Repository(package: package, defaultBranch: "default", + lastCommitDate: .t0, + name: "Repo0", owner: "Owner").save(on: app.db) + try await Version(package: package, latest: .defaultBranch, packageName: "SomePackage", + reference: .branch("default")).save(on: app.db) + let packageResult = try await PackageController.PackageResult + .query(on: app.db, owner: "owner", repository: "repo0") + let linkablePathUrls = [ + "/documentation/semanticversion/semanticversion/minor", + "/documentation/semanticversion/semanticversion/_(_:_:)-4ftn7", + "/documentation/semanticversion/semanticversion/'...(_:)-40b95" + ] - // MUT - let sitemap = try await SiteMapController.package(owner: packageResult.repository.owner, - repository: packageResult.repository.name, - lastActivityAt: packageResult.repository.lastActivityAt, - linkablePathUrls: linkablePathUrls) - let xml = sitemap.render(indentedBy: .spaces(2)) + // MUT + let sitemap = try await SiteMapController.package(owner: packageResult.repository.owner, + repository: packageResult.repository.name, + lastActivityAt: packageResult.repository.lastActivityAt, + linkablePathUrls: linkablePathUrls) + let xml = sitemap.render(indentedBy: .spaces(2)) - // Validation - assertSnapshot(of: xml, as: .init(pathExtension: "xml", diffing: .lines)) + // Validation + assertSnapshot(of: xml, as: .init(pathExtension: "xml", diffing: .lines)) + } } } diff --git a/Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapForPackage_noDocs.1.xml b/Tests/AppTests/__Snapshots__/SitemapTests/siteMapForPackage_noDocs.1.xml similarity index 100% rename from Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapForPackage_noDocs.1.xml rename to Tests/AppTests/__Snapshots__/SitemapTests/siteMapForPackage_noDocs.1.xml diff --git a/Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapForPackage_withDocs.1.xml b/Tests/AppTests/__Snapshots__/SitemapTests/siteMapForPackage_withDocs.1.xml similarity index 100% rename from Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapForPackage_withDocs.1.xml rename to Tests/AppTests/__Snapshots__/SitemapTests/siteMapForPackage_withDocs.1.xml diff --git a/Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapIndex.1.xml b/Tests/AppTests/__Snapshots__/SitemapTests/siteMapIndex.1.xml similarity index 100% rename from Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapIndex.1.xml rename to Tests/AppTests/__Snapshots__/SitemapTests/siteMapIndex.1.xml diff --git a/Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapStaticPages.1.xml b/Tests/AppTests/__Snapshots__/SitemapTests/siteMapStaticPages.1.xml similarity index 100% rename from Tests/AppTests/__Snapshots__/SitemapTests/test_siteMapStaticPages.1.xml rename to Tests/AppTests/__Snapshots__/SitemapTests/siteMapStaticPages.1.xml From 160a986d24cb20704f611fc257b1bbc010d382f0 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:32:39 +0100 Subject: [PATCH 04/15] Convert SiteURLTests --- Tests/AppTests/SiteURLTests.swift | 154 ++++++++++++++---------------- 1 file changed, 71 insertions(+), 83 deletions(-) diff --git a/Tests/AppTests/SiteURLTests.swift b/Tests/AppTests/SiteURLTests.swift index ba78932c9..9f46eb031 100644 --- a/Tests/AppTests/SiteURLTests.swift +++ b/Tests/AppTests/SiteURLTests.swift @@ -12,75 +12,73 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest - @testable import App import Dependencies import Plot +import Testing import Vapor -class SiteURLTests: XCTestCase { +@Suite struct SiteURLTests { - func test_pathComponents_simple() throws { + @Test func pathComponents_simple() throws { let p = SiteURL.privacy.pathComponents - XCTAssertEqual(p.map(\.description), ["privacy"]) + #expect(p.map(\.description) == ["privacy"]) } - func test_pathComponents_with_parameter() throws { + @Test func pathComponents_with_parameter() throws { let p = SiteURL.package(.key, .key, .none).pathComponents - XCTAssertEqual(p.map(\.description), [":owner", ":repository"]) + #expect(p.map(\.description) == [":owner", ":repository"]) } - func test_pathComponents_nested() throws { + @Test func pathComponents_nested() throws { let p = SiteURL.api(.version).pathComponents - XCTAssertEqual(p.map(\.description), ["api", "version"]) + #expect(p.map(\.description) == ["api", "version"]) } - func test_relativeURL() throws { - XCTAssertEqual(SiteURL.home.relativeURL(), "/") - XCTAssertEqual(SiteURL.images("foo.png").relativeURL(), "/images/foo.png") - XCTAssertEqual(SiteURL.privacy.relativeURL(), "/privacy") + @Test func relativeURL() throws { + #expect(SiteURL.home.relativeURL() == "/") + #expect(SiteURL.images("foo.png").relativeURL() == "/images/foo.png") + #expect(SiteURL.privacy.relativeURL() == "/privacy") } - func test_relativeURL_for_Package() throws { - XCTAssertEqual( - SiteURL.package(.value("foo"), .value("bar"), .none).relativeURL(), - "/foo/bar") + @Test func relativeURL_for_Package() throws { + #expect( + SiteURL.package(.value("foo"), .value("bar"), .none).relativeURL() == "/foo/bar") } - func test_relativeURL_with_anchor() throws { - XCTAssertEqual(SiteURL.faq.relativeURL(anchor: "hello"), "/faq#hello") + @Test func relativeURL_with_anchor() throws { + #expect(SiteURL.faq.relativeURL(anchor: "hello") == "/faq#hello") } - func test_relativeURL_with_parameters() throws { + @Test func relativeURL_with_parameters() throws { let url = SiteURL.search.relativeURL(parameters: [ QueryParameter(key: "c d", value: 2), QueryParameter(key: "a b", value: 1) ]) - XCTAssertEqual(url, "/search?c%20d=2&a%20b=1") + #expect(url == "/search?c%20d=2&a%20b=1") } - func test_absoluteURL() throws { + @Test func absoluteURL() throws { withDependencies { $0.environment.siteURL = { "https://indexsite.com" } } operation: { - XCTAssertEqual(SiteURL.home.absoluteURL(), "https://indexsite.com/") - XCTAssertEqual(SiteURL.images("foo.png").absoluteURL(), "https://indexsite.com/images/foo.png") - XCTAssertEqual(SiteURL.privacy.absoluteURL(), "https://indexsite.com/privacy") + #expect(SiteURL.home.absoluteURL() == "https://indexsite.com/") + #expect(SiteURL.images("foo.png").absoluteURL() == "https://indexsite.com/images/foo.png") + #expect(SiteURL.privacy.absoluteURL() == "https://indexsite.com/privacy") } } - func test_absoluteURL_with_anchor() throws { + @Test func absoluteURL_with_anchor() throws { withDependencies { $0.environment.siteURL = { "https://indexsite.com" } } operation: { - XCTAssertEqual(SiteURL.faq.absoluteURL(anchor: "hello"), "https://indexsite.com/faq#hello") + #expect(SiteURL.faq.absoluteURL(anchor: "hello") == "https://indexsite.com/faq#hello") } } - func test_absoluteURL_with_parameters() throws { + @Test func absoluteURL_with_parameters() throws { withDependencies { $0.environment.siteURL = { "https://indexsite.com" } } operation: { @@ -88,109 +86,99 @@ class SiteURLTests: XCTestCase { QueryParameter(key: "c d", value: 2), QueryParameter(key: "a b", value: 1) ]) - XCTAssertEqual(url, "https://indexsite.com/releases.rss?c%20d=2&a%20b=1") + #expect(url == "https://indexsite.com/releases.rss?c%20d=2&a%20b=1") } } - func test_url_escaping() throws { + @Test func url_escaping() throws { withDependencies { $0.environment.siteURL = { "https://indexsite.com" } } operation: { - XCTAssertEqual(SiteURL.package(.value("foo bar"), .value("some repo"), .none).absoluteURL(), - "https://indexsite.com/foo%20bar/some%20repo") + #expect(SiteURL.package(.value("foo bar"), .value("some repo"), .none).absoluteURL() == "https://indexsite.com/foo%20bar/some%20repo") } } - func test_static_relativeURL() throws { - XCTAssertEqual(SiteURL.relativeURL("foo"), "/foo") - XCTAssertEqual(SiteURL.relativeURL("/foo"), "/foo") + @Test func static_relativeURL() throws { + #expect(SiteURL.relativeURL("foo") == "/foo") + #expect(SiteURL.relativeURL("/foo") == "/foo") } - func test_static_absoluteURL() throws { + @Test func static_absoluteURL() throws { withDependencies { $0.environment.siteURL = { "https://indexsite.com" } } operation: { - XCTAssertEqual(SiteURL.absoluteURL("foo"), "https://indexsite.com/foo") - XCTAssertEqual(SiteURL.absoluteURL("/foo"), "https://indexsite.com/foo") + #expect(SiteURL.absoluteURL("foo") == "https://indexsite.com/foo") + #expect(SiteURL.absoluteURL("/foo") == "https://indexsite.com/foo") } } - func test_api_path() throws { - XCTAssertEqual(SiteURL.api(.search).path, "api/search") - XCTAssertEqual(SiteURL.api(.version).path, "api/version") + @Test func api_path() throws { + #expect(SiteURL.api(.search).path == "api/search") + #expect(SiteURL.api(.version).path == "api/version") do { let uuid = UUID() - XCTAssertEqual(SiteURL.api(.versions(.value(uuid), .buildReport)).path, - "api/versions/\(uuid.uuidString)/build-report") - XCTAssertEqual(SiteURL.api(.builds(.value(uuid), .docReport)).path, - "api/builds/\(uuid.uuidString)/doc-report") + #expect(SiteURL.api(.versions(.value(uuid), .buildReport)).path == "api/versions/\(uuid.uuidString)/build-report") + #expect(SiteURL.api(.builds(.value(uuid), .docReport)).path == "api/builds/\(uuid.uuidString)/doc-report") } } - func test_api_pathComponents() throws { - XCTAssertEqual(SiteURL.api(.search).pathComponents.map(\.description), ["api", "search"]) - XCTAssertEqual(SiteURL.api(.version).pathComponents.map(\.description), ["api", "version"]) - XCTAssertEqual(SiteURL.api(.versions(.key, .buildReport)).pathComponents.map(\.description), - ["api", "versions", ":id", "build-report"]) - XCTAssertEqual(SiteURL.api(.packages(.key, .key, .badge)) - .pathComponents.map(\.description), - ["api", "packages", ":owner", ":repository", "badge"]) - XCTAssertEqual(SiteURL.api(.packageCollections).pathComponents.map(\.description), - ["api", "package-collections"]) + @Test func api_pathComponents() throws { + #expect(SiteURL.api(.search).pathComponents.map(\.description) == ["api", "search"]) + #expect(SiteURL.api(.version).pathComponents.map(\.description) == ["api", "version"]) + #expect(SiteURL.api(.versions(.key, .buildReport)).pathComponents.map(\.description) == ["api", "versions", ":id", "build-report"]) + #expect(SiteURL.api(.packages(.key, .key, .badge)) + .pathComponents.map(\.description) == ["api", "packages", ":owner", ":repository", "badge"]) + #expect(SiteURL.api(.packageCollections).pathComponents.map(\.description) == ["api", "package-collections"]) } - func test_apiBaseURL() throws { + @Test func apiBaseURL() throws { withDependencies { $0.environment.siteURL = { "https://example.com" } } operation: { - XCTAssertEqual(SiteURL.apiBaseURL, "https://example.com/api") + #expect(SiteURL.apiBaseURL == "https://example.com/api") } } - func test_packageBuildsURL() throws { + @Test func packageBuildsURL() throws { // owner/repo/builds - XCTAssertEqual(SiteURL.package(.value("foo"), .value("bar"), .builds).path, - "foo/bar/builds") - XCTAssertEqual(SiteURL.package(.key, .key, .builds).pathComponents.map(\.description), - [":owner", ":repository", "builds"]) + #expect(SiteURL.package(.value("foo"), .value("bar"), .builds).path == "foo/bar/builds") + #expect(SiteURL.package(.key, .key, .builds).pathComponents.map(\.description) == [":owner", ":repository", "builds"]) // /builds/{id} let id = UUID() - XCTAssertEqual(SiteURL.builds(.value(id)).path, "builds/\(id.uuidString)") - XCTAssertEqual(SiteURL.builds(.key).pathComponents.map(\.description), ["builds", ":id"]) + #expect(SiteURL.builds(.value(id)).path == "builds/\(id.uuidString)") + #expect(SiteURL.builds(.key).pathComponents.map(\.description) == ["builds", ":id"]) } - func test_packageCollectionURL() throws { - XCTAssertEqual(SiteURL.packageCollectionAuthor(.value("foo")).path, - "foo/collection.json") - XCTAssertEqual(SiteURL.packageCollectionAuthor(.key).pathComponents - .map(\.description), - [":owner", "collection.json"]) + @Test func packageCollectionURL() throws { + #expect(SiteURL.packageCollectionAuthor(.value("foo")).path == "foo/collection.json") + #expect(SiteURL.packageCollectionAuthor(.key).pathComponents + .map(\.description) == [":owner", "collection.json"]) } - func test_docs() throws { - XCTAssertEqual(SiteURL.docs(.builds).path, "docs/builds") - XCTAssertEqual(SiteURL.docs(.builds).pathComponents.map(\.description), ["docs", "builds"]) + @Test func docs() throws { + #expect(SiteURL.docs(.builds).path == "docs/builds") + #expect(SiteURL.docs(.builds).pathComponents.map(\.description) == ["docs", "builds"]) } - func test_QueryParameter_encodedForQueryString() { + @Test func QueryParameter_encodedForQueryString() { // String parameter, no encoding needed - XCTAssertEqual(QueryParameter(key: "foo", value: "bar").encodedForQueryString, "foo=bar") + #expect(QueryParameter(key: "foo", value: "bar").encodedForQueryString == "foo=bar") // String parameter, encoding needed - XCTAssertEqual(QueryParameter(key: "foo", value: "b a r").encodedForQueryString, "foo=b%20a%20r") + #expect(QueryParameter(key: "foo", value: "b a r").encodedForQueryString == "foo=b%20a%20r") // Integer parameter - XCTAssertEqual(QueryParameter(key: "foo", value: 1).encodedForQueryString, "foo=1") + #expect(QueryParameter(key: "foo", value: 1).encodedForQueryString == "foo=1") } - func test_keywords() throws { - XCTAssertEqual(SiteURL.keywords(.value("foo")).path, "keywords/foo") - XCTAssertEqual(SiteURL.keywords(.key).pathComponents.map(\.description), ["keywords", ":keyword"]) + @Test func keywords() throws { + #expect(SiteURL.keywords(.value("foo")).path == "keywords/foo") + #expect(SiteURL.keywords(.key).pathComponents.map(\.description) == ["keywords", ":keyword"]) } - func test_collections() throws { - XCTAssertEqual(SiteURL.collections(.value("foo")).path, "collections/foo") - XCTAssertEqual(SiteURL.collections(.key).pathComponents.map(\.description), ["collections", ":key"]) + @Test func collections() throws { + #expect(SiteURL.collections(.value("foo")).path == "collections/foo") + #expect(SiteURL.collections(.key).pathComponents.map(\.description) == ["collections", ":key"]) } } From c69ce9ceb96a80421e32e2ff09383e6e12b9ba5e Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:33:12 +0100 Subject: [PATCH 05/15] Deprecate SnapshotTestCase --- Tests/AppTests/SnapshotTestCase.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/AppTests/SnapshotTestCase.swift b/Tests/AppTests/SnapshotTestCase.swift index 2913e9112..2ec4732c1 100644 --- a/Tests/AppTests/SnapshotTestCase.swift +++ b/Tests/AppTests/SnapshotTestCase.swift @@ -19,6 +19,7 @@ import SnapshotTesting import Dependencies +@available(*, deprecated) class SnapshotTestCase: AppTestCase { override func setUpWithError() throws { From 8b214f7a89bef75f5296336803daa1579e0cdbae Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:34:32 +0100 Subject: [PATCH 06/15] Move Snapshotting+html to Helpers --- Tests/AppTests/{ => Helpers}/Snapshotting+html.swift | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Tests/AppTests/{ => Helpers}/Snapshotting+html.swift (100%) diff --git a/Tests/AppTests/Snapshotting+html.swift b/Tests/AppTests/Helpers/Snapshotting+html.swift similarity index 100% rename from Tests/AppTests/Snapshotting+html.swift rename to Tests/AppTests/Helpers/Snapshotting+html.swift From c5f64bd3f927e5d73f24eca45570251c292241fd Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:41:12 +0100 Subject: [PATCH 07/15] Move @unchecked Sendable to Snapshotting+html --- Tests/AppTests/Helpers/Snapshotting+html.swift | 7 ++++++- Tests/AppTests/SocialTests.swift | 3 --- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Tests/AppTests/Helpers/Snapshotting+html.swift b/Tests/AppTests/Helpers/Snapshotting+html.swift index 5399590ef..0a94be261 100644 --- a/Tests/AppTests/Helpers/Snapshotting+html.swift +++ b/Tests/AppTests/Helpers/Snapshotting+html.swift @@ -19,7 +19,7 @@ import SnapshotTesting import Dependencies extension Snapshotting where Value == String, Format == String { - public static let html = Snapshotting(pathExtension: "html", diffing: .lines) + public static let html = Snapshotting(pathExtension: "html", diffing: .lines) } extension Snapshotting where Value == () -> HTML, Format == String { @@ -41,3 +41,8 @@ extension Snapshotting where Value == () -> Node, Format == St } } } + + +#warning("drop this") +extension Snapshotting: @unchecked Swift.Sendable {} +extension Diffing: @unchecked Swift.Sendable {} diff --git a/Tests/AppTests/SocialTests.swift b/Tests/AppTests/SocialTests.swift index bc2964bf5..31527bd67 100644 --- a/Tests/AppTests/SocialTests.swift +++ b/Tests/AppTests/SocialTests.swift @@ -282,6 +282,3 @@ class SocialTests: AppTestCase { } } - -extension SnapshotTesting.Snapshotting: @unchecked Swift.Sendable {} -extension SnapshotTesting.Diffing: @unchecked Swift.Sendable {} From 3ab938de033af7d1368540c3f99f39b9bc333b14 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:42:15 +0100 Subject: [PATCH 08/15] Convert SocialTests --- Tests/AppTests/SocialTests.swift | 256 ++++++++++++++++--------------- 1 file changed, 131 insertions(+), 125 deletions(-) diff --git a/Tests/AppTests/SocialTests.swift b/Tests/AppTests/SocialTests.swift index 31527bd67..740e78330 100644 --- a/Tests/AppTests/SocialTests.swift +++ b/Tests/AppTests/SocialTests.swift @@ -12,26 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + @testable import App import Dependencies import InlineSnapshotTesting import NIOConcurrencyHelpers -import XCTVapor +import Testing +import Vapor -class SocialTests: AppTestCase { +@Suite struct SocialTests { - func test_versionUpdateMessage() throws { - XCTAssertEqual( + @Test func versionUpdateMessage() throws { + #expect( Social.versionUpdateMessage( packageName: "packageName", repositoryOwnerName: "owner", url: "http://localhost:8080/owner/SuperAwesomePackage", version: .init(2, 6, 4), summary: "This is a test package", - maxLength: Social.postMaxLength), - """ + maxLength: Social.postMaxLength) == """ ⬆️ owner just released packageName v2.6.4 – This is a test package http://localhost:8080/owner/SuperAwesomePackage#releases @@ -39,15 +41,14 @@ class SocialTests: AppTestCase { ) // no summary - XCTAssertEqual( + #expect( Social.versionUpdateMessage( packageName: "packageName", repositoryOwnerName: "owner", url: "http://localhost:8080/owner/SuperAwesomePackage", version: .init(2, 6, 4), summary: nil, - maxLength: Social.postMaxLength), - """ + maxLength: Social.postMaxLength) == """ ⬆️ owner just released packageName v2.6.4 http://localhost:8080/owner/SuperAwesomePackage#releases @@ -55,15 +56,14 @@ class SocialTests: AppTestCase { ) // empty summary - XCTAssertEqual( + #expect( Social.versionUpdateMessage( packageName: "packageName", repositoryOwnerName: "owner", url: "http://localhost:8080/owner/SuperAwesomePackage", version: .init(2, 6, 4), summary: "", - maxLength: Social.postMaxLength), - """ + maxLength: Social.postMaxLength) == """ ⬆️ owner just released packageName v2.6.4 http://localhost:8080/owner/SuperAwesomePackage#releases @@ -71,15 +71,14 @@ class SocialTests: AppTestCase { ) // whitespace summary - XCTAssertEqual( + #expect( Social.versionUpdateMessage( packageName: "packageName", repositoryOwnerName: "owner", url: "http://localhost:8080/owner/SuperAwesomePackage", version: .init(2, 6, 4), summary: " \n", - maxLength: Social.postMaxLength), - """ + maxLength: Social.postMaxLength) == """ ⬆️ owner just released packageName v2.6.4 http://localhost:8080/owner/SuperAwesomePackage#releases @@ -87,7 +86,7 @@ class SocialTests: AppTestCase { ) } - func test_versionUpdateMessage_trimming() throws { + @Test func versionUpdateMessage_trimming() throws { let msg = Social.versionUpdateMessage( packageName: "packageName", repositoryOwnerName: "owner", @@ -97,24 +96,23 @@ class SocialTests: AppTestCase { maxLength: Social.postMaxLength ) - XCTAssertEqual(msg.count, 490) - XCTAssertEqual(msg, """ + #expect(msg.count == 490) + #expect(msg == """ ⬆️ owner just released packageName v2.6.4 – xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx… http://localhost:8080/owner/SuperAwesomePackage#releases """) } - func test_newPackageMessage() throws { - XCTAssertEqual( + @Test func newPackageMessage() throws { + #expect( Social.newPackageMessage( packageName: "packageName", repositoryOwnerName: "owner", url: "http://localhost:8080/owner/SuperAwesomePackage", summary: "This is a test package", maxLength: Social.postMaxLength - ), - """ + ) == """ 📦 owner just added a new package, packageName – This is a test package http://localhost:8080/owner/SuperAwesomePackage @@ -122,128 +120,136 @@ class SocialTests: AppTestCase { ) } - func test_firehoseMessage_new_version() async throws { - // setup - let pkg = Package(url: "1".asGithubUrl.url, status: .ok) - try await pkg.save(on: app.db) - try await Repository(package: pkg, - name: "repoName", - owner: "owner", - summary: "This is a test package").save(on: app.db) - let version = try Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) - try await version.save(on: app.db) - let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) - - // MUT - let res = Social.firehoseMessage(package: jpr, - version: version, - maxLength: Social.postMaxLength) - - // validate - XCTAssertEqual(res, """ - ⬆️ owner just released MyPackage v1.2.3 – This is a test package + @Test func firehoseMessage_new_version() async throws { + try await withApp { app in + // setup + let pkg = Package(url: "1".asGithubUrl.url, status: .ok) + try await pkg.save(on: app.db) + try await Repository(package: pkg, + name: "repoName", + owner: "owner", + summary: "This is a test package").save(on: app.db) + let version = try Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) + try await version.save(on: app.db) + let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) + + // MUT + let res = Social.firehoseMessage(package: jpr, + version: version, + maxLength: Social.postMaxLength) + // validate + #expect(res == """ + ⬆️ owner just released MyPackage v1.2.3 – This is a test package + http://localhost:8080/owner/repoName#releases """) + } } - func test_firehoseMessage_new_package() async throws { - // setup - let pkg = Package(url: "1".asGithubUrl.url, status: .new) - try await pkg.save(on: app.db) - try await Repository(package: pkg, - name: "repoName", - owner: "owner", - summary: "This is a test package").save(on: app.db) - let version = try Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) - try await version.save(on: app.db) - let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) - - // MUT - let res = Social.firehoseMessage(package: jpr, - version: version, - maxLength: Social.postMaxLength) - - // validate - XCTAssertEqual(res, """ - 📦 owner just added a new package, MyPackage – This is a test package + @Test func firehoseMessage_new_package() async throws { + try await withApp { app in + // setup + let pkg = Package(url: "1".asGithubUrl.url, status: .new) + try await pkg.save(on: app.db) + try await Repository(package: pkg, + name: "repoName", + owner: "owner", + summary: "This is a test package").save(on: app.db) + let version = try Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) + try await version.save(on: app.db) + let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) + + // MUT + let res = Social.firehoseMessage(package: jpr, + version: version, + maxLength: Social.postMaxLength) + // validate + #expect(res == """ + 📦 owner just added a new package, MyPackage – This is a test package + http://localhost:8080/owner/repoName """) + } } - func test_postToFirehose_only_release_and_preRelease() async throws { + @Test func postToFirehose_only_release_and_preRelease() async throws { // ensure we only post about releases and pre-releases - // setup - let pkg = Package(url: "1".asGithubUrl.url) - try await pkg.save(on: app.db) - try await Repository(package: pkg, - name: "repoName", - owner: "repoOwner", - summary: "This is a test package").save(on: app.db) - try await Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) - .save(on: app.db) - try await Version(package: pkg, - commitDate: Date(timeIntervalSince1970: 0), - packageName: "MyPackage", - reference: .tag(2, 0, 0, "b1")).save(on: app.db) - try await Version(package: pkg, packageName: "MyPackage", reference: .branch("main")) - .save(on: app.db) - let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) - let versions = try await Analyze.updateLatestVersions(on: app.db, package: jpr) - - let posted: NIOLockedValueBox = .init(0) + try await withApp { app in + // setup + let pkg = Package(url: "1".asGithubUrl.url) + try await pkg.save(on: app.db) + try await Repository(package: pkg, + name: "repoName", + owner: "repoOwner", + summary: "This is a test package").save(on: app.db) + try await Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) + .save(on: app.db) + try await Version(package: pkg, + commitDate: Date(timeIntervalSince1970: 0), + packageName: "MyPackage", + reference: .tag(2, 0, 0, "b1")).save(on: app.db) + try await Version(package: pkg, packageName: "MyPackage", reference: .branch("main")) + .save(on: app.db) + let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) + let versions = try await Analyze.updateLatestVersions(on: app.db, package: jpr) + + let posted: NIOLockedValueBox = .init(0) + + try await withDependencies { + $0.environment.allowSocialPosts = { true } + $0.httpClient.mastodonPost = { @Sendable _ in posted.withLockedValue { $0 += 1 } } + } operation: { + // MUT + try await Social.postToFirehose(client: app.client, + package: jpr, + versions: versions) + } - try await withDependencies { - $0.environment.allowSocialPosts = { true } - $0.httpClient.mastodonPost = { @Sendable _ in posted.withLockedValue { $0 += 1 } } - } operation: { - // MUT - try await Social.postToFirehose(client: app.client, - package: jpr, - versions: versions) + // validate + try await XCTAssertEqualAsync(posted.withLockedValue { $0 }, 2) } - - // validate - try await XCTAssertEqualAsync(posted.withLockedValue { $0 }, 2) } - func test_postToFirehose_only_latest() async throws { + @Test func postToFirehose_only_latest() async throws { // ensure we only post about latest versions - // setup - let pkg = Package(url: "1".asGithubUrl.url, status: .ok) - try await pkg.save(on: app.db) - try await Repository(package: pkg, - name: "repoName", - owner: "repoOwner", - summary: "This is a test package").save(on: app.db) - try await Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) - .save(on: app.db) - try await Version(package: pkg, packageName: "MyPackage", reference: .tag(2, 0, 0)) - .save(on: app.db) - let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) - let versions = try await Analyze.updateLatestVersions(on: app.db, package: jpr) - - let posted: NIOLockedValueBox = .init(0) - - try await withDependencies { - $0.environment.allowSocialPosts = { true } - $0.httpClient.mastodonPost = { @Sendable msg in - XCTAssertTrue(msg.contains("v2.0.0")) - posted.withLockedValue { $0 += 1 } + try await withApp { app in + // setup + let pkg = Package(url: "1".asGithubUrl.url, status: .ok) + try await pkg.save(on: app.db) + try await Repository(package: pkg, + name: "repoName", + owner: "repoOwner", + summary: "This is a test package").save(on: app.db) + try await Version(package: pkg, packageName: "MyPackage", reference: .tag(1, 2, 3)) + .save(on: app.db) + try await Version(package: pkg, packageName: "MyPackage", reference: .tag(2, 0, 0)) + .save(on: app.db) + let jpr = try await Package.fetchCandidate(app.db, id: pkg.id!) + let versions = try await Analyze.updateLatestVersions(on: app.db, package: jpr) + + let posted: NIOLockedValueBox = .init(0) + + try await withDependencies { + $0.environment.allowSocialPosts = { true } + $0.httpClient.mastodonPost = { @Sendable msg in + #expect(msg.contains("v2.0.0")) + posted.withLockedValue { $0 += 1 } + } + } operation: { + // MUT + try await Social.postToFirehose(client: app.client, + package: jpr, + versions: versions) } - } operation: { - // MUT - try await Social.postToFirehose(client: app.client, - package: jpr, - versions: versions) - } - // validate - try await XCTAssertEqualAsync(posted.withLockedValue { $0 }, 1) + // validate + try await XCTAssertEqualAsync(posted.withLockedValue { $0 }, 1) + } } - func test_urlEncoding() async throws { + @Test func urlEncoding() async throws { let called = ActorIsolated(false) try await withDependencies { $0.environment.mastodonCredentials = { .init(accessToken: "fakeToken") } @@ -254,7 +260,7 @@ class SocialTests: AppTestCase { https://mas.to/api/v1/statuses?status=%E2%AC%86%EF%B8%8F%20owner%20just%20released%20packageName%20v2.6.4%0A%0Ahttp://localhost:8080/owner/SuperAwesomePackage%23releases&visibility=unlisted """ } - XCTAssertEqual(headers, HTTPHeaders([ + #expect(headers == HTTPHeaders([ ("Authorization", "Bearer fakeToken"), ("Idempotency-Key", UUID.id0.uuidString), ])) From f27c0a6711520c62bf4010cc64c856fc4ea9db33 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:47:29 +0100 Subject: [PATCH 09/15] Convert SQLKitExtensionTests --- Tests/AppTests/AppTestCase.swift | 2 +- Tests/AppTests/SQLKitExtensionTests.swift | 35 ++++++++++++----------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Tests/AppTests/AppTestCase.swift b/Tests/AppTests/AppTestCase.swift index 9a9328db1..2f05db0cf 100644 --- a/Tests/AppTests/AppTestCase.swift +++ b/Tests/AppTests/AppTestCase.swift @@ -182,7 +182,7 @@ extension AppTestCase { } -// FIXME: Move this once AppTestCase can be removed. These are helpers created during the transition to Swift Testing. +// FIXME: Move this once AppTestCase can be removed. These are helpers created during the transition to Swift Testing. Also check if we can just create a PostgresDB object from scratch rather than using withApp and app.db for this at the call site. That does a whole migration + reset just to render the SQL needlessly. extension Database { func renderSQL(_ builder: SQLSelectBuilder) -> String { renderSQL(builder.query) diff --git a/Tests/AppTests/SQLKitExtensionTests.swift b/Tests/AppTests/SQLKitExtensionTests.swift index b1ef40570..8f3a4e449 100644 --- a/Tests/AppTests/SQLKitExtensionTests.swift +++ b/Tests/AppTests/SQLKitExtensionTests.swift @@ -15,27 +15,30 @@ @testable import App import SQLKit -import XCTest +import Testing -class SQLKitExtensionTests: AppTestCase { +@Suite struct SQLKitExtensionTests { - func test_OrderByGroup() throws { - let b = SQLOrderBy(SQLIdentifier("id"), .ascending) - .then(SQLIdentifier("foo"), .descending) - XCTAssertEqual(renderSQL(b), #""id" ASC, "foo" DESC"#) + @Test func OrderByGroup() async throws { + try await withApp { app in + let b = SQLOrderBy(SQLIdentifier("id"), .ascending) + .then(SQLIdentifier("foo"), .descending) + #expect(app.db.renderSQL(b) == #""id" ASC, "foo" DESC"#) + } } - func test_OrderByGroup_complex() throws { - let packageName = SQLIdentifier("package_name") - let mergedTerms = SQLBind("a b") - let score = SQLIdentifier("score") - - let orderBy = SQLOrderBy(eq(lower(packageName), mergedTerms), .descending) - .then(score, .descending) - .then(packageName, .ascending) - XCTAssertEqual(renderSQL(orderBy), - #"LOWER("package_name") = $1 DESC, "score" DESC, "package_name" ASC"#) + @Test func OrderByGroup_complex() async throws { + try await withApp { app in + let packageName = SQLIdentifier("package_name") + let mergedTerms = SQLBind("a b") + let score = SQLIdentifier("score") + + let orderBy = SQLOrderBy(eq(lower(packageName), mergedTerms), .descending) + .then(score, .descending) + .then(packageName, .ascending) + #expect(app.db.renderSQL(orderBy) == #"LOWER("package_name") = $1 DESC, "score" DESC, "package_name" ASC"#) + } } } From 8c05a7c4c77d02850fe2b4883b017bf97d43485e Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:49:14 +0100 Subject: [PATCH 10/15] Convert StatsTests --- Tests/AppTests/StatsTests.swift | 46 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/Tests/AppTests/StatsTests.swift b/Tests/AppTests/StatsTests.swift index 846c45cc4..8bff6bae6 100644 --- a/Tests/AppTests/StatsTests.swift +++ b/Tests/AppTests/StatsTests.swift @@ -12,30 +12,34 @@ // See the License for the specific language governing permissions and // limitations under the License. -@testable import App - -import XCTVapor +import Foundation +@testable import App -class StatsTests: AppTestCase { - - func test_fetch() async throws { - // setup - do { - let pkg = Package(id: UUID(), url: "1") - try await pkg.save(on: app.db) +import Testing + + +@Suite struct StatsTests { + + @Test func fetch() async throws { + try await withApp { app in + // setup + do { + let pkg = Package(id: UUID(), url: "1") + try await pkg.save(on: app.db) + } + do { + let pkg = Package(id: UUID(), url: "2") + try await pkg.save(on: app.db) + } + try await Stats.refresh(on: app.db) + + // MUT + let res = try await Stats.fetch(on: app.db) + + // validate + #expect(res == .some(.init(packageCount: 2))) } - do { - let pkg = Package(id: UUID(), url: "2") - try await pkg.save(on: app.db) - } - try await Stats.refresh(on: app.db) - - // MUT - let res = try await Stats.fetch(on: app.db) - - // validate - XCTAssertEqual(res, .some(.init(packageCount: 2))) } } From 28ed152607092b7fe8531014f5a99a7dd441501b Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 09:58:19 +0100 Subject: [PATCH 11/15] Convert StringExtTests --- Tests/AppTests/StringExtTests.swift | 68 ++++++++++++++--------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/Tests/AppTests/StringExtTests.swift b/Tests/AppTests/StringExtTests.swift index d54e076d3..3a23c4f98 100644 --- a/Tests/AppTests/StringExtTests.swift +++ b/Tests/AppTests/StringExtTests.swift @@ -13,61 +13,59 @@ // limitations under the License. import Foundation -import XCTest @testable import App +import Testing -final class StringExtTests: XCTestCase { - func test_pluralised() throws { - XCTAssertEqual("version".pluralized(for: 0), "versions") - XCTAssertEqual("version".pluralized(for: 1), "version") - XCTAssertEqual("version".pluralized(for: 2), "versions") +@Suite struct StringExtTests { - XCTAssertEqual("library".pluralized(for: 0, plural: "libraries"), "libraries") - XCTAssertEqual("library".pluralized(for: 1, plural: "libraries"), "library") - XCTAssertEqual("library".pluralized(for: 2, plural: "libraries"), "libraries") + @Test func pluralised() throws { + #expect("version".pluralized(for: 0) == "versions") + #expect("version".pluralized(for: 1) == "version") + #expect("version".pluralized(for: 2) == "versions") + + #expect("library".pluralized(for: 0, plural: "libraries") == "libraries") + #expect("library".pluralized(for: 1, plural: "libraries") == "library") + #expect("library".pluralized(for: 2, plural: "libraries") == "libraries") } - func testDroppingGitSuffix() { - XCTAssertEqual( - "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server".droppingGitExtension, - "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server" + @Test func droppingGitSuffix() { + #expect( + "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server".droppingGitExtension == "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server" ) - XCTAssertEqual( - "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server.git".droppingGitExtension, - "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server" + #expect( + "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server.git".droppingGitExtension == "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server" ) } - func testDroppingGitHubPrefix() { - XCTAssertEqual( - "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server".droppingGithubComPrefix, - "SwiftPackageIndex/SwiftPackageIndex-Server" + @Test func droppingGitHubPrefix() { + #expect( + "https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server".droppingGithubComPrefix == "SwiftPackageIndex/SwiftPackageIndex-Server" ) } - func testTrimming() { - XCTAssertEqual("".trimmed, nil) - XCTAssertEqual(" ".trimmed, nil) - XCTAssertEqual(" string ".trimmed, "string") - XCTAssertEqual("string".trimmed, "string") + @Test func trimming() { + #expect("".trimmed == nil) + #expect(" ".trimmed == nil) + #expect(" string ".trimmed == "string") + #expect("string".trimmed == "string") } - func test_removingSuffix() throws { - XCTAssertEqual("".removingSuffix(""), "") - XCTAssertEqual("".removingSuffix("bob"), "") - XCTAssertEqual("bob".removingSuffix("bob"), "") - XCTAssertEqual("bobby and bob".removingSuffix("bob"), "bobby and ") - XCTAssertEqual("bobby and bob ".removingSuffix("bob"), "bobby and bob ") - XCTAssertEqual("Bobby and Bob".removingSuffix("bob"), "Bobby and ") - XCTAssertEqual("bobby and bob".removingSuffix("Bob"), "bobby and ") + @Test func removingSuffix() throws { + #expect("".removingSuffix("") == "") + #expect("".removingSuffix("bob") == "") + #expect("bob".removingSuffix("bob") == "") + #expect("bobby and bob".removingSuffix("bob") == "bobby and ") + #expect("bobby and bob ".removingSuffix("bob") == "bobby and bob ") + #expect("Bobby and Bob".removingSuffix("bob") == "Bobby and ") + #expect("bobby and bob".removingSuffix("Bob") == "bobby and ") } - func test_sha256Checksum() throws { - XCTAssertEqual("foo".sha256Checksum, "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") + @Test func sha256Checksum() throws { + #expect("foo".sha256Checksum == "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") } } From bb74a36599dde7712c7c9af3f3deecd507d44fce Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 10:02:26 +0100 Subject: [PATCH 12/15] Convert SwiftVersionTests --- Tests/AppTests/SwiftVersionTests.swift | 54 +++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Tests/AppTests/SwiftVersionTests.swift b/Tests/AppTests/SwiftVersionTests.swift index a1bac7000..c03806cc2 100644 --- a/Tests/AppTests/SwiftVersionTests.swift +++ b/Tests/AppTests/SwiftVersionTests.swift @@ -14,45 +14,45 @@ @testable import App -import XCTest +import Testing -class SwiftVersionTests: XCTestCase { +@Suite struct SwiftVersionTests { - func test_swiftVerRegex() throws { - XCTAssert(SwiftVersion.swiftVerRegex.matches("1")) - XCTAssert(SwiftVersion.swiftVerRegex.matches("1.2")) - XCTAssert(SwiftVersion.swiftVerRegex.matches("1.2.3")) - XCTAssert(SwiftVersion.swiftVerRegex.matches("v1")) - XCTAssertFalse(SwiftVersion.swiftVerRegex.matches("1.")) - XCTAssertFalse(SwiftVersion.swiftVerRegex.matches("1.2.")) - XCTAssertFalse(SwiftVersion.swiftVerRegex.matches("1.2.3-pre")) + @Test func swiftVerRegex() throws { + #expect(SwiftVersion.swiftVerRegex.matches("1")) + #expect(SwiftVersion.swiftVerRegex.matches("1.2")) + #expect(SwiftVersion.swiftVerRegex.matches("1.2.3")) + #expect(SwiftVersion.swiftVerRegex.matches("v1")) + #expect(!SwiftVersion.swiftVerRegex.matches("1.")) + #expect(!SwiftVersion.swiftVerRegex.matches("1.2.")) + #expect(!SwiftVersion.swiftVerRegex.matches("1.2.3-pre")) } - func test_init() throws { - XCTAssertEqual(SwiftVersion("5"), SwiftVersion(5, 0, 0)) - XCTAssertEqual(SwiftVersion("5.2"), SwiftVersion(5, 2, 0)) - XCTAssertEqual(SwiftVersion("5.2.1"), SwiftVersion(5, 2, 1)) - XCTAssertEqual(SwiftVersion("v5"), SwiftVersion(5, 0, 0)) + @Test func SwiftVersion_init() throws { + #expect(SwiftVersion("5") == SwiftVersion(5, 0, 0)) + #expect(SwiftVersion("5.2") == SwiftVersion(5, 2, 0)) + #expect(SwiftVersion("5.2.1") == SwiftVersion(5, 2, 1)) + #expect(SwiftVersion("v5") == SwiftVersion(5, 0, 0)) } - func test_Comparable() throws { - XCTAssertTrue(SwiftVersion("5")! < SwiftVersion("5.1")!) - XCTAssertFalse(SwiftVersion("5")! < SwiftVersion("5.0")!) - XCTAssertFalse(SwiftVersion("5")! > SwiftVersion("5.0")!) - XCTAssertTrue(SwiftVersion("4.2")! < SwiftVersion("5")!) + @Test func SwiftVersion_Comparable() throws { + #expect(SwiftVersion("5")! < SwiftVersion("5.1")!) + #expect(!(SwiftVersion("5")! < SwiftVersion("5.0")!)) + #expect(!(SwiftVersion("5")! > SwiftVersion("5.0")!)) + #expect(SwiftVersion("4.2")! < SwiftVersion("5")!) } - func test_isCompatible() throws { + @Test func isCompatible() throws { let v4_2 = SwiftVersion(4, 2, 0) - XCTAssertTrue(v4_2.isCompatible(with: .init(4, 2, 0))) - XCTAssertTrue(v4_2.isCompatible(with: .init(4, 2, 4))) - XCTAssertFalse(v4_2.isCompatible(with: .init(4, 0, 0))) - XCTAssertFalse(v4_2.isCompatible(with: .init(5, 0, 0))) + #expect(v4_2.isCompatible(with: .init(4, 2, 0))) + #expect(v4_2.isCompatible(with: .init(4, 2, 4))) + #expect(!v4_2.isCompatible(with: .init(4, 0, 0))) + #expect(!v4_2.isCompatible(with: .init(5, 0, 0))) } - func test_latestMajor() throws { - XCTAssertEqual(SwiftVersion.latest.major, 6) + @Test func latestMajor() throws { + #expect(SwiftVersion.latest.major == 6) } } From 0a13c81afc345d93686a22353d7f060552bd6fa6 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 10:08:41 +0100 Subject: [PATCH 13/15] Convert TargetTests --- Tests/AppTests/TargetTests.swift | 80 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/Tests/AppTests/TargetTests.swift b/Tests/AppTests/TargetTests.swift index 8dfe04845..b59de1c23 100644 --- a/Tests/AppTests/TargetTests.swift +++ b/Tests/AppTests/TargetTests.swift @@ -15,54 +15,58 @@ @testable import App import Fluent +import Testing import Vapor -import XCTVapor -final class TargetTests: AppTestCase { +@Suite struct TargetTests { - func test_save() async throws { - // setup - let v = Version() - v.commit = "" // required field - v.commitDate = .distantPast // required field - v.reference = .branch("main") // required field - try await v.save(on: app.db) - let t = try Target(version: v, name: "target") + @Test func save() async throws { + try await withApp { app in + // setup + let v = Version() + v.commit = "" // required field + v.commitDate = .distantPast // required field + v.reference = .branch("main") // required field + try await v.save(on: app.db) + let t = try Target(version: v, name: "target") - // MUT - try await t.save(on: app.db) + // MUT + try await t.save(on: app.db) - // validate - let readBack = try await XCTUnwrapAsync(try await Target.query(on: app.db).first()) - XCTAssertNotNil(readBack.id) - XCTAssertEqual(readBack.$version.id, v.id) - XCTAssertNotNil(readBack.createdAt) - XCTAssertNotNil(readBack.updatedAt) - XCTAssertEqual(readBack.name, "target") + // validate + let readBack = try await XCTUnwrapAsync(try await Target.query(on: app.db).first()) + #expect(readBack.id != nil) + #expect(readBack.$version.id == v.id) + #expect(readBack.createdAt != nil) + #expect(readBack.updatedAt != nil) + #expect(readBack.name == "target") + } } - func test_delete_cascade() async throws { - // setup - let v = Version() - v.commit = "" // required field - v.commitDate = .distantPast // required field - v.reference = .branch("main") // required field - try await v.save(on: app.db) - let t = try Target(version: v, name: "target") - try await t.save(on: app.db) - do { - let target = try await Target.query(on: app.db).first() - XCTAssertNotNil(target) - } + @Test func delete_cascade() async throws { + try await withApp { app in + // setup + let v = Version() + v.commit = "" // required field + v.commitDate = .distantPast // required field + v.reference = .branch("main") // required field + try await v.save(on: app.db) + let t = try Target(version: v, name: "target") + try await t.save(on: app.db) + do { + let target = try await Target.query(on: app.db).first() + #expect(target != nil) + } - // MUT - try await v.delete(on: app.db) + // MUT + try await v.delete(on: app.db) - // validate - do { - let target = try await Target.query(on: app.db).first() - XCTAssertNil(target) + // validate + do { + let target = try await Target.query(on: app.db).first() + #expect(target == nil) + } } } From 1c083f1e8e60f1321ec946ebe95e22f3a446f701 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 10:10:46 +0100 Subject: [PATCH 14/15] Move Util, Util+ext to Helpers --- Tests/AppTests/{ => Helpers}/Util+ext.swift | 0 Tests/AppTests/{ => Helpers}/Util.swift | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Tests/AppTests/{ => Helpers}/Util+ext.swift (100%) rename Tests/AppTests/{ => Helpers}/Util.swift (100%) diff --git a/Tests/AppTests/Util+ext.swift b/Tests/AppTests/Helpers/Util+ext.swift similarity index 100% rename from Tests/AppTests/Util+ext.swift rename to Tests/AppTests/Helpers/Util+ext.swift diff --git a/Tests/AppTests/Util.swift b/Tests/AppTests/Helpers/Util.swift similarity index 100% rename from Tests/AppTests/Util.swift rename to Tests/AppTests/Helpers/Util.swift From db6fcfa71d5cad16740485613713cf14a2527b88 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Wed, 5 Mar 2025 11:24:42 +0100 Subject: [PATCH 15/15] Move Util back, it breaks fixturesDirectory in a weird way --- Tests/AppTests/Helpers/{Util+ext.swift => Extensions.swift} | 0 Tests/AppTests/{Helpers => }/Util.swift | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Tests/AppTests/Helpers/{Util+ext.swift => Extensions.swift} (100%) rename Tests/AppTests/{Helpers => }/Util.swift (100%) diff --git a/Tests/AppTests/Helpers/Util+ext.swift b/Tests/AppTests/Helpers/Extensions.swift similarity index 100% rename from Tests/AppTests/Helpers/Util+ext.swift rename to Tests/AppTests/Helpers/Extensions.swift diff --git a/Tests/AppTests/Helpers/Util.swift b/Tests/AppTests/Util.swift similarity index 100% rename from Tests/AppTests/Helpers/Util.swift rename to Tests/AppTests/Util.swift