import Foundation import Testing @testable import ConjureKit @Test func myMemoryTranslatesWithoutCredentialsAndEncodesInput() async throws { let translation = try await MyMemoryAPI.translate("Hello & goodbye?") { request in let items = URLComponents(url: request.url!, resolvingAgainstBaseURL: false)!.queryItems! #expect(items.contains(URLQueryItem(name: "q", value: "Hello & goodbye?"))) #expect(items.contains(URLQueryItem(name: "langpair", value: "en|ja"))) #expect(request.value(forHTTPHeaderField: "Authorization") == nil) return (Data(#"{"responseStatus":200,"quotaFinished":false,"responseData":{"translatedText":"こんにちは"}}"#.utf8), HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!) } #expect(translation == "こんにちは") await #expect(throws: (any Error).self) { try await MyMemoryAPI.translate(String(repeating: "あ", count: 167)) { _ in Issue.record("Oversized UTF-8 input must not reach the network") throw URLError(.badURL) } } for body in [#"{"responseStatus":200,"quotaFinished":true,"responseData":{"translatedText":"QUOTA EXCEEDED"}}"#, #"{"responseStatus":403,"responseData":{"translatedText":"ERROR"}}"#, #"{"responseStatus":200,"responseData":{"translatedText":""}}"#] { await #expect(throws: (any Error).self) { try await MyMemoryAPI.translate("Hello") { request in (Data(body.utf8), HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!) } } } } @Test func myMemoryUsesNonblankExactMatchWhenPrimaryTranslationIsEmpty() async throws { // MyMemory's live response for "hello" has a blank top translation and a valid exact match. let body = #"{"responseStatus":200,"quotaFinished":false,"responseData":{"translatedText":""},"matches":[{"segment":"hello","translation":"","source":"en-GB","target":"ja-JP"},{"segment":"hello there","translation":"近似","source":"en","target":"ja"},{"segment":"hello","translation":"bonjour","source":"en","target":"fr"},{"segment":"hello","translation":"こんにちは","source":"en-GB","target":"ja-JP"}]}"# let translation = try await MyMemoryAPI.translate("hello") { request in (Data(body.utf8), HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!) } #expect(translation == "こんにちは") } @Test func myMemoryRequestsReversePairAndOnlyUsesMatchingFallback() async throws { let body = #"{"responseStatus":200,"responseData":{"translatedText":""},"matches":[{"segment":"おはよう","translation":"間違い","source":"en","target":"ja"},{"segment":"おはよう","translation":"bonjour","source":"ja","target":"fr"},{"segment":"おはようございます","translation":"Good morning!","source":"ja","target":"en"},{"segment":"おはよう","translation":"Good morning","source":"ja-JP","target":"en-GB"}]}"# let translation = try await MyMemoryAPI.translate( "おはよう", sourceLanguage: "ja", targetLanguage: "en" ) { request in let items = try #require(URLComponents(url: request.url!, resolvingAgainstBaseURL: false)?.queryItems) #expect(items.contains(URLQueryItem(name: "q", value: "おはよう"))) #expect(items.contains(URLQueryItem(name: "langpair", value: "ja|en"))) return (Data(body.utf8), HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!) } #expect(translation == "Good morning") } @Test func myMemoryNeverUsesMatchesToBypassFailureOrReplacePrimaryTranslation() async throws { let matches = #""matches":[{"segment":"hello","translation":"こんにちは","source":"en","target":"ja"}]"# for metadata in [#""responseStatus":403"#, #""responseStatus":200,"quotaFinished":true"#] { await #expect(throws: (any Error).self) { try await MyMemoryAPI.translate("hello") { request in (Data("{\(metadata),\(matches)}".utf8), HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!) } } } let primary = try await MyMemoryAPI.translate("hello") { request in (Data("{\"responseStatus\":200,\"responseData\":{\"translatedText\":\"どうも\"},\(matches)}".utf8), HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!) } #expect(primary == "どうも") await #expect(throws: (any Error).self) { try await MyMemoryAPI.translate("unrelated") { request in (Data("{\"responseStatus\":200,\(matches)}".utf8), HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!) } } }