@@ -4,6 +4,70 @@ import mongoc
44import Nimble
55import XCTest
66
7+ typealias DeleteOneModel = MongoCollection < Document > . DeleteOneModel
8+ typealias DeleteManyModel = MongoCollection < Document > . DeleteManyModel
9+ typealias InsertOneModel = MongoCollection < Document > . InsertOneModel
10+ typealias ReplaceOneModel = MongoCollection < Document > . ReplaceOneModel
11+ typealias UpdateOneModel = MongoCollection < Document > . UpdateOneModel
12+ typealias UpdateManyModel = MongoCollection < Document > . UpdateManyModel
13+
14+ /// A struct representing a server version.
15+ internal struct ServerVersion : Comparable , Decodable {
16+ let major : Int
17+ let minor : Int
18+ let patch : Int
19+
20+ /// initialize a server version from a string
21+ init ( _ str: String ) throws {
22+ let versionComponents = str. split ( separator: " . " ) . prefix ( 3 )
23+ guard versionComponents. count >= 2 else {
24+ throw TestError ( message: " Expected version string \( str) to have at least two .-separated components " )
25+ }
26+
27+ guard let major = Int ( versionComponents [ 0 ] ) else {
28+ throw TestError ( message: " Error parsing major version from \( str) " )
29+ }
30+ guard let minor = Int ( versionComponents [ 1 ] ) else {
31+ throw TestError ( message: " Error parsing minor version from \( str) " )
32+ }
33+
34+ var patch = 0
35+ if versionComponents. count == 3 {
36+ // in case there is text at the end, for ex "3.6.0-rc1", stop first time
37+ /// we encounter a non-numeric character.
38+ let numbersOnly = versionComponents [ 2 ] . prefix { " 0123456789 " . contains ( $0) }
39+ guard let patchValue = Int ( numbersOnly) else {
40+ throw TestError ( message: " Error parsing patch version from \( str) " )
41+ }
42+ patch = patchValue
43+ }
44+
45+ self . init ( major: major, minor: minor, patch: patch)
46+ }
47+
48+ init ( from decoder: Decoder ) throws {
49+ let str = try decoder. singleValueContainer ( ) . decode ( String . self)
50+ try self . init ( str)
51+ }
52+
53+ // initialize given major, minor, and optional patch
54+ init ( major: Int , minor: Int , patch: Int ? = nil ) {
55+ self . major = major
56+ self . minor = minor
57+ self . patch = patch ?? 0
58+ }
59+
60+ static func < ( lhs: ServerVersion , rhs: ServerVersion ) -> Bool {
61+ if lhs. major != rhs. major {
62+ return lhs. major < rhs. major
63+ } else if lhs. minor != rhs. minor {
64+ return lhs. minor < rhs. minor
65+ } else {
66+ return lhs. patch < rhs. patch
67+ }
68+ }
69+ }
70+
771// sourcery: disableTests
872class MongoSwiftTestCase : XCTestCase {
973 /// Gets the name of the database the test case is running against.
@@ -74,15 +138,7 @@ class MongoSwiftTestCase: XCTestCase {
74138 guard let topology = ProcessInfo . processInfo. environment [ " MONGODB_TOPOLOGY " ] else {
75139 return . single
76140 }
77-
78- switch topology {
79- case " sharded_cluster " :
80- return . sharded
81- case " replica_set " :
82- return . replicaSetWithPrimary
83- default :
84- return . single
85- }
141+ return TopologyDescription . TopologyType ( from: topology)
86142 }
87143}
88144
@@ -98,80 +154,13 @@ extension MongoClient {
98154 return try ServerVersion ( versionString)
99155 }
100156
101- /// A struct representing a server version.
102- internal struct ServerVersion : Equatable {
103- let major : Int
104- let minor : Int
105- let patch : Int
106-
107- /// initialize a server version from a string
108- init ( _ str: String ) throws {
109- let versionComponents = str. split ( separator: " . " ) . prefix ( 3 )
110- guard versionComponents. count >= 2 else {
111- throw TestError ( message: " Expected version string \( str) to have at least two .-separated components " )
112- }
113-
114- guard let major = Int ( versionComponents [ 0 ] ) else {
115- throw TestError ( message: " Error parsing major version from \( str) " )
116- }
117- guard let minor = Int ( versionComponents [ 1 ] ) else {
118- throw TestError ( message: " Error parsing minor version from \( str) " )
119- }
120-
121- var patch = 0
122- if versionComponents. count == 3 {
123- // in case there is text at the end, for ex "3.6.0-rc1", stop first time
124- /// we encounter a non-numeric character.
125- let numbersOnly = versionComponents [ 2 ] . prefix { " 0123456789 " . contains ( $0) }
126- guard let patchValue = Int ( numbersOnly) else {
127- throw TestError ( message: " Error parsing patch version from \( str) " )
128- }
129- patch = patchValue
130- }
131-
132- self . init ( major: major, minor: minor, patch: patch)
133- }
134-
135- // initialize given major, minor, and optional patch
136- init ( major: Int , minor: Int , patch: Int ? = nil ) {
137- self . major = major
138- self . minor = minor
139- self . patch = patch ?? 0
140- }
141-
142- func isLessThan( _ version: ServerVersion ) -> Bool {
143- if self . major == version. major {
144- if self . minor == version. minor {
145- // if major & minor equal, just compare patches
146- return self . patch < version. patch
147- }
148- // major equal but minor isn't, so compare minor
149- return self . minor < version. minor
150- }
151- // just compare major versions
152- return self . major < version. major
153- }
154-
155- func isLessThanOrEqualTo( _ version: ServerVersion ) -> Bool {
156- return self == version || self . isLessThan ( version)
157- }
158-
159- func isGreaterThan( _ version: ServerVersion ) -> Bool {
160- return !self . isLessThanOrEqualTo ( version)
161- }
162-
163- func isGreaterThanOrEqualTo( _ version: ServerVersion ) -> Bool {
164- return !self . isLessThan ( version)
165- }
166- }
167-
168157 internal func serverVersionIsInRange( _ min: String ? , _ max: String ? ) throws -> Bool {
169158 let version = try self . serverVersion ( )
170159
171- if let min = min, version. isLessThan ( try ServerVersion ( min) ) {
160+ if let min = min, version < ( try ServerVersion ( min) ) {
172161 return false
173162 }
174- if let max = max, version. isGreaterThan ( try ServerVersion ( max) ) {
163+ if let max = max, version > ( try ServerVersion ( max) ) {
175164 return false
176165 }
177166
@@ -183,6 +172,19 @@ extension MongoClient {
183172 }
184173}
185174
175+ extension Document {
176+ internal func sortedEquals( _ other: Document ) -> Bool {
177+ let keys = self . keys. sorted ( )
178+ let otherKeys = other. keys. sorted ( )
179+
180+ // first compare keys, because rearrangeDoc will discard any that don't exist in `expected`
181+ expect ( keys) . to ( equal ( otherKeys) )
182+
183+ let rearranged = rearrangeDoc ( other, toLookLike: self )
184+ return self == rearranged
185+ }
186+ }
187+
186188/// Cleans and normalizes a given JSON string for comparison purposes
187189func clean( json: String ? ) -> String {
188190 guard let str = json else {
@@ -222,7 +224,7 @@ internal func sortedEqual(_ expectedValue: Document?) -> Predicate<Document> {
222224 return Predicate . define ( " sortedEqual < \( stringify ( expectedValue) ) > " ) { actualExpression, msg in
223225 let actualValue = try actualExpression. evaluate ( )
224226
225- if expectedValue == nil || actualValue == nil {
227+ guard let expected = expectedValue , let actual = actualValue else {
226228 if expectedValue == nil && actualValue != nil {
227229 return PredicateResult (
228230 status: . fail,
@@ -232,14 +234,7 @@ internal func sortedEqual(_ expectedValue: Document?) -> Predicate<Document> {
232234 return PredicateResult ( status: . fail, message: msg)
233235 }
234236
235- let expectedKeys = expectedValue? . keys. sorted ( )
236- let actualKeys = actualValue? . keys. sorted ( )
237-
238- // first compare keys, because rearrangeDoc will discard any that don't exist in `expected`
239- expect ( expectedKeys) . to ( equal ( actualKeys) )
240-
241- let rearranged = rearrangeDoc ( actualValue!, toLookLike: expectedValue!)
242- let matches = expectedValue == rearranged
237+ let matches = expected. sortedEquals ( actual)
243238 return PredicateResult ( status: PredicateStatus ( bool: matches) , message: msg)
244239 }
245240}
0 commit comments