Skip to content

Commit

Permalink
Fix ErrorContextTest and formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxDesiatov committed Dec 30, 2018
1 parent f62d799 commit 5c38aba
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 93 deletions.
4 changes: 4 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
--indentcase false
--trimwhitespace always
--ranges nospace
--empty tuple
--operatorfunc nospace
--ifdef noindent
--stripunusedargs closure-only
73 changes: 40 additions & 33 deletions Sources/XMLCoder/Auxiliaries/XMLStackParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,58 @@ class _XMLStackParser: NSObject {
var root: _XMLElement?
private var stack: [_XMLElement] = []

static func parse(with data: Data) throws -> KeyedBox {
static func parse(with data: Data, errorContextLength length: UInt) throws -> KeyedBox {
let parser = _XMLStackParser()

guard let node = try parser.parse(with: data) else {
throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: [],
debugDescription: "The given data could not be parsed into XML."
))
}
let node = try parser.parse(with: data, errorContextLength: length)

return node.flatten()
}

func parse(with data: Data, errorContextLength) throws -> _XMLElement? {
func parse(with data: Data, errorContextLength: UInt) throws -> _XMLElement {
let xmlParser = XMLParser(data: data)
xmlParser.delegate = self

guard xmlParser.parse() else {
if let error = xmlParser.parserError {
if errorContextLength {
let str = String(data: data, encoding: .utf8) ?? ""
let strArray = str.split(separator: "\n")
var indx = 0
for i in 0...xmlParser.lineNumber{
indx += strArray[i].count
}
let lowerBound = String.Index.init(encodedOffset: indx-errorContextLength)
let upperBound = String.Index.init(encodedOffset: indx+errorContextLength)

throw str[lowerBound..<upperBound]
}

throw error
}
return nil

guard !xmlParser.parse(), root == nil else {
return root!
}

return root
guard let error = xmlParser.parserError else {
throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: [],
debugDescription: "The given data could not be parsed into XML."
))
}

guard errorContextLength > 0 else {
throw error
}

let string = String(data: data, encoding: .utf8) ?? ""
let lines = string.split(separator: "\n")
var errorPosition = 0
let offset = Int(errorContextLength / 2)
for i in 0..<xmlParser.lineNumber - 1 {
errorPosition += lines[i].count
}
errorPosition += xmlParser.columnNumber
let lowerBound = String.Index(encodedOffset: errorPosition - offset)
let upperBound = String.Index(encodedOffset: errorPosition + offset)

let context = string[lowerBound..<upperBound]

throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: [],
debugDescription: """
\(error.localizedDescription) \
at line \(xmlParser.lineNumber), column \(xmlParser.columnNumber):
`\(context)`
""",
underlyingError: error
))
}

func withCurrentElement(_ body: (inout _XMLElement) throws -> Void) rethrows {
func withCurrentElement(_ body: (inout _XMLElement) throws -> ()) rethrows {
guard !stack.isEmpty else {
return
}
Expand Down Expand Up @@ -105,8 +116,4 @@ extension _XMLStackParser: XMLParserDelegate {
currentElement.append(value: string)
}
}

func parser(_: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError)
}
}
2 changes: 1 addition & 1 deletion Sources/XMLCoder/Box/NullBox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extension NullBox: Box {
extension NullBox: SimpleBox {}

extension NullBox: Equatable {
static func == (_: NullBox, _: NullBox) -> Bool {
static func ==(_: NullBox, _: NullBox) -> Bool {
return true
}
}
Expand Down
27 changes: 10 additions & 17 deletions Sources/XMLCoder/Decoder/XMLDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ open class XMLDecoder {

/// Contextual user-provided information for use during decoding.
open var userInfo: [CodingUserInfoKey: Any] = [:]
// The error context lenght
open var errorContextLenght: UInt = 0

// The error context length
open var errorContextLength: UInt = 0

/// Options set on the top-level encoder to pass down the decoding hierarchy.
struct _Options {
Expand All @@ -224,7 +224,6 @@ open class XMLDecoder {
let nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy
let keyDecodingStrategy: KeyDecodingStrategy
let userInfo: [CodingUserInfoKey: Any]
let errorContextLenght: errorContextLenght
}

/// The options set on the top-level decoder.
Expand All @@ -233,8 +232,7 @@ open class XMLDecoder {
dataDecodingStrategy: dataDecodingStrategy,
nonConformingFloatDecodingStrategy: nonConformingFloatDecodingStrategy,
keyDecodingStrategy: keyDecodingStrategy,
userInfo: userInfo,
errorContextLenght: errorContextLenght)
userInfo: userInfo)
}

// MARK: - Constructing a XML Decoder
Expand All @@ -252,15 +250,10 @@ open class XMLDecoder {
/// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid XML.
/// - throws: An error if any box throws an error during decoding.
open func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T {
let topLevel: Box
do {
topLevel = try _XMLStackParser.parse(with: data, errorContextLength: options.errorContextLenght))
} catch {
throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: [],
debugDescription: "The given data was not valid XML.", underlyingError: error
))
}
let topLevel: Box = try _XMLStackParser.parse(
with: data,
errorContextLength: errorContextLength
)

let decoder = _XMLDecoder(referencing: topLevel, options: options)

Expand Down Expand Up @@ -293,9 +286,9 @@ class _XMLDecoder: Decoder {
public var userInfo: [CodingUserInfoKey: Any] {
return options.userInfo
}

// The error context lenght
open var errorContextLenght: UInt
open var errorContextLenght: UInt = 0

// MARK: - Initialization

Expand Down
4 changes: 2 additions & 2 deletions Sources/XMLCoder/Encoder/XMLEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ open class XMLEncoder {
/// Encode the `Date` as a custom value encoded by the given closure.
///
/// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place.
case custom((Date, Encoder) throws -> Void)
case custom((Date, Encoder) throws -> ())
}

/// The strategy to use for encoding `String` values.
Expand All @@ -86,7 +86,7 @@ open class XMLEncoder {
/// Encode the `Data` as a custom value encoded by the given closure.
///
/// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place.
case custom((Data, Encoder) throws -> Void)
case custom((Data, Encoder) throws -> ())
}

/// The strategy to use for non-XML-conforming floating-point values (IEEE 754 infinity and NaN).
Expand Down
6 changes: 4 additions & 2 deletions Tests/XMLCoderTests/Auxiliary/XMLStackParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class XMLStackParserTests: XCTestCase {
let xmlString = "<container><value>42</value></container>"
let xmlData = xmlString.data(using: .utf8)!

let root: _XMLElement? = try parser.parse(with: xmlData)
let root: _XMLElement? = try parser.parse(with: xmlData,
errorContextLength: 0)

let expected = _XMLElement(
key: "container",
Expand All @@ -37,6 +38,7 @@ class XMLStackParserTests: XCTestCase {
let xmlString = "lorem ipsum"
let xmlData = xmlString.data(using: .utf8)!

XCTAssertThrowsError(try parser.parse(with: xmlData))
XCTAssertThrowsError(try parser.parse(with: xmlData,
errorContextLength: 0))
}
}
52 changes: 52 additions & 0 deletions Tests/XMLCoderTests/ErrorContextTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// ErrorContextTest.swift
// XMLCoder
//
// Created by Matvii Hodovaniuk on 12/27/18.
//

import Foundation
import XCTest
@testable import XMLCoder

final class ErrorContextTest: XCTestCase {
struct Container: Codable {
let value: [String: Int]
}

func testErrorContext() {
let decoder = XMLDecoder()
decoder.errorContextLength = 8

let xmlString =
"""
<container>
test1
</blah>
<container>
test2
</container>
"""
let xmlData = xmlString.data(using: .utf8)!

XCTAssertThrowsError(try decoder.decode(Container.self,
from: xmlData)) { error in
guard case let DecodingError.dataCorrupted(ctx) = error,
let underlying = ctx.underlyingError else {
XCTAssert(false, "wrong error type thrown")
return
}

XCTAssertEqual(ctx.debugDescription, """
\(underlying.localizedDescription) \
at line 3, column 8:
`blah>
<c`
""")
}
}

static var allTests = [
("testErrorContext", testErrorContext),
]
}
38 changes: 0 additions & 38 deletions Tests/XMLCoderTests/ErrorHandle.swift

This file was deleted.

4 changes: 4 additions & 0 deletions XMLCoder.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
BF9457F521CBB6BC005ACFDE /* DecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457EA21CBB6BC005ACFDE /* DecimalTests.swift */; };
BF9457F621CBB6BC005ACFDE /* KeyedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457EB21CBB6BC005ACFDE /* KeyedTests.swift */; };
BF9457F721CBB6BC005ACFDE /* DataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457EC21CBB6BC005ACFDE /* DataTests.swift */; };
D1E0C85321D8E65E0042A261 /* ErrorContextTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1E0C85121D8E6540042A261 /* ErrorContextTest.swift */; };
D1FC040521C7EF8200065B43 /* RJISample.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FC040421C7EF8200065B43 /* RJISample.swift */; };
OBJ_48 /* DecodingErrorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* DecodingErrorExtension.swift */; };
OBJ_49 /* XMLDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* XMLDecoder.swift */; };
Expand Down Expand Up @@ -161,6 +162,7 @@
BF9457EA21CBB6BC005ACFDE /* DecimalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecimalTests.swift; sourceTree = "<group>"; };
BF9457EB21CBB6BC005ACFDE /* KeyedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyedTests.swift; sourceTree = "<group>"; };
BF9457EC21CBB6BC005ACFDE /* DataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataTests.swift; sourceTree = "<group>"; };
D1E0C85121D8E6540042A261 /* ErrorContextTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorContextTest.swift; sourceTree = "<group>"; };
D1FC040421C7EF8200065B43 /* RJISample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RJISample.swift; sourceTree = "<group>"; };
OBJ_10 /* DecodingErrorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodingErrorExtension.swift; sourceTree = "<group>"; };
OBJ_11 /* XMLDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XMLDecoder.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -322,6 +324,7 @@
OBJ_29 /* BreakfastTest.swift */,
OBJ_30 /* CDCatalog.swift */,
OBJ_31 /* CDTest.swift */,
D1E0C85121D8E6540042A261 /* ErrorContextTest.swift */,
OBJ_33 /* NodeEncodingStrategyTests.swift */,
OBJ_34 /* NoteTest.swift */,
OBJ_35 /* PlantCatalog.swift */,
Expand Down Expand Up @@ -551,6 +554,7 @@
BF9457CD21CBB516005ACFDE /* FloatBoxTests.swift in Sources */,
BF9457F621CBB6BC005ACFDE /* KeyedTests.swift in Sources */,
BF9457C821CBB516005ACFDE /* BoolBoxTests.swift in Sources */,
D1E0C85321D8E65E0042A261 /* ErrorContextTest.swift in Sources */,
BF9457F421CBB6BC005ACFDE /* UIntTests.swift in Sources */,
OBJ_89 /* RJITest.swift in Sources */,
BF9457F121CBB6BC005ACFDE /* FloatTests.swift in Sources */,
Expand Down

0 comments on commit 5c38aba

Please sign in to comment.