@@ -13,98 +13,107 @@ final class SQLClientSwiftTests: XCTestCase {
1313 private var password : String { env ( " PASSWORD " ) }
1414 private var database : String { env ( " DATABASE " ) }
1515 private var canConnect : Bool { !host. isEmpty && !username. isEmpty && !password. isEmpty }
16+ private var client : SQLClient ! // global client
1617
1718 private func makeClient( ) async throws -> SQLClient {
19+ let c = SQLClient ( )
20+ try await c. connect ( server: host, username: username, password: password,
21+ database: database. isEmpty ? nil : database)
22+ return c
23+ }
24+
25+ /// Called before each XCTest method is run. Able to throw errors on setup.
26+ /// Centralises boilerplate setup making
27+ override func setupWithError( ) throws {
28+ try await super. setupWithError ( )
1829 guard canConnect else {
1930 throw XCTSkip ( " Set HOST, USERNAME, PASSWORD environment variables to run tests. " )
2031 }
21- let client = SQLClient ( )
22- try await client. connect ( server: host, username: username, password: password,
23- database: database. isEmpty ? nil : database)
24- return client
32+ client = try await makeClient ( )
2533 }
2634
35+ /// Called after each XCTest method is run. Able to throw errors on cleanup.
36+ /// Ensures cleanup from each test is completed after the test is run. Before
37+ /// the next test is run.
38+ override func tearDownWithError( ) throws {
39+ try await client. disconnect ( )
40+ try await super. tearDownWithError ( )
41+ }
42+
43+
2744 func testConnect( ) async throws {
28- let client = try await makeClient ( )
29- let connected = await client. isConnected
45+ // Use a local client, as the global client is already connected
46+ let localClient = SQLClient ( )
47+ try await localClient. connect ( server: host, username: username, password: password,
48+ database: database. isEmpty ? nil : database)
49+
50+ let connected = await localClient. isConnected
3051 XCTAssertTrue ( connected)
31- await client. disconnect ( )
32- let isConnected = await client. isConnected
52+
53+ await localClient. disconnect ( )
54+ let isConnected = await localClient. isConnected
3355 XCTAssertFalse ( isConnected)
3456 }
3557
3658 func testDoubleConnectThrows( ) async throws {
37- let client = try await makeClient ( )
38- defer { Task { await client. disconnect ( ) } }
59+ // Use a local client as the global client is already connected
60+ let localClient = SQLClient ( )
61+ try await localClient. connect ( server: host, username: username, password: password,
62+ database: database. isEmpty ? nil : database)
63+ // Defer is used here as race condition on cleanup is inconsequential
64+ defer { Task { await localClient. disconnect ( ) } }
65+
3966 do {
40- try await client . connect ( server: host, username: username, password: password)
67+ try await localClient . connect ( server: host, username: username, password: password)
4168 XCTFail ( " Expected alreadyConnected " )
4269 } catch SQLClientError . alreadyConnected { }
4370 }
4471
4572 func testSelectScalar( ) async throws {
46- let client = try await makeClient ( )
47- defer { Task { await client. disconnect ( ) } }
4873 let rows = try await client. query ( " SELECT 42 AS Answer " )
4974 XCTAssertEqual ( rows. count, 1 )
5075 XCTAssertEqual ( rows [ 0 ] . int ( " Answer " ) , 42 )
5176 }
5277
5378 func testSelectNull( ) async throws {
54- let client = try await makeClient ( )
55- defer { Task { await client. disconnect ( ) } }
5679 let rows = try await client. query ( " SELECT NULL AS Val " )
5780 XCTAssertTrue ( rows [ 0 ] . isNull ( " Val " ) )
5881 }
5982
6083 func testSelectString( ) async throws {
61- let client = try await makeClient ( )
62- defer { Task { await client. disconnect ( ) } }
6384 let rows = try await client. query ( " SELECT 'Hello' AS Msg " )
6485 XCTAssertEqual ( rows [ 0 ] . string ( " Msg " ) , " Hello " )
6586 }
6687
6788 func testSelectFloat( ) async throws {
68- let client = try await makeClient ( )
69- defer { Task { await client. disconnect ( ) } }
7089 let rows = try await client. query ( " SELECT CAST(3.14 AS FLOAT) AS Pi " )
7190 XCTAssertEqual ( rows [ 0 ] . double ( " Pi " ) ?? 0 , 3.14 , accuracy: 0.001 )
7291 }
7392
7493 func testSelectBit( ) async throws {
75- let client = try await makeClient ( )
76- defer { Task { await client. disconnect ( ) } }
7794 let rows = try await client. query ( " SELECT CAST(1 AS BIT) AS Flag " )
7895 XCTAssertEqual ( rows [ 0 ] . bool ( " Flag " ) , true )
7996 }
8097
8198 func testSelectDateTime( ) async throws {
82- let client = try await makeClient ( )
83- defer { Task { await client. disconnect ( ) } }
8499 let rows = try await client. query ( " SELECT GETDATE() AS Now " )
85100 XCTAssertNotNil ( rows [ 0 ] . date ( " Now " ) )
86101 }
87102
88103 func testMultipleRows( ) async throws {
89- let client = try await makeClient ( )
90- defer { Task { await client. disconnect ( ) } }
91104 let rows = try await client. query ( " SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 " )
92105 XCTAssertEqual ( rows. count, 3 )
93106 XCTAssertEqual ( rows. map { $0. int ( " n " ) } , [ 1 , 2 , 3 ] )
94107 }
95108
96109 func testMultipleResultSets( ) async throws {
97- let client = try await makeClient ( )
98- defer { Task { await client. disconnect ( ) } }
99110 let result = try await client. execute ( " SELECT 1 AS A; SELECT 2 AS B; " )
100111 XCTAssertEqual ( result. tables. count, 2 )
101112 XCTAssertEqual ( result. tables [ 0 ] [ 0 ] . int ( " A " ) , 1 )
102113 XCTAssertEqual ( result. tables [ 1 ] [ 0 ] . int ( " B " ) , 2 )
103114 }
104115
105116 func testRowsAffected( ) async throws {
106- let client = try await makeClient ( )
107- defer { Task { await client. disconnect ( ) } }
108117 try await client. run ( """
109118 IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T;
110119 CREATE TABLE #T (id INT);
@@ -116,21 +125,16 @@ final class SQLClientSwiftTests: XCTestCase {
116125 }
117126
118127 func testParameterisedQuery( ) async throws {
119- let client = try await makeClient ( )
120- defer { Task { await client. disconnect ( ) } }
121128 let rows = try await client. execute ( " SELECT ? AS Name " , parameters: [ " O'Brien " ] )
122129 XCTAssertEqual ( rows. rows [ 0 ] . string ( " Name " ) , " O'Brien " )
123130 }
124131
125132 func testNullParameter( ) async throws {
126- let client = try await makeClient ( )
127- defer { Task { await client. disconnect ( ) } }
128133 let rows = try await client. execute ( " SELECT ? AS Val " , parameters: [ nil ] )
129134 XCTAssertTrue ( rows. rows [ 0 ] . isNull ( " Val " ) )
130135 }
131136
132137 func testParameterCountMismatch( ) async throws {
133- let client = try await makeClient ( )
134138 defer { Task { await client. disconnect ( ) } }
135139 do {
136140 _ = try await client. execute ( " SELECT ? AS A " , parameters: [ 1 , 2 ] )
@@ -139,35 +143,27 @@ final class SQLClientSwiftTests: XCTestCase {
139143 }
140144
141145 func testDecodableStruct( ) async throws {
142- let client = try await makeClient ( )
143- defer { Task { await client. disconnect ( ) } }
144146 struct Point : Decodable { let x : Int ; let y : Int }
145147 let points : [ Point ] = try await client. query ( " SELECT 10 AS x, 20 AS y " )
146148 XCTAssertEqual ( points [ 0 ] . x, 10 )
147149 XCTAssertEqual ( points [ 0 ] . y, 20 )
148150 }
149151
150152 func testDecodableSnakeCase( ) async throws {
151- let client = try await makeClient ( )
152- defer { Task { await client. disconnect ( ) } }
153153 struct Item : Decodable { let itemId : Int ; let itemName : String }
154154 let items : [ Item ] = try await client. query ( " SELECT 7 AS item_id, 'Widget' AS item_name " )
155155 XCTAssertEqual ( items [ 0 ] . itemId, 7 )
156156 XCTAssertEqual ( items [ 0 ] . itemName, " Widget " )
157157 }
158158
159159 func testBadSQLThrows( ) async throws {
160- let client = try await makeClient ( )
161- defer { Task { await client. disconnect ( ) } }
162160 do {
163161 _ = try await client. execute ( " THIS IS NOT VALID SQL " )
164162 XCTFail ( " Expected executionFailed " )
165163 } catch SQLClientError . executionFailed { }
166164 }
167165
168166 func testEmptySQLThrows( ) async throws {
169- let client = try await makeClient ( )
170- defer { Task { await client. disconnect ( ) } }
171167 do {
172168 _ = try await client. execute ( " " )
173169 XCTFail ( " Expected noCommandText " )
0 commit comments