diff --git a/Sources/MongoSwift/BSON/BSON.swift b/Sources/MongoSwift/BSON/BSON.swift index fbc56e66d..f7e222be7 100644 --- a/Sources/MongoSwift/BSON/BSON.swift +++ b/Sources/MongoSwift/BSON/BSON.swift @@ -288,11 +288,11 @@ public enum BSON { case let .decimal128(d): return d case let .int64(i): - return BSONDecimal128(String(i)) + return try? BSONDecimal128(String(i)) case let .int32(i): - return BSONDecimal128(String(i)) + return try? BSONDecimal128(String(i)) case let .double(d): - return BSONDecimal128(String(d)) + return try? BSONDecimal128(String(d)) default: return nil } @@ -306,7 +306,7 @@ extension BSON { BSONNull.self, BSONUndefined.self, BSONMinKey.self, - MaxKey.self, + BSONMaxKey.self, BSONSymbol.self, Double.self, String.self, @@ -336,7 +336,7 @@ extension BSON { case .minKey: return BSONMinKey() case .maxKey: - return MaxKey() + return BSONMaxKey() case let .symbol(v): return v case let .double(v): diff --git a/Sources/MongoSwift/BSON/BSONDecoder.swift b/Sources/MongoSwift/BSON/BSONDecoder.swift index be479f6d7..96351c0ea 100644 --- a/Sources/MongoSwift/BSON/BSONDecoder.swift +++ b/Sources/MongoSwift/BSON/BSONDecoder.swift @@ -359,7 +359,10 @@ extension _BSONDecoder { return try Data(from: self) case .binary: let binary = try self.unboxCustom(value) { $0.binaryValue } - return binary.data + guard let data = binary.data.getBytes(at: 0, length: binary.data.writerIndex) else { + throw InternalError(message: "Cannot read \(binary.data.writerIndex) bytes from Binary.data") + } + return Data(data) case .base64: let base64Str = try self.unboxCustom(value) { $0.stringValue } diff --git a/Sources/MongoSwift/BSON/BSONDocument.swift b/Sources/MongoSwift/BSON/BSONDocument.swift index 78bd293b8..e87340b05 100644 --- a/Sources/MongoSwift/BSON/BSONDocument.swift +++ b/Sources/MongoSwift/BSON/BSONDocument.swift @@ -329,8 +329,8 @@ extension BSONDocument { return String(cString: json) } - /// Returns a copy of the raw BSON data for this `BSONDocument`, represented as `Data`. - public var rawBSON: Data { + /// Returns a copy of the raw BSON data for this `Document`, represented as `Data`. + public func toData() -> Data { let data = self.withBSONPointer { ptr in // swiftlint:disable:next force_unwrapping bson_get_data(ptr)! // documented as always returning a value. @@ -448,7 +448,7 @@ extension BSONDocument { self = newSelf } } catch { - fatalError("Failed to set the value for key \(key) to \(newValue ?? "nil"): \(error)") + fatalError("Failed to set the value for key \"\(key)\" to \(newValue ?? "nil"): \(error)") } } } diff --git a/Sources/MongoSwift/BSON/BSONDocumentIterator.swift b/Sources/MongoSwift/BSON/BSONDocumentIterator.swift index 2a3819d32..76e887df8 100644 --- a/Sources/MongoSwift/BSON/BSONDocumentIterator.swift +++ b/Sources/MongoSwift/BSON/BSONDocumentIterator.swift @@ -79,7 +79,7 @@ public class BSONDocumentIterator: IteratorProtocol { /// Returns the current value's type. Assumes the iterator is in a valid position. internal var currentType: BSONType { self.withBSONIterPointer { iterPtr in - BSONType(rawValue: bson_iter_type(iterPtr).rawValue) ?? .invalid + BSONType(rawValue: UInt8(bson_iter_type(iterPtr).rawValue)) ?? .invalid } } @@ -219,7 +219,7 @@ public class BSONDocumentIterator: IteratorProtocol { .int64: Int64.self, .decimal128: BSONDecimal128.self, .minKey: BSONMinKey.self, - .maxKey: MaxKey.self, + .maxKey: BSONMaxKey.self, .null: BSONNull.self, .undefined: BSONUndefined.self ] diff --git a/Sources/MongoSwift/BSON/BSONValue.swift b/Sources/MongoSwift/BSON/BSONValue.swift index c4163b5b9..9bfdf9ce3 100644 --- a/Sources/MongoSwift/BSON/BSONValue.swift +++ b/Sources/MongoSwift/BSON/BSONValue.swift @@ -1,8 +1,12 @@ import CLibMongoC import Foundation +import NIO + +/// This shared allocator instance should be used for all underlying `ByteBuffer` creation. +private let BSON_ALLOCATOR = ByteBufferAllocator() /// The possible types of BSON values and their corresponding integer values. -public enum BSONType: UInt32 { +public enum BSONType: UInt8 { /// An invalid type case invalid = 0x00 /// 64-bit binary floating point @@ -196,27 +200,61 @@ public struct BSONBinary: BSONValue, Equatable, Codable, Hashable { internal var bson: BSON { .binary(self) } /// The binary data. - public let data: Data + public let data: ByteBuffer /// The binary subtype for this data. - public let subtype: UInt8 + public let subtype: Subtype /// Subtypes for BSON Binary values. - public enum Subtype: UInt8 { + public struct Subtype: Equatable, Codable, Hashable, RawRepresentable { + // swiftlint:disable force_unwrapping /// Generic binary subtype - case generic, - /// A function - function, - /// Binary (old) - binaryDeprecated, - /// UUID (old) - uuidDeprecated, - /// UUID (RFC 4122) - uuid, - /// MD5 - md5, - /// User defined - userDefined = 0x80 + public static let generic = Subtype(rawValue: 0x00)! + /// A function + public static let function = Subtype(rawValue: 0x01)! + /// Binary (old) + public static let binaryDeprecated = Subtype(rawValue: 0x02)! + /// UUID (old) + public static let uuidDeprecated = Subtype(rawValue: 0x03)! + /// UUID (RFC 4122) + public static let uuid = Subtype(rawValue: 0x04)! + /// MD5 + public static let md5 = Subtype(rawValue: 0x05)! + /// Encrypted BSON value + public static let encryptedValue = Subtype(rawValue: 0x06)! + // swiftlint:enable force_unwrapping + + /// Subtype indicator value + public let rawValue: UInt8 + + /// Initializes a `Subtype` with a custom value. + /// Returns nil if rawValue within reserved range [0x07, 0x80). + public init?(rawValue: UInt8) { + guard !(rawValue > 0x06 && rawValue < 0x80) else { + return nil + } + self.rawValue = rawValue + } + + internal init(_ value: bson_subtype_t) { self.rawValue = UInt8(value.rawValue) } + + /// Initializes a `Subtype` with a custom value. This value must be in the range 0x80-0xFF. + /// - Throws: + /// - `InvalidArgumentError` if value passed is outside of the range 0x80-0xFF + public static func userDefined(_ value: Int) throws -> Subtype { + guard let byteValue = UInt8(exactly: value) else { + throw InvalidArgumentError(message: "Cannot represent \(value) as UInt8") + } + guard byteValue >= 0x80 else { + throw InvalidArgumentError( + message: "userDefined value must be greater than or equal to 0x80 got \(byteValue)" + ) + } + guard let subtype = Subtype(rawValue: byteValue) else { + throw InvalidArgumentError(message: "Cannot represent \(byteValue) as Subtype") + } + return subtype + } } /// Initializes a `BSONBinary` instance from a `UUID`. @@ -238,29 +276,24 @@ public struct BSONBinary: BSONValue, Equatable, Codable, Hashable { /// Initializes a `BSONBinary` instance from a `Data` object and a `UInt8` subtype. /// - Throws: /// - `InvalidArgumentError` if the provided data is incompatible with the specified subtype. - public init(data: Data, subtype: UInt8) throws { - if [Subtype.uuid.rawValue, Subtype.uuidDeprecated.rawValue].contains(subtype) && data.count != 16 { + public init(data: Data, subtype: Subtype) throws { + if [Subtype.uuid, Subtype.uuidDeprecated].contains(subtype) && data.count != 16 { throw InvalidArgumentError( message: "Binary data with UUID subtype must be 16 bytes, but data has \(data.count) bytes" ) } self.subtype = subtype - self.data = data - } - - /// Initializes a `BSONBinary` instance from a `Data` object and a `Subtype`. - /// - Throws: - /// - `InvalidArgumentError` if the provided data is incompatible with the specified subtype. - public init(data: Data, subtype: Subtype) throws { - try self.init(data: data, subtype: subtype.rawValue) + var buffer = BSON_ALLOCATOR.buffer(capacity: data.count) + buffer.writeBytes(data) + self.data = buffer } - /// Initializes a `BSONBinary` instance from a base64 `String` and a `UInt8` subtype. + /// Initializes a `BSONBinary` instance from a base64 `String` and a `Subtype`. /// - Throws: /// - `InvalidArgumentError` if the base64 `String` is invalid or if the provided data is /// incompatible with the specified subtype. - public init(base64: String, subtype: UInt8) throws { + public init(base64: String, subtype: Subtype) throws { guard let dataObj = Data(base64Encoded: base64) else { throw InvalidArgumentError( message: @@ -270,14 +303,6 @@ public struct BSONBinary: BSONValue, Equatable, Codable, Hashable { try self.init(data: dataObj, subtype: subtype) } - /// Initializes a `BSONBinary` instance from a base64 `String` and a `Subtype`. - /// - Throws: - /// - `InvalidArgumentError` if the base64 `String` is invalid or if the provided data is - /// incompatible with the specified subtype. - public init(base64: String, subtype: Subtype) throws { - try self.init(base64: base64, subtype: subtype.rawValue) - } - public init(from decoder: Decoder) throws { throw getDecodingError(type: BSONBinary.self, decoder: decoder) } @@ -287,9 +312,11 @@ public struct BSONBinary: BSONValue, Equatable, Codable, Hashable { } internal func encode(to document: inout BSONDocument, forKey key: String) throws { - let subtype = bson_subtype_t(UInt32(self.subtype)) - let length = self.data.count - let byteArray = [UInt8](self.data) + let subtype = bson_subtype_t(UInt32(self.subtype.rawValue)) + let length = self.data.writerIndex + guard let byteArray = self.data.getBytes(at: 0, length: length) else { + throw InternalError(message: "Cannot read \(length) bytes from Binary.data") + } try document.withMutableBSONPointer { docPtr in guard bson_append_binary(docPtr, key, Int32(key.utf8.count), subtype, byteArray, UInt32(length)) else { throw bsonTooLargeError(value: self, forKey: key) @@ -318,7 +345,7 @@ public struct BSONBinary: BSONValue, Equatable, Codable, Hashable { } let dataObj = Data(bytes: data, count: Int(length)) - return try self.init(data: dataObj, subtype: UInt8(subtype.rawValue)) + return try self.init(data: dataObj, subtype: Subtype(subtype)) }) } @@ -326,13 +353,16 @@ public struct BSONBinary: BSONValue, Equatable, Codable, Hashable { /// - Throws: /// - `InvalidArgumentError` if a non-UUID subtype is set on this `BSONBinary`. public func toUUID() throws -> UUID { - guard [Subtype.uuid.rawValue, Subtype.uuidDeprecated.rawValue].contains(self.subtype) else { + guard [Subtype.uuid, Subtype.uuidDeprecated].contains(self.subtype) else { throw InvalidArgumentError( message: "Expected a UUID binary subtype, got subtype \(self.subtype) instead." ) } - let data = self.data + guard let data = self.data.getBytes(at: 0, length: 16) else { + throw InternalError(message: "Unable to read 16 bytes from Binary.data") + } + let uuid: uuid_t = ( data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], @@ -487,16 +517,20 @@ public struct BSONDecimal128: BSONValue, Equatable, Codable, CustomStringConvert self.decimal128 = bsonDecimal } - /// Initializes a `BSONDecimal128` value from the provided `String`. Returns `nil` if the input is not a valid - /// Decimal128 string. - /// - SeeAlso: https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst - public init?(_ data: String) { - do { - let bsonType = try BSONDecimal128.toLibBSONType(data) - self.init(bsonDecimal: bsonType) - } catch { - return nil - } + /** + * Initializes a `BSONDecimal128` value from the provided `String`. + * + * - Parameters: + * - a BSONDecimal128 number as a string. + * + * - Throws: + * - A `InvalidArgumentError` if the string does not represent a BSONDecimal128 encodable value. + * + * - SeeAlso: https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst + */ + public init(_ data: String) throws { + let bsonType = try BSONDecimal128.toLibBSONType(data) + self.init(bsonDecimal: bsonType) } public init(from decoder: Decoder) throws { @@ -731,7 +765,7 @@ public struct BSONCode: BSONValue, Equatable, Codable, Hashable { } /// A struct to represent the BSON MaxKey type. -internal struct MaxKey: BSONValue, Equatable, Codable, Hashable { +internal struct BSONMaxKey: BSONValue, Equatable, Codable, Hashable { internal var bson: BSON { .maxKey } internal static var bsonType: BSONType { .maxKey } @@ -748,7 +782,7 @@ internal struct MaxKey: BSONValue, Equatable, Codable, Hashable { internal init() {} internal init(from decoder: Decoder) throws { - throw getDecodingError(type: MaxKey.self, decoder: decoder) + throw getDecodingError(type: BSONMaxKey.self, decoder: decoder) } internal func encode(to: Encoder) throws { @@ -757,7 +791,7 @@ internal struct MaxKey: BSONValue, Equatable, Codable, Hashable { internal static func from(iterator iter: BSONDocumentIterator) throws -> BSON { guard iter.currentType == .maxKey else { - throw wrongIterTypeError(iter, expected: MaxKey.self) + throw wrongIterTypeError(iter, expected: BSONMaxKey.self) } return .maxKey } @@ -813,11 +847,6 @@ public struct BSONObjectID: BSONValue, Equatable, CustomStringConvertible, Codab } } - /// The timestamp used to create this `BSONObjectID` - public var timestamp: UInt32 { - withUnsafePointer(to: self.oid) { oidPtr in UInt32(bson_oid_get_time_t(oidPtr)) } - } - public var description: String { self.hex } @@ -831,12 +860,13 @@ public struct BSONObjectID: BSONValue, Equatable, CustomStringConvertible, Codab self.oid = oid } - /// Initializes an `BSONObjectID` from the provided hex `String`. Returns `nil` if the string is not a valid - /// ObjectID. + /// Initializes an `BSONObjectID` from the provided hex `String`. + /// - Throws: + /// - `InvalidArgumentError` if string passed is not a valid BSONObjectID /// - SeeAlso: https://github.com/mongodb/specifications/blob/master/source/objectid.rst - public init?(_ hex: String) { + public init(_ hex: String) throws { guard bson_oid_is_valid(hex, hex.utf8.count) else { - return nil + throw InvalidArgumentError(message: "Cannot create ObjectId from \(hex)") } var oid_t = bson_oid_t() bson_oid_init_from_string(&oid_t, hex) @@ -851,7 +881,7 @@ public struct BSONObjectID: BSONValue, Equatable, CustomStringConvertible, Codab // assumes that the BSONObjectID is stored as a valid hex string. let container = try decoder.singleValueContainer() let hex = try container.decode(String.self) - guard let oid = BSONObjectID(hex) else { + guard let oid = try? BSONObjectID(hex) else { throw DecodingError.dataCorrupted( DecodingError.Context( codingPath: decoder.codingPath, diff --git a/Sources/MongoSwift/BSON/Overwritable.swift b/Sources/MongoSwift/BSON/Overwritable.swift index 79f94f3a9..269744b16 100644 --- a/Sources/MongoSwift/BSON/Overwritable.swift +++ b/Sources/MongoSwift/BSON/Overwritable.swift @@ -8,7 +8,7 @@ internal protocol Overwritable: BSONValue { * * - Throws: * - `InternalError` if the `BSONValue` is an `Int` and cannot be written to BSON. - * - `LogicError` if the `BSONValue` is a `Decimal128` or `BSONObjectID` and is improperly formatted. + * - `LogicError` if the `BSONValue` is a `BSONDecimal128` or `BSONObjectID` and is improperly formatted. */ func writeToCurrentPosition(of iter: BSONDocumentIterator) throws } diff --git a/Tests/BSONTests/BSONCorpusTests.swift b/Tests/BSONTests/BSONCorpusTests.swift index 0c63a8d74..dc328d392 100644 --- a/Tests/BSONTests/BSONCorpusTests.swift +++ b/Tests/BSONTests/BSONCorpusTests.swift @@ -138,7 +138,7 @@ final class BSONCorpusTests: MongoSwiftTestCase { // for cB input: // native_to_bson( bson_to_native(cB) ) = cB let docFromCB = try BSONDocument(fromBSON: cBData) - expect(docFromCB.rawBSON).to(equal(cBData)) + expect(docFromCB.toData()).to(equal(cBData)) // test round tripping through documents // We create an array by reading every element out of the document (and therefore out of the @@ -148,7 +148,7 @@ final class BSONCorpusTests: MongoSwiftTestCase { // translation layer is lossy and/or buggy. let nativeFromDoc = docFromCB.toArray() let docFromNative = BSONDocument(fromArray: nativeFromDoc) - expect(docFromNative.rawBSON).to(equal(cBData)) + expect(docFromNative.toData()).to(equal(cBData)) // native_to_canonical_extended_json( bson_to_native(cB) ) = cEJ expect(docFromCB.canonicalExtendedJSON).to(cleanEqual(test.canonicalExtJSON)) @@ -165,7 +165,7 @@ final class BSONCorpusTests: MongoSwiftTestCase { // native_to_bson( json_to_native(cEJ) ) = cB (unless lossy) if !lossy { - expect(try BSONDocument(fromJSON: cEJData).rawBSON).to(equal(cBData)) + expect(try BSONDocument(fromJSON: cEJData).toData()).to(equal(cBData)) } // for dB input (if it exists): @@ -193,7 +193,7 @@ final class BSONCorpusTests: MongoSwiftTestCase { // native_to_bson( json_to_native(dEJ) ) = cB (unless lossy) if !lossy { - expect(try BSONDocument(fromJSON: dEJ).rawBSON).to(equal(cBData)) + expect(try BSONDocument(fromJSON: dEJ).toData()).to(equal(cBData)) } } @@ -212,13 +212,13 @@ final class BSONCorpusTests: MongoSwiftTestCase { } let description = "\(testFile.description)-\(test.description)" - switch BSONType(rawValue: UInt32(testFile.bsonType.dropFirst(2), radix: 16)!)! { + switch BSONType(rawValue: UInt8(testFile.bsonType.dropFirst(2), radix: 16)!)! { case .invalid: // "top level document" uses 0x00 for the bson type expect(try BSONDocument(fromJSON: test.string)) .to(throwError(), description: description) case .decimal128: - expect(BSONDecimal128(test.string)) - .to(beNil(), description: description) + expect(try BSONDecimal128(test.string)) + .to(throwError(), description: description) default: throw TestError( message: "\(description): parse error tests not implemented" diff --git a/Tests/BSONTests/BSONValueTests.swift b/Tests/BSONTests/BSONValueTests.swift index d9ac00742..6acd567f1 100644 --- a/Tests/BSONTests/BSONValueTests.swift +++ b/Tests/BSONTests/BSONValueTests.swift @@ -7,9 +7,9 @@ import XCTest final class BSONValueTests: MongoSwiftTestCase { func testInvalidDecimal128() throws { - expect(BSONDecimal128("hi")).to(beNil()) - expect(BSONDecimal128("123.4.5")).to(beNil()) - expect(BSONDecimal128("10")).toNot(beNil()) + expect(try BSONDecimal128("hi")).to(throwError()) + expect(try BSONDecimal128("123.4.5")).to(throwError()) + expect(try BSONDecimal128("10")).toNot(throwError()) } func testUUIDBytes() throws { @@ -38,10 +38,10 @@ final class BSONValueTests: MongoSwiftTestCase { self.checkTrueAndFalse(val: .int64(64), alternate: .int64(65)) // Double self.checkTrueAndFalse(val: 1.618, alternate: 2.718) - // Decimal128 + // BSONDecimal128 self.checkTrueAndFalse( - val: .decimal128(BSONDecimal128("1.618")!), - alternate: .decimal128(BSONDecimal128("2.718")!) + val: .decimal128(try BSONDecimal128("1.618")), + alternate: .decimal128(try BSONDecimal128("2.718")) ) // Bool self.checkTrueAndFalse(val: true, alternate: false) @@ -119,14 +119,10 @@ final class BSONValueTests: MongoSwiftTestCase { bson_oid_to_string(&oid_t, &oid_c) let oid = String(cString: &oid_c) - // read the timestamp used to create the oid - let timestamp = UInt32(bson_oid_get_time_t(&oid_t)) - // initialize a new oid with the oid_t ptr // expect the values to be equal let objectId = BSONObjectID(bsonOid: oid_t) expect(objectId.hex).to(equal(oid)) - expect(objectId.timestamp).to(equal(timestamp)) // round trip the objectId. // expect the encoded oid to equal the original @@ -140,14 +136,12 @@ final class BSONValueTests: MongoSwiftTestCase { expect(_id).to(equal(objectId)) expect(_id.hex).to(equal(objectId.hex)) - expect(_id.timestamp).to(equal(objectId.timestamp)) // expect that we can pull the correct timestamp if // initialized from the original string - let objectIdFromString = BSONObjectID(oid)! + let objectIdFromString = try BSONObjectID(oid) expect(objectIdFromString).to(equal(objectId)) expect(objectIdFromString.hex).to(equal(oid)) - expect(objectIdFromString.timestamp).to(equal(timestamp)) } func testObjectIDJSONCodable() throws { @@ -192,7 +186,7 @@ final class BSONValueTests: MongoSwiftTestCase { ] candidates.compactMap { $0 }.forEach { l in - // Skip the Decimal128 conversions until they're implemented + // Skip the BSONDecimal128 conversions until they're implemented // TODO: don't skip these (SWIFT-367) guard l.decimal128Value == nil else { return @@ -203,7 +197,7 @@ final class BSONValueTests: MongoSwiftTestCase { BSONNumberTestCase.compare(computed: l.toInt64(), expected: self.int64) BSONNumberTestCase.compare(computed: l.toDouble(), expected: self.double) - // Skip double for this conversion since it generates a Decimal128(5.0) =/= Decimal128(5) + // Skip double for this conversion since it generates a BSONDecimal128(5.0) =/= BSONDecimal128(5) if l.doubleValue == nil { BSONNumberTestCase.compare(computed: l.toDecimal128(), expected: self.decimal) } @@ -212,26 +206,57 @@ final class BSONValueTests: MongoSwiftTestCase { } func testBSONNumber() throws { - let decimal128 = BSONDecimal128("5.5")! + let decimal128 = try BSONDecimal128("5.5") let double: BSON = 5.5 expect(double.toDouble()).to(equal(5.5)) expect(double.toDecimal128()).to(equal(decimal128)) let cases = [ - BSONNumberTestCase(int: 5, double: 5.0, int32: Int32(5), int64: Int64(5), decimal: BSONDecimal128("5")!), + BSONNumberTestCase( + int: 5, + double: 5.0, + int32: Int32(5), + int64: Int64(5), + decimal: try BSONDecimal128("5") + ), BSONNumberTestCase( int: -5, double: -5.0, int32: Int32(-5), int64: Int64(-5), - decimal: BSONDecimal128("-5")! + decimal: try BSONDecimal128("-5") + ), + BSONNumberTestCase( + int: 0, + double: 0.0, + int32: Int32(0), + int64: Int64(0), + decimal: try BSONDecimal128("0") ), - BSONNumberTestCase(int: 0, double: 0.0, int32: Int32(0), int64: Int64(0), decimal: BSONDecimal128("0")!), - BSONNumberTestCase(int: nil, double: 1.234, int32: nil, int64: nil, decimal: BSONDecimal128("1.234")!), - BSONNumberTestCase(int: nil, double: -31.234, int32: nil, int64: nil, decimal: BSONDecimal128("-31.234")!) + BSONNumberTestCase( + int: nil, + double: 1.234, + int32: nil, + int64: nil, + decimal: try BSONDecimal128("1.234") + ), + BSONNumberTestCase( + int: nil, + double: -31.234, + int32: nil, + int64: nil, + decimal: try BSONDecimal128("-31.234") + ) ] cases.forEach { $0.run() } } + + func testBSONBinarySubtype() { + // Check the subtype bounds are kept + expect(try BSONBinary.Subtype.userDefined(0x100)).to(throwError()) + expect(try BSONBinary.Subtype.userDefined(0x79)).to(throwError()) + expect(BSONBinary.Subtype(rawValue: 0x79)).to(beNil()) + } } diff --git a/Tests/BSONTests/CodecTests.swift b/Tests/BSONTests/CodecTests.swift index fc8699227..c40be6310 100644 --- a/Tests/BSONTests/CodecTests.swift +++ b/Tests/BSONTests/CodecTests.swift @@ -283,7 +283,7 @@ final class CodecTests: MongoSwiftTestCase { let int64: Int64 let dec: BSONDecimal128 let minkey: BSONMinKey - let maxkey: MaxKey + let maxkey: BSONMaxKey let regex: BSONRegularExpression let symbol: BSONSymbol let undefined: BSONUndefined @@ -297,7 +297,7 @@ final class CodecTests: MongoSwiftTestCase { doc: ["x": 1], arr: [.int32(1), .int32(2)], binary: try BSONBinary(base64: "//8=", subtype: .generic), - oid: BSONObjectID("507f1f77bcf86cd799439011")!, + oid: try BSONObjectID("507f1f77bcf86cd799439011"), bool: true, date: Date(timeIntervalSinceReferenceDate: 5000), code: BSONCode(code: "hi"), @@ -305,13 +305,13 @@ final class CodecTests: MongoSwiftTestCase { ts: BSONTimestamp(timestamp: 1, inc: 2), int32: 5, int64: 6, - dec: BSONDecimal128("1.2E+10")!, + dec: try BSONDecimal128("1.2E+10"), minkey: BSONMinKey(), - maxkey: MaxKey(), + maxkey: BSONMaxKey(), regex: BSONRegularExpression(pattern: "^abc", options: "imx"), symbol: BSONSymbol("i am a symbol"), undefined: BSONUndefined(), - dbpointer: BSONDBPointer(ref: "some.namespace", id: BSONObjectID("507f1f77bcf86cd799439011")!), + dbpointer: BSONDBPointer(ref: "some.namespace", id: try BSONObjectID("507f1f77bcf86cd799439011")), null: BSONNull() ) } @@ -398,7 +398,7 @@ final class CodecTests: MongoSwiftTestCase { expect(try decoder.decode(Int32.self, from: "42")).to(equal(Int32(42))) expect(try decoder.decode(Int32.self, from: "{\"$numberInt\": \"42\"}")).to(equal(Int32(42))) - let oid = BSONObjectID("507f1f77bcf86cd799439011")! + let oid = try BSONObjectID("507f1f77bcf86cd799439011") expect(try decoder.decode(BSONObjectID.self, from: "{\"$oid\": \"507f1f77bcf86cd799439011\"}")).to(equal(oid)) expect(try decoder.decode(String.self, from: "\"somestring\"")).to(equal("somestring")) @@ -412,7 +412,7 @@ final class CodecTests: MongoSwiftTestCase { expect(try decoder.decode( BSONDecimal128.self, from: "{\"$numberDecimal\": \"1.2E+10\"}" - )).to(equal(BSONDecimal128("1.2E+10")!)) + )).to(equal(try BSONDecimal128("1.2E+10"))) let binary = try BSONBinary(base64: "//8=", subtype: .generic) expect( @@ -459,7 +459,7 @@ final class CodecTests: MongoSwiftTestCase { ).to(equal(regex)) expect(try decoder.decode(BSONMinKey.self, from: "{\"$minKey\": 1}")).to(equal(BSONMinKey())) - expect(try decoder.decode(MaxKey.self, from: "{\"$maxKey\": 1}")).to(equal(MaxKey())) + expect(try decoder.decode(BSONMaxKey.self, from: "{\"$maxKey\": 1}")).to(equal(BSONMaxKey())) expect(try decoder.decode(Bool.self, from: "false")).to(beFalse()) expect(try decoder.decode(Bool.self, from: "true")).to(beTrue()) @@ -700,7 +700,7 @@ final class CodecTests: MongoSwiftTestCase { expect(try decoder.decode(AnyBSONStruct.self, from: wrappedInt64.canonicalExtendedJSON).x).to(equal(int64)) // decimal128 - let decimal = BSON.decimal128(BSONDecimal128("1.2E+10")!) + let decimal = BSON.decimal128(try BSONDecimal128("1.2E+10")) expect(try decoder.decode(BSON.self, from: "{ \"$numberDecimal\" : \"1.2E+10\" }")).to(equal(decimal)) diff --git a/Tests/BSONTests/Document+SequenceTests.swift b/Tests/BSONTests/Document+SequenceTests.swift index 15dbb0eaf..824ef08ca 100644 --- a/Tests/BSONTests/Document+SequenceTests.swift +++ b/Tests/BSONTests/Document+SequenceTests.swift @@ -5,7 +5,7 @@ import TestsCommon import XCTest final class Document_SequenceTests: MongoSwiftTestCase { - func testIterator() { + func testIterator() throws { let doc: BSONDocument = [ "string": "test string", "true": true, @@ -14,7 +14,7 @@ final class Document_SequenceTests: MongoSwiftTestCase { "int32": .int32(5), "int64": .int64(123), "double": .double(15), - "decimal128": .decimal128(BSONDecimal128("1.2E+10")!), + "decimal128": .decimal128(try BSONDecimal128("1.2E+10")), "minkey": .minKey, "maxkey": .maxKey, "date": .datetime(Date(timeIntervalSince1970: 5000)), @@ -54,7 +54,7 @@ final class Document_SequenceTests: MongoSwiftTestCase { let decimalTup = iter.next()! expect(decimalTup.key).to(equal("decimal128")) - expect(decimalTup.value).to(equal(.decimal128(BSONDecimal128("1.2E+10")!))) + expect(decimalTup.value).to(equal(.decimal128(try BSONDecimal128("1.2E+10")))) let minTup = iter.next()! expect(minTup.key).to(equal("minkey")) @@ -81,7 +81,7 @@ final class Document_SequenceTests: MongoSwiftTestCase { ] var expectedValues: [BSON] = [ "test string", true, false, 25, .int32(5), .int64(123), .double(15), - .decimal128(BSONDecimal128("1.2E+10")!), .minKey, .maxKey, .datetime(Date(timeIntervalSince1970: 5000)), + .decimal128(try BSONDecimal128("1.2E+10")), .minKey, .maxKey, .datetime(Date(timeIntervalSince1970: 5000)), .timestamp(BSONTimestamp(timestamp: 5, inc: 10)) ] for (k, v) in doc { diff --git a/Tests/BSONTests/DocumentTests.swift b/Tests/BSONTests/DocumentTests.swift index a743135a6..044bdec55 100644 --- a/Tests/BSONTests/DocumentTests.swift +++ b/Tests/BSONTests/DocumentTests.swift @@ -81,14 +81,14 @@ final class DocumentTests: MongoSwiftTestCase { "int32": .int32(5), "int64": .int64(10), "double": .double(15), - "decimal128": .decimal128(BSONDecimal128("1.2E+10")!), + "decimal128": .decimal128(try! BSONDecimal128("1.2E+10")), "minkey": .minKey, "maxkey": .maxKey, "date": .datetime(Date(timeIntervalSince1970: 500.004)), "timestamp": .timestamp(BSONTimestamp(timestamp: 5, inc: 10)), "nestedarray": [[1, 2], [.int32(3), .int32(4)]], "nesteddoc": ["a": 1, "b": 2, "c": false, "d": [3, 4]], - "oid": .objectID(BSONObjectID("507f1f77bcf86cd799439011")!), + "oid": .objectID(try! BSONObjectID("507f1f77bcf86cd799439011")), "regex": .regex(BSONRegularExpression(pattern: "^abc", options: "imx")), "array1": [1, 2], "array2": ["string1", "string2"], @@ -121,8 +121,8 @@ final class DocumentTests: MongoSwiftTestCase { "binary3": .binary(try BSONBinary(data: uuidData, subtype: .uuidDeprecated)), "binary4": .binary(try BSONBinary(data: uuidData, subtype: .uuid)), "binary5": .binary(try BSONBinary(data: testData, subtype: .md5)), - "binary6": .binary(try BSONBinary(data: testData, subtype: .userDefined)), - "binary7": .binary(try BSONBinary(data: testData, subtype: 200)) + "binary6": .binary(try BSONBinary(data: testData, subtype: try .userDefined(0x80))), + "binary7": .binary(try BSONBinary(data: testData, subtype: try .userDefined(0xFF))) ] try doc.merge(binaryData) @@ -148,12 +148,12 @@ final class DocumentTests: MongoSwiftTestCase { expect(doc["int32"]).to(equal(.int32(5))) expect(doc["int64"]).to(equal(.int64(10))) expect(doc["double"]).to(equal(15.0)) - expect(doc["decimal128"]).to(equal(.decimal128(BSONDecimal128("1.2E+10")!))) + expect(doc["decimal128"]).to(equal(.decimal128(try BSONDecimal128("1.2E+10")))) expect(doc["minkey"]).to(equal(.minKey)) expect(doc["maxkey"]).to(equal(.maxKey)) expect(doc["date"]).to(equal(.datetime(Date(timeIntervalSince1970: 500.004)))) expect(doc["timestamp"]).to(equal(.timestamp(BSONTimestamp(timestamp: 5, inc: 10)))) - expect(doc["oid"]).to(equal(.objectID(BSONObjectID("507f1f77bcf86cd799439011")!))) + expect(doc["oid"]).to(equal(.objectID(try BSONObjectID("507f1f77bcf86cd799439011")))) let regex = doc["regex"]?.regexValue expect(regex).to(equal(BSONRegularExpression(pattern: "^abc", options: "imx"))) @@ -179,8 +179,8 @@ final class DocumentTests: MongoSwiftTestCase { expect(doc["binary3"]).to(equal(.binary(try BSONBinary(data: uuidData, subtype: .uuidDeprecated)))) expect(doc["binary4"]).to(equal(.binary(try BSONBinary(data: uuidData, subtype: .uuid)))) expect(doc["binary5"]).to(equal(.binary(try BSONBinary(data: testData, subtype: .md5)))) - expect(doc["binary6"]).to(equal(.binary(try BSONBinary(data: testData, subtype: .userDefined)))) - expect(doc["binary7"]).to(equal(.binary(try BSONBinary(data: testData, subtype: 200)))) + expect(doc["binary6"]).to(equal(.binary(try BSONBinary(data: testData, subtype: try .userDefined(0x80))))) + expect(doc["binary7"]).to(equal(.binary(try BSONBinary(data: testData, subtype: try .userDefined(0xFF))))) let nestedArray = doc["nestedarray"]?.arrayValue?.compactMap { $0.arrayValue?.compactMap { $0.toInt() } } expect(nestedArray?[0]).to(equal([1, 2])) @@ -198,12 +198,12 @@ final class DocumentTests: MongoSwiftTestCase { expect(DocumentTests.testDoc.int32).to(equal(.int32(5))) expect(DocumentTests.testDoc.int64).to(equal(.int64(10))) expect(DocumentTests.testDoc.double).to(equal(15.0)) - expect(DocumentTests.testDoc.decimal128).to(equal(.decimal128(BSONDecimal128("1.2E+10")!))) + expect(DocumentTests.testDoc.decimal128).to(equal(.decimal128(try BSONDecimal128("1.2E+10")))) expect(DocumentTests.testDoc.minkey).to(equal(.minKey)) expect(DocumentTests.testDoc.maxkey).to(equal(.maxKey)) expect(DocumentTests.testDoc.date).to(equal(.datetime(Date(timeIntervalSince1970: 500.004)))) expect(DocumentTests.testDoc.timestamp).to(equal(.timestamp(BSONTimestamp(timestamp: 5, inc: 10)))) - expect(DocumentTests.testDoc.oid).to(equal(.objectID(BSONObjectID("507f1f77bcf86cd799439011")!))) + expect(DocumentTests.testDoc.oid).to(equal(.objectID(try BSONObjectID("507f1f77bcf86cd799439011")))) let codewscope = DocumentTests.testDoc.codewscope?.codeWithScopeValue expect(codewscope?.code).to(equal("console.log(x);")) @@ -258,7 +258,7 @@ final class DocumentTests: MongoSwiftTestCase { func testRawBSON() throws { let doc = try BSONDocument(fromJSON: "{\"a\" : [{\"$numberInt\": \"10\"}]}") - let fromRawBSON = try BSONDocument(fromBSON: doc.rawBSON) + let fromRawBSON = try BSONDocument(fromBSON: doc.toData()) expect(doc).to(equal(fromRawBSON)) } @@ -351,8 +351,8 @@ final class DocumentTests: MongoSwiftTestCase { "int32": .int32(32), "int64": .int64(Int64.max), "bool": false, - "decimal": .decimal128(BSONDecimal128("1.2E+10")!), - "oid": .objectID(), + "decimal": .decimal128(try! BSONDecimal128("1.2E+10")), + "oid": .objectID(BSONObjectID()), "timestamp": .timestamp(BSONTimestamp(timestamp: 1, inc: 2)), "datetime": .datetime(Date(msSinceEpoch: 1000)) ] @@ -387,7 +387,7 @@ final class DocumentTests: MongoSwiftTestCase { doc["double"] = 3.0 expect(doc.pointerAddress).to(equal(pointer)) - doc["decimal"] = .decimal128(BSONDecimal128("100")!) + doc["decimal"] = .decimal128(try BSONDecimal128("100")) expect(doc.pointerAddress).to(equal(pointer)) // overwrite int64 with int64 @@ -409,7 +409,7 @@ final class DocumentTests: MongoSwiftTestCase { "int32": .int32(15), "int64": .int64(Int64.min), "bool": true, - "decimal": .decimal128(BSONDecimal128("100")!), + "decimal": .decimal128(try BSONDecimal128("100")), "oid": .objectID(newOid), "timestamp": .timestamp(BSONTimestamp(timestamp: 5, inc: 10)), "datetime": .datetime(Date(msSinceEpoch: 2000)) @@ -430,7 +430,7 @@ final class DocumentTests: MongoSwiftTestCase { "int32": .int32(15), "int64": BSON(integerLiteral: bigInt), "bool": true, - "decimal": .decimal128(BSONDecimal128("100")!), + "decimal": .decimal128(try BSONDecimal128("100")), "oid": .objectID(newOid), "timestamp": .timestamp(BSONTimestamp(timestamp: 5, inc: 10)), "datetime": .datetime(Date(msSinceEpoch: 2000)) @@ -481,7 +481,7 @@ final class DocumentTests: MongoSwiftTestCase { let overwritablePairs: [(String, BSON)] = [ ("double", BSON(10)), ("int32", "hi"), - ("int64", .decimal128(BSONDecimal128("1.0")!)), + ("int64", .decimal128(try BSONDecimal128("1.0"))), ("bool", [1, 2, 3]), ("decimal", 100), ("oid", 25.5), @@ -498,7 +498,7 @@ final class DocumentTests: MongoSwiftTestCase { expect(overwritableDoc).to(equal([ "double": BSON(10), "int32": "hi", - "int64": .decimal128(BSONDecimal128("1.0")!), + "int64": .decimal128(try BSONDecimal128("1.0")), "bool": [1, 2, 3], "decimal": 100, "oid": 25.5, diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 0c534466c..fb9d3bb9b 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -39,6 +39,7 @@ extension BSONValueTests { ("testObjectIDRoundTrip", testObjectIDRoundTrip), ("testObjectIDJSONCodable", testObjectIDJSONCodable), ("testBSONNumber", testBSONNumber), + ("testBSONBinarySubtype", testBSONBinarySubtype), ] }