Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MockURLProtocol for unit testing (requires session to be added to update date init) #3

Open
eonist opened this issue Jan 12, 2025 · 0 comments

Comments

@eonist
Copy link
Member

eonist commented Jan 12, 2025

import Foundation

class MockURLProtocol: URLProtocol {
    static var requestHandler: ((URLRequest) throws -> (HTTPURLResponse, Data?))?

    override class func canInit(with request: URLRequest) -> Bool {
        // Handle all types of requests
        return true
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        // Return the original request
        return request
    }

    override func startLoading() {
        guard let handler = MockURLProtocol.requestHandler else {
            fatalError("Handler is not set.")
        }

        do {
            let (response, data) = try handler(request)
            client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
            if let data = data {
                client?.urlProtocol(self, didLoad: data)
            }
            client?.urlProtocolDidFinishLoading(self)
        } catch {
            client?.urlProtocol(self, didFailWithError: error)
        }
    }

    override func stopLoading() {
        // Required method; nothing to clean up.
    }
}
import XCTest
@testable import NetTime

final class UnitTests: XCTestCase {
    /**
     * Tests that `Date.updateTime` handles missing `Date` header gracefully.
     */
    func testUpdateTimeWithMissingDateHeader() {
        // Create a mock URL session that returns a response without the `Date` header
        let url = URL(string: "https://example.com")!
        let configuration = URLSessionConfiguration.ephemeral
        configuration.protocolClasses = [MockURLProtocol.self]
        let session = URLSession(configuration: configuration)
        
        MockURLProtocol.requestHandler = { request in
            let response = HTTPURLResponse(
                url: request.url!,
                statusCode: 200,
                httpVersion: nil,
                headerFields: [:]
            )!
            return (response, nil)
        }
        
        let expectation = self.expectation(description: "Completion handler invoked")
        Date.updateTime(with: url, session: session) { result in
            if case .failure(let error) = result {
                XCTAssertEqual(error, .missingDateHeader)
            } else {
                XCTFail("Expected failure due to missing Date header")
            }
            expectation.fulfill()
        }
        waitForExpectations(timeout: 5, handler: nil)
    }
}
import XCTest
@testable import NetTime

final class UnitTests: XCTestCase {
    /**
     * Tests `Date.updateTime` with a custom date formatter.
     */
    func testUpdateTimeWithCustomDateFormatter() {
        // Assume that we have modified the Date.updateTime method to accept a custom formatter
        let customFormatter = DateFormatter()
        customFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
        customFormatter.locale = Locale(identifier: "en_US_POSIX")
        customFormatter.timeZone = TimeZone(secondsFromGMT: 0)
        
        // Create a mock URL session that returns a date in custom format
        let url = URL(string: "https://example.com")!
        let configuration = URLSessionConfiguration.ephemeral
        configuration.protocolClasses = [MockURLProtocol.self]
        let session = URLSession(configuration: configuration)
        
        MockURLProtocol.requestHandler = { request in
            let headers = ["Date": "2025-01-12T17:44:00+0000"]
            let response = HTTPURLResponse(
                url: request.url!,
                statusCode: 200,
                httpVersion: nil,
                headerFields: headers
            )!
            return (response, nil)
        }
        
        let expectation = self.expectation(description: "Completion handler invoked")
        Date.updateTime(with: url, session: session, formatter: customFormatter) { result in
            if case .success = result {
                // Verify that timeGap is set correctly
                XCTAssertNotEqual(Date.timeGap, 0, "Expected timeGap to be updated")
            } else {
                XCTFail("Expected success when using custom date formatter")
            }
            expectation.fulfill()
        }
        waitForExpectations(timeout: 5, handler: nil)
    }
}

import XCTest
@testable import NetTime

final class UnitTests: XCTestCase {
    /**
     * Tests that `Date.updateTime` handles network failures.
     */
    func testUpdateTimeWithNetworkFailure() {
        // Create a mock URL session that simulates a network error
        let url = URL(string: "https://example.com")!
        let configuration = URLSessionConfiguration.ephemeral
        configuration.protocolClasses = [MockURLProtocol.self]
        let session = URLSession(configuration: configuration)
        
        MockURLProtocol.requestHandler = { request in
            throw NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: nil)
        }
        
        let expectation = self.expectation(description: "Completion handler invoked")
        Date.updateTime(with: url, session: session) { result in
            if case .failure(let error) = result {
                XCTAssertEqual(error, .networkError(NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: nil)))
            } else {
                XCTFail("Expected failure due to network error")
            }
            expectation.fulfill()
        }
        waitForExpectations(timeout: 5, handler: nil)
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant