From 86fdc792f376e469bafe1def19b65fcdae47c8fa Mon Sep 17 00:00:00 2001 From: Patrick Freed Date: Wed, 15 May 2019 11:49:28 -0400 Subject: [PATCH] update test utils: conform server version to comparable and move it out of client extension, add sortedEquals to Document, move model typealiases (cherry picked from commit de9662a1653e971c082687f23e3d0df5678413ae) --- Sources/MongoSwift/SDAM.swift | 12 ++ Tests/MongoSwiftTests/CrudTests.swift | 7 - Tests/MongoSwiftTests/MongoClientTests.swift | 50 +++--- Tests/MongoSwiftTests/TestUtils.swift | 169 +++++++++---------- 4 files changed, 119 insertions(+), 119 deletions(-) diff --git a/Sources/MongoSwift/SDAM.swift b/Sources/MongoSwift/SDAM.swift index e63bcc3df..05da9ad83 100644 --- a/Sources/MongoSwift/SDAM.swift +++ b/Sources/MongoSwift/SDAM.swift @@ -196,6 +196,18 @@ public struct TopologyDescription { case sharded = "Sharded" /// A topology whose type is not yet known. case unknown = "Unknown" + + /// Internal initializer used for translating evergreen config and spec test topologies to a `TopologyType` + internal init(from str: String) { + switch str { + case "sharded", "sharded_cluster": + self = .sharded + case "replicaset", "replica_set": + self = .replicaSetWithPrimary + default: + self = .single + } + } } /// The type of this topology. diff --git a/Tests/MongoSwiftTests/CrudTests.swift b/Tests/MongoSwiftTests/CrudTests.swift index 847ed4000..055132ae8 100644 --- a/Tests/MongoSwiftTests/CrudTests.swift +++ b/Tests/MongoSwiftTests/CrudTests.swift @@ -259,13 +259,6 @@ private class BulkWriteTest: CrudTest { return BulkWriteOptions(ordered: ordered) } - private typealias DeleteOneModel = MongoCollection.DeleteOneModel - private typealias DeleteManyModel = MongoCollection.DeleteManyModel - private typealias InsertOneModel = MongoCollection.InsertOneModel - private typealias ReplaceOneModel = MongoCollection.ReplaceOneModel - private typealias UpdateOneModel = MongoCollection.UpdateOneModel - private typealias UpdateManyModel = MongoCollection.UpdateManyModel - private static func parseWriteModel(_ request: Document) throws -> WriteModel { let name: String = try request.get("name") let args: Document = try request.get("arguments") diff --git a/Tests/MongoSwiftTests/MongoClientTests.swift b/Tests/MongoSwiftTests/MongoClientTests.swift index 19da8eab6..1e3c148be 100644 --- a/Tests/MongoSwiftTests/MongoClientTests.swift +++ b/Tests/MongoSwiftTests/MongoClientTests.swift @@ -38,7 +38,7 @@ final class MongoClientTests: MongoSwiftTestCase { } func testServerVersion() throws { - typealias Version = MongoClient.ServerVersion + typealias Version = ServerVersion expect(try MongoClient().serverVersion()).toNot(throwError()) @@ -55,36 +55,36 @@ final class MongoClientTests: MongoSwiftTestCase { expect(try Version("3.6.1.1")).to(equal(three61)) // lt - expect(three6.isLessThan(three6)).to(beFalse()) - expect(three6.isLessThan(three61)).to(beTrue()) - expect(three61.isLessThan(three6)).to(beFalse()) - expect(three61.isLessThan(three7)).to(beTrue()) - expect(three7.isLessThan(three6)).to(beFalse()) - expect(three7.isLessThan(three61)).to(beFalse()) + expect(three6 < three6).to(beFalse()) + expect(three6 < three61).to(beTrue()) + expect(three61 < three6).to(beFalse()) + expect(three61 < three7).to(beTrue()) + expect(three7 < three6).to(beFalse()) + expect(three7 < three61).to(beFalse()) // lte - expect(three6.isLessThanOrEqualTo(three6)).to(beTrue()) - expect(three6.isLessThanOrEqualTo(three61)).to(beTrue()) - expect(three61.isLessThanOrEqualTo(three6)).to(beFalse()) - expect(three61.isLessThanOrEqualTo(three7)).to(beTrue()) - expect(three7.isLessThanOrEqualTo(three6)).to(beFalse()) - expect(three7.isLessThanOrEqualTo(three61)).to(beFalse()) + expect(three6 <= three6).to(beTrue()) + expect(three6 <= three61).to(beTrue()) + expect(three61 <= three6).to(beFalse()) + expect(three61 <= three7).to(beTrue()) + expect(three7 <= three6).to(beFalse()) + expect(three7 <= three61).to(beFalse()) // gt - expect(three6.isGreaterThan(three6)).to(beFalse()) - expect(three6.isGreaterThan(three61)).to(beFalse()) - expect(three61.isGreaterThan(three6)).to(beTrue()) - expect(three61.isGreaterThan(three7)).to(beFalse()) - expect(three7.isGreaterThan(three6)).to(beTrue()) - expect(three7.isGreaterThan(three61)).to(beTrue()) + expect(three6 > three6).to(beFalse()) + expect(three6 > three61).to(beFalse()) + expect(three61 > three6).to(beTrue()) + expect(three61 > three7).to(beFalse()) + expect(three7 > three6).to(beTrue()) + expect(three7 > three61).to(beTrue()) // gte - expect(three6.isGreaterThanOrEqualTo(three6)).to(beTrue()) - expect(three6.isGreaterThanOrEqualTo(three61)).to(beFalse()) - expect(three61.isGreaterThanOrEqualTo(three6)).to(beTrue()) - expect(three61.isGreaterThanOrEqualTo(three7)).to(beFalse()) - expect(three7.isGreaterThanOrEqualTo(three6)).to(beTrue()) - expect(three7.isGreaterThanOrEqualTo(three61)).to(beTrue()) + expect(three6 >= three6).to(beTrue()) + expect(three6 >= three61).to(beFalse()) + expect(three61 >= three6).to(beTrue()) + expect(three61 >= three7).to(beFalse()) + expect(three7 >= three6).to(beTrue()) + expect(three7 >= three61).to(beTrue()) // invalid strings expect(try Version("hi")).to(throwError()) diff --git a/Tests/MongoSwiftTests/TestUtils.swift b/Tests/MongoSwiftTests/TestUtils.swift index 88ca50d6f..291eb416e 100644 --- a/Tests/MongoSwiftTests/TestUtils.swift +++ b/Tests/MongoSwiftTests/TestUtils.swift @@ -4,6 +4,70 @@ import mongoc import Nimble import XCTest +typealias DeleteOneModel = MongoCollection.DeleteOneModel +typealias DeleteManyModel = MongoCollection.DeleteManyModel +typealias InsertOneModel = MongoCollection.InsertOneModel +typealias ReplaceOneModel = MongoCollection.ReplaceOneModel +typealias UpdateOneModel = MongoCollection.UpdateOneModel +typealias UpdateManyModel = MongoCollection.UpdateManyModel + +/// A struct representing a server version. +internal struct ServerVersion: Comparable, Decodable { + let major: Int + let minor: Int + let patch: Int + + /// initialize a server version from a string + init(_ str: String) throws { + let versionComponents = str.split(separator: ".").prefix(3) + guard versionComponents.count >= 2 else { + throw TestError(message: "Expected version string \(str) to have at least two .-separated components") + } + + guard let major = Int(versionComponents[0]) else { + throw TestError(message: "Error parsing major version from \(str)") + } + guard let minor = Int(versionComponents[1]) else { + throw TestError(message: "Error parsing minor version from \(str)") + } + + var patch = 0 + if versionComponents.count == 3 { + // in case there is text at the end, for ex "3.6.0-rc1", stop first time + /// we encounter a non-numeric character. + let numbersOnly = versionComponents[2].prefix { "0123456789".contains($0) } + guard let patchValue = Int(numbersOnly) else { + throw TestError(message: "Error parsing patch version from \(str)") + } + patch = patchValue + } + + self.init(major: major, minor: minor, patch: patch) + } + + init(from decoder: Decoder) throws { + let str = try decoder.singleValueContainer().decode(String.self) + try self.init(str) + } + + // initialize given major, minor, and optional patch + init(major: Int, minor: Int, patch: Int? = nil) { + self.major = major + self.minor = minor + self.patch = patch ?? 0 + } + + static func < (lhs: ServerVersion, rhs: ServerVersion) -> Bool { + if lhs.major != rhs.major { + return lhs.major < rhs.major + } else if lhs.minor != rhs.minor { + return lhs.minor < rhs.minor + } else { + return lhs.patch < rhs.patch + } + } +} + // sourcery: disableTests class MongoSwiftTestCase: XCTestCase { /// Gets the name of the database the test case is running against. @@ -74,15 +138,7 @@ class MongoSwiftTestCase: XCTestCase { guard let topology = ProcessInfo.processInfo.environment["MONGODB_TOPOLOGY"] else { return .single } - - switch topology { - case "sharded_cluster": - return .sharded - case "replica_set": - return .replicaSetWithPrimary - default: - return .single - } + return TopologyDescription.TopologyType(from: topology) } } @@ -98,80 +154,13 @@ extension MongoClient { return try ServerVersion(versionString) } - /// A struct representing a server version. - internal struct ServerVersion: Equatable { - let major: Int - let minor: Int - let patch: Int - - /// initialize a server version from a string - init(_ str: String) throws { - let versionComponents = str.split(separator: ".").prefix(3) - guard versionComponents.count >= 2 else { - throw TestError(message: "Expected version string \(str) to have at least two .-separated components") - } - - guard let major = Int(versionComponents[0]) else { - throw TestError(message: "Error parsing major version from \(str)") - } - guard let minor = Int(versionComponents[1]) else { - throw TestError(message: "Error parsing minor version from \(str)") - } - - var patch = 0 - if versionComponents.count == 3 { - // in case there is text at the end, for ex "3.6.0-rc1", stop first time - /// we encounter a non-numeric character. - let numbersOnly = versionComponents[2].prefix { "0123456789".contains($0) } - guard let patchValue = Int(numbersOnly) else { - throw TestError(message: "Error parsing patch version from \(str)") - } - patch = patchValue - } - - self.init(major: major, minor: minor, patch: patch) - } - - // initialize given major, minor, and optional patch - init(major: Int, minor: Int, patch: Int? = nil) { - self.major = major - self.minor = minor - self.patch = patch ?? 0 - } - - func isLessThan(_ version: ServerVersion) -> Bool { - if self.major == version.major { - if self.minor == version.minor { - // if major & minor equal, just compare patches - return self.patch < version.patch - } - // major equal but minor isn't, so compare minor - return self.minor < version.minor - } - // just compare major versions - return self.major < version.major - } - - func isLessThanOrEqualTo(_ version: ServerVersion) -> Bool { - return self == version || self.isLessThan(version) - } - - func isGreaterThan(_ version: ServerVersion) -> Bool { - return !self.isLessThanOrEqualTo(version) - } - - func isGreaterThanOrEqualTo(_ version: ServerVersion) -> Bool { - return !self.isLessThan(version) - } - } - internal func serverVersionIsInRange(_ min: String?, _ max: String?) throws -> Bool { let version = try self.serverVersion() - if let min = min, version.isLessThan(try ServerVersion(min)) { + if let min = min, version < (try ServerVersion(min)) { return false } - if let max = max, version.isGreaterThan(try ServerVersion(max)) { + if let max = max, version > (try ServerVersion(max)) { return false } @@ -183,6 +172,19 @@ extension MongoClient { } } +extension Document { + internal func sortedEquals(_ other: Document) -> Bool { + let keys = self.keys.sorted() + let otherKeys = other.keys.sorted() + + // first compare keys, because rearrangeDoc will discard any that don't exist in `expected` + expect(keys).to(equal(otherKeys)) + + let rearranged = rearrangeDoc(other, toLookLike: self) + return self == rearranged + } +} + /// Cleans and normalizes a given JSON string for comparison purposes func clean(json: String?) -> String { guard let str = json else { @@ -222,7 +224,7 @@ internal func sortedEqual(_ expectedValue: Document?) -> Predicate { return Predicate.define("sortedEqual <\(stringify(expectedValue))>") { actualExpression, msg in let actualValue = try actualExpression.evaluate() - if expectedValue == nil || actualValue == nil { + guard let expected = expectedValue, let actual = actualValue else { if expectedValue == nil && actualValue != nil { return PredicateResult( status: .fail, @@ -232,14 +234,7 @@ internal func sortedEqual(_ expectedValue: Document?) -> Predicate { return PredicateResult(status: .fail, message: msg) } - let expectedKeys = expectedValue?.keys.sorted() - let actualKeys = actualValue?.keys.sorted() - - // first compare keys, because rearrangeDoc will discard any that don't exist in `expected` - expect(expectedKeys).to(equal(actualKeys)) - - let rearranged = rearrangeDoc(actualValue!, toLookLike: expectedValue!) - let matches = expectedValue == rearranged + let matches = expected.sortedEquals(actual) return PredicateResult(status: PredicateStatus(bool: matches), message: msg) } }