krz/octosentry

macOS menu bar app to monitor GitHub security alerts

clone: git clone https://gitbay.org/krz/octosentry.git

1.1.1: octosentryTests/GitHubHostTests.swift · raw

  1//
  2//  GitHubHostTests.swift
  3//  octosentryTests
  4//
  5
  6import Foundation
  7import Testing
  8@testable import octosentry
  9
 10struct GitHubHostTests {
 11
 12    // MARK: - github.com
 13
 14    @Test func theDefaultIsGitHubDotCom() {
 15        #expect(GitHubHost.dotCom.isDotCom)
 16        #expect(GitHubHost.dotCom.displayName == "github.com")
 17        #expect(GitHubHost.dotCom.apiBaseURL.absoluteString == "https://api.github.com")
 18        #expect(GitHubHost.dotCom.webBaseURL.absoluteString == "https://github.com")
 19    }
 20
 21    @Test func dotComKeepsItsExistingAuthEndpoints() {
 22        #expect(GitHubHost.dotCom.deviceCodeURL.absoluteString == "https://github.com/login/device/code")
 23        #expect(GitHubHost.dotCom.accessTokenURL.absoluteString == "https://github.com/login/oauth/access_token")
 24    }
 25
 26    // Naming github.com explicitly is still github.com, not an enterprise host.
 27    @Test func namingGitHubDotComExplicitlyIsNotEnterprise() {
 28        #expect(GitHubHost(host: "github.com", clientID: "abc").isDotCom)
 29        #expect(GitHubHost(host: "https://github.com", clientID: "abc").isDotCom)
 30    }
 31
 32    // MARK: - Enterprise Server
 33
 34    // GHES serves the REST API from the same host under /api/v3, not from a
 35    // separate api. domain.
 36    @Test func enterpriseAPILivesUnderApiV3OnTheSameHost() {
 37        let host = GitHubHost(host: "github.example.com", clientID: "abc")
 38
 39        #expect(host.apiBaseURL.absoluteString == "https://github.example.com/api/v3")
 40        #expect(host.webBaseURL.absoluteString == "https://github.example.com")
 41        #expect(!host.isDotCom)
 42    }
 43
 44    @Test func enterpriseAuthEndpointsAreOnTheInstance() {
 45        let host = GitHubHost(host: "github.example.com", clientID: "abc")
 46
 47        #expect(host.deviceCodeURL.absoluteString == "https://github.example.com/login/device/code")
 48        #expect(host.accessTokenURL.absoluteString == "https://github.example.com/login/oauth/access_token")
 49    }
 50
 51    // MARK: - Normalizing what a user pastes
 52
 53    @Test func aPastedURLIsReducedToItsHost() {
 54        for input in [
 55            "https://github.example.com",
 56            "http://github.example.com",
 57            "github.example.com/",
 58            "https://github.example.com/some/path",
 59            "  GitHub.Example.com  ",
 60        ] {
 61            #expect(GitHubHost(host: input, clientID: "abc").host == "github.example.com", "input: \(input)")
 62        }
 63    }
 64
 65    @Test func anEmptyHostMeansGitHubDotCom() {
 66        #expect(GitHubHost(host: "", clientID: nil).isDotCom)
 67        #expect(GitHubHost(host: "   ", clientID: nil).isDotCom)
 68        #expect(GitHubHost(host: nil, clientID: nil).isDotCom)
 69    }
 70
 71    @Test func anEmptyClientIDIsTreatedAsAbsent() {
 72        #expect(GitHubHost(host: "github.example.com", clientID: "").clientID == nil)
 73        #expect(GitHubHost(host: "github.example.com", clientID: "  ").clientID == nil)
 74        #expect(GitHubHost(host: "github.example.com", clientID: " abc ").clientID == "abc")
 75    }
 76
 77    // MARK: - Persistence
 78
 79    @Test func roundTripsThroughCodable() throws {
 80        for host in [GitHubHost.dotCom, GitHubHost(host: "github.example.com", clientID: "abc")] {
 81            let decoded = try JSONDecoder().decode(GitHubHost.self, from: try JSONEncoder().encode(host))
 82            #expect(decoded == host)
 83        }
 84    }
 85
 86    // An account written before Enterprise support has no host field.
 87    @Test func anAccountWithoutAHostFieldDecodesAsGitHubDotCom() throws {
 88        let json = """
 89        {"id": 7, "login": "octocat", "keychainAccount": "account-7", "hasRepoScope": false}
 90        """
 91
 92        let account = try JSONDecoder().decode(Account.self, from: Data(json.utf8))
 93
 94        #expect(account.host == .dotCom)
 95        #expect(account.displayName == "octocat")
 96    }
 97
 98    // MARK: - Accounts
 99
100    // Ids are only unique within an instance, so two accounts that happen to
101    // share an id on different hosts must not share a Keychain item.
102    @Test func sameIdOnDifferentHostsGetsDifferentKeychainItems() {
103        let dotCom = Account.new(id: 7, login: "octocat", hasRepoScope: false)
104        let enterprise = Account.new(
105            id: 7,
106            login: "octocat",
107            hasRepoScope: false,
108            host: GitHubHost(host: "github.example.com", clientID: "abc")
109        )
110
111        #expect(dotCom.keychainAccount != enterprise.keychainAccount)
112    }
113
114    @Test func enterpriseAccountsAreLabelledWithTheirHost() {
115        let account = Account.new(
116            id: 7,
117            login: "octocat",
118            hasRepoScope: false,
119            host: GitHubHost(host: "github.example.com", clientID: "abc")
120        )
121
122        #expect(account.displayName == "octocat @ github.example.com")
123    }
124}