Skip to content

Commit

Permalink
Improve empty array handling
Browse files Browse the repository at this point in the history
Incorrect code was being generated for a JSON attribute whose value is an empty array.
  • Loading branch information
ijoshsmith committed Jan 5, 2017
1 parent 3a2d030 commit e1d202e
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 12 deletions.
2 changes: 1 addition & 1 deletion json2swift/failable-initializer-translation.swift
Expand Up @@ -67,9 +67,9 @@ fileprivate extension SwiftPrimitiveValueType {
case .anything,
.element,
.elementArray,
.emptyArray,
.nullable,
.valueArray: return .any
case .emptyArray: return .emptyArray
case .number(_, let isFloatingPoint): return isFloatingPoint ? .double : .int
case .date(_, let format): return .date(format: format)
case .url: return .url
Expand Down
25 changes: 14 additions & 11 deletions json2swift/swift-code-generation.swift
Expand Up @@ -246,6 +246,7 @@ internal extension TransformationFromJSON {
private static func letStatementForPrimitiveValue(_ attributeName: String, _ propertyName: String, _ type: SwiftPrimitiveValueType) -> LineOfCode {
switch type {
case .any: return "let \(propertyName) = json[\"\(attributeName)\"] as? Any"
case .emptyArray: return "let \(propertyName) = json[\"\(attributeName)\"] as? [Any?]"
case .bool, .int, .string: return "let \(propertyName) = json[\"\(attributeName)\"] as? \(type.name)"
case .double: return "let \(propertyName) = Double(json: json, key: \"\(attributeName)\")" // Allows an integer to be interpreted as a double.
case .url: return "let \(propertyName) = URL(json: json, key: \"\(attributeName)\")"
Expand All @@ -267,16 +268,17 @@ internal extension TransformationFromJSON {

private static func letStatementForArrayOfOptionalPrimitiveValues(_ attributeName: String, _ propertyName: String, _ elementType: SwiftPrimitiveValueType) -> LineOfCode {
switch elementType {
case .any, .bool, .int, .string: return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalValueArray() as [\(elementType.name)?] })"
case .date(let format): return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalDateArray(withFormat: \"\(format)\") })"
case .double: return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalDoubleArray() })"
case .url: return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalURLArray() })"
case .any, .bool, .int, .string, .emptyArray: return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalValueArray() as [\(elementType.name)?] })"
case .date(let format): return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalDateArray(withFormat: \"\(format)\") })"
case .double: return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalDoubleArray() })"
case .url: return "let \(propertyName) = (json[\"\(attributeName)\"] as? [Any]).map({ $0.toOptionalURLArray() })"
}
}

private static func letStatementForArrayOfRequiredPrimitiveValues(_ attributeName: String, _ propertyName: String, _ elementType: SwiftPrimitiveValueType) -> LineOfCode {
switch elementType {
case .any: return "let \(propertyName) = json[\"\(attributeName)\"] as? [Any?]" // Any is treated as optional.
case .emptyArray: return "let \(propertyName) = json[\"\(attributeName)\"] as? [[Any?]]"
case .bool, .int, .string: return "let \(propertyName) = json[\"\(attributeName)\"] as? [\(elementType.name)]"
case .date(let format): return "let \(propertyName) = (json[\"\(attributeName)\"] as? [String]).flatMap({ $0.toDateArray(withFormat: \"\(format)\") })"
case .double: return "let \(propertyName) = (json[\"\(attributeName)\"] as? [NSNumber]).map({ $0.toDoubleArray() })"
Expand All @@ -288,13 +290,14 @@ internal extension TransformationFromJSON {
fileprivate extension SwiftPrimitiveValueType {
var name: String {
switch self {
case .any: return "Any"
case .bool: return "Bool"
case .date: return "Date"
case .double: return "Double"
case .int: return "Int"
case .string: return "String"
case .url: return "URL"
case .any: return "Any"
case .bool: return "Bool"
case .date: return "Date"
case .double: return "Double"
case .emptyArray: return "[Any?]"
case .int: return "Int"
case .string: return "String"
case .url: return "URL"
}
}
}
1 change: 1 addition & 0 deletions json2swift/swift-data-model.swift
Expand Up @@ -55,4 +55,5 @@ enum SwiftPrimitiveValueType {
case string
case bool
case any
case emptyArray
}
10 changes: 10 additions & 0 deletions unit_tests/swift-code-generation-primitive-array-tests.swift
Expand Up @@ -32,6 +32,11 @@ class swift_code_generation_primitive_array_tests: XCTestCase {
XCTAssertEqual(transformation.letStatement, "let p = (json[\"a\"] as? [NSNumber]).map({ $0.toDoubleArray() })")
}

func test_array_of_required_emptyArray() {
let transformation = TransformationFromJSON.toPrimitiveValueArray(attributeName: "a", propertyName: "p", elementType: .emptyArray, hasOptionalElements: false)
XCTAssertEqual(transformation.letStatement, "let p = json[\"a\"] as? [[Any?]]")
}

func test_array_of_required_int() {
let transformation = TransformationFromJSON.toPrimitiveValueArray(attributeName: "a", propertyName: "p", elementType: .int, hasOptionalElements: false)
XCTAssertEqual(transformation.letStatement, "let p = json[\"a\"] as? [Int]")
Expand Down Expand Up @@ -69,6 +74,11 @@ class swift_code_generation_primitive_array_tests: XCTestCase {
XCTAssertEqual(transformation.letStatement, "let p = (json[\"a\"] as? [Any]).map({ $0.toOptionalDoubleArray() })")
}

func test_array_of_optional_emptyArray() {
let transformation = TransformationFromJSON.toPrimitiveValueArray(attributeName: "a", propertyName: "p", elementType: .emptyArray, hasOptionalElements: true)
XCTAssertEqual(transformation.letStatement, "let p = (json[\"a\"] as? [Any]).map({ $0.toOptionalValueArray() as [[Any?]?] })")
}

func test_array_of_optional_int() {
let transformation = TransformationFromJSON.toPrimitiveValueArray(attributeName: "a", propertyName: "p", elementType: .int, hasOptionalElements: true)
XCTAssertEqual(transformation.letStatement, "let p = (json[\"a\"] as? [Any]).map({ $0.toOptionalValueArray() as [Int?] })")
Expand Down
5 changes: 5 additions & 0 deletions unit_tests/swift-code-generation-primitive-value-tests.swift
Expand Up @@ -14,6 +14,11 @@ class swift_code_generation_primitive_value_tests: XCTestCase {
XCTAssertEqual(transformation.letStatement, "let p = json[\"a\"] as? Any")
}

func test_emptyArray() {
let transformation = TransformationFromJSON.toPrimitiveValue(attributeName: "a", propertyName: "p", type: .emptyArray)
XCTAssertEqual(transformation.letStatement, "let p = json[\"a\"] as? [Any?]")
}

func test_bool() {
let transformation = TransformationFromJSON.toPrimitiveValue(attributeName: "a", propertyName: "p", type: .bool)
XCTAssertEqual(transformation.letStatement, "let p = json[\"a\"] as? Bool")
Expand Down

0 comments on commit e1d202e

Please sign in to comment.