Files
SwiftCBOR/Tests/CBORDecoderTests.swift

205 lines
15 KiB
Swift

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<UInt8> = [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))
}
}
}