374 lines
9.8 KiB
Swift
374 lines
9.8 KiB
Swift
//
|
|
// EndpointValidatorTests.swift
|
|
// readeckTests
|
|
//
|
|
// Created by Ilyas Hallak on 05.12.25.
|
|
//
|
|
|
|
import XCTest
|
|
@testable import readeck
|
|
|
|
final class EndpointValidatorTests: XCTestCase {
|
|
|
|
// MARK: - Standard HTTPS URLs
|
|
|
|
func testNormalize_FullHTTPSURL() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_DomainWithoutScheme_AddsHTTPS() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("example.com"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_DomainWithSubdomain() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("api.example.com"),
|
|
"https://api.example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_DomainWithWWW() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("www.example.com"),
|
|
"https://www.example.com"
|
|
)
|
|
}
|
|
|
|
// MARK: - HTTP URLs (Critical for Tailscale)
|
|
|
|
func testNormalize_ExplicitHTTP_PreservesHTTP() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://example.com"),
|
|
"http://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_HTTPWithTailscaleIP() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://100.80.0.1"),
|
|
"http://100.80.0.1"
|
|
)
|
|
}
|
|
|
|
func testNormalize_HTTPWithTailscaleIPAndPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://100.80.0.1:8080"),
|
|
"http://100.80.0.1:8080"
|
|
)
|
|
}
|
|
|
|
// MARK: - Custom Ports (Critical!)
|
|
|
|
func testNormalize_HTTPSWithCustomPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com:8443"),
|
|
"https://example.com:8443"
|
|
)
|
|
}
|
|
|
|
func testNormalize_HTTPWithCustomPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://example.com:8080"),
|
|
"http://example.com:8080"
|
|
)
|
|
}
|
|
|
|
func testNormalize_DomainWithPortNoScheme_AddsHTTPS() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("example.com:3000"),
|
|
"https://example.com:3000"
|
|
)
|
|
}
|
|
|
|
func testNormalize_PortOnly8080() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("localhost:8080"),
|
|
"https://localhost:8080"
|
|
)
|
|
}
|
|
|
|
func testNormalize_PortOnly9090() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("server:9090"),
|
|
"https://server:9090"
|
|
)
|
|
}
|
|
|
|
// MARK: - Tailscale IP Addresses
|
|
|
|
func testNormalize_TailscaleIPNoScheme_AddsHTTPS() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("100.80.0.1"),
|
|
"https://100.80.0.1"
|
|
)
|
|
}
|
|
|
|
func testNormalize_TailscaleIPWithPortNoScheme() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("100.80.0.1:8080"),
|
|
"https://100.80.0.1:8080"
|
|
)
|
|
}
|
|
|
|
func testNormalize_TailscaleIPWithHTTPAndPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://100.95.200.50:3000"),
|
|
"http://100.95.200.50:3000"
|
|
)
|
|
}
|
|
|
|
func testNormalize_TailscaleIPWithHTTPSAndPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://100.120.10.5:8443"),
|
|
"https://100.120.10.5:8443"
|
|
)
|
|
}
|
|
|
|
// MARK: - Private IP Addresses
|
|
|
|
func testNormalize_PrivateIPv4NoScheme() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("192.168.1.100"),
|
|
"https://192.168.1.100"
|
|
)
|
|
}
|
|
|
|
func testNormalize_PrivateIPv4WithPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("192.168.1.100:9090"),
|
|
"https://192.168.1.100:9090"
|
|
)
|
|
}
|
|
|
|
func testNormalize_PrivateIPv4WithHTTPAndPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://192.168.1.100:8080"),
|
|
"http://192.168.1.100:8080"
|
|
)
|
|
}
|
|
|
|
func testNormalize_LocalhostWithHTTP() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://localhost:8080"),
|
|
"http://localhost:8080"
|
|
)
|
|
}
|
|
|
|
// MARK: - Trailing Slashes
|
|
|
|
func testNormalize_RemovesTrailingSlash() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com/"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_RemovesTrailingSlashFromPath() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com/api/"),
|
|
"https://example.com/api"
|
|
)
|
|
}
|
|
|
|
func testNormalize_RemovesTrailingSlashWithPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://100.80.0.1:8080/"),
|
|
"http://100.80.0.1:8080"
|
|
)
|
|
}
|
|
|
|
// MARK: - Query Parameters and Fragments
|
|
|
|
func testNormalize_RemovesQueryParameters() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com?query=test"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_RemovesFragment() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com#section"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_RemovesQueryAndFragment() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com?query=test#section"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_RemovesQueryWithPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://192.168.1.100:9090?debug=true"),
|
|
"http://192.168.1.100:9090"
|
|
)
|
|
}
|
|
|
|
func testNormalize_ComplexQueryParameters() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com/path?param1=value1¶m2=value2"),
|
|
"https://example.com/path"
|
|
)
|
|
}
|
|
|
|
// MARK: - Paths
|
|
|
|
func testNormalize_PreservesPath() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com/readeck"),
|
|
"https://example.com/readeck"
|
|
)
|
|
}
|
|
|
|
func testNormalize_PreservesNestedPath() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com/api/v1"),
|
|
"https://example.com/api/v1"
|
|
)
|
|
}
|
|
|
|
func testNormalize_PathWithPortNoScheme() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("example.com:8080/readeck"),
|
|
"https://example.com:8080/readeck"
|
|
)
|
|
}
|
|
|
|
func testNormalize_HTTPWithPathAndPort() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://100.80.0.1:3000/api"),
|
|
"http://100.80.0.1:3000/api"
|
|
)
|
|
}
|
|
|
|
// MARK: - Whitespace Handling
|
|
|
|
func testNormalize_TrimsLeadingWhitespace() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize(" https://example.com"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_TrimsTrailingWhitespace() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com "),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_TrimsBothWhitespace() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize(" https://example.com "),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
func testNormalize_TrimsWhitespaceFromComplexURL() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize(" http://100.80.0.1:8080/api "),
|
|
"http://100.80.0.1:8080/api"
|
|
)
|
|
}
|
|
|
|
// MARK: - Edge Cases
|
|
|
|
func testNormalize_EmptyString() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize(""),
|
|
""
|
|
)
|
|
}
|
|
|
|
func testNormalize_OnlyWhitespace() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize(" "),
|
|
""
|
|
)
|
|
}
|
|
|
|
func testNormalize_StandardPort80_Preserved() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://example.com:80"),
|
|
"http://example.com:80"
|
|
)
|
|
}
|
|
|
|
func testNormalize_StandardPort443_Preserved() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("https://example.com:443"),
|
|
"https://example.com:443"
|
|
)
|
|
}
|
|
|
|
// MARK: - Complex Real-World Scenarios
|
|
|
|
func testNormalize_TailscaleWithPathQueryAndTrailingSlash() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("http://100.80.0.1:8080/readeck/?setup=true"),
|
|
"http://100.80.0.1:8080/readeck"
|
|
)
|
|
}
|
|
|
|
func testNormalize_UserInputWithEverything() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize(" http://192.168.1.50:9090/api/v1/?debug=true#main "),
|
|
"http://192.168.1.50:9090/api/v1"
|
|
)
|
|
}
|
|
|
|
func testNormalize_InvalidScheme_ConvertsToHTTPS() {
|
|
XCTAssertEqual(
|
|
EndpointValidator.normalize("ftp://example.com"),
|
|
"https://example.com"
|
|
)
|
|
}
|
|
|
|
// MARK: - isValid Tests
|
|
|
|
func testIsValid_ValidHTTPSURL() {
|
|
XCTAssertTrue(EndpointValidator.isValid("https://example.com"))
|
|
}
|
|
|
|
func testIsValid_ValidHTTPURL() {
|
|
XCTAssertTrue(EndpointValidator.isValid("http://example.com"))
|
|
}
|
|
|
|
func testIsValid_ValidDomainWithoutScheme() {
|
|
XCTAssertTrue(EndpointValidator.isValid("example.com"))
|
|
}
|
|
|
|
func testIsValid_ValidTailscaleIP() {
|
|
XCTAssertTrue(EndpointValidator.isValid("100.80.0.1:8080"))
|
|
}
|
|
|
|
func testIsValid_ValidIPWithPort() {
|
|
XCTAssertTrue(EndpointValidator.isValid("192.168.1.100:9090"))
|
|
}
|
|
|
|
func testIsValid_EmptyString() {
|
|
XCTAssertFalse(EndpointValidator.isValid(""))
|
|
}
|
|
|
|
func testIsValid_OnlyWhitespace() {
|
|
XCTAssertFalse(EndpointValidator.isValid(" "))
|
|
}
|
|
|
|
func testIsValid_ValidWithPath() {
|
|
XCTAssertTrue(EndpointValidator.isValid("https://example.com/api"))
|
|
}
|
|
|
|
func testIsValid_ValidHTTPWithPortAndPath() {
|
|
XCTAssertTrue(EndpointValidator.isValid("http://100.80.0.1:3000/readeck"))
|
|
}
|
|
}
|