diff --git a/LocalPackages/AIChat/Sources/AIChat/URL+Extension.swift b/LocalPackages/AIChat/Sources/AIChat/URL+Extension.swift index 1e0978f346..b09269d7bb 100644 --- a/LocalPackages/AIChat/Sources/AIChat/URL+Extension.swift +++ b/LocalPackages/AIChat/Sources/AIChat/URL+Extension.swift @@ -20,6 +20,12 @@ import Foundation extension URL { + enum Constants { + static let duckDuckGoHost = "duckduckgo.com" + static let chatQueryName = "ia" + static let chatQueryValue = "chat" + } + func addingOrReplacingQueryItem(_ queryItem: URLQueryItem) -> URL { guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: false) else { return self @@ -34,7 +40,7 @@ extension URL { } var isDuckAIURL: Bool { - guard let host = self.host, host == "duckduckgo.com" else { + guard let host = self.host, host == Constants.duckDuckGoHost else { return false } @@ -43,6 +49,6 @@ extension URL { return false } - return queryItems.contains { $0.name == "ia" && $0.value == "chat" } + return queryItems.contains { $0.name == Constants.chatQueryName && $0.value == Constants.chatQueryValue } } } diff --git a/LocalPackages/AIChat/Tests/URLExtensionTests.swift b/LocalPackages/AIChat/Tests/URLExtensionTests.swift index fc72d2a759..caa5b50236 100644 --- a/LocalPackages/AIChat/Tests/URLExtensionTests.swift +++ b/LocalPackages/AIChat/Tests/URLExtensionTests.swift @@ -20,10 +20,23 @@ import XCTest @testable import AIChat -class URLExtensionTests: XCTestCase { +final class URLExtensionTests: XCTestCase { + private enum TestURLs { + static let exampleDomain = "https://example.com" + static let duckDuckGoDomain = "https://duckduckgo.com" + + static let example = "\(exampleDomain)" + static let exampleWithKeyOldValue = "\(exampleDomain)?key=oldValue" + static let exampleWithExistingQuery = "\(exampleDomain)?existingKey=existingValue" + static let exampleWithMultipleQueryItems = "\(exampleDomain)?key1=value1&key2=value2" + static let duckDuckGoChat = "\(duckDuckGoDomain)/?ia=chat" + static let duckDuckGoWithMissingQuery = "\(duckDuckGoDomain)/" + static let duckDuckGoDifferentQuery = "\(duckDuckGoDomain)/?ia=search" + static let duckDuckGoAdditionalQueryItems = "\(duckDuckGoDomain)/?ia=chat&other=param" + } func testAddingQueryItemToEmptyURL() { - let url = URL(string: "https://example.com")! + let url = URL(string: TestURLs.example)! let queryItem = URLQueryItem(name: "key", value: "value") let result = url.addingOrReplacingQueryItem(queryItem) @@ -33,7 +46,7 @@ class URLExtensionTests: XCTestCase { } func testReplacingExistingQueryItem() { - let url = URL(string: "https://example.com?key=oldValue")! + let url = URL(string: TestURLs.exampleWithKeyOldValue)! let queryItem = URLQueryItem(name: "key", value: "newValue") let result = url.addingOrReplacingQueryItem(queryItem) @@ -43,7 +56,7 @@ class URLExtensionTests: XCTestCase { } func testAddingQueryItemToExistingQuery() { - let url = URL(string: "https://example.com?existingKey=existingValue")! + let url = URL(string: TestURLs.exampleWithExistingQuery)! let queryItem = URLQueryItem(name: "newKey", value: "newValue") let result = url.addingOrReplacingQueryItem(queryItem) @@ -53,7 +66,7 @@ class URLExtensionTests: XCTestCase { } func testReplacingOneOfMultipleQueryItems() { - let url = URL(string: "https://example.com?key1=value1&key2=value2")! + let url = URL(string: TestURLs.exampleWithMultipleQueryItems)! let queryItem = URLQueryItem(name: "key1", value: "newValue1") let result = url.addingOrReplacingQueryItem(queryItem) @@ -63,7 +76,7 @@ class URLExtensionTests: XCTestCase { } func testAddingQueryItemWithNilValue() { - let url = URL(string: "https://example.com")! + let url = URL(string: TestURLs.example)! let queryItem = URLQueryItem(name: "key", value: nil) let result = url.addingOrReplacingQueryItem(queryItem) @@ -73,7 +86,7 @@ class URLExtensionTests: XCTestCase { } func testReplacingQueryItemWithNilValue() { - let url = URL(string: "https://example.com?key=value")! + let url = URL(string: "\(TestURLs.example)?key=value")! let queryItem = URLQueryItem(name: "key", value: nil) let result = url.addingOrReplacingQueryItem(queryItem) @@ -83,7 +96,7 @@ class URLExtensionTests: XCTestCase { } func testIsDuckAIURLWithValidURL() { - if let url = URL(string: "https://duckduckgo.com/?ia=chat") { + if let url = URL(string: TestURLs.duckDuckGoChat) { XCTAssertTrue(url.isDuckAIURL, "The URL should be identified as a DuckDuckGo AI URL.") } else { XCTFail("Failed to create URL from string.") @@ -91,7 +104,7 @@ class URLExtensionTests: XCTestCase { } func testIsDuckAIURLWithInvalidDomain() { - if let url = URL(string: "https://example.com/?ia=chat") { + if let url = URL(string: TestURLs.exampleWithExistingQuery) { XCTAssertFalse(url.isDuckAIURL, "The URL should not be identified as a DuckDuckGo AI URL due to the domain.") } else { XCTFail("Failed to create URL from string.") @@ -99,7 +112,7 @@ class URLExtensionTests: XCTestCase { } func testIsDuckAIURLWithMissingQueryItem() { - if let url = URL(string: "https://duckduckgo.com/") { + if let url = URL(string: TestURLs.duckDuckGoWithMissingQuery) { XCTAssertFalse(url.isDuckAIURL, "The URL should not be identified as a DuckDuckGo AI URL due to missing query item.") } else { XCTFail("Failed to create URL from string.") @@ -107,7 +120,7 @@ class URLExtensionTests: XCTestCase { } func testIsDuckAIURLWithDifferentQueryItem() { - if let url = URL(string: "https://duckduckgo.com/?ia=search") { + if let url = URL(string: TestURLs.duckDuckGoDifferentQuery) { XCTAssertFalse(url.isDuckAIURL, "The URL should not be identified as a DuckDuckGo AI URL due to different query item value.") } else { XCTFail("Failed to create URL from string.") @@ -115,7 +128,7 @@ class URLExtensionTests: XCTestCase { } func testIsDuckAIURLWithAdditionalQueryItems() { - if let url = URL(string: "https://duckduckgo.com/?ia=chat&other=param") { + if let url = URL(string: TestURLs.duckDuckGoAdditionalQueryItems) { XCTAssertTrue(url.isDuckAIURL, "The URL should be identified as a DuckDuckGo AI URL even with additional query items.") } else { XCTFail("Failed to create URL from string.")