tiny_tds 2.1.3.pre → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +0 -0
  3. data/.gitattributes +0 -0
  4. data/.gitignore +0 -0
  5. data/.rubocop.yml +0 -0
  6. data/.travis.yml +1 -1
  7. data/CHANGELOG.md +12 -1
  8. data/CODE_OF_CONDUCT.md +0 -0
  9. data/Gemfile +0 -0
  10. data/ISSUE_TEMPLATE.md +0 -0
  11. data/MIT-LICENSE +0 -0
  12. data/README.md +13 -7
  13. data/Rakefile +0 -0
  14. data/VERSION +1 -1
  15. data/appveyor.yml +15 -1
  16. data/docker-compose.yml +22 -0
  17. data/ext/tiny_tds/client.c +90 -44
  18. data/ext/tiny_tds/client.h +5 -3
  19. data/ext/tiny_tds/extconf.rb +0 -0
  20. data/ext/tiny_tds/extconsts.rb +1 -1
  21. data/ext/tiny_tds/result.c +24 -10
  22. data/ext/tiny_tds/result.h +0 -0
  23. data/ext/tiny_tds/tiny_tds_ext.c +0 -0
  24. data/ext/tiny_tds/tiny_tds_ext.h +0 -0
  25. data/lib/tiny_tds.rb +0 -0
  26. data/lib/tiny_tds/bin.rb +0 -0
  27. data/lib/tiny_tds/client.rb +0 -0
  28. data/lib/tiny_tds/error.rb +0 -0
  29. data/lib/tiny_tds/gem.rb +0 -0
  30. data/lib/tiny_tds/result.rb +0 -0
  31. data/lib/tiny_tds/version.rb +0 -0
  32. data/patches/freetds/1.00.27/0001-mingw_missing_inet_pton.diff +0 -0
  33. data/patches/freetds/1.00.27/0002-Don-t-use-MSYS2-file-libws2_32.diff +0 -0
  34. data/patches/libiconv/1.14/1-avoid-gets-error.patch +0 -0
  35. data/tasks/native_gem.rake +0 -0
  36. data/tasks/package.rake +0 -0
  37. data/tasks/ports.rake +0 -0
  38. data/tasks/ports/freetds.rb +0 -0
  39. data/tasks/ports/libiconv.rb +0 -0
  40. data/tasks/ports/openssl.rb +0 -0
  41. data/tasks/ports/recipe.rb +0 -0
  42. data/tasks/test.rake +0 -0
  43. data/test/appveyor/dbsetup.ps1 +0 -0
  44. data/test/appveyor/dbsetup.sql +0 -0
  45. data/test/benchmark/query.rb +0 -0
  46. data/test/benchmark/query_odbc.rb +0 -0
  47. data/test/benchmark/query_tinytds.rb +0 -0
  48. data/test/client_test.rb +99 -54
  49. data/test/gem_test.rb +15 -15
  50. data/test/result_test.rb +83 -42
  51. data/test/schema/sqlserver_2000.sql +0 -0
  52. data/test/schema/sqlserver_2005.sql +0 -0
  53. data/test/schema/sqlserver_2008.sql +0 -0
  54. data/test/schema/sqlserver_2014.sql +0 -0
  55. data/test/schema/sqlserver_2016.sql +0 -0
  56. data/test/schema/sqlserver_azure.sql +0 -0
  57. data/test/schema/sybase_ase.sql +0 -0
  58. data/test/schema_test.rb +12 -12
  59. data/test/test_helper.rb +58 -4
  60. data/test/thread_test.rb +1 -1
  61. data/tiny_tds.gemspec +1 -0
  62. metadata +45 -7
File without changes
File without changes
File without changes
data/lib/tiny_tds.rb CHANGED
File without changes
data/lib/tiny_tds/bin.rb CHANGED
File without changes
File without changes
File without changes
data/lib/tiny_tds/gem.rb CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
data/tasks/package.rake CHANGED
File without changes
data/tasks/ports.rake CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
data/tasks/test.rake CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/test/client_test.rb CHANGED
@@ -2,9 +2,7 @@
2
2
  require 'test_helper'
3
3
 
4
4
  class ClientTest < TinyTds::TestCase
5
-
6
- describe 'With valid credentials' do
7
-
5
+ describe 'with valid credentials' do
8
6
  before do
9
7
  @client = new_connection
10
8
  end
@@ -67,10 +65,12 @@ class ClientTest < TinyTds::TestCase
67
65
  client.close if client
68
66
  end
69
67
  end unless sqlserver_azure?
70
-
71
68
  end
72
69
 
73
70
  describe 'With in-valid options' do
71
+ before(:all) do
72
+ init_toxiproxy
73
+ end
74
74
 
75
75
  it 'raises an argument error when no :host given and :dataserver is blank' do
76
76
  assert_raises(ArgumentError) { new_connection :dataserver => nil, :host => nil }
@@ -132,30 +132,64 @@ class ClientTest < TinyTds::TestCase
132
132
  end
133
133
  end
134
134
 
135
- it 'must run this test to prove we account for dropped connections' do
136
- skip
135
+ it 'raises TinyTds exception with tcp socket network failure' do
136
+ skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
137
137
  begin
138
- client = new_connection :login_timeout => 2, :timeout => 2
138
+ client = new_connection timeout: 2, port: 1234
139
139
  assert_client_works(client)
140
- STDOUT.puts "Disconnect network!"
141
- sleep 10
142
- STDOUT.puts "This should not get stuck past 6 seconds!"
143
- action = lambda { client.execute('SELECT 1 as [one]').each }
140
+ action = lambda { client.execute("waitfor delay '00:00:05'").do }
141
+
142
+ # Use toxiproxy to close the TCP socket after 1 second.
143
+ # We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
144
+ # the network connection needs to close after the sql batch is sent and before the timeout above is hit
145
+ Toxiproxy[:sqlserver_test].toxic(:slow_close, delay: 1000).apply do
146
+ assert_raise_tinytds_error(action) do |e|
147
+ assert_equal 20003, e.db_error_number
148
+ assert_equal 6, e.severity
149
+ assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
150
+ end
151
+ end
152
+ ensure
153
+ assert_new_connections_work
154
+ end
155
+ end
156
+
157
+ it 'raises TinyTds exception with dead connection network failure' do
158
+ skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
159
+ begin
160
+ client = new_connection timeout: 2, port: 1234
161
+ assert_client_works(client)
162
+ action = lambda { client.execute("waitfor delay '00:00:05'").do }
163
+
164
+ # Use toxiproxy to close the network connection after 1 second.
165
+ # We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
166
+ # the network connection needs to close after the sql batch is sent and before the timeout above is hit
167
+ Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 1000).apply do
168
+ assert_raise_tinytds_error(action) do |e|
169
+ assert_equal 20047, e.db_error_number
170
+ assert_includes [1,9], e.severity
171
+ assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
172
+ end
173
+ end
174
+ ensure
175
+ assert_new_connections_work
176
+ end
177
+ end
178
+
179
+ it 'raises TinyTds exception with login timeout' do
180
+ skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
181
+ begin
182
+ action = lambda do
183
+ Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 0).apply do
184
+ new_connection login_timeout: 1, port: 1234
185
+ end
186
+ end
144
187
  assert_raise_tinytds_error(action) do |e|
145
188
  assert_equal 20003, e.db_error_number
146
189
  assert_equal 6, e.severity
147
190
  assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
148
191
  end
149
192
  ensure
150
- STDOUT.puts "Reconnect network!"
151
- sleep 10
152
- action = lambda { client.execute('SELECT 1 as [one]').each }
153
- assert_raise_tinytds_error(action) do |e|
154
- assert_equal 20047, e.db_error_number
155
- assert_equal 1, e.severity
156
- assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
157
- end
158
- close_client(client)
159
193
  assert_new_connections_work
160
194
  end
161
195
  end
@@ -174,57 +208,68 @@ class ClientTest < TinyTds::TestCase
174
208
 
175
209
  end
176
210
 
177
- describe 'Private methods' do
178
-
211
+ describe '#parse_username' do
179
212
  let(:client) { @client = new_connection }
180
213
 
181
- it '#parse_username returns username if azure is not true' do
182
- username = 'user@abc123.database.windows.net'
183
- client.send(:parse_username, username: username).must_equal username
214
+ it 'returns username if azure is not true' do
215
+ _(
216
+ client.send(:parse_username, username: 'user@abc123.database.windows.net')
217
+ ).must_equal 'user@abc123.database.windows.net'
184
218
  end
185
219
 
186
- it '#parse_username returns short username if azure is true' do
187
- client.send(:parse_username,
188
- username: 'user@abc123.database.windows.net',
189
- host: 'abc123.database.windows.net',
190
- azure: true
220
+ it 'returns short username if azure is true' do
221
+ _(
222
+ client.send(
223
+ :parse_username,
224
+ username: 'user@abc123.database.windows.net',
225
+ host: 'abc123.database.windows.net',
226
+ azure: true
227
+ )
191
228
  ).must_equal 'user@abc123'
192
229
  end
193
230
 
194
- it '#parse_username returns full username if azure is false' do
195
- client.send(:parse_username,
196
- username: 'user@abc123.database.windows.net',
197
- host: 'abc123.database.windows.net',
198
- azure: false
231
+ it 'returns full username if azure is false' do
232
+ _(
233
+ client.send(
234
+ :parse_username,
235
+ username: 'user@abc123.database.windows.net',
236
+ host: 'abc123.database.windows.net',
237
+ azure: false
238
+ )
199
239
  ).must_equal 'user@abc123.database.windows.net'
200
240
  end
201
241
 
202
- it '#parse_username returns short username if passed and azure is true' do
203
- client.send(:parse_username,
204
- username: 'user@abc123',
205
- host: 'abc123.database.windows.net',
206
- azure: true
242
+ it 'returns short username if passed and azure is true' do
243
+ _(
244
+ client.send(
245
+ :parse_username,
246
+ username: 'user@abc123',
247
+ host: 'abc123.database.windows.net',
248
+ azure: true
249
+ )
207
250
  ).must_equal 'user@abc123'
208
251
  end
209
252
 
210
- it '#parse_username returns username with servername if passed and azure is true' do
211
- client.send(:parse_username,
212
- username: 'user',
213
- host: 'abc123.database.windows.net',
214
- azure: true
253
+ it 'returns username with servername if passed and azure is true' do
254
+ _(
255
+ client.send(
256
+ :parse_username,
257
+ username: 'user',
258
+ host: 'abc123.database.windows.net',
259
+ azure: true
260
+ )
215
261
  ).must_equal 'user@abc123'
216
262
  end
217
263
 
218
- it '#parse_username returns username with servername if passed and azure is false' do
219
- client.send(:parse_username,
220
- username: 'user',
221
- host: 'abc123.database.windows.net',
222
- azure: false
264
+ it 'returns username with servername if passed and azure is false' do
265
+ _(
266
+ client.send(
267
+ :parse_username,
268
+ username: 'user',
269
+ host: 'abc123.database.windows.net',
270
+ azure: false
271
+ )
223
272
  ).must_equal 'user'
224
273
  end
225
-
226
274
  end
227
-
228
-
229
275
  end
230
-
data/test/gem_test.rb CHANGED
@@ -21,13 +21,13 @@ class GemTest < MiniTest::Spec
21
21
  let(:root_path) { TinyTds::Gem.root_path }
22
22
 
23
23
  it 'should be the root path' do
24
- root_path.must_equal gem_root
24
+ _(root_path).must_equal gem_root
25
25
  end
26
26
 
27
27
  it 'should be the root path no matter the cwd' do
28
28
  Dir.chdir '/'
29
29
 
30
- root_path.must_equal gem_root
30
+ _(root_path).must_equal gem_root
31
31
  end
32
32
  end
33
33
 
@@ -35,19 +35,19 @@ class GemTest < MiniTest::Spec
35
35
  let(:ports_root_path) { TinyTds::Gem.ports_root_path }
36
36
 
37
37
  it 'should be the ports path' do
38
- ports_root_path.must_equal File.join(gem_root,'ports')
38
+ _(ports_root_path).must_equal File.join(gem_root,'ports')
39
39
  end
40
40
 
41
41
  it 'should be the ports path no matter the cwd' do
42
42
  Dir.chdir '/'
43
43
 
44
- ports_root_path.must_equal File.join(gem_root,'ports')
44
+ _(ports_root_path).must_equal File.join(gem_root,'ports')
45
45
  end
46
46
  end
47
47
 
48
48
  describe '#ports_bin_paths' do
49
49
  let(:ports_bin_paths) { TinyTds::Gem.ports_bin_paths }
50
-
50
+
51
51
  describe 'when the ports directories exist' do
52
52
  let(:fake_bin_paths) do
53
53
  ports_host_root = File.join(gem_root, 'ports', 'fake-host-with-dirs')
@@ -74,12 +74,12 @@ class GemTest < MiniTest::Spec
74
74
  end
75
75
 
76
76
  it 'should return all the bin directories' do
77
- ports_bin_paths.sort.must_equal fake_bin_paths.sort
77
+ _(ports_bin_paths.sort).must_equal fake_bin_paths.sort
78
78
  end
79
79
 
80
80
  it 'should return all the bin directories regardless of cwd' do
81
81
  Dir.chdir '/'
82
- ports_bin_paths.sort.must_equal fake_bin_paths.sort
82
+ _(ports_bin_paths.sort).must_equal fake_bin_paths.sort
83
83
  end
84
84
  end
85
85
 
@@ -89,19 +89,19 @@ class GemTest < MiniTest::Spec
89
89
  end
90
90
 
91
91
  it 'should return no directories' do
92
- ports_bin_paths.must_be_empty
92
+ _(ports_bin_paths).must_be_empty
93
93
  end
94
94
 
95
95
  it 'should return no directories regardless of cwd' do
96
96
  Dir.chdir '/'
97
- ports_bin_paths.must_be_empty
97
+ _(ports_bin_paths).must_be_empty
98
98
  end
99
99
  end
100
100
  end
101
101
 
102
102
  describe '#ports_lib_paths' do
103
103
  let(:ports_lib_paths) { TinyTds::Gem.ports_lib_paths }
104
-
104
+
105
105
  describe 'when the ports directories exist' do
106
106
  let(:fake_lib_paths) do
107
107
  ports_host_root = File.join(gem_root, 'ports', 'fake-host-with-dirs')
@@ -128,12 +128,12 @@ class GemTest < MiniTest::Spec
128
128
  end
129
129
 
130
130
  it 'should return all the lib directories' do
131
- ports_lib_paths.sort.must_equal fake_lib_paths.sort
131
+ _(ports_lib_paths.sort).must_equal fake_lib_paths.sort
132
132
  end
133
133
 
134
134
  it 'should return all the lib directories regardless of cwd' do
135
135
  Dir.chdir '/'
136
- ports_lib_paths.sort.must_equal fake_lib_paths.sort
136
+ _(ports_lib_paths.sort).must_equal fake_lib_paths.sort
137
137
  end
138
138
  end
139
139
 
@@ -144,12 +144,12 @@ class GemTest < MiniTest::Spec
144
144
 
145
145
 
146
146
  it 'should return no directories' do
147
- ports_lib_paths.must_be_empty
147
+ _(ports_lib_paths).must_be_empty
148
148
  end
149
149
 
150
150
  it 'should return no directories regardless of cwd' do
151
151
  Dir.chdir '/'
152
- ports_lib_paths.must_be_empty
152
+ _(ports_lib_paths).must_be_empty
153
153
  end
154
154
  end
155
155
  end
@@ -169,7 +169,7 @@ class GemTest < MiniTest::Spec
169
169
  end
170
170
 
171
171
  it "should return a #{expected} ports host" do
172
- TinyTds::Gem.ports_host.must_equal expected
172
+ _(TinyTds::Gem.ports_host).must_equal expected
173
173
  end
174
174
  end
175
175
  end
data/test/result_test.rb CHANGED
@@ -80,7 +80,7 @@ class ResultTest < TinyTds::TestCase
80
80
  @client.execute("DELETE FROM [datatypes]").do
81
81
  @client.execute("INSERT INTO [datatypes] ([char_10], [varchar_50]) VALUES ('1', '2')").do
82
82
  result = @client.execute("SELECT TOP (1) [char_10] + 'test' + [varchar_50] AS [test] FROM [datatypes]").each.first['test']
83
- result.must_equal "1 test2"
83
+ _(result).must_equal "1 test2"
84
84
  end
85
85
  end
86
86
 
@@ -135,10 +135,10 @@ class ResultTest < TinyTds::TestCase
135
135
  text = 'test affected rows sql'
136
136
  @client.execute("DELETE FROM [datatypes]").do
137
137
  afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
138
- ['Fixnum', 'Integer'].must_include afrows.class.name
138
+ _(['Fixnum', 'Integer']).must_include afrows.class.name
139
139
  @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
140
140
  pk1 = @client.execute(@client.identity_sql).each.first['Ident']
141
- ['Fixnum', 'Integer'].must_include pk1.class.name, 'we it be able to CAST to bigint'
141
+ _(['Fixnum', 'Integer']).must_include pk1.class.name, 'we it be able to CAST to bigint'
142
142
  @client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
143
143
  afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
144
144
  assert_equal 1, afrows
@@ -215,34 +215,34 @@ class ResultTest < TinyTds::TestCase
215
215
  @client.execute("DELETE FROM [datatypes]").do
216
216
  @client.execute("ROLLBACK TRANSACTION").do
217
217
  count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first['count']
218
- 0.wont_equal count
218
+ _(count).wont_equal 0
219
219
  end
220
220
 
221
221
  it 'has a #fields accessor with logic default and valid outcome' do
222
222
  result = @client.execute(@query1)
223
- result.fields.must_equal ['one']
223
+ _(result.fields).must_equal ['one']
224
224
  result.each
225
- result.fields.must_equal ['one']
225
+ _(result.fields).must_equal ['one']
226
226
  end
227
227
 
228
228
  it 'always returns an array for fields for all sql' do
229
229
  result = @client.execute("USE [tinytdstest]")
230
- result.fields.must_equal []
230
+ _(result.fields).must_equal []
231
231
  result.do
232
- result.fields.must_equal []
232
+ _(result.fields).must_equal []
233
233
  end
234
234
 
235
235
  it 'returns fields even when no results are found' do
236
236
  no_results_query = "SELECT [id], [varchar_50] FROM [datatypes] WHERE [varchar_50] = 'NOTFOUND'"
237
237
  # Fields before each.
238
238
  result = @client.execute(no_results_query)
239
- result.fields.must_equal ['id','varchar_50']
239
+ _(result.fields).must_equal ['id','varchar_50']
240
240
  result.each
241
- result.fields.must_equal ['id','varchar_50']
241
+ _(result.fields).must_equal ['id','varchar_50']
242
242
  # Each then fields
243
243
  result = @client.execute(no_results_query)
244
244
  result.each
245
- result.fields.must_equal ['id','varchar_50']
245
+ _(result.fields).must_equal ['id','varchar_50']
246
246
  end
247
247
 
248
248
  it 'allows the result to be canceled before reading' do
@@ -254,27 +254,27 @@ class ResultTest < TinyTds::TestCase
254
254
  it 'works in tandem with the client when needing to find out if client has sql sent and result is canceled or not' do
255
255
  # Default state.
256
256
  @client = TinyTds::Client.new(connection_options)
257
- @client.sqlsent?.must_equal false
258
- @client.canceled?.must_equal false
257
+ _(@client.sqlsent?).must_equal false
258
+ _(@client.canceled?).must_equal false
259
259
  # With active result before and after cancel.
260
260
  result = @client.execute(@query1)
261
- @client.sqlsent?.must_equal true
262
- @client.canceled?.must_equal false
261
+ _(@client.sqlsent?).must_equal true
262
+ _(@client.canceled?).must_equal false
263
263
  result.cancel
264
- @client.sqlsent?.must_equal false
265
- @client.canceled?.must_equal true
264
+ _(@client.sqlsent?).must_equal false
265
+ _(@client.canceled?).must_equal true
266
266
  assert result.cancel, 'must be safe to call again'
267
267
  # With each and no block.
268
268
  @client.execute(@query1).each
269
- @client.sqlsent?.must_equal false
270
- @client.canceled?.must_equal false
269
+ _(@client.sqlsent?).must_equal false
270
+ _(@client.canceled?).must_equal false
271
271
  # With each and block.
272
272
  @client.execute(@query1).each do |row|
273
- @client.sqlsent?.must_equal true, 'when iterating over each row in a block'
274
- @client.canceled?.must_equal false
273
+ _(@client.sqlsent?).must_equal true, 'when iterating over each row in a block'
274
+ _(@client.canceled?).must_equal false
275
275
  end
276
- @client.sqlsent?.must_equal false
277
- @client.canceled?.must_equal false
276
+ _(@client.sqlsent?).must_equal false
277
+ _(@client.canceled?).must_equal false
278
278
  # With each and block canceled half way thru.
279
279
  count = @client.execute("SELECT COUNT([id]) AS [count] FROM [datatypes]").each[0]['count']
280
280
  assert count > 10, 'since we want to cancel early for test'
@@ -284,25 +284,25 @@ class ResultTest < TinyTds::TestCase
284
284
  break if index > 10
285
285
  index += 1
286
286
  end
287
- @client.sqlsent?.must_equal true
288
- @client.canceled?.must_equal false
287
+ _(@client.sqlsent?).must_equal true
288
+ _(@client.canceled?).must_equal false
289
289
  result.cancel
290
- @client.sqlsent?.must_equal false
291
- @client.canceled?.must_equal true
290
+ _(@client.sqlsent?).must_equal false
291
+ _(@client.canceled?).must_equal true
292
292
  # With do method.
293
293
  @client.execute(@query1).do
294
- @client.sqlsent?.must_equal false
295
- @client.canceled?.must_equal true
294
+ _(@client.sqlsent?).must_equal false
295
+ _(@client.canceled?).must_equal true
296
296
  # With insert method.
297
297
  rollback_transaction(@client) do
298
298
  @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('test')").insert
299
- @client.sqlsent?.must_equal false
300
- @client.canceled?.must_equal true
299
+ _(@client.sqlsent?).must_equal false
300
+ _(@client.canceled?).must_equal true
301
301
  end
302
302
  # With first
303
303
  @client.execute("SELECT [id] FROM [datatypes]").each(:first => true)
304
- @client.sqlsent?.must_equal false
305
- @client.canceled?.must_equal true
304
+ _(@client.sqlsent?).must_equal false
305
+ _(@client.canceled?).must_equal true
306
306
  end
307
307
 
308
308
  it 'use same string object for hash keys' do
@@ -337,7 +337,7 @@ class ResultTest < TinyTds::TestCase
337
337
 
338
338
  it 'with LOGINPROPERTY function' do
339
339
  v = @client.execute("SELECT LOGINPROPERTY('sa', 'IsLocked') as v").first['v']
340
- v.must_equal 0
340
+ _(v).must_equal 0
341
341
  end
342
342
 
343
343
  describe 'with multiple result sets' do
@@ -652,6 +652,48 @@ class ResultTest < TinyTds::TestCase
652
652
  assert_equal 1, messages.length, 'there should be one message after one print statement'
653
653
  assert_equal msg, m.message, 'message text'
654
654
  end
655
+
656
+ it 'must raise an error preceded by a `print` message' do
657
+ messages.clear
658
+ action = lambda { @client.execute("EXEC tinytds_TestPrintWithError").do }
659
+ assert_raise_tinytds_error(action) do |e|
660
+ assert_equal 'hello', messages.first.message, 'message text'
661
+
662
+ assert_equal "Error following print", e.message
663
+ assert_equal 16, e.severity
664
+ assert_equal 50000, e.db_error_number
665
+ end
666
+ end
667
+
668
+ it 'calls the provided message handler for each of a series of `print` messages' do
669
+ messages.clear
670
+ @client.execute("EXEC tinytds_TestSeveralPrints").do
671
+ assert_equal ['hello 1', 'hello 2', 'hello 3'], messages.map { |e| e.message }, 'message list'
672
+ end
673
+
674
+ it 'should flush info messages before raising error in cases of timeout' do
675
+ @client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
676
+ action = lambda { @client.execute("print 'hello'; waitfor delay '00:00:02'").do }
677
+ messages.clear
678
+ assert_raise_tinytds_error(action) do |e|
679
+ assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
680
+ assert_equal 6, e.severity
681
+ assert_equal 20003, e.db_error_number
682
+ assert_equal 'hello', messages.first&.message, 'message text'
683
+ end
684
+ end
685
+
686
+ it 'should print info messages before raising error in cases of timeout' do
687
+ @client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
688
+ action = lambda { @client.execute("raiserror('hello', 1, 1) with nowait; waitfor delay '00:00:02'").do }
689
+ messages.clear
690
+ assert_raise_tinytds_error(action) do |e|
691
+ assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
692
+ assert_equal 6, e.severity
693
+ assert_equal 20003, e.db_error_number
694
+ assert_equal 'hello', messages.first&.message, 'message text'
695
+ end
696
+ end
655
697
  end
656
698
 
657
699
  it 'must not raise an error when severity is 10 or less' do
@@ -684,7 +726,7 @@ class ResultTest < TinyTds::TestCase
684
726
  end
685
727
 
686
728
  it 'throws an error when you execute another query with other results pending' do
687
- result1 = @client.execute(@query1)
729
+ @client.execute(@query1)
688
730
  action = lambda { @client.execute(@query1) }
689
731
  assert_raise_tinytds_error(action) do |e|
690
732
  assert_match %r|with results pending|i, e.message
@@ -717,22 +759,22 @@ class ResultTest < TinyTds::TestCase
717
759
  it 'must not error at all from reading non-convertable charcters and just use ? marks' do
718
760
  close_client
719
761
  @client = new_connection :encoding => 'ASCII'
720
- @client.charset.must_equal 'ASCII'
721
- find_value(202, :nvarchar_50).must_equal 'test nvarchar_50 ??'
762
+ _(@client.charset).must_equal 'ASCII'
763
+ _(find_value(202, :nvarchar_50)).must_equal 'test nvarchar_50 ??'
722
764
  end
723
765
 
724
766
  it 'must error gracefully from writing non-convertable characters' do
725
767
  close_client
726
768
  @client = new_connection :encoding => 'ASCII'
727
- @client.charset.must_equal 'ASCII'
769
+ _(@client.charset).must_equal 'ASCII'
728
770
  rollback_transaction(@client) do
729
771
  text = 'Test ✓'
730
772
  @client.execute("DELETE FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").do
731
773
  action = lambda { @client.execute("INSERT INTO [datatypes] ([nvarchar_50]) VALUES ('#{text}')").do }
732
774
  assert_raise_tinytds_error(action) do |e|
733
- e.message.must_match %r{Unclosed quotation mark}i
734
- e.severity.must_equal 15
735
- e.db_error_number.must_equal 105
775
+ _(e.message).must_match %r{Unclosed quotation mark}i
776
+ _(e.severity).must_equal 15
777
+ _(e.db_error_number).must_equal 105
736
778
  end
737
779
  assert_followup_query
738
780
  end
@@ -770,4 +812,3 @@ class ResultTest < TinyTds::TestCase
770
812
  end
771
813
 
772
814
  end
773
-