mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-28 23:01:34 +00:00
195 lines
9.0 KiB
Swift
195 lines
9.0 KiB
Swift
import XCTest
|
|
@testable import Hapi
|
|
|
|
final class ManualPairingFormTests: XCTestCase {
|
|
private let companion = "hapicompanion://bind?hub=https%3A%2F%2FHub.Example.com%3A443%2F&code=Tok%2BValue%3Ateam"
|
|
private let web = "https://app.hapi.run/?hub=http%3A%2F%2F192.168.1.20%3A3006&token=Tok%2BValue%3Ateam"
|
|
|
|
func testPristineFormHasNoExampleValuesOrErrors() {
|
|
var form = ManualPairingForm()
|
|
XCTAssertEqual(form.scheme, .https)
|
|
XCTAssertEqual(form.address, "")
|
|
XCTAssertEqual(form.accessToken, "")
|
|
XCTAssertNil(form.submission)
|
|
XCTAssertNil(form.error(for: .address))
|
|
XCTAssertNil(form.error(for: .accessToken))
|
|
form.selectScheme(.http)
|
|
XCTAssertEqual(form.address, "")
|
|
XCTAssertNil(form.error(for: .address), "Selecting a protocol must not validate an untouched empty address")
|
|
}
|
|
|
|
func testTypingIsNotRewrittenUntilEditingEnds() {
|
|
var form = ManualPairingForm()
|
|
for input in ["h", "https:", "https://", " HTTPS://Hub.Example.com:443/path?q=1#f "] {
|
|
form.edit(input, in: .address)
|
|
XCTAssertEqual(form.address, input)
|
|
XCTAssertNil(form.error(for: .address))
|
|
}
|
|
form.finishEditing(.address)
|
|
XCTAssertEqual(form.address, "hub.example.com")
|
|
XCTAssertEqual(form.scheme, .https)
|
|
XCTAssertNil(form.error(for: .address))
|
|
}
|
|
|
|
func testBareAddressesUseTheSelectedSchemeWithoutGuessing() throws {
|
|
for scheme in ManualPairingForm.Scheme.allCases {
|
|
for host in ["Hub.Example.com", "192.168.1.20:3006", "localhost:3006", "[::1]:3006"] {
|
|
var form = readyForm()
|
|
form.selectScheme(scheme)
|
|
form.edit(host, in: .address)
|
|
form.finishEditing(.address)
|
|
XCTAssertEqual(try XCTUnwrap(form.submission).hubURL, scheme.prefix + host.lowercased())
|
|
}
|
|
}
|
|
}
|
|
|
|
func testURLPastesReplaceAddressAndSynchronizeSchemeWithoutChangingToken() throws {
|
|
var form = readyForm()
|
|
for (url, origin, scheme) in [
|
|
(" HTTP://192.168.1.20:3006/path\n", "http://192.168.1.20:3006", ManualPairingForm.Scheme.http),
|
|
("https://Hub.Example.com:443/", "https://hub.example.com", .https),
|
|
("http://hub.example.com:80/?q=1#f", "http://hub.example.com", .http),
|
|
("https://[2001:db8::1]:8443/", "https://[2001:db8::1]:8443", .https),
|
|
] {
|
|
for _ in 0..<2 {
|
|
XCTAssertTrue(form.paste(url, into: .address))
|
|
XCTAssertEqual(form.scheme, scheme)
|
|
XCTAssertEqual(form.scheme.prefix + form.address, origin)
|
|
XCTAssertEqual(try XCTUnwrap(form.submission).hubURL, origin)
|
|
XCTAssertEqual(form.accessToken, "original:team")
|
|
XCTAssertFalse(form.didImportLink)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testMenuSelectionWinsOverAnExplicitSchemeStillBeingEdited() throws {
|
|
var form = readyForm()
|
|
form.edit("https://hub.example.com:8443", in: .address)
|
|
form.selectScheme(.http)
|
|
XCTAssertEqual(form.address, "hub.example.com:8443")
|
|
XCTAssertEqual(try XCTUnwrap(form.submission).hubURL, "http://hub.example.com:8443")
|
|
}
|
|
|
|
func testBothLinkFormsImportFromEitherFieldAndReplaceTheWholeForm() throws {
|
|
for field in [ManualPairingForm.Field.address, .accessToken] {
|
|
for (link, origin) in [(companion, "https://hub.example.com"), (web, "http://192.168.1.20:3006")] {
|
|
var form = readyForm()
|
|
for _ in 0..<2 {
|
|
XCTAssertTrue(form.paste(" \n" + link + " \n", into: field))
|
|
XCTAssertTrue(form.didImportLink)
|
|
XCTAssertEqual(form.scheme.prefix + form.address, origin)
|
|
XCTAssertEqual(form.accessToken, "Tok+Value:team")
|
|
XCTAssertEqual(try XCTUnwrap(form.submission), .init(hubURL: origin, accessToken: "Tok+Value:team"))
|
|
XCTAssertNil(form.error(for: .address))
|
|
XCTAssertNil(form.error(for: .accessToken))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func testAHandTypedLinkIsOnlyImportedAtEndEditing() {
|
|
var form = ManualPairingForm()
|
|
for input in ["hapicompanion:", "hapicompanion://bind?hub=https://hub.test&code=t", companion] {
|
|
form.edit(input, in: .address)
|
|
XCTAssertEqual(form.address, input)
|
|
XCTAssertEqual(form.accessToken, "")
|
|
XCTAssertFalse(form.didImportLink)
|
|
XCTAssertNil(form.submission, "Raw links are never a hidden submit source")
|
|
}
|
|
form.finishEditing(.address)
|
|
XCTAssertEqual(form.address, "hub.example.com")
|
|
XCTAssertTrue(form.didImportLink)
|
|
XCTAssertNotNil(form.submission)
|
|
}
|
|
|
|
func testEditsAfterImportAreTheOnlySubmissionSource() throws {
|
|
var form = ManualPairingForm()
|
|
form.paste(companion, into: .accessToken)
|
|
form.edit("new:namespace", in: .accessToken)
|
|
form.edit("different.example.com:8443", in: .address)
|
|
form.selectScheme(.http)
|
|
XCTAssertFalse(form.didImportLink)
|
|
XCTAssertEqual(try XCTUnwrap(form.submission), .init(hubURL: "http://different.example.com:8443", accessToken: "new:namespace"))
|
|
form.edit("", in: .address)
|
|
XCTAssertNil(form.submission)
|
|
form.edit("hub.test", in: .address)
|
|
form.edit(" \n ", in: .accessToken)
|
|
XCTAssertNil(form.submission)
|
|
}
|
|
|
|
func testMalformedLinksStayVisibleAndNeverFallBackToTheWebHost() {
|
|
let invalidLinks = [
|
|
"hapicompanion://bind?hub=https://hub.test",
|
|
"hapicompanion://pair?hub=https://hub.test&code=secret",
|
|
"https://app.hapi.run/?hub=https://hub.test",
|
|
"https://app.hapi.run/?token=secret",
|
|
"https://app.hapi.run/?hub=https://hub.test&token=",
|
|
"https://app.hapi.run/?hub=ftp://hub.test&token=secret",
|
|
"https://app.hapi.run/?hub=https://hub.test&token=%zz",
|
|
"https://app.hapi.run/?%68ub=https://hub.test&code=secret",
|
|
"hapicompanion://bind?hub=https://hub.test:99999&code=secret",
|
|
]
|
|
for field in [ManualPairingForm.Field.address, .accessToken] {
|
|
for link in invalidLinks {
|
|
var form = readyForm()
|
|
XCTAssertTrue(form.paste(link, into: field))
|
|
XCTAssertEqual(form.text(for: field), link)
|
|
XCTAssertEqual(form.error(for: field), .invalidLink, link)
|
|
XCTAssertEqual(form.scheme, .https)
|
|
XCTAssertEqual(field == .address ? form.accessToken : form.address,
|
|
field == .address ? "original:team" : "original.test")
|
|
XCTAssertFalse(form.didImportLink)
|
|
XCTAssertNil(form.submission)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testInvalidAddressesBlockSubmissionAndErrorsAppearAfterEditingEnds() {
|
|
for input in ["", " ", "https://", "ftp://hub.test", "file:///tmp/hub", "bad host", "https://user:pass@hub.test", "hub.test:99999", "hub.test:0", "https://hub.test/%zz", "::1"] {
|
|
var form = readyForm()
|
|
form.edit(input, in: .address)
|
|
XCTAssertNil(form.error(for: .address))
|
|
XCTAssertNil(form.submission, input)
|
|
form.finishEditing(.address)
|
|
XCTAssertEqual(form.error(for: .address), .invalidAddress, input)
|
|
form.edit("valid.test", in: .address)
|
|
XCTAssertNil(form.error(for: .address))
|
|
XCTAssertNotNil(form.submission)
|
|
}
|
|
}
|
|
|
|
func testOrdinaryTextUsesTheTextControlsInsertionRules() {
|
|
var form = readyForm()
|
|
for field in [ManualPairingForm.Field.address, .accessToken] {
|
|
for text in ["hub.test", "secret:team", "segment", "\n"] {
|
|
XCTAssertFalse(form.paste(text, into: field))
|
|
XCTAssertEqual(form.address, "original.test")
|
|
XCTAssertEqual(form.accessToken, "original:team")
|
|
}
|
|
}
|
|
XCTAssertFalse(form.paste("https://not-a-pairing-link.test", into: .accessToken))
|
|
}
|
|
|
|
func testTokenRemainsOpaqueExceptForSurroundingWhitespace() throws {
|
|
var form = readyForm()
|
|
for token in [" AbC+Def%2B:namespace ", "token?token=value", "a b:team", "https://an-opaque-token.test"] {
|
|
form.edit(token, in: .accessToken)
|
|
form.finishEditing(.accessToken)
|
|
let expected = token.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
XCTAssertEqual(form.accessToken, expected)
|
|
XCTAssertEqual(try XCTUnwrap(form.submission).accessToken, expected)
|
|
}
|
|
form.edit("\n ", in: .accessToken)
|
|
form.finishEditing(.accessToken)
|
|
XCTAssertEqual(form.error(for: .accessToken), .missingToken)
|
|
XCTAssertNil(form.submission)
|
|
}
|
|
|
|
private func readyForm() -> ManualPairingForm {
|
|
var form = ManualPairingForm()
|
|
form.edit("original.test", in: .address)
|
|
form.edit("original:team", in: .accessToken)
|
|
return form
|
|
}
|
|
}
|