// // MAVLinkTests.swift // MAVLinkTests // // Created by Max Odnovolyk on 9/28/16. // Copyright © 2016 Build Apps. All rights reserved. // import Foundation import XCTest @testable import MAVLink class DataExtensionsTests: XCTestCase { // MARK: - Test number(at offset: Data.Index, byteOrder: CFByteOrder) throws -> T func testGetNumberCannotGetTooLargeNumber() { let data = Data(count: 4) let test: () throws -> Void = { let _: Int32 = try data.number(at: 1) } XCTAssertThrowsError(try test()) { error in switch error { case let ParseError.valueSizeOutOfBounds(offset, size, upperBound) where offset + size > upperBound: break default: XCTFail("Unexpected error thrown") } } } func testGetNumberDidGetNumberAtOffset() { let data = Data(bytes: [0x00, 0x00, 0x01, 0x02, 0x03, 0x04]) let expectedNumber: UInt32 = 0x01_02_03_04 let receivedNumber: UInt32 = try! data.number(at: 2, byteOrder: .bigEndian) XCTAssert(receivedNumber == expectedNumber, "Method should return number value available at specified offset in data") } func testGetNumberByteOrderIsSwappedOnLittleEndianSystem() { let memoryBytes: [UInt8] = [0x04, 0x03, 0x02, 0x01] let expectedNumber: UInt32 = 0x01_02_03_04 let data = Data(bytes: memoryBytes) let receivedNumber: UInt32 = try! data.number(at: 0, byteOrder: .littleEndian) XCTAssert(receivedNumber == expectedNumber, "Method expects swapped bytes in memory on little-endian system (most significant digit byte at the end)") } func testGetNumberByteOrderRemainsSameOnBigEndianSystem() { let memoryBytes: [UInt8] = [0x01, 0x02, 0x03, 0x04] let expectedNumber: UInt32 = 0x01_02_03_04 let data = Data(bytes: memoryBytes) let receivedNumber: UInt32 = try! data.number(at: 0, byteOrder: .bigEndian) XCTAssert(receivedNumber == expectedNumber, "Method expects less significant digit byte at the end of value's memory chunk") } // MARK: Test array(at offset: Data.Index, capacity: Int) throws -> [T] func testGetArrayCannotAccessBytesOutOfDataUpperBound() { let data = Data(count: 4) let test: () throws -> Void = { let _: [UInt8] = try data.array(at: 1, capacity: 4) } XCTAssertThrowsError(try test()) { error in switch error { case let ParseError.valueSizeOutOfBounds(offset, size, upperBound) where offset + size > upperBound: break default: XCTFail("Unexpected error thrown") } } } func testGetArrayDidGetArrayAtOffset() { let data = Data(bytes: [0x00, 0x00, 0x01, 0x02, 0x03, 0x00]) let expectedArray: [UInt8] = [0x01, 0x02, 0x03] let receivedArray: [UInt8] = try! data.array(at: 2, capacity: 3) XCTAssert(receivedArray == expectedArray, "Expect array values at specified offset in data") } func testGetArrayDidGetRequestedNumberOfItems() { let data = Data(count: 4) let itemsCountToGet = 3 let receivedArray: [UInt8] = try! data.array(at: 1, capacity: itemsCountToGet) XCTAssert(receivedArray.count == itemsCountToGet, "Expect requested capacity of array to be equal to received array's count") } // MARK: Test string(at offset: Data.Index, length: Int) throws -> String func testGetStringCannotAccessBytesOutOfDataUpperBound() { let data = Data(count: 4) XCTAssertThrowsError(try data.string(at: 1, length: 4)) { error in switch error { case let ParseError.valueSizeOutOfBounds(offset, size, upperBound) where offset + size > upperBound: break default: XCTFail("Unexpected error thrown") } } } func testGetStringCannotReadNonASCIISEncodedString() { // Check that invalidStringEncoding is thrown in case of non ASCII compatible strings. // It looks like all strings are ASCII compatible for String(bytes: encoding:) method. } func testGetStringDidReadASCIIEncodedStringAtSpecifiedOffset() { let data = Data(bytes: [0x60, 0x61, 0x62, 0x63, 0x64, 0x65]) // "`abcde" let string = try! data.string(at: 3, length: 3) XCTAssert(string == "cde", "Expect string at offset 3 (cde)") } func testGetStringDidReadEmptyNullTerminatedASCIIEncodedString() { let data = Data(bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) // "\0\0\0\0\0\0" let string = try! data.string(at: 1, length: 4) XCTAssert(string == "", "Expect to get empty string from zeroed data bytes") } func testGetStringDidReadNullTerminatedASCIIEncodedString() { let data = Data(bytes: [0x60, 0x61, 0x62, 0x0, 0x64, 0x65]) // "`ab\0de" let string = try! data.string(at: 1, length: 4) XCTAssert(string == "ab", "Expect cutted off by null-termination string") } func testGetStringDidReadExactlyLengthSizedASCIIEncodedStringWithoutNullTermination() { let data = Data(bytes: [0x60, 0x61, 0x62, 0x63, 0x64, 0x65]) // "`abcde" let string = try! data.string(at: 1, length: 3) XCTAssert(string == "abc", "Expect cutted off by length limit string") } // MARK: Test enumeration(at offset: Data.Index) throws -> T where T.RawValue: MAVLinkNumber func testGetEnumerationCannotInitWithUnknownValue() { let data = Data(bytes: [UInt8(ADSBAltitudeType.enumEnd)]) let test: () throws -> Void = { let _: ADSBAltitudeType = try data.enumeration(at: 0) } XCTAssertThrowsError(try test()) { error in switch error { case ParseEnumError.unknownValue: break default: XCTFail("Unexpected error thrown") } } } func testGetEnumerationDidGetProperCaseAtOffset() { let data = Data(bytes: [0x00, 0x00, ADSBAltitudeType.geometric.rawValue]) let adsbAltitudeType: ADSBAltitudeType = try! data.enumeration(at: 2) XCTAssert(adsbAltitudeType == .geometric, "Expected adsbAltitudeType is .geometric") } // MARK: - Test set(_ number: T, at offset: Data.Index, byteOrder: CFByteOrder) throws -> Void func testSetNumberCannotSetTooLargeNumber() { var data = Data(count: 4) XCTAssertThrowsError(try data.set(Int32(1), at: 1)) { error in switch error { case let PackError.valueSizeOutOfBounds(offset, size, upperBound) where offset + size > upperBound: break default: XCTFail("Unexpected error thrown") } } } func testSetNumberDidSetNumberAtOffset() { var data = Data(count: 6) let number: UInt32 = 0x01_02_03_04 let expectedData = Data(bytes: [0x00, 0x00, 0x01, 0x02, 0x03, 0x04]) try! data.set(number, at: 2, byteOrder: .bigEndian) XCTAssert(data == expectedData, "Method should set number at specified offset in data memory") } func testSetNumberByteOrderIsSwappedOnLittleEndianSystem() { var data = Data(count: 4) let number: UInt32 = 0x01_02_03_04 let expectedData = Data(bytes: [0x04, 0x03, 0x02, 0x01]) try! data.set(number, at: 0, byteOrder: .littleEndian) XCTAssert(data == expectedData, "Method should write swapped bytes in memory on little-endian system (most significant digit byte at the end)") } func testSetNumberByteOrderRemainsSameOnBigEndianSystem() { var data = Data(count: 4) let number: UInt32 = 0x01_02_03_04 let expectedData = Data(bytes: [0x01, 0x02, 0x03, 0x04]) try! data.set(number, at: 0, byteOrder: .bigEndian) XCTAssert(data == expectedData, "Method should write less significant digit byte at the end of data's memory chunk") } // MARK: Test set(_ array: [T], at offset: Data.Index, capacity: Int) throws func testSetArrayCannotSetArrayWithLessCapacityThanArrayCount() { var data = Data(count: 6) let array = Array(repeating: 0, count: 4) XCTAssertThrowsError(try data.set(array, at: 0, capacity: 3)) { error in switch error { case let PackError.invalidValueLength(offset, providedValueLength, allowedLength) where offset == 0 && providedValueLength > allowedLength: break default: XCTFail("Unexpected error thrown") } } } func testSetArrayCannotSetValuesOutOfDataUpperBound() { var data = Data(count: 10) let array = Array(repeating: 0, count: 2) XCTAssertThrowsError(try data.set(array, at: 0, capacity: 16)) { error in switch error { case let PackError.valueSizeOutOfBounds(offset, size, upperBound) where offset == 0 && offset + size > upperBound: break default: XCTFail("Unexpected error thrown") } } } func testSetArrayDidSetValuesAtOffset() { var data = Data(count: 6) let array: [UInt8] = [0x01, 0x02, 0x03, 0x04] let expectedData = Data(bytes: [0x00, 0x01, 0x02, 0x03, 0x04, 0x00]) try! data.set(array, at: 1, capacity: 4) XCTAssert(data == expectedData, "Method should write array values at specified offset") } // MARK: Test set(_ string: String, at offset: Data.Index, length: Int) throws func testSetStringCannotSetNonASCIIString() { var data = Data(count: 10) XCTAssertThrowsError(try data.set("💩", at: 0, length: 4)) { error in switch error { case let PackError.invalidStringEncoding(offset, string) where offset == 0 && string == "💩": break default: XCTFail("Unexpected error thrown") } } } func testSetStringCanntSetTooLongString() { var data = Data(count: 5) XCTAssertThrowsError(try data.set("abcdef", at: 0, length: 6)) { error in switch error { case let PackError.valueSizeOutOfBounds(offset, size, upperBound) where offset == 0 && offset + size > upperBound: break default: XCTFail("Unexpected error thrown") } } } func testSetStringDidSetNullTerminatedStringAtOffset() { var data = Data(bytes: Array(repeating: 0xFF, count: 5)) let expectedData = Data(bytes: [0xFF, 0x61, 0x62, 0x63, 0x00]) try! data.set("abc", at: 1, length: 4) XCTAssert(data == expectedData, "Method should write ASCII string bytes at specified offset with null byte at the end") } func testSetStringDidSetEmptyString() { var data = Data(bytes: Array(repeating: 0xFF, count: 5)) let expectedData = Data(bytes: [0xFF, 0xFF, 0x00, 0xFF, 0xFF]) try! data.set("", at: 2, length: 3) XCTAssert(data == expectedData, "Method should accept empty string as valid ASCII encoded string and add null termination") } // MARK: Test set(_ enumeration: T, at offset: Data.Index) throws func testSetEnumerationDidSetProperRawValueAtOffset() { var data = Data(bytes: Array(repeating: 0x00, count: 4)) let expectedData = Data(bytes: [0x00, 0x00, 0x00, MAVVTOLState.fw.rawValue]) try! data.set(MAVVTOLState.fw, at: 3) XCTAssert(data == expectedData, "Method should set appropriate case raw value at specified offset") } // MARK: - Test write-read methods calls return consistent values func testGetNumberDidGetSameValuePreviouslySetWithSetNumberCall() { var data = Data(count: 10) let offset = 1 let number = UInt64(0x01_02_03_04_05_06_07_08) try! data.set(number, at: offset) let receivedNumber: UInt64 = try! data.number(at: offset) XCTAssert(receivedNumber == number) } func testGetArrayDidGetSameValuePreviouslySetWithSetArrayCall() { var data = Data(count: 10) let offset = 1 let array: [UInt8] = [0x00, 0x01, 0x02, 0x03, 0x04] try! data.set(array, at: offset, capacity: 5) let receivedArray: [UInt8] = try! data.array(at: offset, capacity: 5) XCTAssert(receivedArray == array) } func testGetStringDidGetSameValuePreviouslySetWithSetStringCall() { var data = Data(count: 10) let offset = 1 let string = "test" try! data.set(string, at: offset, length: 9) let receivedString = try! data.string(at: offset, length: 9) XCTAssert(receivedString == string) } func testGetEnumerationDidGetSameValuePreviouslySetWithSetEnumerationCall() { var data = Data(count: 10) let offset = 1 let mavvtolState = MAVVTOLState.fw try! data.set(mavvtolState, at: offset) let receivedMavvtolState: MAVVTOLState = try! data.enumeration(at: offset) XCTAssert(receivedMavvtolState == mavvtolState) } }