import XCTest @testable import SwiftCBOR class CBORDecoderTests: XCTestCase { func testDecodeNumbers() { for i in (0..<24) { XCTAssertEqual(try! CBORDecoder(input: [UInt8(i)]).decodeItem(), CBOR.unsignedInt(UInt64(i))) } XCTAssertEqual(try! CBORDecoder(input: [0x18, 0xff]).decodeItem(), 255) XCTAssertEqual(try! CBORDecoder(input: [0x19, 0x03, 0xe8]).decodeItem(), 1000) // Network byte order! XCTAssertEqual(try! CBORDecoder(input: [0x19, 0xff, 0xff]).decodeItem(), 65535) do { _ = try CBORDecoder(input: [0x19, 0xff]).decodeItem(); XCTAssertTrue(false) } catch { XCTAssertTrue(true) } XCTAssertEqual(try! CBORDecoder(input: [0x1a, 0x00, 0x0f, 0x42, 0x40]).decodeItem(), 1000000) XCTAssertEqual(try! CBORDecoder(input: [0x1a, 0xff, 0xff, 0xff, 0xff]).decodeItem(), 4294967295) do { _ = try CBORDecoder(input: [0x1a]).decodeItem(); XCTAssertTrue(false) } catch { XCTAssertTrue(true) } XCTAssertEqual(try! CBORDecoder(input: [0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00]).decodeItem(), 1000000000000) XCTAssertEqual(try! CBORDecoder(input: [0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]).decodeItem(), CBOR.unsignedInt(18446744073709551615)) do { _ = try CBORDecoder(input: [0x1b, 0x00, 0x00]).decodeItem(); XCTAssertTrue(false) } catch { XCTAssertTrue(true) } XCTAssertEqual(try! CBORDecoder(input: [0x20]).decodeItem(), -1) XCTAssertEqual(try! CBORDecoder(input: [0x21]).decodeItem(), CBOR.negativeInt(1)) XCTAssertEqual(try! CBORDecoder(input: [0x37]).decodeItem(), -24) XCTAssertEqual(try! CBORDecoder(input: [0x38, 0xff]).decodeItem(), -256) XCTAssertEqual(try! CBORDecoder(input: [0x39, 0x03, 0xe7]).decodeItem(), -1000) XCTAssertEqual(try! CBORDecoder(input: [0x3a, 0x00, 0x0f, 0x42, 0x3f]).decodeItem(), CBOR.negativeInt(999999)) XCTAssertEqual(try! CBORDecoder(input: [0x3b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x0f, 0xff]).decodeItem(), CBOR.negativeInt(999999999999)) } func testDecodeByteStrings() { XCTAssertEqual(try! CBORDecoder(input: [0x40]).decodeItem(), CBOR.byteString([])) XCTAssertEqual(try! CBORDecoder(input: [0x41, 0xf0]).decodeItem(), CBOR.byteString([0xf0])) XCTAssertEqual(try! CBORDecoder(input: [0x57, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xaa]).decodeItem(), CBOR.byteString([0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xaa])) XCTAssertEqual(try! CBORDecoder(input: [0x58, 0]).decodeItem(), CBOR.byteString([])) XCTAssertEqual(try! CBORDecoder(input: [0x58, 1, 0xf0]).decodeItem(), CBOR.byteString([0xf0])) XCTAssertEqual(try! CBORDecoder(input: [0x59, 0x00, 3, 0xc0, 0xff, 0xee]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee])) XCTAssertEqual(try! CBORDecoder(input: [0x5a, 0x00, 0x00, 0x00, 3, 0xc0, 0xff, 0xee]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee])) XCTAssertEqual(try! CBORDecoder(input: [0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3, 0xc0, 0xff, 0xee]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee])) XCTAssertEqual(try! CBORDecoder(input: [0x5f, 0x58, 3, 0xc0, 0xff, 0xee, 0x43, 0xc0, 0xff, 0xee, 0xff]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee])) } func testDecodeData() { XCTAssertEqual(try! CBORDecoder(input: [0x40]).decodeItem(), CBOR.byteString([])) XCTAssertEqual(try! CBORDecoder(input: [0x41, 0xf0]).decodeItem(), CBOR.byteString([0xf0])) XCTAssertEqual(try! CBORDecoder(input: [0x57, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xaa]).decodeItem(), CBOR.byteString([0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xaa])) XCTAssertEqual(try! CBORDecoder(input: [0x58, 0]).decodeItem(), CBOR.byteString([])) XCTAssertEqual(try! CBORDecoder(input: [0x58, 1, 0xf0]).decodeItem(), CBOR.byteString([0xf0])) XCTAssertEqual(try! CBORDecoder(input: [0x59, 0x00, 3, 0xc0, 0xff, 0xee]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee])) XCTAssertEqual(try! CBORDecoder(input: [0x5a, 0x00, 0x00, 0x00, 3, 0xc0, 0xff, 0xee]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee])) XCTAssertEqual(try! CBORDecoder(input: [0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3, 0xc0, 0xff, 0xee]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee])) XCTAssertEqual(try! CBORDecoder(input: [0x5f, 0x58, 3, 0xc0, 0xff, 0xee, 0x43, 0xc0, 0xff, 0xee, 0xff]).decodeItem(), CBOR.byteString([0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee])) } func testDecodeUtf8Strings() { XCTAssertEqual(try! CBORDecoder(input: [0x60]).decodeItem(), CBOR.utf8String("")) XCTAssertEqual(try! CBORDecoder(input: [0x61, 0x42]).decodeItem(), "B") XCTAssertEqual(try! CBORDecoder(input: [0x78, 0]).decodeItem(), "") XCTAssertEqual(try! CBORDecoder(input: [0x78, 1, 0x42]).decodeItem(), "B") XCTAssertEqual(try! CBORDecoder(input: [0x79, 0x00, 3, 0x41, 0x42, 0x43]).decodeItem(), CBOR.utf8String("ABC")) XCTAssertEqual(try! CBORDecoder(input: [0x7a, 0x00, 0x00, 0x00, 3, 0x41, 0x42, 0x43]).decodeItem(), "ABC") XCTAssertEqual(try! CBORDecoder(input: [0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3, 0x41, 0x42, 0x43]).decodeItem(), "ABC") XCTAssertEqual(try! CBORDecoder(input: [0x7f, 0x78, 3, 0x41, 0x42, 0x43, 0x63, 0x41, 0x42, 0x43, 0xff]).decodeItem(), "ABCABC") } func testDecodeArrays() { XCTAssertEqual(try! CBORDecoder(input: [0x80]).decodeItem(), []) XCTAssertEqual(try! CBORDecoder(input: [0x82, 0x18, 1, 0x79, 0x00, 3, 0x41, 0x42, 0x43]).decodeItem(), [1, "ABC"]) XCTAssertEqual(try! CBORDecoder(input: [0x98, 0]).decodeItem(), []) XCTAssertEqual(try! CBORDecoder(input: [0x98, 3, 0x18, 2, 0x18, 2, 0x79, 0x00, 3, 0x41, 0x42, 0x43, 0xff]).decodeItem(), [2, 2, "ABC"]) XCTAssertEqual(try! CBORDecoder(input: [0x9f, 0x18, 255, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2, 0x18, 1, 0x79, 0x00, 3, 0x41, 0x42, 0x43, 0x79, 0x00, 3, 0x41, 0x42, 0x43, 0xff]).decodeItem(), [255, [1, "ABC"], "ABC"]) XCTAssertEqual(try! CBORDecoder(input: [0x9f, 0x81, 0x01, 0x82, 0x02, 0x03, 0x9f, 0x04, 0x05, 0xff, 0xff]).decodeItem(), [[1], [2, 3], [4, 5]]) } func testDecodeMaps() { XCTAssertEqual(try! CBORDecoder(input: [0xa0]).decodeItem(), [:]) XCTAssertEqual(try! CBORDecoder(input: [0xa1, 0x63, 0x6b, 0x65, 0x79, 0x37]).decodeItem()!["key"], -24) XCTAssertEqual(try! CBORDecoder(input: [0xb8, 1, 0x63, 0x6b, 0x65, 0x79, 0x81, 0x37]).decodeItem(), ["key" : [-24]]) XCTAssertEqual(try! CBORDecoder(input: [0xbf, 0x63, 0x6b, 0x65, 0x79, 0xa1, 0x63, 0x6b, 0x65, 0x79, 0x37, 0xff]).decodeItem(), ["key" : ["key" : -24]]) XCTAssertEqual(try! CBORDecoder(input: [0xa3, 0x63, 0x5f, 0x69, 0x64, 0x63, 0x61, 0x61, 0x61, 0x68, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x64, 0x63, 0x61, 0x6b, 0x65, 0x67, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0xf9, 0x4a, 0x00]).decodeItem(), ["_id": "aaa", "category": "cake", "ordinal": CBOR.half(12.0)]) } func testDecodeTagged() { XCTAssertEqual(try! CBORDecoder(input: [0xc0, 0x79, 0x00, 3, 0x41, 0x42, 0x43]).decodeItem(), CBOR.tagged(.standardDateTimeString, "ABC")) XCTAssertEqual(try! CBORDecoder(input: [0xd8, 255, 0x79, 0x00, 3, 0x41, 0x42, 0x43]).decodeItem(), CBOR.tagged(.init(rawValue: 255), "ABC")) XCTAssertEqual(try! CBORDecoder(input: [0xdb, 255, 255, 255, 255, 255, 255, 255, 255, 0x79, 0x00, 3, 0x41, 0x42, 0x43]).decodeItem(), CBOR.tagged(.init(rawValue: UInt64.max), "ABC")) XCTAssertEqual(try! CBORDecoder(input: [0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3, 0xbf, 0x63, 0x6b, 0x65, 0x79, 0xa1, 0x63, 0x6b, 0x65, 0x79, 0x37, 0xff]).decodeItem(), CBOR.tagged(.negativeBignum, ["key" : ["key" : -24]])) } func testDecodeSimple() { XCTAssertEqual(try! CBORDecoder(input: [0xe0]).decodeItem(), CBOR.simple(0)) XCTAssertEqual(try! CBORDecoder(input: [0xf3]).decodeItem(), CBOR.simple(19)) XCTAssertEqual(try! CBORDecoder(input: [0xf8, 19]).decodeItem(), CBOR.simple(19)) XCTAssertEqual(try! CBORDecoder(input: [0xf4]).decodeItem(), false) XCTAssertEqual(try! CBORDecoder(input: [0xf5]).decodeItem(), true) XCTAssertEqual(try! CBORDecoder(input: [0xf6]).decodeItem(), CBOR.null) XCTAssertEqual(try! CBORDecoder(input: [0xf7]).decodeItem(), CBOR.undefined) } func testDecodeFloats() { XCTAssertEqual(try! CBORDecoder(input: [0xf9, 0xc4, 0x00]).decodeItem(), CBOR.half(-4.0)) XCTAssertEqual(try! CBORDecoder(input: [0xf9, 0xfc, 0x00]).decodeItem(), CBOR.half(-Float.infinity)) XCTAssertEqual(try! CBORDecoder(input: [0xfa, 0x47, 0xc3, 0x50, 0x00]).decodeItem(), 100000.0) XCTAssertEqual(try! CBORDecoder(input: [0xfa, 0x7f, 0x80, 0x00, 0x00]).decodeItem(), CBOR.float(Float.infinity)) XCTAssertEqual(try! CBORDecoder(input: [0xfb, 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]).decodeItem(), CBOR.double(-4.1)) } func testDecodeDates() { let dateOne = Date(timeIntervalSince1970: 1363896240) XCTAssertEqual(try! CBOR.decode([0xc1, 0x1a, 0x51, 0x4b, 0x67, 0xb0]), CBOR.date(dateOne)) let dateTwo = Date(timeIntervalSince1970: 1363896240.5) XCTAssertEqual(try! CBOR.decode([0xc1, 0xfb, 0x41, 0xd4, 0x52, 0xd9, 0xec, 0x20, 0x00, 0x00]), CBOR.date(dateTwo)) } func testDecodePerformance() { var data : ArraySlice = [0x9f] for i in (0..<255) { data.append(contentsOf: [0xbf, 0x63, 0x6b, 0x65, 0x79, 0xa1, 0x63, 0x6b, 0x65, 0x79, 0x18, UInt8(i), 0xff]) } data.append(0xff) self.measure { _ = try! CBORDecoder(input: data).decodeItem() } } func testDecodeMapFromIssue29() { let loremIpsumData: [UInt8] = [0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x51, 0x75, 0x69, 0x73, 0x71, 0x75, 0x65, 0x20, 0x65, 0x78, 0x20, 0x61, 0x6e, 0x74, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x20, 0x75, 0x74, 0x20, 0x66, 0x61, 0x75, 0x63, 0x69, 0x62, 0x75, 0x73, 0x20, 0x70, 0x68, 0x61, 0x72, 0x65, 0x74, 0x72, 0x61, 0x2c, 0x20, 0x61, 0x63, 0x63, 0x75, 0x6d, 0x73, 0x61, 0x6e, 0x20, 0x65, 0x74, 0x20, 0x61, 0x75, 0x67, 0x75, 0x65, 0x2e, 0x20, 0x56, 0x65, 0x73, 0x74, 0x69, 0x62, 0x75, 0x6c, 0x75, 0x6d, 0x20, 0x76, 0x75, 0x6c, 0x70, 0x75, 0x74, 0x61, 0x74, 0x65, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x6c, 0x69, 0x67, 0x75, 0x6c, 0x61, 0x2c, 0x20, 0x65, 0x75, 0x20, 0x74, 0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x72, 0x63, 0x69, 0x20, 0x6c, 0x61, 0x63, 0x69, 0x6e, 0x69, 0x61, 0x20, 0x71, 0x75, 0x69, 0x73, 0x2e, 0x20, 0x50, 0x72, 0x6f, 0x69, 0x6e, 0x20, 0x73, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x69, 0x73, 0x71, 0x75, 0x65, 0x20, 0x64, 0x75, 0x69, 0x20, 0x61, 0x74, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x72, 0x61, 0x74, 0x2c, 0x20, 0x69, 0x64, 0x20, 0x62, 0x6c, 0x61, 0x6e, 0x64, 0x69, 0x74, 0x20, 0x66, 0x65, 0x6c, 0x69, 0x73, 0x20, 0x76, 0x65, 0x68, 0x69, 0x63, 0x75, 0x6c, 0x61, 0x2e, 0x20, 0x4d, 0x61, 0x65, 0x63, 0x65, 0x6e, 0x61, 0x73, 0x20, 0x61, 0x63, 0x20, 0x6e, 0x69, 0x73, 0x6c, 0x20, 0x61, 0x20, 0x6f, 0x64, 0x69, 0x6f, 0x20, 0x76, 0x61, 0x72, 0x69, 0x75, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x75, 0x6d, 0x20, 0x6c] let data: [UInt8] = [0xbf, 0x63, 0x6f, 0x66, 0x66, 0x00, 0x64, 0x64, 0x61, 0x74, 0x61, 0x59, 0x01, 0x2c] + loremIpsumData + [0x62, 0x72, 0x63, 0x00, 0x63, 0x6c, 0x65, 0x6e, 0x19, 0x01, 0x2c, 0xff] let expectedMap = CBOR.map([ CBOR.utf8String("off"): CBOR.unsignedInt(0), CBOR.utf8String("data"): CBOR.byteString(loremIpsumData), CBOR.utf8String("rc"): CBOR.unsignedInt(0), CBOR.utf8String("len"): CBOR.unsignedInt(300) ]) let decoded = try! CBOR.decode(data) XCTAssertEqual(decoded, expectedMap) } func testDecodeFromIssue78() { struct CborFiles: Codable { let files: [File] let status: Int } struct File: Codable { let name: String let time, id, size, checksum: Int } let withDefiniteArrayHex = "bf6566696c657381a5626964016474696d651a001b7d4868636865636b73756d1a0ad227576473697a6505646e616d656d2f6c66732f68722f31312e68726673746174757301ff" let _ = try! CodableCBORDecoder().decode(CborFiles.self, from: withDefiniteArrayHex.hexaData) let withIndefiniteArrayHex = "bf6566696c65739fa5626964016474696d651a001b7d4868636865636b73756d1a0ad227576473697a6505646e616d656d2f6c66732f68722f31312e6872ff6673746174757301ff" let _ = try! CodableCBORDecoder().decode(CborFiles.self, from: withIndefiniteArrayHex.hexaData) } func testDecodeOfStructContainingNestedIndefiniteMapsAndArrays() { struct NestedIndefinite: Codable, Equatable { let nested: [String: [String: [[String: [[[String: [[String: Int]]]? ]]]]]] } let hex = "bf666e6573746564bf6161bf61629fbf61639f9fbf61649fbf6165187bffffffff9fff9ff6ffffffffffffff" let decoded = try! CodableCBORDecoder().decode(NestedIndefinite.self, from: hex.hexaData) let expected = NestedIndefinite(nested: ["a": ["b": [["c": [[["d": [["e": 123 ]] ]], [], [nil]]]]]]) XCTAssertEqual(decoded, expected) } func testDecodeFailsForExtremelyDeepStructures() { let justOverTags: [UInt8] = Array(repeating: 202, count: 1025) + [0] XCTAssertThrowsError(try CBOR.decode(justOverTags, options: CBOROptions(maximumDepth: 1024))) { error in XCTAssertEqual(error as? CBORError, CBORError.maximumDepthExceeded) } let endlessTags: [UInt8] = Array(repeating: 202, count: 10000) + [0] XCTAssertThrowsError(try CBOR.decode(endlessTags, options: CBOROptions(maximumDepth: 1024))) { error in XCTAssertEqual(error as? CBORError, CBORError.maximumDepthExceeded) } } func testDecodeFailsForSillyMaximumDepths() { let singleItem: [UInt8] = [0] XCTAssertThrowsError(try CBOR.decode(singleItem, options: CBOROptions(maximumDepth: -1))) { error in XCTAssertEqual(error as? CBORError, CBORError.maximumDepthExceeded) } } func testDecodeSucceedsForAllowedDeepStructures() { let singleItem: [UInt8] = [0] XCTAssertNoThrow(try CBOR.decode(singleItem, options: CBOROptions(maximumDepth: 0))) let endlessTags: [UInt8] = Array(repeating: 202, count: 1024) + [0] XCTAssertNoThrow(try CBOR.decode(endlessTags, options: CBOROptions(maximumDepth: 1024))) } func testRandomInputDoesNotHitStackLimits() { for _ in 1...50 { let length = Int.random(in: 1...1_000_000) let randomData: [UInt8] = Array(repeating: UInt8.random(in: 0...255), count: length) _ = try? CBOR.decode(randomData, options: CBOROptions(maximumDepth: 512)) } } }