Skip to content
This repository has been archived by the owner on Sep 19, 2018. It is now read-only.

Commit

Permalink
Resolves merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
mdmathias committed Sep 16, 2016
2 parents ec8cce8 + dba5e3e commit bd9fee9
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 18 deletions.
3 changes: 3 additions & 0 deletions Sources/JSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ extension JSON {

/// Unexpected JSON `value` was found that is not convertible `to` type
case valueNotConvertible(value: JSON, to: Any.Type)

/// The JSON is not serializable to a `String`.
case stringSerializationError
}

}
Expand Down
19 changes: 13 additions & 6 deletions Sources/JSONParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,11 @@ public struct JSONParser {
return try decodeNumberAsString(from: start)
}
}

throw Error.valueInvalid(offset: loc, character: UnicodeScalar(input[loc]))
if loc < input.count {
throw Error.valueInvalid(offset: loc, character: UnicodeScalar(input[loc]))
} else {
throw Error.endOfStreamUnexpected
}
}

private mutating func skipWhitespace() {
Expand Down Expand Up @@ -652,12 +655,16 @@ private struct NumberParser {
return
}

guard input[loc] == Literal.PERIOD else {
switch input[loc] {
case Literal.PERIOD:
state = .decimal

case Literal.e, Literal.E:
state = .exponent

default:
state = .done
return
}

state = .decimal
}

mutating func parsePreDecimalDigits(f: (UInt8) throws -> Void) rethrows {
Expand Down
26 changes: 19 additions & 7 deletions Sources/JSONSerializing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,34 @@ extension JSON {

/// Attempt to serialize `JSON` into an `Data`.
/// - returns: A byte-stream containing the `JSON` ready for wire transfer.
/// - throws: Errors that arise from `NSJSONSerialization`.
/// - see: Foundation.NSJSONSerialization
/// - throws: Errors that arise from `JSONSerialization`.
/// - see: Foundation.JSONSerialization
public func serialize() throws -> Data {
return try JSONSerialization.data(withJSONObject: toNSJSONSerializationValue(), options: [])
return try JSONSerialization.data(withJSONObject: toJSONSerializationValue(), options: [])
}

/// Attempt to serialize `JSON` into a `String`.
/// - returns: A `String` containing the `JSON`.
/// - throws: A `JSON.Error.StringSerializationError` or errors that arise from `JSONSerialization`.
/// - see: Foundation.JSONSerialization
public func serializeString() throws -> String {
let data = try self.serialize()
guard let json = String(data: data, encoding: String.Encoding.utf8) else {
throw Error.stringSerializationError
}
return json
}

/// A function to help with the serialization of `JSON`.
/// - returns: An `Any` suitable for `NSJSONSerialization`'s use.
private func toNSJSONSerializationValue() -> Any {
/// - returns: An `Any` suitable for `JSONSerialization`'s use.
private func toJSONSerializationValue() -> Any {
switch self {
case .array(let jsonArray):
return jsonArray.map { $0.toNSJSONSerializationValue() }
return jsonArray.map { $0.toJSONSerializationValue() }
case .dictionary(let jsonDictionary):
var cocoaDictionary = Swift.Dictionary<Swift.String, Any>(minimumCapacity: jsonDictionary.count)
for (key, json) in jsonDictionary {
cocoaDictionary[key] = json.toNSJSONSerializationValue()
cocoaDictionary[key] = json.toJSONSerializationValue()
}
return cocoaDictionary
case .string(let str):
Expand Down
13 changes: 12 additions & 1 deletion Sources/JSONSubscripting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,17 @@ extension JSON {

extension JSON {

/// Decodes a `JSON` instance if it is not `.Null`, throws otherwise.
/// - parameter json: An instance of `JSON`.
/// - returns: An instance of some type that conforms to `JSONDecodable`.
/// - throws: `Error.ValueNotConvertible` if the `JSON` instance is `.Null`.
private static func getDecoded<Decoded: JSONDecodable>(json: JSON) throws -> Decoded {
guard json != .null else {
throw Error.valueNotConvertible(value: json, to: Decoded.self)
}
return try Decoded.init(json: json)
}

/// Optionally decodes into the returning type from a path into JSON.
/// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
/// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
Expand All @@ -288,7 +299,7 @@ extension JSON {
/// instance does not match the decoded value.
/// * Any error that arises from decoding the value.
public func decode<Decoded: JSONDecodable>(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? {
return try mapOptional(at: path, alongPath: options, transform: Decoded.init)
return try mapOptional(at: path, alongPath: options, transform: JSON.getDecoded)
}

/// Optionally retrieves a `Double` from a path into JSON.
Expand Down
28 changes: 26 additions & 2 deletions Tests/JSONParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,33 @@ class JSONParserTests: XCTestCase {
XCTAssertEqual(value, JSON.string(expect))
}

func testThatParserFailsWhenIncompleteDataIsPresent() {
for s in [" ", "[0,", "{\"\":"] {
do {
let value = try JSONParser.parse(" ")
XCTFail("Unexpectedly parsed \(s) as \(value)")
} catch JSONParser.Error.endOfStreamUnexpected {
// expected error - do nothing
} catch {
XCTFail("Unexpected error \(error)")
}
}
}

func testThatParserUnderstandsNumbers() {
for (string, shouldBeInt) in [
(" 0 ", 0),
("123", 123),
(" -20 ", -20),
("-0", 0),
("0e0", 0),
("0e1", 0),
("0e1", 0),
("-0e20", 0),
("0.1e1", 1),
("0.1E1", 1),
("0e01", 0),
("0.1e0001", 1),
] {
do {
let value = try JSONParser.parse(string).getInt()
Expand All @@ -172,6 +194,8 @@ class JSONParserTests: XCTestCase {
("123.45E2", 123.45E2),
("123.45e+2", 123.45e+2),
("-123.45e-2", -123.45e-2),
("0.1e-1", 0.01),
("-0.1E-1", -0.01),
] {
do {
let value = try JSONParser.parse(string).getDouble()
Expand All @@ -192,10 +216,10 @@ class JSONParserTests: XCTestCase {
("1.0e", JSONParser.Error.endOfStreamUnexpected),
("1.0e+", JSONParser.Error.endOfStreamUnexpected),
("1.0e-", JSONParser.Error.endOfStreamUnexpected),
("0e1", JSONParser.Error.endOfStreamGarbage(offset: 1)),
] {
do {
_ = try JSONParser.parse(string)
let value = try JSONParser.parse(string)
XCTFail("Unexpectedly parsed \(string) as \(value)")
} catch let error as JSONParser.Error {
XCTAssert(error == expectedError)
} catch {
Expand Down
34 changes: 32 additions & 2 deletions Tests/JSONSerializingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,41 @@ class JSONSerializingTests: XCTestCase {
let json = JSONFromFixture("sample.JSON")
let noWhiteSpaceData = dataFromFixture("sampleNoWhiteSpace.JSON")

func testThatJSONCanBeSerialized() {
func testThatJSONCanBeSerializedToNSData() {
let data = try! json.serialize()
XCTAssertGreaterThan(data.count, 0, "There should be data.")
}

func testThatJSONCanBeSerializedToString() {
let string = try! json.serializeString()
XCTAssertGreaterThan(string.characters.count, 0, "There should be characters.")
}

func testThatJSONDataIsEqual() {
let serializedJSONData = try! json.serialize()
let noWhiteSpaceJSON = try! JSON(data: noWhiteSpaceData)
let noWhiteSpaceSerializedJSONData = try! noWhiteSpaceJSON.serialize()
XCTAssertEqual(serializedJSONData, noWhiteSpaceSerializedJSONData, "Serialized data should be equal.")
}

func testThatJSONStringIsEqual() {
let serializedJSONString = try! json.serializeString()
let noWhiteSpaceJSON = try! JSON(data: noWhiteSpaceData)
let noWhiteSpaceSerializedJSONString = try! noWhiteSpaceJSON.serializeString()
XCTAssertEqual(serializedJSONString, noWhiteSpaceSerializedJSONString, "Serialized string should be equal.")
}

func testThatJSONSerializationMakesEqualJSON() {
func testThatJSONDataSerializationMakesEqualJSON() {
let serializedJSONData = try! json.serialize()
let serialJSON = try! JSON(data: serializedJSONData)
XCTAssert(json == serialJSON, "The JSON values should be equal.")
}

func testThatJSONStringSerializationMakesEqualJSON() {
let serializedJSONString = try! json.serializeString()
let serialJSON = try! JSON(jsonString: serializedJSONString)
XCTAssert(json == serialJSON, "The JSON values should be equal.")
}

func testThatJSONSerializationHandlesBoolsCorrectly() {
let json = JSON.dictionary([
Expand All @@ -36,6 +54,18 @@ class JSONSerializingTests: XCTestCase {
let deserialized = JSON.dictionary(deserializedResult)
XCTAssertEqual(json, deserialized, "Serialize/Deserialize succeed with Bools")
}

func testThatJSONStringSerializationHandlesBoolsCorrectly() {
let json = JSON.dictionary([
"foo": .bool(true),
"bar": .bool(false),
"baz": .int(123),
])
let string = try! json.serializeString()
let deserializedResult = try! JSON(jsonString: string).getDictionary()
let deserialized = JSON.dictionary(deserializedResult)
XCTAssertEqual(json, deserialized, "Serialize/Deserialize succeed with Bools")
}
}


Expand Down
22 changes: 22 additions & 0 deletions Tests/JSONSubscriptingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ class JSONSubscriptingTests: XCTestCase {
}
}

func testDecodeNullBecomesNilProducesOptional() {
let json: JSON = ["type": "Apartment", "resident": .null]
do {
let apartment = try json.decode(alongPath: .NullBecomesNil, type: Apartment.self)
XCTAssertNil(apartment?.resident, "This resident should be nil!")
} catch {
XCTFail("There should be no error: \(error)")
}
}

func testJSONDictionaryUnexpectedSubscript() {
do {
_ = try residentJSON.decode(at: 1, type: Resident.self)
Expand Down Expand Up @@ -429,6 +439,18 @@ extension Resident: JSONDecodable {
}
}

private struct Apartment {
let type: String
let resident: Resident?
}

extension Apartment: JSONDecodable {
fileprivate init(json: JSON) throws {
type = try json.getString(at: "type")
resident = try json.decode(at: "resident", alongPath: .NullBecomesNil, type: Resident.self)
}
}

extension Resident: Equatable {}

private func ==(lhs: Resident, rhs: Resident) -> Bool {
Expand Down

0 comments on commit bd9fee9

Please sign in to comment.