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

[Swift4] bug fix for date encoding Issues #1442

Merged
merged 1 commit into from
Nov 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ open class CodableHelper {
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
formatter.dateFormat = Configuration.dateFormat
decoder.dateDecodingStrategy = .formatted(formatter)
}

Expand Down Expand Up @@ -55,7 +55,7 @@ open class CodableHelper {
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
formatter.dateFormat = Configuration.dateFormat
encoder.dateEncodingStrategy = .formatted(formatter)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,16 @@ extension Data: JSONEncodable {
}

private let dateFormatter: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = Configuration.dateFormat
fmt.locale = Locale(identifier: "en_US_POSIX")
return fmt
if let formatter = CodableHelper.dateformatter {
return formatter
} else {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = Configuration.dateFormat
return formatter
}
}()

extension Date: JSONEncodable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,13 +455,16 @@ open class FakeAPI {
/**
Fake endpoint to test group parameters (optional)

- parameter requiredStringGroup: (query) Required String in group parameters
- parameter requiredBooleanGroup: (header) Required Boolean in group parameters
- parameter requiredInt64Group: (query) Required Integer in group parameters
- parameter stringGroup: (query) String in group parameters (optional)
- parameter booleanGroup: (header) Boolean in group parameters (optional)
- parameter int64Group: (query) Integer in group parameters (optional)
- parameter completion: completion handler to receive the data and the error objects
*/
open class func testGroupParameters(stringGroup: Int? = nil, booleanGroup: Bool? = nil, int64Group: Int64? = nil, completion: @escaping ((_ data: Void?,_ error: Error?) -> Void)) {
testGroupParametersWithRequestBuilder(stringGroup: stringGroup, booleanGroup: booleanGroup, int64Group: int64Group).execute { (response, error) -> Void in
open class func testGroupParameters(requiredStringGroup: Int, requiredBooleanGroup: Bool, requiredInt64Group: Int64, stringGroup: Int? = nil, booleanGroup: Bool? = nil, int64Group: Int64? = nil, completion: @escaping ((_ data: Void?,_ error: Error?) -> Void)) {
testGroupParametersWithRequestBuilder(requiredStringGroup: requiredStringGroup, requiredBooleanGroup: requiredBooleanGroup, requiredInt64Group: requiredInt64Group, stringGroup: stringGroup, booleanGroup: booleanGroup, int64Group: int64Group).execute { (response, error) -> Void in
if error == nil {
completion((), error)
} else {
Expand All @@ -475,22 +478,28 @@ open class FakeAPI {
Fake endpoint to test group parameters (optional)
- DELETE /fake
- Fake endpoint to test group parameters (optional)
- parameter requiredStringGroup: (query) Required String in group parameters
- parameter requiredBooleanGroup: (header) Required Boolean in group parameters
- parameter requiredInt64Group: (query) Required Integer in group parameters
- parameter stringGroup: (query) String in group parameters (optional)
- parameter booleanGroup: (header) Boolean in group parameters (optional)
- parameter int64Group: (query) Integer in group parameters (optional)
- returns: RequestBuilder<Void>
*/
open class func testGroupParametersWithRequestBuilder(stringGroup: Int? = nil, booleanGroup: Bool? = nil, int64Group: Int64? = nil) -> RequestBuilder<Void> {
open class func testGroupParametersWithRequestBuilder(requiredStringGroup: Int, requiredBooleanGroup: Bool, requiredInt64Group: Int64, stringGroup: Int? = nil, booleanGroup: Bool? = nil, int64Group: Int64? = nil) -> RequestBuilder<Void> {
let path = "/fake"
let URLString = PetstoreClientAPI.basePath + path
let parameters: [String:Any]? = nil

var url = URLComponents(string: URLString)
url?.queryItems = APIHelper.mapValuesToQueryItems([
"required_string_group": requiredStringGroup.encodeToJSON(),
"required_int64_group": requiredInt64Group.encodeToJSON(),
"string_group": stringGroup?.encodeToJSON(),
"int64_group": int64Group?.encodeToJSON()
])
let nillableHeaders: [String: Any?] = [
"required_boolean_group": requiredBooleanGroup,
"boolean_group": booleanGroup
]
let headerParameters = APIHelper.rejectNilHeaders(nillableHeaders)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ open class CodableHelper {
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
formatter.dateFormat = Configuration.dateFormat
decoder.dateDecodingStrategy = .formatted(formatter)
}

Expand Down Expand Up @@ -55,7 +55,7 @@ open class CodableHelper {
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
formatter.dateFormat = Configuration.dateFormat
encoder.dateEncodingStrategy = .formatted(formatter)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,16 @@ extension Data: JSONEncodable {
}

private let dateFormatter: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = Configuration.dateFormat
fmt.locale = Locale(identifier: "en_US_POSIX")
return fmt
if let formatter = CodableHelper.dateformatter {
return formatter
} else {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = Configuration.dateFormat
return formatter
}
}()

extension Date: JSONEncodable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
1A501F48219C3DC600F372F6 /* DateFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A501F47219C3DC600F372F6 /* DateFormatTests.swift */; };
54DA06C1D70D78EC0EC72B61 /* Pods_SwaggerClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F65B6638217EDDC99D103B16 /* Pods_SwaggerClientTests.framework */; };
6D4EFB951C692C6300B96B06 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFB941C692C6300B96B06 /* AppDelegate.swift */; };
6D4EFB971C692C6300B96B06 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4EFB961C692C6300B96B06 /* ViewController.swift */; };
Expand All @@ -30,6 +31,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
1A501F47219C3DC600F372F6 /* DateFormatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateFormatTests.swift; sourceTree = "<group>"; };
289E8A9E9C0BB66AD190C7C6 /* Pods-SwaggerClientTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwaggerClientTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests.debug.xcconfig"; sourceTree = "<group>"; };
6D4EFB911C692C6300B96B06 /* SwaggerClient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwaggerClient.app; sourceTree = BUILT_PRODUCTS_DIR; };
6D4EFB941C692C6300B96B06 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -132,6 +134,7 @@
6D4EFBB41C693BE200B96B06 /* PetAPITests.swift */,
6D4EFBB61C693BED00B96B06 /* StoreAPITests.swift */,
6D4EFBB81C693BFC00B96B06 /* UserAPITests.swift */,
1A501F47219C3DC600F372F6 /* DateFormatTests.swift */,
);
path = SwaggerClientTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -360,6 +363,7 @@
files = (
6D4EFBB71C693BED00B96B06 /* StoreAPITests.swift in Sources */,
6D4EFBB91C693BFC00B96B06 /* UserAPITests.swift in Sources */,
1A501F48219C3DC600F372F6 /* DateFormatTests.swift in Sources */,
6D4EFBB51C693BE200B96B06 /* PetAPITests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//
// DateFormatTests.swift
// SwaggerClientTests
//
// Created by James on 14/11/2018.
// Copyright © 2018 Swagger. All rights reserved.
//

import Foundation
import XCTest
@testable import PetstoreClient
@testable import SwaggerClient

class DateFormatTests: XCTestCase {

struct DateTest: Codable {
let date: Date
}

override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}

func testEncodeToJSONAlwaysResultsInUTCEncodedDate() {
var dateComponents = DateComponents()
dateComponents.calendar = Calendar(identifier: .gregorian)
dateComponents.year = 2018
dateComponents.month = 11
dateComponents.day = 14
dateComponents.hour = 11
dateComponents.minute = 35
dateComponents.second = 43
dateComponents.nanosecond = 500

// Testing a date with a timezone of +00:00 (UTC)
dateComponents.timeZone = TimeZone(secondsFromGMT: 0)
XCTAssert(dateComponents.isValidDate)

guard let utcDate = dateComponents.date else {
XCTFail("Couldn't get a valid date")
return
}

var encodedDate = utcDate.encodeToJSON() as! String
XCTAssert(encodedDate.hasSuffix("Z"))

// test with a positive timzone offset from UTC
dateComponents.timeZone = TimeZone(secondsFromGMT: 60 * 60) // +01:00
XCTAssert(dateComponents.isValidDate)

guard let nonUTCDate1 = dateComponents.date else {
XCTFail("Couldn't get a valid date")
return
}

encodedDate = nonUTCDate1.encodeToJSON() as! String
XCTAssert(encodedDate.hasSuffix("Z"))

// test with a negative timzone offset from UTC
dateComponents.timeZone = TimeZone(secondsFromGMT: -(60 * 60)) // -01:00
XCTAssert(dateComponents.isValidDate)

guard let nonUTCDate2 = dateComponents.date else {
XCTFail("Couldn't get a valid date")
return
}

encodedDate = nonUTCDate2.encodeToJSON() as! String
XCTAssert(encodedDate.hasSuffix("Z"))
}

func testCodableAlwaysResultsInUTCEncodedDate() {
let jsonData = "{\"date\":\"1970-01-01T00:00:00.000Z\"}".data(using: .utf8)!
let decodeResult = CodableHelper.decode(DateTest.self, from: jsonData)
XCTAssert(decodeResult.decodableObj != nil && decodeResult.error == nil)

var dateComponents = DateComponents()
dateComponents.calendar = Calendar(identifier: .gregorian)
dateComponents.year = 1970
dateComponents.month = 01
dateComponents.day = 01
dateComponents.hour = 00
dateComponents.minute = 00
dateComponents.second = 00

// Testing a date with a timezone of +00:00 (UTC)
dateComponents.timeZone = TimeZone(secondsFromGMT: 0)
XCTAssert(dateComponents.isValidDate)

guard let date = dateComponents.date else {
XCTFail("Couldn't get a valid date")
return
}

let dateTest = DateTest(date: date)
let encodeResult = CodableHelper.encode(dateTest)
XCTAssert(encodeResult.data != nil && encodeResult.error == nil)
guard let jsonString = String(data: encodeResult.data!, encoding: .utf8) else {
XCTFail("Unable to convert encoded data to string.")
return
}

let exampleJSONString = "{\"date\":\"1970-01-01T00:00:00.000Z\"}"
XCTAssert(jsonString == exampleJSONString, "Encoded JSON String: \(jsonString) should match: \(exampleJSONString)")
}

}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.3.0-SNAPSHOT
3.3.3-SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
import Foundation

open class PetstoreClientAPI {
open static var basePath = "http://petstore.swagger.io:80/v2"
open static var credential: URLCredential?
open static var customHeaders: [String:String] = [:]
open static var requestBuilderFactory: RequestBuilderFactory = AlamofireRequestBuilderFactory()
public static var basePath = "http://petstore.swagger.io:80/v2"
public static var credential: URLCredential?
public static var customHeaders: [String:String] = [:]
public static var requestBuilderFactory: RequestBuilderFactory = AlamofireRequestBuilderFactory()
}

open class RequestBuilder<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,63 @@ open class FakeAPI {
return requestBuilder.init(method: "GET", URLString: (url?.string ?? URLString), parameters: parameters, isBody: false, headers: headerParameters)
}

/**
Fake endpoint to test group parameters (optional)

- parameter requiredStringGroup: (query) Required String in group parameters
- parameter requiredBooleanGroup: (header) Required Boolean in group parameters
- parameter requiredInt64Group: (query) Required Integer in group parameters
- parameter stringGroup: (query) String in group parameters (optional)
- parameter booleanGroup: (header) Boolean in group parameters (optional)
- parameter int64Group: (query) Integer in group parameters (optional)
- parameter completion: completion handler to receive the data and the error objects
*/
open class func testGroupParameters(requiredStringGroup: Int, requiredBooleanGroup: Bool, requiredInt64Group: Int64, stringGroup: Int? = nil, booleanGroup: Bool? = nil, int64Group: Int64? = nil, completion: @escaping ((_ data: Void?,_ error: Error?) -> Void)) {
testGroupParametersWithRequestBuilder(requiredStringGroup: requiredStringGroup, requiredBooleanGroup: requiredBooleanGroup, requiredInt64Group: requiredInt64Group, stringGroup: stringGroup, booleanGroup: booleanGroup, int64Group: int64Group).execute { (response, error) -> Void in
if error == nil {
completion((), error)
} else {
completion(nil, error)
}
}
}


/**
Fake endpoint to test group parameters (optional)
- DELETE /fake
- Fake endpoint to test group parameters (optional)
- parameter requiredStringGroup: (query) Required String in group parameters
- parameter requiredBooleanGroup: (header) Required Boolean in group parameters
- parameter requiredInt64Group: (query) Required Integer in group parameters
- parameter stringGroup: (query) String in group parameters (optional)
- parameter booleanGroup: (header) Boolean in group parameters (optional)
- parameter int64Group: (query) Integer in group parameters (optional)
- returns: RequestBuilder<Void>
*/
open class func testGroupParametersWithRequestBuilder(requiredStringGroup: Int, requiredBooleanGroup: Bool, requiredInt64Group: Int64, stringGroup: Int? = nil, booleanGroup: Bool? = nil, int64Group: Int64? = nil) -> RequestBuilder<Void> {
let path = "/fake"
let URLString = PetstoreClientAPI.basePath + path
let parameters: [String:Any]? = nil

var url = URLComponents(string: URLString)
url?.queryItems = APIHelper.mapValuesToQueryItems([
"required_string_group": requiredStringGroup.encodeToJSON(),
"required_int64_group": requiredInt64Group.encodeToJSON(),
"string_group": stringGroup?.encodeToJSON(),
"int64_group": int64Group?.encodeToJSON()
])
let nillableHeaders: [String: Any?] = [
"required_boolean_group": requiredBooleanGroup,
"boolean_group": booleanGroup
]
let headerParameters = APIHelper.rejectNilHeaders(nillableHeaders)

let requestBuilder: RequestBuilder<Void>.Type = PetstoreClientAPI.requestBuilderFactory.getNonDecodableBuilder()

return requestBuilder.init(method: "DELETE", URLString: (url?.string ?? URLString), parameters: parameters, isBody: false, headers: headerParameters)
}

/**
test inline additionalProperties

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
if stringResponse.result.isFailure {
completion(
nil,
ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.result.error as Error!)
ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.result.error!)
)
return
}
Expand Down Expand Up @@ -356,7 +356,7 @@ open class AlamofireDecodableRequestBuilder<T:Decodable>: AlamofireRequestBuilde
if stringResponse.result.isFailure {
completion(
nil,
ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.result.error as Error!)
ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.result.error!)
)
return
}
Expand Down
Loading