Skip to content

Commit

Permalink
fix(cts): all tests green
Browse files Browse the repository at this point in the history
  • Loading branch information
Fluf22 committed Jan 29, 2024
1 parent 7f27498 commit 2230ecb
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

public protocol Credentials {
/// ApplicationID to target. Is passed as a HTTP header.
var applicationID: String { get }
var appId: String { get }

/**
* APIKey for a given ApplicationID. Is passed as a HTTP header.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public enum AlgoliaError: Error, LocalizedError {
case noReachableHosts(intermediateErrors: [Error])
case missingData
case decodingFailure(Error)
case runtimeError(String)
case invalidCredentials(String)
case invalidArgument(String, String)

public var errorDescription: String? {
switch self {
Expand All @@ -27,6 +30,12 @@ public enum AlgoliaError: Error, LocalizedError {
return "Missing response data"
case .decodingFailure:
return "Response decoding failed"
case let .runtimeError(error):
return "\(error)"
case let .invalidCredentials(credential):
return "`\(credential)` is missing."
case let .invalidArgument(argument, operationId):
return "Parameter `\(argument)` is required when calling `\(operationId)`."
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public enum UserAgentController {
}

public internal(set) static var extensions: [UserAgentExtending] = [
UserAgent.operatingSystem, UserAgent.library,
UserAgent.library, UserAgent.operatingSystem,
]

public static var httpHeaderValue: String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
}
paramsType.enhanceParameters(step.parameters, stepOut, ope);

// Swift is strongly-typed and compiled language,
// it can't have nil object when something is expected
if (language.equals("swift")) {
@SuppressWarnings("unchecked")
var isNotTestable =
step.type != null &&
step.type.equals("method") &&
((List<Map<String, Object>>) stepOut.getOrDefault("parametersWithDataType", new ArrayList<>())).stream()
.anyMatch(item -> (boolean) item.getOrDefault("isNullObject", false));
if (isNotTestable) {
continue;
}
}

if (step.expected.type != null) {
switch (step.expected.type) {
case "userAgent":
Expand Down
2 changes: 1 addition & 1 deletion playground/swift/playground/playground/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Task {
.init(firstname: "Warren", lastname: "Speach", followers: 42, company: "Norwalk Crmc")
]

let client = SearchClient(applicationID: applicationID, apiKey: apiKey)
let client = SearchClient(appId: applicationID, apiKey: apiKey)

for contact in contacts {
let saveObjRes = try await client.saveObject(indexName: "contacts", body: contact)
Expand Down
21 changes: 17 additions & 4 deletions templates/swift/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ typealias Client = {{classname}}
private var configuration: Configuration
private var transporter: Transporter
var applicationID: String {
self.configuration.applicationID
var appId: String {
self.configuration.appId
}

public init(configuration: Configuration, transporter: Transporter) {
Expand All @@ -28,8 +28,8 @@ typealias Client = {{classname}}
self.init(configuration: configuration, transporter: Transporter(configuration: configuration))
}

public convenience init(applicationID: String, apiKey: String{{#hasRegionalHost}}, region: Region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}{{/hasRegionalHost}}) throws {
self.init(configuration: try Configuration(applicationID: applicationID, apiKey: apiKey{{#hasRegionalHost}}, region: region{{/hasRegionalHost}}))
public convenience init(appId: String, apiKey: String{{#hasRegionalHost}}, region: Region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}{{/hasRegionalHost}}) throws {
self.init(configuration: try Configuration(appId: appId, apiKey: apiKey{{#hasRegionalHost}}, region: region{{/hasRegionalHost}}))
}

{{#operation}}
Expand Down Expand Up @@ -105,6 +105,19 @@ typealias Client = {{classname}}
{{/isDeprecated}}
{{^returnType}}@discardableResult{{/returnType}}
{{#vendorExtensions}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func {{operationId}}WithHTTPInfo({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{#lambda.to-codable}}{{{dataType}}}{{/lambda.to-codable}}{{/isEnum}}{{^required}}? = nil{{/required}}, {{/allParams}}requestOptions userRequestOptions: RequestOptions? = nil) async throws -> Response<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}AnyCodable{{/returnType}}> {
{{#pathParams}}{{#isString}}{{#required}}guard !{{{paramName}}}.isEmpty else {
throw AlgoliaError.invalidArgument("{{{paramName}}}", "{{{operationId}}}")
}

{{/required}}{{/isString}}{{/pathParams}}{{#queryParams}}{{#isString}}{{#required}}guard !{{{paramName}}}.isEmpty else {
throw AlgoliaError.invalidArgument("{{{paramName}}}", "{{{operationId}}}")
}

{{/required}}{{/isString}}{{/queryParams}}{{#bodyParam}}{{#isFreeFormObject}}{{#required}}guard !{{{paramName}}}.isEmpty else {
throw AlgoliaError.invalidArgument("{{{paramName}}}", "{{{operationId}}}")
}

{{/required}}{{/isFreeFormObject}}{{/bodyParam}}
{{^pathParams}}let{{/pathParams}}{{#pathParams}}{{#-first}}var{{/-first}}{{/pathParams}} resourcePath = "{{{path}}}"{{#pathParams}}
let {{paramName}}PreEscape = "\({{#isEnum}}{{paramName}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}.rawValue{{/isContainer}}{{/isEnum}}{{^isEnum}}APIHelper.mapValueToPathItem({{paramName}}){{/isEnum}})"
let {{paramName}}PostEscape = {{paramName}}PreEscape.addingPercentEncoding(withAllowedCharacters: .{{#x-is-custom-request}}urlPathAllowed{{/x-is-custom-request}}{{^x-is-custom-request}}urlPathAlgoliaAllowed{{/x-is-custom-request}}) ?? ""
Expand Down
41 changes: 30 additions & 11 deletions templates/swift/client_configuration.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Core
import AnyCodable
#endif

typealias {{#lambda.client-to-name}}{{{client}}}{{/lambda.client-to-name}}ClientConfiguration = Configuration

public struct Configuration: Core.Configuration, Credentials {
{{#hasRegionalHost}}

Expand All @@ -14,7 +16,7 @@ public struct Configuration: Core.Configuration, Credentials {
]
{{/hasRegionalHost}}

public let applicationID: String
public let appId: String
public let apiKey: String
public var writeTimeout: TimeInterval
public var readTimeout: TimeInterval
Expand All @@ -24,33 +26,41 @@ public struct Configuration: Core.Configuration, Credentials {

public let batchSize: Int{{/isSearchClient}}

init(applicationID: String,
init(appId: String,
apiKey: String,{{#hasRegionalHost}}
region: Region{{#fallbackToAliasHost}}? = nil{{/fallbackToAliasHost}},{{/hasRegionalHost}}
writeTimeout: TimeInterval = DefaultConfiguration.default.writeTimeout,
readTimeout: TimeInterval = DefaultConfiguration.default.readTimeout,
logLevel: LogLevel = DefaultConfiguration.default.logLevel,
defaultHeaders: [String: String]? = DefaultConfiguration.default.defaultHeaders{{#isSearchClient}},
batchSize: Int = 1000{{/isSearchClient}}) throws {
self.applicationID = applicationID
guard !appId.isEmpty else {
throw AlgoliaError.invalidCredentials("appId")
}

guard !apiKey.isEmpty else {
throw AlgoliaError.invalidCredentials("apiKey")
}

self.appId = appId
self.apiKey = apiKey
self.writeTimeout = writeTimeout
self.readTimeout = readTimeout
self.logLevel = logLevel
self.defaultHeaders = [
"X-Algolia-Application-Id": applicationID,
"X-Algolia-Application-Id": appId,
"X-Algolia-API-Key": apiKey,
"Content-Type": "application/json"
].merging(defaultHeaders ?? [:]) { (_, new) in new }{{#isSearchClient}}

self.batchSize = batchSize{{/isSearchClient}}

{{^hasRegionalHost}}
{{^uniqueHost}}{{^hasRegionalHost}}
func buildHost(_ components: (suffix: String, callType: RetryableHost.CallTypeSupport)) throws
-> RetryableHost
{
guard let url = URL(string: "https://\(applicationID)\(components.suffix)") else {
throw GenericError(description: "Malformed URL")
guard let url = URL(string: "https://\(appId)\(components.suffix)") else {
throw AlgoliaError.runtimeError("Malformed URL")
}

return RetryableHost(url: url, callType: components.callType)
Expand All @@ -68,10 +78,19 @@ public struct Configuration: Core.Configuration, Credentials {
].map(buildHost).shuffled()

self.hosts = hosts + commonHosts
{{/hasRegionalHost}}
{{/hasRegionalHost}}{{/uniqueHost}}
{{#uniqueHost}}
guard let url = URL(string: "https://{{{.}}}") else {
throw AlgoliaError.runtimeError("Malformed URL")
}

self.hosts = [
.init(url: url)
]
{{/uniqueHost}}
{{#hasRegionalHost}}
guard {{#fallbackToAliasHost}}region == nil || {{/fallbackToAliasHost}}authorizedRegions.contains(region{{#fallbackToAliasHost}}!{{/fallbackToAliasHost}}) else {
throw GenericError(description:
throw AlgoliaError.runtimeError(
"`region` {{^fallbackToAliasHost}}is required and {{/fallbackToAliasHost}}must be one of the following: \(authorizedRegions.map { $0.rawValue }.joined(separator: ", "))"
)
}
Expand All @@ -80,7 +99,7 @@ public struct Configuration: Core.Configuration, Credentials {
if let region = region {
{{/fallbackToAliasHost}}
guard let url = URL(string: "https://{{{regionalHost}}}".replacingOccurrences(of: "{region}", with: region.rawValue)) else {
throw GenericError(description: "Malformed URL")
throw AlgoliaError.runtimeError("Malformed URL")
}

self.hosts = [
Expand All @@ -89,7 +108,7 @@ public struct Configuration: Core.Configuration, Credentials {
{{#fallbackToAliasHost}}
} else {
guard let url = URL(string: "https://{{{hostWithFallback}}}") else {
throw GenericError(description: "Malformed URL")
throw AlgoliaError.runtimeError("Malformed URL")
}

self.hosts = [
Expand Down
4 changes: 3 additions & 1 deletion templates/swift/tests/client/createClient.mustache
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{{^autoCreateClient}}let client = {{/autoCreateClient}}try {{client}}(applicationID: "{{parametersWithDataTypeMap.appId.value}}", apiKey: "{{parametersWithDataTypeMap.apiKey.value}}"{{#hasRegionalHost}}, region: {{#parametersWithDataTypeMap.region}}Region(rawValue: "{{parametersWithDataTypeMap.region.value}}"){{/parametersWithDataTypeMap.region}}{{^parametersWithDataTypeMap.region}}nil{{/parametersWithDataTypeMap.region}}{{/hasRegionalHost}})
let configuration: {{import}}.Configuration = try {{import}}.Configuration(appId: "{{parametersWithDataTypeMap.appId.value}}", apiKey: "{{parametersWithDataTypeMap.apiKey.value}}"{{#hasRegionalHost}}, region: {{#parametersWithDataTypeMap.region}}Region(rawValue: "{{parametersWithDataTypeMap.region.value}}"){{/parametersWithDataTypeMap.region}}{{^parametersWithDataTypeMap.region}}nil{{/parametersWithDataTypeMap.region}}{{/hasRegionalHost}})
let transporter: Transporter = Transporter(configuration: configuration, requestBuilder: EchoRequestBuilder())
{{^autoCreateClient}}let client = {{/autoCreateClient}}{{client}}(configuration: configuration, transporter: transporter)
4 changes: 3 additions & 1 deletion templates/swift/tests/client/method.mustache
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
let response = try await client{{#path}}.{{.}}WithHTTPInfo{{/path}}({{#parametersWithDataType}}{{> tests/generateParams }}{{^-last}}, {{/-last}}{{/parametersWithDataType}})
let response = try await client{{#path}}.{{.}}WithHTTPInfo{{/path}}(
{{#parametersWithDataType}}{{> tests/generateParams }}{{^-last}},{{/-last}}
{{/parametersWithDataType}})
let responseBodyData = try XCTUnwrap(response.bodyData)
let echoResponse = try CodableHelper.jsonDecoder.decode(EchoResponse.self, from: responseBodyData)
14 changes: 6 additions & 8 deletions templates/swift/tests/client/suite.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import Utils

final class {{client}}ClientTests: XCTestCase {
let APPLICATION_ID = ""
let API_KEY = ""
let APPLICATION_ID = "my_application_id"
let API_KEY = "my_api_key"
{{#blocksClient}}
{{#tests}}

Expand All @@ -20,9 +20,8 @@ final class {{client}}ClientTests: XCTestCase {
*/
func test{{#lambda.titlecase}}{{testType}}{{/lambda.titlecase}}Test{{testIndex}}() async throws {
{{#autoCreateClient}}
let statusCode: HTTPStatusСode = 200
let configuration: {{import}}.Configuration = try {{import}}.Configuration(applicationID: APPLICATION_ID, apiKey: API_KEY{{#hasRegionalHost}}, region: Region.{{defaultRegion}}{{/hasRegionalHost}})
let transporter: Transporter = Transporter(configuration: configuration, requestBuilder: EchoRequestBuilder(statusCode: statusCode))
let configuration: {{import}}.Configuration = try {{import}}.Configuration(appId: APPLICATION_ID, apiKey: API_KEY{{#hasRegionalHost}}, region: Region.{{defaultRegion}}{{/hasRegionalHost}})
let transporter: Transporter = Transporter(configuration: configuration, requestBuilder: EchoRequestBuilder())
let client: {{client}} = {{client}}(configuration: configuration, transporter: transporter)
{{/autoCreateClient}}

Expand All @@ -31,7 +30,6 @@ final class {{client}}ClientTests: XCTestCase {
do {
{{#dynamicTemplate}}{{/dynamicTemplate}}

_ = client
XCTFail("Expected an error to be thrown")
} catch {
XCTAssertEqual(error.localizedDescription, "{{{expectedError}}}")
Expand All @@ -44,7 +42,7 @@ final class {{client}}ClientTests: XCTestCase {

let pattern = "{{#lambda.escapeSlash}}{{{match}}}{{/lambda.escapeSlash}}"
let rule = StringRule(pattern: pattern)
let userAgent = try XCTUnwrap(echoResponse.headers?["user-agent"])
let userAgent = try XCTUnwrap(echoResponse.headers?["User-Agent"])
guard let userAgent = userAgent else {
XCTFail("Expected user-agent header")
return
Expand All @@ -58,7 +56,7 @@ final class {{client}}ClientTests: XCTestCase {
XCTAssertEqual(TimeInterval({{{match.parametersWithDataTypeMap.responseTimeout.value}}} / 1000), echoResponse.timeout);
{{/testTimeouts}}
{{#testHost}}
XCTAssertEqual("{{{match}}}", echoResponse.url);
XCTAssertEqual("{{{match}}}", echoResponse.host);
{{/testHost}}
{{/match}}
{{/isError}}
Expand Down
2 changes: 1 addition & 1 deletion templates/swift/tests/paramValue.mustache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{{#isObject}}{{objectName}}({{^hasAdditionalProperties}}{{#value}}{{> tests/generateParams}}{{^-last}}, {{/-last}}{{/value}}{{/hasAdditionalProperties}}{{#hasAdditionalProperties}}from: [{{#value}}"{{key}}": {{> tests/paramValue }}{{^-last}}, {{/-last}}{{/value}}]{{/hasAdditionalProperties}}){{/isObject}}{{#isString}}{{#isAnyType}}AnyCodable({{/isAnyType}}"{{{value}}}"{{#isAnyType}}){{/isAnyType}}{{/isString}}{{#isNumber}}{{#isLong}}Int64({{/isLong}}{{{value}}}{{#isLong}}){{/isLong}}{{/isNumber}}{{#isBoolean}}{{{value}}}{{/isBoolean}}{{#isEnum}}{{objectName}}.{{#lambda.swiftIdentifier}}{{#lambda.camelcase}}{{valueEscaped}}{{/lambda.camelcase}}{{/lambda.swiftIdentifier}}{{/isEnum}}{{#isArray}}[{{#value}}{{> tests/generateParams}}{{^-last}}, {{/-last}}{{/value}}]{{/isArray}}{{#isMap}}Map[{{{.}}}]{{/isMap}}{{#isFreeFormObject}}{{#isAnyType}}[{{#value}}{{#entrySet}}"{{key}}": "{{{value}}}"{{/entrySet}}{{/value}}]{{/isAnyType}}{{^isAnyType}}[{{#value}}{{>tests/generateParams}}{{^-last}}, {{/-last}}{{/value}}]{{/isAnyType}}{{/isFreeFormObject}}{{#isNull}}""{{/isNull}}
{{#isObject}}{{objectName}}({{^hasAdditionalProperties}}{{#value}}{{> tests/generateParams}}{{^-last}}, {{/-last}}{{/value}}{{/hasAdditionalProperties}}{{#hasAdditionalProperties}}from: [{{#value}}"{{key}}": {{> tests/paramValue }}{{^-last}}, {{/-last}}{{/value}}]{{/hasAdditionalProperties}}){{/isObject}}{{#isString}}{{#isAnyType}}AnyCodable({{/isAnyType}}"{{{value}}}"{{#isAnyType}}){{/isAnyType}}{{/isString}}{{#isNumber}}{{#isLong}}Int64({{/isLong}}{{{value}}}{{#isLong}}){{/isLong}}{{/isNumber}}{{#isBoolean}}{{{value}}}{{/isBoolean}}{{#isEnum}}{{objectName}}.{{#lambda.swiftIdentifier}}{{#lambda.camelcase}}{{valueEscaped}}{{/lambda.camelcase}}{{/lambda.swiftIdentifier}}{{/isEnum}}{{#isArray}}[{{#value}}{{> tests/generateParams}}{{^-last}}, {{/-last}}{{/value}}]{{/isArray}}{{#isMap}}Map[{{{.}}}]{{/isMap}}{{#isFreeFormObject}}{{#isAnyType}}[{{#value}}{{#entrySet}}"{{key}}": "{{{value}}}"{{/entrySet}}{{/value}}]{{/isAnyType}}{{^isAnyType}}[{{^value}}:{{/value}}{{#value}}{{>tests/generateParams}}{{^-last}}, {{/-last}}{{/value}}]{{/isAnyType}}{{/isFreeFormObject}}{{#isNull}}{{#inClientTest}}{{{objectName}}}(){{/inClientTest}}{{/isNull}}
8 changes: 3 additions & 5 deletions templates/swift/tests/requests/requests.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,16 @@ import Utils

final class {{client}}RequestsTests: XCTestCase {
typealias StringMapObject = [String: String?]
let APPLICATION_ID = ""
let API_KEY = ""
let APPLICATION_ID = "my_application_id"
let API_KEY = "my_api_key"
{{#blocksRequests}}
{{#tests}}
/**
{{testName}}
*/
func test{{#lambda.titlecase}}{{method}}{{/lambda.titlecase}}Test{{testIndex}}() async throws {
let configuration: {{import}}.Configuration = try {{import}}.Configuration(applicationID: APPLICATION_ID, apiKey: API_KEY{{#hasRegionalHost}}, region: Region.{{defaultRegion}}{{/hasRegionalHost}})
let configuration: {{import}}.Configuration = try {{import}}.Configuration(appId: APPLICATION_ID, apiKey: API_KEY{{#hasRegionalHost}}, region: Region.{{defaultRegion}}{{/hasRegionalHost}})
let transporter: Transporter = Transporter(configuration: configuration, requestBuilder: EchoRequestBuilder())
let client: {{client}} = {{client}}(configuration: configuration, transporter: transporter)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
//
// Data.swift
// Utils.swift
//
//
// Created by Algolia on 26/01/2024.
//

import Foundation
#if canImport(AnyCodable)
import AnyCodable
#endif

#if canImport(AnyCodable)
public typealias Object = [String: AnyCodable]
#else
public typealias Object = [String: Any]
#endif

public typealias StringMapObject = [String: String?]

public extension Data {
var jsonString: String? {
Expand Down

0 comments on commit 2230ecb

Please # to comment.