import Foundation import Testing @testable import gitbay private func makeClient() throws -> (GitbayClient, StubProtocol.Box) { let box = StubProtocol.box() let client = GitbayClient( instance: try GitbayInstance(url: "https://gitbay.org"), token: "test-token", session: box.session() ) return (client, box) } private let listingJSON = """ {"protocol_version":1,"data":{"path":"krz/gitbay","home":"Home",\ "pages":["API","Admin","Home","Parity"]},"exit_code":0} """ @MainActor struct WikiViewModelTests { @Test func listsPagesAndNamesTheLandingPage() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 200, json: listingJSON)) let model = WikiViewModel(client: client, repoPath: "krz/gitbay") await model.load() let listing = try #require(model.state.value) #expect(listing.home == "Home") #expect(listing.pages == ["API", "Admin", "Home", "Parity"]) #expect(stub.seen.first?.url.query() == "argv=wiki&argv=list&argv=krz/gitbay") } @Test func aRepoWithoutAWikiIsAnEmptyState() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 404, json: #"{"protocol_version":1,"error":"krz/quiet has no wiki","exit_code":3}"#)) let model = WikiViewModel(client: client, repoPath: "krz/quiet") await model.load() guard case .empty(let message) = model.state else { Issue.record("expected .empty, got \(model.state)") return } #expect(message.contains("no wiki")) } @Test func anEmptyWikiIsAnEmptyStateNotAList() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"path":"krz/gitbay","pages":[]},"exit_code":0}"#)) let model = WikiViewModel(client: client, repoPath: "krz/gitbay") await model.load() guard case .empty = model.state else { Issue.record("expected .empty, got \(model.state)") return } } } @MainActor struct WikiPageViewModelTests { @Test func loadsAPageAndKeepsItsFileName() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 200, json: """ {"protocol_version":1,"data":{"path":"krz/gitbay","page":"Parity",\ "file":"Parity.org","size":11,"content":"#+title: x"},"exit_code":0} """)) let model = WikiPageViewModel(client: client, repoPath: "krz/gitbay", page: "Parity") await model.load() let page = try #require(model.state.value) // The file name is what picks the renderer, so it must survive. #expect(page.file == "Parity.org") #expect(page.content == "#+title: x") #expect(stub.seen.first?.url.query() == "argv=wiki&argv=show&argv=krz/gitbay&argv=Parity") } @Test func aMissingPageIsAnEmptyState() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 404, json: #"{"protocol_version":1,"error":"no wiki page \"Nope\" in krz/gitbay","exit_code":3}"#)) let model = WikiPageViewModel(client: client, repoPath: "krz/gitbay", page: "Nope") await model.load() guard case .empty = model.state else { Issue.record("expected .empty, got \(model.state)") return } } } struct WikiRenderingTests { @Test func orgPagesGetTheOrgRendererAndMarkdownPagesDoNot() { // Wiki pages here are .org as often as .md; the file name decides. #expect(ReadmeView(name: "Parity.org", content: "* x").isOrg) #expect(!ReadmeView(name: "Home.md", content: "# x").isOrg) #expect(!ReadmeView(name: "Notes.markdown", content: "# x").isOrg) } }