gitbayTests/DefinitionLinkTests.swift
99 lines · 4199 bytes
10 symbols in this file
1import Foundation
2import Testing
3@testable import gitbay
4
5private func makeClient() throws -> (GitbayClient, StubProtocol.Box) {
6 let box = StubProtocol.box()
7 let client = GitbayClient(
8 instance: try GitbayInstance(url: "https://gitbay.org"),
9 token: "test-token",
10 session: box.session()
11 )
12 return (client, box)
13}
14
15private func argv(_ url: URL) -> [String] {
16 URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.compactMap(\.value) ?? []
17}
18
19struct DefinitionLinkTests {
20
21 private let defs: [String: Definition] = [
22 "Parse": Definition(name: "Parse", count: 1, path: "lib.go", line: 3),
23 "Run": Definition(name: "Run", count: 2, path: "lib.go", line: 4),
24 ]
25
26 @Test func definedNamesLinkAndOthersStayPlain() {
27 let line = Definition.link(AttributedString("\tParse(); Parser(); Run(x)"), definitions: defs)
28
29 let linked = line.runs.compactMap { run -> String? in
30 run.link.map { _ in String(line[run.range].characters) }
31 }
32 // Parser is a different name, not Parse with a tail.
33 #expect(linked == ["Parse", "Run"])
34 #expect(line.runs.compactMap(\.link).map { Definition.name(in: $0) } == ["Parse", "Run"])
35 }
36
37 @Test func aLineWithNoDefinitionsIsUnchanged() {
38 let text = AttributedString("// nothing here")
39 #expect(Definition.link(text, definitions: defs) == text)
40 #expect(Definition.link(AttributedString("Parse"), definitions: [:]) == AttributedString("Parse"))
41 }
42
43 @Test func aDefinitionURLIsOnlyOurs() {
44 #expect(Definition.name(in: URL(string: "https://gitbay.org/x")!) == nil)
45 }
46}
47
48@MainActor
49struct FileDefinitionsTests {
50
51 @Test func theFileReadsTheDefinitionsItUses() async throws {
52 let (client, stub) = try makeClient()
53 stub.enqueue(.init(status: 200, json: """
54 {"protocol_version":1,"data":{"path":"krz/app","ref":"main","file":"use.go","size":10,\
55 "binary":false,"content":"Parse()\\n"},"exit_code":0}
56 """, match: "argv=cat"))
57 stub.enqueue(.init(status: 200, json: """
58 {"protocol_version":1,"data":[{"name":"Parse","count":1,"path":"lib.go","line":3}],"exit_code":0}
59 """, match: "argv=definitions"))
60 let model = FileViewModel(client: client, repoPath: "krz/app", filePath: "use.go", ref: "main")
61
62 await model.load()
63
64 let read = try #require(stub.seen.first { $0.url.absoluteString.contains("argv=definitions") })
65 #expect(argv(read.url) == ["repo", "definitions", "krz/app", "use.go", "--ref", "main"])
66 #expect(model.definitions["Parse"]?.line == 3)
67 }
68
69 /// A server without the command, or a ref that is not indexed, leaves
70 /// the file plain rather than failing it.
71 @Test func noDefinitionsLeaveTheFileReadable() async throws {
72 let (client, stub) = try makeClient()
73 stub.enqueue(.init(status: 200, json: """
74 {"protocol_version":1,"data":{"path":"krz/app","ref":"dev","file":"use.go","size":10,\
75 "binary":false,"content":"Parse()\\n"},"exit_code":0}
76 """, match: "argv=cat"))
77 stub.enqueue(.init(status: 404, json: #"{"protocol_version":1,"error":"only the default branch is indexed","exit_code":3}"#, match: "argv=definitions"))
78 let model = FileViewModel(client: client, repoPath: "krz/app", filePath: "use.go", ref: "dev")
79
80 await model.load()
81
82 #expect(model.state.value?.content == "Parse()\n")
83 #expect(model.definitions.isEmpty)
84 }
85
86 @Test func proseFilesAreNotLinked() async throws {
87 let (client, stub) = try makeClient()
88 stub.enqueue(.init(status: 200, json: """
89 {"protocol_version":1,"data":{"path":"krz/app","ref":"main","file":"README.md","size":10,\
90 "binary":false,"content":"# Parse\\n"},"exit_code":0}
91 """, match: "argv=cat"))
92 let model = FileViewModel(client: client, repoPath: "krz/app", filePath: "README.md", ref: "main")
93
94 await model.load()
95
96 #expect(model.state.value != nil)
97 #expect(!stub.seen.contains { $0.url.absoluteString.contains("argv=definitions") })
98 }
99}