From ccaedb975ea0be755aa8012925b3642786d09573 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Tue, 10 Dec 2024 11:51:09 +0800 Subject: [PATCH] update codec coverage (#245) * update Codec test * update blstest * update jam test * update encoder test * update encode & decode * update Results test * update codec * update todo & test * update test * udpate decoder * update codec test * update encode & decode * update codec * update more test * update encode & decode * update test --- Codec/Sources/Codec/JamEncoder.swift | 26 ++ Codec/Tests/CodecTests/DecoderTests.swift | 236 ++++++++++ Codec/Tests/CodecTests/EncodeSizeTests.swift | 92 ++++ Codec/Tests/CodecTests/EncoderTests.swift | 423 +++++++++++++++++- .../Tests/CodecTests/IntegerCodecTests.swift | 5 + Codec/Tests/CodecTests/ResultTests.swift | 87 ++++ .../CodecTests/SortedKeyValuesTests.swift | 15 + Codec/Tests/CodecTests/SortedSetTests.swift | 3 + Utils/Tests/UtilsTests/Crypto/BLSTests.swift | 2 +- .../xcshareddata/swiftpm/Package.resolved | 22 +- 10 files changed, 906 insertions(+), 5 deletions(-) create mode 100644 Codec/Tests/CodecTests/DecoderTests.swift create mode 100644 Codec/Tests/CodecTests/EncodeSizeTests.swift create mode 100644 Codec/Tests/CodecTests/ResultTests.swift create mode 100644 Codec/Tests/CodecTests/SortedKeyValuesTests.swift diff --git a/Codec/Sources/Codec/JamEncoder.swift b/Codec/Sources/Codec/JamEncoder.swift index 2cc3e467..756148df 100644 --- a/Codec/Sources/Codec/JamEncoder.swift +++ b/Codec/Sources/Codec/JamEncoder.swift @@ -85,6 +85,16 @@ private class EncodeContext: Encoder { } } + fileprivate func encodeOptional(_ value: Encodable) throws { + let mirror = Mirror(reflecting: value) + if let someValue = mirror.children.first?.value as? Encodable { + data.append(UInt8(1)) // Encode presence flag + try encode(someValue) // Encode the unwrapped value + } else { + data.append(UInt8(0)) // Encode absence flag + } + } + fileprivate func encode(_ value: some Encodable) throws { if let value = value as? Data { encodeData(value, lengthPrefix: true) @@ -94,6 +104,8 @@ private class EncodeContext: Encoder { encodeData(value.data, lengthPrefix: false) } else if let value = value as? [Encodable] { try encodeArray(value) + } else if Mirror(reflecting: value).displayStyle == .optional { + try encodeOptional(value) } else { try value.encode(to: self) } @@ -489,6 +501,20 @@ private struct JamSingleValueEncodingContainer: SingleValueEncodingContainer { encoder.encodeInt(value) } + mutating func encode(_: Double) throws { + throw EncodingError.invalidValue( + Double.self, + EncodingError.Context(codingPath: codingPath, debugDescription: "Double is not supported") + ) + } + + mutating func encode(_: Float) throws { + throw EncodingError.invalidValue( + Float.self, + EncodingError.Context(codingPath: codingPath, debugDescription: "Float is not supported") + ) + } + mutating func encode(_ value: some Encodable) throws { try encoder.encode(value) } diff --git a/Codec/Tests/CodecTests/DecoderTests.swift b/Codec/Tests/CodecTests/DecoderTests.swift new file mode 100644 index 00000000..277ca2ab --- /dev/null +++ b/Codec/Tests/CodecTests/DecoderTests.swift @@ -0,0 +1,236 @@ +import Foundation +import Testing + +@testable import Codec + +struct DecoderTests { + @Test func decodeOverflowLength() throws { + let overflowLength = UInt64.max + let lengthData = Data([241]) + withUnsafeBytes(of: overflowLength) { Data($0) } + let data = Data(repeating: 0, count: 8) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(Data.self, from: lengthData + data) + } + } + + @Test func decodeUnsupportedType() throws { + struct UnsupportedType: Codable {} + let unsupportedEncodedData = Data([0]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(UnsupportedType.self, from: unsupportedEncodedData) + } + } + + @Test func decodeCorruptedString() throws { + let invalidUTF8Data = Data([0x02, 0xC3, 0x28]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(String.self, from: invalidUTF8Data) + } + } + + @Test func decodeCorruptedNumericData() throws { + let corruptedNumericData = Data([0xFF, 0xFF, 0xFF, 0xFF]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(Int.self, from: corruptedNumericData) + } + } + + @Test func decodeIncorrectEncoding() throws { + let incorrectEncodedData = Data([255, 255, 255]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(Int.self, from: incorrectEncodedData) + } + } + + @Test func decodeInvalidKeyedContainer() throws { + let invalidKeyedData = Data([1, 1, 0, 0, 0, 0, 0, 0, 0]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([String: Int].self, from: invalidKeyedData) + } + } + + @Test func decodeInvalidUnkeyedContainer() throws { + let invalidUnkeyedData = Data([5, 104, 101, 108]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([Int].self, from: invalidUnkeyedData) + } + struct UnkeyedDouble: Codable { + var doubleValue: Double + } + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(UnkeyedDouble.self, from: invalidUnkeyedData) + } + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(UnkeyedDouble?.self, from: invalidUnkeyedData) + } + struct UnkeyedFloat: Codable { + var floatValue: Float + } + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(UnkeyedFloat?.self, from: invalidUnkeyedData) + } + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(UnkeyedFloat.self, from: invalidUnkeyedData) + } + } + + @Test func decodeCorruptedNestedStructure() throws { + let corruptedEncodedData = Data([2, 3, 0, 1, 2]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([String: [Int]].self, from: corruptedEncodedData) + } + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([String: [Int]]?.self, from: corruptedEncodedData) + } + } + + @Test func decodeEmptyDataForArray() throws { + let emptyData = Data() + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([Int].self, from: emptyData) + } + } + + @Test func decodeUnsupportedArrayFormat() throws { + let unsupportedArrayFormat = Data([5, 0, 0, 0, 0, 0, 0, 0]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([Int].self, from: unsupportedArrayFormat) + } + } + + @Test func decodeLargeArray() throws { + let maxLength = 0xFFFF_FFFF + let encoded = try JamEncoder.encode(maxLength) + var data = Data() + data.append(contentsOf: encoded) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([Int].self, from: Data(data + Data(repeating: 0, count: maxLength))) + } + } + + @Test func decodeInvalidInt() throws { + let encoded16 = try JamEncoder.encode(0xFFFF_FFFF) + #expect(throws: Error.self) { + _ = try JamDecoder.decode(UInt16.self, from: encoded16) + } + + let maxLength: UInt64 = 0x1_0000_0000 + let encoded = try JamEncoder.encode(maxLength) + #expect(encoded.count == 8) + let decoded = try JamDecoder.decode(UInt64.self, from: encoded) + #expect(decoded == maxLength) + let lengthData = Data([241, 0, 0, 0, 0, 0, 0, 0]) + let data = Data(repeating: 0, count: Int(maxLength)) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(Data.self, from: lengthData + data) + } + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode([UInt8].self, from: lengthData + data) + } + } + + @Test func decodeData() throws { + let encodedData = Data([3, 0, 1, 2]) + let decoded = try JamDecoder.decode(Data.self, from: encodedData) + + #expect(decoded == Data([0, 1, 2])) + } + + @Test func decodeBool() throws { + let encodedTrue = Data([1]) + let encodedFalse = Data([0]) + + let decodedTrue = try JamDecoder.decode(Bool.self, from: encodedTrue) + let decodedFalse = try JamDecoder.decode(Bool.self, from: encodedFalse) + + #expect(decodedTrue == true) + #expect(decodedFalse == false) + } + + @Test func decodeString() throws { + let encoded = Data([5, 104, 101, 108, 108, 111]) + let decoded = try JamDecoder.decode(String.self, from: encoded) + #expect(decoded == "hello") + + #expect(throws: Error.self) { + _ = try JamDecoder.decode(String.self, from: Data([6, 104, 101, 108, 108, 111])) + } + } + + @Test func decodeArray() throws { + let encoded = Data([3, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0]) + let decoded = try JamDecoder.decode([Int].self, from: encoded) + + #expect(decoded == [1, 2, 3]) + } + + @Test func decodeInt() throws { + let encoded = Data([1, 0, 0, 0, 0, 0, 0, 0]) + let decoded = try JamDecoder.decode(Int.self, from: encoded) + + #expect(decoded == 1) + } + + @Test func decodeOptional() throws { + let encodedSome = Data([1, 1, 0, 0, 0, 0, 0, 0, 0]) + let encodedNone = Data([0]) + + let decodedSome = try JamDecoder.decode(Int?.self, from: encodedSome) + let decodedNone = try JamDecoder.decode(Int?.self, from: encodedNone) + + #expect(decodedSome == .some(1)) + #expect(decodedNone == .none) + } + + @Test func decodeFixedWidthInteger() throws { + var encodedInt8 = Data([251]) + let encodedUInt64 = Data([21, 205, 91, 7, 0, 0, 0, 0]) + + let decodedInt8 = try JamDecoder.decode(Int8.self, from: encodedInt8) + let decodedUInt64 = try JamDecoder.decode(UInt64.self, from: encodedUInt64) + + #expect(decodedInt8 == -5) + #expect(decodedUInt64 == 123_456_789) + #expect(throws: Error.self) { + _ = try encodedInt8.read(length: 8) + } + } + + @Test func decodeInvalidData() throws { + let invalidEncodedData = Data([0, 0, 0, 123]) + #expect(throws: Error.self) { + _ = try JamDecoder.decode(Int8.self, from: invalidEncodedData) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode(Double.self, from: Data()) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode(Float.self, from: Data()) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode(Int?.self, from: Data()) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode(Int?.self, from: Data([2])) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode(String.self, from: Data([1, 2, 3])) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode([Int].self, from: Data([21, 205, 91, 7, 0, 0, 0, 0])) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode([Data].self, from: Data([21, 205, 91, 7, 0, 0, 0, 0])) + } + #expect(throws: Error.self) { + _ = try JamDecoder.decode(Data.self, from: Data([21, 205, 91, 7, 0, 0, 0, 0])) + } + } + + @Test func decodeEmptyString() throws { + let invalidEncodedData = Data() + #expect(throws: Error.self) { + _ = try JamDecoder.decode(String.self, from: invalidEncodedData) + } + } +} diff --git a/Codec/Tests/CodecTests/EncodeSizeTests.swift b/Codec/Tests/CodecTests/EncodeSizeTests.swift new file mode 100644 index 00000000..8ad1caf3 --- /dev/null +++ b/Codec/Tests/CodecTests/EncodeSizeTests.swift @@ -0,0 +1,92 @@ +import Foundation +import Testing + +@testable import Codec + +extension Int: EncodedSize, @retroactive Error { + public var encodedSize: Int { + MemoryLayout.size + } + + public static var encodeedSizeHint: Int? { + MemoryLayout.size + } +} + +struct EncodeSizeTests { + @Test + func encodeFixedWidthInteger() throws { + #expect(Int(42).encodedSize == MemoryLayout.size) + #expect(Int8(-5).encodedSize == MemoryLayout.size) + #expect(UInt32(123_456).encodedSize == MemoryLayout.size) + #expect(Int.encodeedSizeHint == MemoryLayout.size) + #expect(Int8.encodeedSizeHint == MemoryLayout.size) + #expect(UInt32.encodeedSizeHint == MemoryLayout.size) + } + + @Test + func encodeBool() throws { + #expect(true.encodedSize == 1) + #expect(false.encodedSize == 1) + #expect(Bool.encodeedSizeHint == 1) + } + + @Test + func encodeStringAndData() throws { + #expect("test".encodedSize == 4) + #expect("".encodedSize == 0) + #expect(Data([0x01, 0x02, 0x03]).encodedSize == 4) + #expect(Data().encodedSize == 1) + #expect(String.encodeedSizeHint == nil) + #expect(Data.encodeedSizeHint == nil) + } + + @Test + func encodeArrayAndSet() throws { + let intArray = [1, 2, 3] + let emptyArray: [Int] = [] + let intSet: Set = [4, 5, 6] + let emptySet: Set = [] + + #expect(intArray.encodedSize == UInt32(3).variableEncodingLength() + 3 * MemoryLayout.size) + #expect(emptyArray.encodedSize == UInt32(0).variableEncodingLength()) + #expect(intSet.encodedSize >= UInt32(3).variableEncodingLength()) + #expect(emptySet.encodedSize == UInt32(0).variableEncodingLength()) + #expect([Int].encodeedSizeHint == nil) + #expect(Set.encodeedSizeHint == nil) + } + + @Test + func encodeDictionary() throws { + let dict: [Int: String] = [1: "one", 2: "two"] + let emptyDict: [Int: String] = [:] + + let expectedSize = UInt32(2).variableEncodingLength() + + 1.encodedSize + "one".encodedSize + + 1.encodedSize + "two".encodedSize + + #expect(dict.encodedSize == expectedSize) + #expect(emptyDict.encodedSize == UInt32(0).variableEncodingLength()) + #expect([Int: String].encodeedSizeHint == nil) + } + + @Test + func encodeOptional() throws { + let someValue: Int? = 42 + let noneValue: Int? = nil + + #expect(someValue.encodedSize == 1 + MemoryLayout.size) + #expect(noneValue.encodedSize == 1) + #expect(Int?.encodeedSizeHint == nil) + } + + @Test + func encodeResult() throws { + let successResult: Result = .success("OK") + let failureResult: Result = .failure(404) + + #expect(successResult.encodedSize == 1 + "OK".encodedSize) + #expect(failureResult.encodedSize == 1 + MemoryLayout.size) + #expect(Result.encodeedSizeHint == nil) + } +} diff --git a/Codec/Tests/CodecTests/EncoderTests.swift b/Codec/Tests/CodecTests/EncoderTests.swift index 021bbaf5..0996ea9c 100644 --- a/Codec/Tests/CodecTests/EncoderTests.swift +++ b/Codec/Tests/CodecTests/EncoderTests.swift @@ -3,11 +3,430 @@ import Testing @testable import Codec -// TODO: add more tests struct EncoderTests { + struct TestStruct: Codable { + let intValue: Int + let optionalIntValue: Int? + let optionalIntValue2: Int? + let stringValue: String + let optionalStringValue: String? + let optionalStringValue2: String? + let boolValue: Bool + let optionalBoolValue: Bool? + let optionalBoolValue2: Bool? + let uintValue: UInt + let optionalUintValue: UInt? + let optionalUintValue2: UInt? + let int8Value: Int8 + let optionalInt8Value: Int8? + let optionalInt8Value2: Int8? + let uint8Value: UInt8 + let optionalUint8Value: UInt8? + let optionalUint8Value2: UInt8? + let int16Value: Int16 + let optionalInt16Value: Int16? + let optionalInt16Value2: Int16? + let uint16Value: UInt16 + let optionalUint16Value: UInt16? + let optionalUint16Value2: UInt16? + let int32Value: Int32 + let optionalInt32Value: Int32? + let optionalInt32Value2: Int32? + let uint32Value: UInt32 + let optionalUint32Value: UInt32? + let optionalUint32Value2: UInt32? + let int64Value: Int64 + let optionalInt64Value: Int64? + let optionalInt64Value2: Int64? + let uint64Value: UInt64 + let optionalUint64Value: UInt64? + let optionalUint64Value2: UInt64? + } + + @Test + func encodeDecodeFullStruct() throws { + let testObject = TestStruct( + intValue: 42, + optionalIntValue: 42, + optionalIntValue2: nil, + stringValue: "hello", + optionalStringValue: nil, + optionalStringValue2: "world", + boolValue: true, + optionalBoolValue: nil, + optionalBoolValue2: false, + uintValue: 99, + optionalUintValue: nil, + optionalUintValue2: 100, + int8Value: -12, + optionalInt8Value: nil, + optionalInt8Value2: 120, + uint8Value: 255, + optionalUint8Value: nil, + optionalUint8Value2: 128, + int16Value: -1234, + optionalInt16Value: nil, + optionalInt16Value2: 1234, + uint16Value: 65535, + optionalUint16Value: nil, + optionalUint16Value2: 32767, + int32Value: -123_456, + optionalInt32Value: nil, + optionalInt32Value2: 123_456, + uint32Value: 4_294_967_295, + optionalUint32Value: nil, + optionalUint32Value2: 2_147_483_647, + int64Value: -1_234_567_890_123, + optionalInt64Value: nil, + optionalInt64Value2: 1_234_567_890_123, + uint64Value: 18_446_744_073_709_551_615, + optionalUint64Value: nil, + optionalUint64Value2: 9_223_372_036_854_775_807 + ) + + let encoded = try JamEncoder.encode(testObject) + #expect(encoded.count > 0) + + let decoded = try JamDecoder.decode(TestStruct.self, from: encoded) + + #expect(decoded.intValue == testObject.intValue) + #expect(decoded.optionalIntValue == testObject.optionalIntValue) + #expect(decoded.optionalIntValue2 == testObject.optionalIntValue2) + #expect(decoded.stringValue == testObject.stringValue) + #expect(decoded.optionalStringValue == testObject.optionalStringValue) + #expect(decoded.optionalStringValue2 == testObject.optionalStringValue2) + #expect(decoded.boolValue == testObject.boolValue) + #expect(decoded.optionalBoolValue == testObject.optionalBoolValue) + #expect(decoded.optionalBoolValue2 == testObject.optionalBoolValue2) + #expect(decoded.uintValue == testObject.uintValue) + #expect(decoded.optionalUintValue == testObject.optionalUintValue) + #expect(decoded.optionalUintValue2 == testObject.optionalUintValue2) + #expect(decoded.int8Value == testObject.int8Value) + #expect(decoded.optionalInt8Value == testObject.optionalInt8Value) + #expect(decoded.optionalInt8Value2 == testObject.optionalInt8Value2) + #expect(decoded.uint8Value == testObject.uint8Value) + #expect(decoded.optionalUint8Value == testObject.optionalUint8Value) + #expect(decoded.optionalUint8Value2 == testObject.optionalUint8Value2) + #expect(decoded.int16Value == testObject.int16Value) + #expect(decoded.optionalInt16Value == testObject.optionalInt16Value) + #expect(decoded.optionalInt16Value2 == testObject.optionalInt16Value2) + #expect(decoded.uint16Value == testObject.uint16Value) + #expect(decoded.optionalUint16Value == testObject.optionalUint16Value) + #expect(decoded.optionalUint16Value2 == testObject.optionalUint16Value2) + #expect(decoded.int32Value == testObject.int32Value) + #expect(decoded.optionalInt32Value == testObject.optionalInt32Value) + #expect(decoded.optionalInt32Value2 == testObject.optionalInt32Value2) + #expect(decoded.uint32Value == testObject.uint32Value) + #expect(decoded.optionalUint32Value == testObject.optionalUint32Value) + #expect(decoded.optionalUint32Value2 == testObject.optionalUint32Value2) + #expect(decoded.int64Value == testObject.int64Value) + #expect(decoded.optionalInt64Value == testObject.optionalInt64Value) + #expect(decoded.optionalInt64Value2 == testObject.optionalInt64Value2) + #expect(decoded.uint64Value == testObject.uint64Value) + #expect(decoded.optionalUint64Value == testObject.optionalUint64Value) + #expect(decoded.optionalUint64Value2 == testObject.optionalUint64Value2) + } + + @Test func encodeOpStruct() throws { + struct DoubleStruct: Codable { + let value: Double + } + struct OpDoubleStruct: Codable { + let value: Double? + } + struct FloatStruct: Codable { + let value: Float + } + struct OpFloatStruct: Codable { + let value: Float? + } + #expect(throws: Error.self) { + _ = try JamEncoder.encode(DoubleStruct(value: 0)) + } + #expect(throws: Error.self) { + _ = try JamEncoder.encode(OpDoubleStruct(value: 0)) + } + #expect(throws: Error.self) { + _ = try JamEncoder.encode(OpFloatStruct(value: 0)) + } + #expect(throws: Error.self) { + _ = try JamEncoder.encode(FloatStruct(value: 0)) + } + + struct DoubleTest: Encodable { + let doubleValue: Double + func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(doubleValue) + } + } + #expect(throws: Error.self) { + _ = try JamEncoder.encode(DoubleTest(doubleValue: 0)) + } + + struct FloatTest: Encodable { + let floatValue: Float + func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(floatValue) + } + } + #expect(throws: Error.self) { + _ = try JamEncoder.encode(FloatTest(floatValue: 0)) + } + } + + struct UnkeyedTest: Codable { + var boolValue: Bool + let stringValue: String + let intValue: Int + let int8Value: Int8 + let int16Value: Int16 + let int32Value: Int32 + let int64Value: Int64 + let uintValue: UInt + let uint8Value: UInt8 + let uint16Value: UInt16 + let uint32Value: UInt32 + let uint64Value: UInt64 + let dataValue: Data + let nestedValues: [UnkeyedTest] + + func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(boolValue) + try container.encode(stringValue) + try container.encode(intValue) + try container.encode(int8Value) + try container.encode(int16Value) + try container.encode(int32Value) + try container.encode(int64Value) + try container.encode(uintValue) + try container.encode(uint8Value) + try container.encode(uint16Value) + try container.encode(uint32Value) + try container.encode(uint64Value) + try container.encode(dataValue) + try container.encode(nestedValues) + } + + init(boolValue: Bool = false, + stringValue: String = "", + intValue: Int = 0, + int8Value: Int8 = 0, + int16Value: Int16 = 0, + int32Value: Int32 = 0, + int64Value: Int64 = 0, + uintValue: UInt = 0, + uint8Value: UInt8 = 0, + uint16Value: UInt16 = 0, + uint32Value: UInt32 = 0, + uint64Value: UInt64 = 0, + dataValue: Data = Data(), + nestedValues: [UnkeyedTest] = []) + { + self.boolValue = boolValue + self.stringValue = stringValue + self.intValue = intValue + self.int8Value = int8Value + self.int16Value = int16Value + self.int32Value = int32Value + self.int64Value = int64Value + self.uintValue = uintValue + self.uint8Value = uint8Value + self.uint16Value = uint16Value + self.uint32Value = uint32Value + self.uint64Value = uint64Value + self.dataValue = dataValue + self.nestedValues = nestedValues + } + + init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + boolValue = try container.decode(Bool.self) + stringValue = try container.decode(String.self) + intValue = try container.decode(Int.self) + int8Value = try container.decode(Int8.self) + int16Value = try container.decode(Int16.self) + int32Value = try container.decode(Int32.self) + int64Value = try container.decode(Int64.self) + uintValue = try container.decode(UInt.self) + uint8Value = try container.decode(UInt8.self) + uint16Value = try container.decode(UInt16.self) + uint32Value = try container.decode(UInt32.self) + uint64Value = try container.decode(UInt64.self) + dataValue = try container.decode(Data.self) + nestedValues = try container.decode([UnkeyedTest].self) + } + } + + @Test func testUnkeyedContainer() throws { + let testData = UnkeyedTest( + boolValue: true, + stringValue: "Hello", + intValue: 42, + int8Value: Int8(8), + int16Value: Int16(16), + int32Value: Int32(32), + int64Value: Int64(64), + uintValue: UInt(128), + uint8Value: UInt8(8), + uint16Value: UInt16(16), + uint32Value: UInt32(32), + uint64Value: UInt64(64), + dataValue: Data([0x01, 0x02, 0x03]), + nestedValues: [ + UnkeyedTest( + boolValue: false, + stringValue: "Nested", + intValue: 99, + int8Value: 1, + int16Value: 2, + int32Value: 3, + int64Value: 4, + uintValue: 5, + uint8Value: 6, + uint16Value: 7, + uint32Value: 8, + uint64Value: 9, + dataValue: Data([0x01]), + nestedValues: [] + ), + ] + ) + + let encoded = try JamEncoder.encode(testData) + #expect(encoded.count > 0) + let decoded = try JamDecoder.decode(UnkeyedTest.self, from: encoded, withConfig: testData) + #expect(testData.intValue == decoded.intValue) + #expect(testData.dataValue == decoded.dataValue) + } + + @Test func encodeDouble() throws { + #expect(throws: Error.self) { + _ = try JamEncoder.encode(Double(1.0)) + } + } + + @Test func encodeFloat() throws { + #expect(throws: Error.self) { + _ = try JamEncoder.encode(Float(1.0)) + } + } + @Test func encodeData() throws { let data = Data([0, 1, 2]) let encoded = try JamEncoder.encode(data) - #expect(encoded == Data([3, 0, 1, 2])) + #expect(encoded == Data([3, 0, 1, 2])) // Length prefix of 3 bytes + } + + @Test func encodeBool() throws { + let trueValue = true + let falseValue = false + + let encodedTrue = try JamEncoder.encode(trueValue) + let encodedFalse = try JamEncoder.encode(falseValue) + + #expect(encodedTrue == Data([1])) // True encoded as 1 byte + #expect(encodedFalse == Data([0])) // False encoded as 1 byte + } + + @Test func encodeString() throws { + let stringValue = "hello" + let encoded = try JamEncoder.encode(stringValue) + #expect(encoded == Data([5, 104, 101, 108, 108, 111])) + } + + @Test func encodeArray() throws { + let arrayValue: [Int] = [1, 2, 3] + let encoded = try JamEncoder.encode(arrayValue) + #expect(encoded == Data([ + 3, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ])) // Array with length prefix and encoded integers + } + + @Test func encodeOptional() throws { + let optionalValue: Int? = 1 + let encodedSome = try JamEncoder.encode(optionalValue) + + let encodedNone = try JamEncoder.encode(Int?.none) + + #expect(encodedSome == Data([1, 1, 0, 0, 0, 0, 0, 0, 0])) // Optional with value encoded + #expect(encodedNone == Data([0])) // None encoded as 1 byte (0) + } + + @Test func encodeInt() throws { + let intValue = 123_456_789 + let encoded = try JamEncoder.encode(intValue) + + #expect(encoded == Data([21, 205, 91, 7, 0, 0, 0, 0])) // Integer with encoded size + } + + @Test func encodeFixedWidthInteger() throws { + let int8Value: Int8 = -5 + let uint64Value: UInt64 = 123_456_789 + + let encodedInt8 = try JamEncoder.encode(int8Value) + let encodedUInt64 = try JamEncoder.encode(uint64Value) + + #expect(encodedInt8 == Data([251])) // Int8 encoding (signed byte) + #expect(encodedUInt64 == Data([21, 205, 91, 7, 0, 0, 0, 0])) // UInt64 encoding + } + + @Test func encodeFixedMoreTests() throws { + let int16Value: Int16 = 1 + let int32Value: Int32 = 1 + let int64Value: Int64 = 1 + let uintValue: UInt = 65535 + let uint16Value: UInt16 = 65535 + let nilValue: Int64? = nil + + let encodedNil = try JamEncoder.encode(nilValue) + #expect(encodedNil == Data([0])) + try #expect(JamDecoder.decode(Int64?.self, from: encodedNil) == nilValue) + + let encodedInt16 = try JamEncoder.encode(int16Value) + #expect(encodedInt16 == Data([1, 0])) + try #expect(JamDecoder.decode(Int16.self, from: encodedInt16) == int16Value) + + let encodedInt32 = try JamEncoder.encode(int32Value) + #expect(encodedInt32 == Data([1, 0, 0, 0])) + try #expect(JamDecoder.decode(Int32.self, from: encodedInt32) == int32Value) + + let encodedInt64 = try JamEncoder.encode(int64Value) + #expect(encodedInt64 == Data([1, 0, 0, 0, 0, 0, 0, 0])) + try #expect(JamDecoder.decode(Int64.self, from: encodedInt64) == int64Value) + + let encodedUInt = try JamEncoder.encode(uintValue) + #expect(encodedUInt == Data([255, 255, 0, 0, 0, 0, 0, 0])) + try #expect(JamDecoder.decode(UInt.self, from: encodedUInt) == uintValue) + + let encodedUInt16 = try JamEncoder.encode(uint16Value) + #expect(encodedUInt16 == Data([255, 255])) + try #expect(JamDecoder.decode(UInt16.self, from: encodedUInt16) == uint16Value) } } diff --git a/Codec/Tests/CodecTests/IntegerCodecTests.swift b/Codec/Tests/CodecTests/IntegerCodecTests.swift index 0aacae8c..69836b82 100644 --- a/Codec/Tests/CodecTests/IntegerCodecTests.swift +++ b/Codec/Tests/CodecTests/IntegerCodecTests.swift @@ -111,5 +111,10 @@ import Testing #expect(data.decode() == 0x0E) #expect(data.decode() == 0x0F) #expect(data.decode() == nil) + #expect(data.decode(length: 20) as UInt64? == nil) + #expect(data.decode(length: -1) as UInt64? == nil) + var emptyBytes: [UInt8] = [] + let result = IntegerCodec.decode { emptyBytes.popLast() } + #expect(result == nil) } } diff --git a/Codec/Tests/CodecTests/ResultTests.swift b/Codec/Tests/CodecTests/ResultTests.swift new file mode 100644 index 00000000..5a220dca --- /dev/null +++ b/Codec/Tests/CodecTests/ResultTests.swift @@ -0,0 +1,87 @@ +import Foundation +import Testing + +@testable import Codec + +struct ResultCodingTests { + enum ResultError: Error, Codable { + case unknownError(String) + } + + enum MyResult: Codable { + case success(Success) + case failure(ResultError) + + private enum CodingKeys: String, CodingKey { + case success, failure + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let value = try container.decode(Success.self, forKey: .success) + self = .success(value) + } + + // Encodable implementation + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + switch self { + case let .success(value): + try container.encode(value, forKey: .success) + case let .failure(error): + try container.encode(error, forKey: .failure) + } + } + } + + struct TestStruct: Codable, Equatable { + let name: String + } + + @Test func structTests() throws { + let successResult: MyResult = .success(TestStruct(name: "Success")) + let failureResult: MyResult = .failure(.unknownError("Test Error")) + + let encodedSuccess = try JamEncoder.encode(successResult) + let encodedFailure = try JamEncoder.encode(failureResult) + + let decodedSuccess = try JamDecoder.decode(MyResult.self, from: encodedSuccess) + let decodedFailure = try JamDecoder.decode(MyResult.self, from: encodedFailure) + + #expect(decodedFailure != nil) + #expect(decodedSuccess != nil) + } + + @Test func result() throws { + let successResult: MyResult = .success("Success!") + let failureResult: MyResult = .failure(.unknownError("An unknown error occurred")) + + let encodedSuccess = try JamEncoder.encode(successResult) + let encodedFailure = try JamEncoder.encode(failureResult) + + let decodedSuccess = try JamDecoder.decode(MyResult.self, from: encodedSuccess) + let decodedFailure = try JamDecoder.decode(MyResult.self, from: encodedFailure) + #expect(decodedFailure != nil) + #expect(decodedSuccess != nil) + } + + @Test func variant() throws { + let successResult: Result = .success("Success!") + let failureResult: Result = .failure(0) + let encodedSuccess = try JamEncoder.encode(successResult) + let encodedFailure = try JamEncoder.encode(failureResult) + let invalidData0 = Data([0x00] + encodedSuccess) + let invalidData1 = Data([0x01] + encodedFailure) + // Invalid variant value (e.g. value 2) + let invalidData = Data([0x02] + "Invalid variant".utf8) + let decoded0 = try JamDecoder.decode(Result.self, from: invalidData0) + let decoded1 = try JamDecoder.decode(Result.self, from: invalidData1) + #expect(decoded0 != nil) + #expect(decoded1 != nil) + // Expect decoding to fail and return nil + #expect(throws: Error.self) { + _ = try JamDecoder.decode(Result.self, from: invalidData) + } + } +} diff --git a/Codec/Tests/CodecTests/SortedKeyValuesTests.swift b/Codec/Tests/CodecTests/SortedKeyValuesTests.swift new file mode 100644 index 00000000..4c45ba78 --- /dev/null +++ b/Codec/Tests/CodecTests/SortedKeyValuesTests.swift @@ -0,0 +1,15 @@ +import Foundation +import Testing + +@testable import Codec + +struct SortedKeyValuesTests { + @Test func encode() throws { + let testCase: SortedKeyValues = SortedKeyValues(alias: [1: 1, 2: 2, 3: 3]) + let encoded = try JamEncoder.encode(testCase) + #expect(encoded == Data([3, 1, 1, 2, 2, 3, 3])) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(SortedKeyValues.self, from: Data([3, 3, 3, 2, 2, 1, 1])) + } + } +} diff --git a/Codec/Tests/CodecTests/SortedSetTests.swift b/Codec/Tests/CodecTests/SortedSetTests.swift index 1e4b8a4b..80dfe27c 100644 --- a/Codec/Tests/CodecTests/SortedSetTests.swift +++ b/Codec/Tests/CodecTests/SortedSetTests.swift @@ -13,6 +13,9 @@ struct SortedSetTests { @Test func decode() throws { let decoded = try JamDecoder.decode(SortedSet.self, from: Data([3, 1, 2, 3])) #expect(decoded.alias == [1, 2, 3]) + #expect(throws: DecodingError.self) { + _ = try JamDecoder.decode(SortedSet.self, from: Data([3, 2, 1, 3])) + } } @Test func invalidData() throws { diff --git a/Utils/Tests/UtilsTests/Crypto/BLSTests.swift b/Utils/Tests/UtilsTests/Crypto/BLSTests.swift index c54f26e8..3c644f65 100644 --- a/Utils/Tests/UtilsTests/Crypto/BLSTests.swift +++ b/Utils/Tests/UtilsTests/Crypto/BLSTests.swift @@ -114,7 +114,7 @@ import Testing } @Test func PublicKey() throws { - let keyData1 = Data144.random() + let keyData1 = Data144() #expect(throws: Error.self) { _ = try BLS.PublicKey(data: keyData1) } diff --git a/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4463c998..bd080355 100644 --- a/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/boka.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "2856b6aedabfe15f31e49c84318b9d7a155b1858de6e4c24b935eed8adb6cc4c", + "originHash" : "8e21a58b6d7f842c098f4e974e374c6d0247726a1d3017dda720b3de822a747b", "pins" : [ { "identity" : "async-channels", @@ -73,6 +73,15 @@ "version" : "4.9.1" } }, + { + "identity" : "runtime", + "kind" : "remoteSourceControl", + "location" : "https://github.com/wickwirew/Runtime.git", + "state" : { + "revision" : "b90e9ab1c66a964a9edf32fe38ea2774c0e5821b", + "version" : "2.2.7" + } + }, { "identity" : "swift-algorithms", "kind" : "remoteSourceControl", @@ -163,6 +172,15 @@ "version" : "1.3.0" } }, + { + "identity" : "swift-json-schema", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ajevans99/swift-json-schema.git", + "state" : { + "revision" : "671f1777a96343b99435d2eb8af72bcb49d175bd", + "version" : "0.2.1" + } + }, { "identity" : "swift-log", "kind" : "remoteSourceControl", @@ -229,7 +247,7 @@ { "identity" : "swift-numerics", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-numerics", + "location" : "https://github.com/apple/swift-numerics.git", "state" : { "branch" : "main", "revision" : "e30276bff2ff5ed80566fbdca49f50aa160b0e83"