gitbayTests/BodyReferenceTests.swift

v1.14.1
gitbay-ios/gitbayTests/BodyReferenceTests.swift history · blame · raw

123 lines · 4562 bytes

  1import Foundation
  2import OrgSwift
  3import Testing
  4@testable import gitbay
  5
  6/// `#N`, `!N`, `owner/name#N` and `owner/name!N`, found the way the web's
  7/// autolink package finds them: `#` is an issue, `!` a merge request.
  8struct BodyReferenceTests {
  9
 10    private func refs(_ text: String, repo: String = "krz/gitbay") -> [BodyReference] {
 11        bodyReferences(in: text, repo: repo)
 12    }
 13
 14    @Test func bareHashIsAnIssueInThisRepo() {
 15        #expect(refs("see #12 please") == [
 16            BodyReference(range: 4..<7, destination: .issue(repo: "krz/gitbay", number: 12)),
 17        ])
 18    }
 19
 20    @Test func bangIsAMergeRequest() {
 21        #expect(refs("!3") == [
 22            BodyReference(range: 0..<2, destination: .mr(repo: "krz/gitbay", number: 3)),
 23        ])
 24    }
 25
 26    @Test func crossRepoReferenceNamesItsRepo() {
 27        #expect(refs("fixed in krz/solar#7 and krz/solar!8.") == [
 28            BodyReference(range: 9..<20, destination: .issue(repo: "krz/solar", number: 7)),
 29            BodyReference(range: 25..<36, destination: .mr(repo: "krz/solar", number: 8)),
 30        ])
 31    }
 32
 33    @Test func aBareReferenceNeedsABoundaryBefore() {
 34        #expect(refs("a1b2#3").isEmpty)
 35        #expect(refs("(#4)").map(\.range) == [1..<3])
 36        #expect(refs("[#5]").map(\.range) == [1..<3])
 37        #expect(refs("line\n#6").map(\.range) == [5..<7])
 38    }
 39
 40    @Test func digitsMustEndAtAWordBoundary() {
 41        #expect(refs("#12abc").isEmpty)
 42        #expect(refs("#12, #13").count == 2)
 43    }
 44
 45    @Test func aCrossReferenceIsNotAlsoReadAsABareOne() {
 46        #expect(refs("krz/solar#7").count == 1)
 47    }
 48
 49    @Test func offsetsCountCharactersNotBytes() {
 50        #expect(refs("é #1").map(\.range) == [2..<4])
 51    }
 52
 53    @Test func theURLRoundTrips() throws {
 54        for destination in [NotificationDestination.issue(repo: "krz/gitbay", number: 12),
 55                            .mr(repo: "krz/solar", number: 3)] {
 56            let url = try #require(referenceURL(destination))
 57            #expect(referenceDestination(url) == destination)
 58        }
 59        #expect(referenceDestination(URL(string: "https://gitbay.org/krz/gitbay/issues/1")!) == nil)
 60    }
 61}
 62
 63@MainActor
 64struct BodyReferenceMarkdownTests {
 65
 66    private func links(_ markdown: String) -> [String: URL] {
 67        let attributed = MarkdownView.attributed(markdown, referenceRepo: "krz/gitbay")
 68        var found: [String: URL] = [:]
 69        for run in attributed.runs {
 70            if let link = run.link {
 71                found[String(attributed[run.range].characters)] = link
 72            }
 73        }
 74        return found
 75    }
 76
 77    @Test func referencesBecomeLinks() {
 78        let found = links("closes #12, see krz/solar!3")
 79        #expect(found["#12"] == referenceURL(.issue(repo: "krz/gitbay", number: 12)))
 80        #expect(found["krz/solar!3"] == referenceURL(.mr(repo: "krz/solar", number: 3)))
 81    }
 82
 83    @Test func codeSpansAndExistingLinksAreLeftAlone() {
 84        let found = links("`#12` and [#13](https://example.com)")
 85        #expect(found.count == 1)
 86        #expect(found["#13"] == URL(string: "https://example.com"))
 87    }
 88
 89    @Test func noRepoMeansNoReferenceLinks() {
 90        #expect(MarkdownView.attributed("#12").runs.allSatisfy { $0.link == nil })
 91    }
 92}
 93
 94/// Org bodies reach the transform as `OrgSwiftUI` hands it prose: verbatim
 95/// and code carry the `.code` intent, links carry `.link`.
 96struct BodyReferenceOrgTests {
 97
 98    private func links(_ org: String) -> [String: URL] {
 99        guard case .paragraph(let objects) = OrgParser.parse(org).elements.first else { return [:] }
100        var attributed = OrgAttributedStringRenderer().inline(objects)
101        linkReferences(in: &attributed, repo: "krz/gitbay")
102        var found: [String: URL] = [:]
103        for run in attributed.runs {
104            if let link = run.link {
105                found[String(attributed[run.range].characters)] = link
106            }
107        }
108        return found
109    }
110
111    @Test func referencesBecomeLinks() {
112        let found = links("closes #12, see krz/solar!3")
113        #expect(found["#12"] == referenceURL(.issue(repo: "krz/gitbay", number: 12)))
114        #expect(found["krz/solar!3"] == referenceURL(.mr(repo: "krz/solar", number: 3)))
115    }
116
117    @Test func verbatimCodeAndExistingLinksAreLeftAlone() {
118        let found = links("=#12= ~!4~ and [[https://example.com][#13]] but *#14*")
119        #expect(found.count == 2)
120        #expect(found["#13"] == URL(string: "https://example.com"))
121        #expect(found["#14"] == referenceURL(.issue(repo: "krz/gitbay", number: 14)))
122    }
123}