]> git.saurik.com Git - apple/xnu.git/blobdiff - libkdd/tests/Tests.swift
xnu-3789.1.32.tar.gz
[apple/xnu.git] / libkdd / tests / Tests.swift
diff --git a/libkdd/tests/Tests.swift b/libkdd/tests/Tests.swift
new file mode 100644 (file)
index 0000000..ec88ed2
--- /dev/null
@@ -0,0 +1,1336 @@
+//
+//  Tests.swift
+//
+//  Some of these tests here verify that kdd is able to parse old
+//  kcdata files and generate the correct output. To do so, we include
+//  compressed versions of the raw kcdata and as well as the expected
+//  plist output.
+//
+//  NOTE: If you're adding sample data/plist files, you'll need to first
+//        add them to the project and then make sure each is part of the
+//        tests target.
+//
+//  Other tests verify the expected behavior of libkdd for certain
+//  situations.
+//
+//
+
+import XCTest
+import Foundation
+
+// Swift's bridging to uuid_t is awkward.
+
+func nsuuid2uuid_t(nsuuid : NSUUID) -> uuid_t {
+    let dat = nsuuid2array(nsuuid)
+    return nsarray2uuid(dat)
+}
+
+func nsarray2uuid(x : AnyObject) -> uuid_t {
+    let a = x as! NSArray
+    return uuid_t(UInt8(a[0] as! Int),
+                  UInt8(a[1] as! Int),
+                  UInt8(a[2] as! Int),
+                  UInt8(a[3] as! Int),
+                  UInt8(a[4] as! Int),
+                  UInt8(a[5] as! Int),
+                  UInt8(a[6] as! Int),
+                  UInt8(a[7] as! Int),
+                  UInt8(a[8] as! Int),
+                  UInt8(a[9] as! Int),
+                  UInt8(a[10] as! Int),
+                  UInt8(a[11] as! Int),
+                  UInt8(a[12] as! Int),
+                  UInt8(a[13] as! Int),
+                  UInt8(a[14] as! Int),
+                  UInt8(a[15] as! Int))
+}
+
+func nsuuid2array(uuid : NSUUID) -> [Int] {
+    var ret = [Int]()
+    let ptr = UnsafeMutablePointer<UInt8>.alloc(16)
+    
+    defer { ptr.dealloc(16) }
+
+    uuid.getUUIDBytes(ptr)
+    for i in 0..<16 {
+        ret.append(Int(ptr[i]))
+    }
+    return ret
+}
+
+func decompress(data:NSData) throws -> NSData {
+    var stream = z_stream(next_in: nil, avail_in: 0, total_in: 0, next_out: nil, avail_out: 0, total_out: 0, msg: nil, state: nil, zalloc: nil, zfree: nil, opaque: nil, data_type: 0, adler: 0, reserved: 0)
+
+    let bufsize : Int = 1000
+    let buffer = UnsafeMutablePointer<UInt8>.alloc(bufsize)
+    defer { buffer.dealloc(bufsize) }
+    let output = NSMutableData()
+    stream.next_out = buffer
+    stream.avail_out = UInt32(bufsize)
+    stream.next_in = UnsafeMutablePointer(data.bytes)
+    stream.avail_in = UInt32(data.length)
+    inflateInit2_(&stream, 16+MAX_WBITS, ZLIB_VERSION, Int32(sizeof(z_stream)))
+
+    while (true) {
+        let z = inflate(&stream, Z_NO_FLUSH);
+        if (z == Z_OK || z == Z_STREAM_END) {
+            output.appendBytes(buffer, length: bufsize - Int(stream.avail_out))
+            stream.avail_out = UInt32(bufsize)
+            stream.next_out = buffer
+            if (z == Z_STREAM_END) {
+                return output;
+            }
+        } else {
+            throw NSError(domain: "zlib", code: Int(z), userInfo: nil)
+        }
+    }
+}
+
+
+
+class Tests: XCTestCase {
+    
+    override func setUp() {
+        super.setUp()
+        continueAfterFailure = false
+    }
+    
+    override func tearDown() {
+        // Put teardown code here. This method is called after the invocation of each test method in the class.
+        super.tearDown()
+    }
+    
+    func parseBuffer(buffer:NSData) throws -> NSDictionary {
+        var error : NSError?
+        guard let dict = parseKCDataBuffer(UnsafeMutablePointer(buffer.bytes), UInt32(buffer.length), &error)
+        else {
+                XCTAssert(error != nil)
+                throw error!
+        }
+        return dict
+    }
+
+    func testPaddingFlags(pad : Int) {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
+        item.flags = UInt64(pad)
+        item.size = UInt32(sizeof(dyld_uuid_info_32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
+
+        var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
+        buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+            else { XCTFail(); return; }
+
+        var uuidarray = nsuuid2array(uuid)
+        for _ in 0..<pad {
+            uuidarray.removeLast()
+        }
+
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == uuidarray)
+    }
+
+    func testPaddingFlags() {
+        for i in 0..<15 {
+            testPaddingFlags(i)
+        }
+    }
+
+    func testBootArgs() {
+        let s = "hello, I am some boot args"
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS)
+        item.flags = 0
+        item.size = UInt32(s.utf8.count + 1)
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        s.nulTerminatedUTF8.withUnsafeBufferPointer({
+            buffer.appendBytes($0.baseAddress, length:s.utf8.count + 1)
+        })
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer) else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["boot_args"] == s)
+    }
+
+    func testBootArgsMissingNul() {
+        let s = "hello, I am some boot args"
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS)
+        item.flags = 0
+        item.size = UInt32(s.utf8.count)
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        s.nulTerminatedUTF8.withUnsafeBufferPointer({
+            buffer.appendBytes($0.baseAddress, length:s.utf8.count)
+        })
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+    func testLoadInfo() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
+        item.flags = 0
+        item.size = UInt32(sizeof(dyld_uuid_info_32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
+
+        var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
+        buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nsuuid2array(uuid))
+    }
+
+    func testLoadInfoWrongSize() {
+        // test what happens when a struct size is short
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
+        item.flags = 0
+        item.size = UInt32(sizeof(dyld_uuid_info_32)) - 1
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
+
+        var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
+        buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32) - 1)
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
+        var uuidarray = nsuuid2array(uuid)
+        uuidarray.removeLast()
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == uuidarray)
+    }
+
+    func testLoadInfoWayWrongSize() {
+        // test what happens when a struct size is short
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
+        item.flags = 0
+        item.size = UInt32(sizeof(dyld_uuid_info_32)) - 16
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
+
+        var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid))
+        buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32) - 16)
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42)
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nil)
+    }
+
+    func testLoadInfoPreposterousWrongSize() {
+        // test what happens when a struct size is short
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO)
+        item.flags = 0
+        item.size = UInt32(1)
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var payload = UInt8(42)
+        buffer.appendBytes(&payload, length:1)
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == nil)
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nil)
+    }
+
+
+    func testNewArray(n : Int, pad : Int) {
+        let buffer = NSMutableData(capacity:1000)!
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) + UInt32(pad)
+        item.flags = UInt64(STACKSHOT_KCTYPE_DONATING_PIDS) << 32 | UInt64(n)
+        item.size = UInt32(n * sizeof(UInt32) + pad)
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        for i in 0..<n {
+            var payload = UInt32(42 * i)
+            buffer.appendBytes(&payload, length:sizeof(UInt32))
+        }
+
+        for i in 0..<pad {
+            var payload = UInt8(42-i)
+            buffer.appendBytes(&payload, length:sizeof(UInt8))
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["donating_pids"]??.count == n)
+        for i in 0..<n {
+            let x = dict["kcdata_crashinfo"] as? NSDictionary
+            let y = x?["donating_pids"] as? NSArray
+            XCTAssert((y?[i]) as? NSObject == 42 * i)
+        }
+    }
+
+    func testNewArrays() {
+        self.testNewArray(0,pad:0)
+        for i in 1..<20 {
+            for pad in 0..<16 {
+                self.testNewArray(i, pad:pad)
+            }
+        }
+    }
+
+
+    func testArrayLoadInfo(n : Int) {
+        let buffer = NSMutableData(capacity:1000)!
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
+        item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
+        item.size = UInt32(n * sizeof(dyld_uuid_info_32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
+
+
+        for i in 0..<n {
+            var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
+
+            buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32))
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
+        for i in 0..<n {
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i)
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nsuuid2array(uuid))
+        }
+    }
+
+    func testArrayLoadInfo() {
+        for n in 0..<20 {
+            testArrayLoadInfo(n)
+        }
+    }
+
+    func testArrayLoadInfoWrongSize() {
+        // test what happens when array element sizes are too short
+
+        let n = 7
+        let wrong = 1
+        let buffer = NSMutableData(capacity:1000)!
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
+        item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
+        item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
+
+        for i in 0..<n {
+            var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
+            buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)-wrong)
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var uuidarray = nsuuid2array(uuid)
+        uuidarray.removeLast()
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
+        for i in 0..<n {
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i)
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == uuidarray)
+        }
+    }
+
+
+    func testArrayLoadInfoWayWrongSize() {
+        // test what happens when array element sizes are too short
+
+        let n = 7
+        let wrong = 16
+        let buffer = NSMutableData(capacity:1000)!
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
+        item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
+        item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")!
+
+        for i in 0..<n {
+            var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid))
+            buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)-wrong)
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
+        for i in 0..<n {
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i)
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nil)
+        }
+    }
+
+    func testArrayLoadInfoPreposterouslyWrongSize() {
+        // test what happens when array element sizes are too short
+
+        let n = 7
+        let wrong = 19
+        let buffer = NSMutableData(capacity:1000)!
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0)
+        item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n)
+        item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        for i in 0..<n {
+            var payload = UInt8(42*i)
+            buffer.appendBytes(&payload, length:1)
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n)
+        for i in 0..<n {
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == nil)
+            XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nil)
+        }
+    }
+
+
+    func testNested() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var payload : UInt64 = 42
+        buffer.appendBytes(&payload, length:sizeof(UInt64))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        let buffer2 = NSMutableData(capacity:1000)!
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer2.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_NESTED_KCDATA)
+        item.flags = 0
+        item.size = UInt32(buffer.length)
+        buffer2.appendBytes(&item, length: sizeof(kcdata_item))
+        buffer2.appendData(buffer)
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer2.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict2 = try? self.parseBuffer(buffer2)
+            else { XCTFail(); return; }
+
+        XCTAssert(dict2["kcdata_crashinfo"]?["kcdata_crashinfo"]??["crashed_threadid"] == 42)
+    }
+
+
+    func testReadThreadid() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var payload : UInt64 = 42
+        buffer.appendBytes(&payload, length:sizeof(UInt64))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+
+        XCTAssert(dict["kcdata_crashinfo"]!["crashed_threadid"] == 42)
+    }
+    
+
+    func testRepeatedKey() {
+        // test a repeated item of the same key causes error
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var payload : UInt64 = 42
+        buffer.appendBytes(&payload, length:sizeof(UInt64))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        payload = 42
+        buffer.appendBytes(&payload, length:sizeof(UInt64))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+
+    func testContainer() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+        var payload64 : UInt64
+        var payload32 : UInt32
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload64 = 42
+        buffer.appendBytes(&payload64, length:sizeof(UInt64))
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+
+        XCTAssert(dict["kcdata_crashinfo"]?["task_snapshots"]??["0"]??["crashed_threadid"] == 42)
+
+    }
+
+    func testRepeatedContainer() {
+        //repeated container of same name and key shoudl fail
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+        var payload64 : UInt64
+        var payload32 : UInt32
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload64 = 42
+        buffer.appendBytes(&payload64, length:sizeof(UInt64))
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload64 = 42
+        buffer.appendBytes(&payload64, length:sizeof(UInt64))
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_END)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+
+    func testContainerNoEnd() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+        var payload64 : UInt64
+        var payload32 : UInt32
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload64 = 42
+        buffer.appendBytes(&payload64, length:sizeof(UInt64))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+    func testContainerNoEndNoEnd() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+        var payload64 : UInt64
+        var payload32 : UInt32
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt32))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK)
+        buffer.appendBytes(&payload32, length:sizeof(UInt32))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        payload64 = 42
+        buffer.appendBytes(&payload64, length:sizeof(UInt64))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+
+
+    func testNoEnd() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = UInt32(sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var payload : UInt64 = 42
+        buffer.appendBytes(&payload, length:sizeof(UInt64))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+
+    func  testCrazySize() {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = 99999
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var payload : UInt64 = 42
+        buffer.appendBytes(&payload, length:sizeof(UInt64))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+    func testReadRepeatedArray() {
+        // repeated arrays should be concatenated
+        let n = 10
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY)
+        item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
+        item.size = UInt32(n * sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        for i in 0..<n {
+            var payload : UInt64 = UInt64(i)
+            buffer.appendBytes(&payload, length:sizeof(UInt64))
+        }
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY)
+        item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
+        item.size = UInt32(n * sizeof(UInt64))
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        for i in 0..<n {
+            var payload : UInt64 = UInt64(i)
+            buffer.appendBytes(&payload, length:sizeof(UInt64))
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+            else { XCTFail(); return }
+
+        XCTAssert( 2*n == dict["kcdata_crashinfo"]!["crashed_threadid"]!!.count)
+        for i in 0..<2*n {
+            let x = dict["kcdata_crashinfo"] as? NSDictionary
+            let y = x?["crashed_threadid"] as? NSArray
+            XCTAssert((y?[i]) as? NSObject == i % n)
+        }
+    }
+
+    func testReadThreadidArray(n : Int, pad : Int) {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        
+        item.type = UInt32(KCDATA_TYPE_ARRAY)
+        item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
+        item.size = UInt32(n * sizeof(UInt64) + pad)
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        for i in 0..<n {
+            var payload : UInt64 = UInt64(i)
+            buffer.appendBytes(&payload, length:sizeof(UInt64))
+        }
+
+        for _ in 0..<pad {
+            var payload : UInt8 = 0
+            buffer.appendBytes(&payload, length:1)
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+        
+        XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count)
+        for i in 0..<n {
+            let x = dict["kcdata_crashinfo"] as? NSDictionary
+            let y = x?["crashed_threadid"] as? NSArray
+            XCTAssert((y?[i]) as? NSObject == i)
+        }
+
+    }
+    
+    func testReadThreadidArray() {
+        // test that we can correctly read old arrays with a variety of sizes and paddings
+        self.testReadThreadidArray(0, pad:0)
+        for n in 1..<100 {
+            for pad in 0..<16 {
+                self.testReadThreadidArray(n, pad:pad)
+            }
+        }
+    }
+
+    func testReadThreadidArrayWrongSize1() {
+        /// for old style arrays, if the element size is determined by the type.   If the array of that size element at the given count doesn't fit, then parsing should fail
+
+        let n = 1
+        
+        let buffer = NSMutableData(capacity:1000)!
+        
+        var item = kcdata_item()
+        
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        
+        item.type = UInt32(KCDATA_TYPE_ARRAY)
+        item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
+        item.size = UInt32(4)
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        
+        var payload : UInt32 = UInt32(42)
+        buffer.appendBytes(&payload, length:sizeof(UInt32))
+        
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+    
+    func testReadThreadidArrayWrongSize5() {
+        /// if the count is bigger than the buffer, parsing will just fail
+        
+        let n = 5
+        
+        let buffer = NSMutableData(capacity:1000)!
+        
+        var item = kcdata_item()
+        
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        
+        item.type = UInt32(KCDATA_TYPE_ARRAY)
+        item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
+        item.size = UInt32(4)
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        
+        var payload : UInt32 = UInt32(42)
+        buffer.appendBytes(&payload, length:sizeof(UInt32))
+        
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+        
+        XCTAssert( (try? self.parseBuffer(buffer)) == nil )
+    }
+
+    
+    func testReadThreadidArrayPaddedSize() {
+        // test that we can tolerate a little padding at the end of an array
+        let n = 5
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY)
+        item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
+        item.size = UInt32(n * sizeof(UInt64)) + 1
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        for i in 0..<n {
+            var payload : UInt64 = UInt64(i)
+            buffer.appendBytes(&payload, length:sizeof(UInt64))
+        }
+        var payload : UInt8 = 0
+        buffer.appendBytes(&payload, length:1)
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+
+        XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count)
+        for i in 0..<n {
+            let x = dict["kcdata_crashinfo"] as? NSDictionary
+            let y = x?["crashed_threadid"] as? NSArray
+            XCTAssert((y?[i]) as? NSObject == i)
+        }
+    }
+
+    func testReadThreadidArrayPaddedSize15() {
+        // test that we can tolerate a little padding at the end of an array
+        let n = 5
+
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(KCDATA_TYPE_ARRAY)
+        item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n)
+        item.size = UInt32(n * sizeof(UInt64)) + 15
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        for i in 0..<n {
+            var payload : UInt64 = UInt64(i)
+            buffer.appendBytes(&payload, length:sizeof(UInt64))
+        }
+        for i in 0..<15 {
+            i;
+            var payload : UInt8 = 0
+            buffer.appendBytes(&payload, length:1)
+        }
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+
+        XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count)
+        for i in 0..<n {
+            let x = dict["kcdata_crashinfo"] as? NSDictionary
+            let y = x?["crashed_threadid"] as? NSArray
+            XCTAssert((y?[i]) as? NSObject == i)
+        }
+    }
+
+
+    func testReadThreadidWrongSize(size : UInt32) {
+        let buffer = NSMutableData(capacity:1000)!
+
+        var item = kcdata_item()
+
+        item.type = KCDATA_BUFFER_BEGIN_CRASHINFO
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID)
+        item.flags = 0
+        item.size = size
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        var payload : UInt64 = 42
+        buffer.appendBytes(&payload, length:Int(size))
+
+        item.type = KCDATA_TYPE_BUFFER_END
+        item.flags = 0
+        item.size = 0
+        buffer.appendBytes(&item, length: sizeof(kcdata_item))
+
+        guard let dict = try? self.parseBuffer(buffer)
+        else { XCTFail(); return; }
+
+        XCTAssert(dict["kcdata_crashinfo"]?["crashed_threadid"] == nil)
+    }
+
+    func testReadThreadidWrongSize0() {
+        self.testReadThreadidWrongSize(0)
+    }
+
+    func testReadThreadidWrongSize7() {
+        self.testReadThreadidWrongSize(7)
+    }
+
+    func dataWithResource(name:String) -> NSData? {
+        guard let filename =  NSBundle(forClass: self.classForCoder).pathForResource(name, ofType: nil)
+        else { return nil }
+        return NSData(contentsOfFile:filename)!
+    }
+    
+    func testSampleStackshot(name : String) {
+        // check that we agree with sample file
+
+        guard let sampledata = self.dataWithResource(name)
+            else { XCTFail(); return }
+        var dict : NSDictionary?
+
+        dict = try? self.parseBuffer(sampledata)
+
+        if (dict == nil) {
+            if let decoded = NSData(base64EncodedData: sampledata, options:.IgnoreUnknownCharacters) {
+                dict = try? self.parseBuffer(decoded)
+            }
+        }
+
+        if (dict == nil) {
+            if let decompressed = try? decompress(sampledata) {
+                dict = try? self.parseBuffer(decompressed)
+            }
+        }
+
+        if (dict == nil) {
+            XCTFail(); return;
+        }
+
+        guard let plistdata = self.dataWithResource(name + ".plist.gz") ??
+                              self.dataWithResource(name + ".plist")
+            else {XCTFail(); return}
+
+        var dict2 = try? NSPropertyListSerialization.propertyListWithData(plistdata, options: NSPropertyListReadOptions.Immutable, format: nil)
+        if dict2 == nil {
+            dict2 = try? NSPropertyListSerialization.propertyListWithData(decompress(plistdata), options: .Immutable, format: nil)
+        }
+
+        XCTAssert(dict2 != nil)
+
+        XCTAssert(dict == dict2 as? NSDictionary)
+
+        // check that we agree with python
+
+        #if os(OSX)
+
+            let kcdatapy = NSBundle(forClass: self.classForCoder).pathForResource("kcdata.py", ofType: nil)
+
+        let task = NSTask()
+        task.launchPath = kcdatapy
+        task.arguments = ["-p",
+                          NSBundle(forClass:self.classForCoder).pathForResource(name, ofType: nil)!]
+        let pipe = NSPipe()
+        task.standardOutput = pipe
+        task.launch()
+
+        let data = pipe.fileHandleForReading.readDataToEndOfFile()
+
+            guard let dict3 = try? NSPropertyListSerialization.propertyListWithData(data, options: .Immutable, format: nil) as? NSDictionary
+            else { XCTFail(); return }
+
+        XCTAssert(dict == dict3)
+
+        #endif
+    }
+
+    func testSampleStackshot() {
+        self.testSampleStackshot("stackshot-sample")
+    }
+
+    func testSampleStackshotOldArrays() {
+        self.testSampleStackshot("stackshot-sample-old-arrays")
+    }
+
+    func testSampleStackshotNewArrays() {
+        self.testSampleStackshot("stackshot-sample-new-arrays")
+    }
+
+    func testSampleDeltaStackshotOldArrays() {
+        self.testSampleStackshot("delta-stackshot-sample-old-arrays")
+    }
+
+    func testSampleDeltaStackshotNewArrays() {
+        self.testSampleStackshot("delta-stackshot-sample-new-arrays")
+    }
+
+    func testSampleCorpse() {
+        self.testSampleStackshot("corpse-sample")
+    }
+
+    func testSampleStackshotTailspin() {
+        self.testSampleStackshot("stackshot-sample-tailspin")
+    }
+
+    func testSampleStackshotTailspin2() {
+        self.testSampleStackshot("stackshot-sample-tailspin-2")
+    }
+
+    func testSampleExitReason() {
+        self.testSampleStackshot("exitreason-sample")
+    }
+    
+    func testSampleThreadT() {
+        self.testSampleStackshot("stackshot-sample-ths-thread-t")
+    }
+
+    func testSampleCpuTimes() {
+        self.testSampleStackshot("stackshot-sample-cputime")
+    }
+
+    func testSampleDuration() {
+        self.testSampleStackshot("stackshot-sample-duration")
+    }
+
+    func testSampleNested() {
+        self.testSampleStackshot("nested-sample")
+    }
+
+    func testSampleTermWithReason() {
+        self.testSampleStackshot("test-twr-sample")
+    }
+
+    func testSampleCorpseTermWithReason() {
+        self.testSampleStackshot("corpse-twr-sample")
+    }
+
+    func testSampleCorpseTermWithReasonV2() {
+        self.testSampleStackshot("corpse-twr-sample-v2")
+    }
+
+    func testSampleCodesigningExitReason() {
+        self.testSampleStackshot("exitreason-codesigning")
+    }
+
+    func testStackshotSharedcacheV2() {
+        self.testSampleStackshot("stackshot-sample-sharedcachev2")
+    }
+
+    func testStackshotFaultStats() {
+        self.testSampleStackshot("stackshot-fault-stats")
+    }
+
+    func testStackshotwithKCID() {
+        self.testSampleStackshot("stackshot-with-kcid")
+    }
+
+    func testXNUPostTestConfig() {
+        self.testSampleStackshot("xnupost_testconfig-sample")
+    }
+
+    func testTrivial() {
+    }
+}