slacker 1.0.14 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/README.markdown +22 -22
- data/Rakefile +11 -11
- data/bin/slacker +32 -32
- data/bin/slacker_new +34 -34
- data/lib/slacker.rb +180 -175
- data/lib/slacker/application.rb +224 -214
- data/lib/slacker/command_line_formatter.rb +61 -61
- data/lib/slacker/configuration.rb +59 -59
- data/lib/slacker/formatter.rb +14 -14
- data/lib/slacker/query_result_matcher.rb +178 -178
- data/lib/slacker/rspec_ext.rb +57 -57
- data/lib/slacker/rspec_monkey.rb +7 -7
- data/lib/slacker/sql.rb +39 -39
- data/lib/slacker/sql_preprocessor.rb +23 -23
- data/lib/slacker/string_helper.rb +16 -16
- data/lib/slacker/version.rb +3 -3
- data/lib/slacker_new/project/data/sample_1/my_table_expected_power_results.csv +11 -11
- data/lib/slacker_new/project/data/sample_1/my_table_initial_data.csv +11 -11
- data/lib/slacker_new/project/data/sample_1/numbers_expected_output.csv +3 -3
- data/lib/slacker_new/project/database.yml +9 -9
- data/lib/slacker_new/project/lib/helpers/my_helper.rb +1 -1
- data/lib/slacker_new/project/spec/sample_1.rb +66 -66
- data/lib/slacker_new/project/sql/sample_1/my_table_on_power.sql.erb +1 -1
- data/lib/slacker_new/project/sql/sample_1/play_with_numbers.sql.erb +16 -16
- data/lib/slacker_new/project/sql/sample_1/sysobjects_with_params.sql.erb +1 -1
- data/slacker.gemspec +27 -27
- data/spec/application_spec.rb +13 -13
- data/spec/query_result_matcher_spec.rb +268 -268
- data/spec/rspec_ext_spec.rb +87 -87
- data/spec/slacker_spec.rb +59 -59
- data/spec/spec_helper.rb +19 -9
- data/spec/test_files/matcher/test_1.csv +3 -3
- data/spec/test_files/test_slacker_project/data/test_1.csv +3 -3
- data/spec/test_files/test_slacker_project/sql/nest/nested_1.sql.erb +1 -1
- data/spec/test_files/test_slacker_project/sql/no_params.sql.erb +2 -2
- data/spec/test_files/test_slacker_project/sql/params.sql.erb +1 -1
- metadata +24 -24
@@ -1,2 +1,2 @@
|
|
1
|
-
select x, y, convert(int, Power(x, y)) as [power]
|
1
|
+
select x, y, convert(int, Power(x, y)) as [power]
|
2
2
|
from MyTable;
|
@@ -1,16 +1,16 @@
|
|
1
|
-
declare @x int;
|
2
|
-
declare @y int;
|
3
|
-
|
4
|
-
set @x = <%= options[:x]%>;
|
5
|
-
set @y = <%= options[:y]%>;
|
6
|
-
|
7
|
-
-- Return just the product of @x and @y
|
8
|
-
select @x * @y [product] union all
|
9
|
-
select 12;
|
10
|
-
|
11
|
-
-- Return the numbers and their sum
|
12
|
-
select @x x, @y y, @x + @y [sum];
|
13
|
-
|
14
|
-
-- Get the two numbers in one column and their sum with 32 in another
|
15
|
-
select @x p, @x + 32 s union all
|
16
|
-
select @y p, @y + 32 s;
|
1
|
+
declare @x int;
|
2
|
+
declare @y int;
|
3
|
+
|
4
|
+
set @x = <%= options[:x]%>;
|
5
|
+
set @y = <%= options[:y]%>;
|
6
|
+
|
7
|
+
-- Return just the product of @x and @y
|
8
|
+
select @x * @y [product] union all
|
9
|
+
select 12;
|
10
|
+
|
11
|
+
-- Return the numbers and their sum
|
12
|
+
select @x x, @y y, @x + @y [sum];
|
13
|
+
|
14
|
+
-- Get the two numbers in one column and their sum with 32 in another
|
15
|
+
select @x p, @x + 32 s union all
|
16
|
+
select @y p, @y + 32 s;
|
@@ -1,2 +1,2 @@
|
|
1
|
-
<%# Every parameter passed to a SQL template appears in the options hash available to the template %>
|
1
|
+
<%# Every parameter passed to a SQL template appears in the options hash available to the template %>
|
2
2
|
select * from sysobjects where xtype = '<%= options[:xtype] %>';
|
data/slacker.gemspec
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "slacker/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "slacker"
|
7
|
-
s.version = Slacker::VERSION
|
8
|
-
s.authors = ["Vassil Kovatchev"]
|
9
|
-
s.email = ["vassil.kovatchev@gmail.com"]
|
10
|
-
s.homepage = "https://github.com/vassilvk/slacker/wiki"
|
11
|
-
s.summary = %q{Behavior Driven Development for SQL Server}
|
12
|
-
s.description = %q{RSpec-based framework for developing automated tests for SQL Server}
|
13
|
-
s.license = 'MIT'
|
14
|
-
|
15
|
-
s.rubyforge_project = "slacker"
|
16
|
-
|
17
|
-
s.files = ['README.markdown', 'Rakefile', 'Gemfile', 'slacker.gemspec'] + Dir.glob("{bin,lib,spec}/**/*")
|
18
|
-
s.test_files = Dir.glob("spec/**/*")
|
19
|
-
s.executables = ['slacker', 'slacker_new']
|
20
|
-
s.require_paths = ["lib"]
|
21
|
-
|
22
|
-
s.required_ruby_version = '>= 1.9.2'
|
23
|
-
|
24
|
-
s.add_dependency 'bundler', '~> 1.0', '>= 1.0.15'
|
25
|
-
s.add_dependency 'ruby-odbc', '= 0.99997'
|
26
|
-
s.add_dependency 'rspec', '~> 3.0'
|
27
|
-
end
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "slacker/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "slacker"
|
7
|
+
s.version = Slacker::VERSION
|
8
|
+
s.authors = ["Vassil Kovatchev"]
|
9
|
+
s.email = ["vassil.kovatchev@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/vassilvk/slacker/wiki"
|
11
|
+
s.summary = %q{Behavior Driven Development for SQL Server}
|
12
|
+
s.description = %q{RSpec-based framework for developing automated tests for SQL Server}
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.rubyforge_project = "slacker"
|
16
|
+
|
17
|
+
s.files = ['README.markdown', 'Rakefile', 'Gemfile', 'slacker.gemspec'] + Dir.glob("{bin,lib,spec}/**/*")
|
18
|
+
s.test_files = Dir.glob("spec/**/*")
|
19
|
+
s.executables = ['slacker', 'slacker_new']
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.required_ruby_version = '>= 1.9.2'
|
23
|
+
|
24
|
+
s.add_dependency 'bundler', '~> 1.0', '>= 1.0.15'
|
25
|
+
s.add_dependency 'ruby-odbc', '= 0.99997'
|
26
|
+
s.add_dependency 'rspec', '~> 3.0'
|
27
|
+
end
|
data/spec/application_spec.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
require 'slacker'
|
2
|
-
|
3
|
-
describe Slacker::Application do
|
4
|
-
it 'responds to run' do
|
5
|
-
Slacker.application.should respond_to(:run)
|
6
|
-
end
|
7
|
-
|
8
|
-
it 'responds to target_folder_structure with the correct list of folders' do
|
9
|
-
app = Slacker.application
|
10
|
-
app.should respond_to(:target_folder_structure)
|
11
|
-
folder_struct = app.target_folder_structure
|
12
|
-
folder_struct.should == ['data', 'debug
|
13
|
-
end
|
1
|
+
require 'slacker'
|
2
|
+
|
3
|
+
describe Slacker::Application do
|
4
|
+
it 'responds to run' do
|
5
|
+
Slacker.application.should respond_to(:run)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'responds to target_folder_structure with the correct list of folders' do
|
9
|
+
app = Slacker.application
|
10
|
+
app.should respond_to(:target_folder_structure)
|
11
|
+
folder_struct = app.target_folder_structure
|
12
|
+
folder_struct.should == ['data', 'debug/passed_examples', 'debug/failed_examples', 'sql', 'spec', 'lib', 'lib/helpers']
|
13
|
+
end
|
14
14
|
end
|
@@ -1,268 +1,268 @@
|
|
1
|
-
require 'slacker'
|
2
|
-
require 'spec_helper'
|
3
|
-
require 'time'
|
4
|
-
require 'odbc'
|
5
|
-
|
6
|
-
describe Slacker::QueryResultMatcher do
|
7
|
-
def deep_copy(obj)
|
8
|
-
Marshal.load(Marshal.dump(obj))
|
9
|
-
end
|
10
|
-
|
11
|
-
before(:each) do
|
12
|
-
@subject = [{'Field 1' => 12, 'Field_2' => nil, 'b' => ''},
|
13
|
-
{'Field 1' => 'test string', 'Field_2' => ODBC::TimeStamp.new('2011-01-30'), 'b' => 8.9}]
|
14
|
-
end
|
15
|
-
|
16
|
-
shared_examples_for 'table-based matcher' do
|
17
|
-
it 'correctly rejects a non-matching query result based on wrong columns' do
|
18
|
-
one_column_too_few = deep_copy(@subject).each{|row| row.delete('b')}
|
19
|
-
one_column_too_many = deep_copy(@subject).each{|row| row['new column'] = 'val 1'}
|
20
|
-
wrong_column_name = deep_copy(@subject).each{|row| row.delete('Field_2'); row['Field_x'] = 'val x'}
|
21
|
-
|
22
|
-
@matcher.matches?(one_column_too_few).should
|
23
|
-
@matcher.
|
24
|
-
|
25
|
-
@matcher.matches?(one_column_too_many).should
|
26
|
-
@matcher.
|
27
|
-
|
28
|
-
@matcher.matches?(wrong_column_name).should
|
29
|
-
@matcher.
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'correctly rejects a non-matching query result based on number of records' do
|
33
|
-
one_row_too_few = deep_copy(@subject)
|
34
|
-
one_row_too_few.shift
|
35
|
-
one_row_too_many = deep_copy(@subject) << @subject[0]
|
36
|
-
empty_query_result = []
|
37
|
-
|
38
|
-
@matcher.matches?(one_row_too_few).should
|
39
|
-
@matcher.
|
40
|
-
|
41
|
-
@matcher.matches?(one_row_too_many).should
|
42
|
-
@matcher.
|
43
|
-
|
44
|
-
@matcher.matches?(empty_query_result).should
|
45
|
-
@matcher.
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'correctly rejects a non-matching query result based on a value' do
|
49
|
-
wrong_int = deep_copy(@subject)
|
50
|
-
wrong_int[0]['Field 1'] = 14
|
51
|
-
|
52
|
-
wrong_int_type = deep_copy(@subject)
|
53
|
-
wrong_int_type[1]['Field 1'] = 14
|
54
|
-
|
55
|
-
wrong_nil = deep_copy(@subject)
|
56
|
-
wrong_nil[0]['Field 1'] = nil
|
57
|
-
|
58
|
-
wrong_non_nil = deep_copy(@subject)
|
59
|
-
wrong_non_nil[0]['Field_2'] = 'whatever'
|
60
|
-
|
61
|
-
misplaced_fields = deep_copy(@subject)
|
62
|
-
misplaced_fields[0].delete('Field 1')
|
63
|
-
misplaced_fields[1].delete('Field 1')
|
64
|
-
misplaced_fields[0]['Field 1'] = 12
|
65
|
-
misplaced_fields[1]['Field 1'] = 'test string'
|
66
|
-
|
67
|
-
@matcher.matches?(wrong_int).should
|
68
|
-
@matcher.
|
69
|
-
|
70
|
-
|
71
|
-
@matcher.matches?(wrong_int_type).should
|
72
|
-
@matcher.
|
73
|
-
|
74
|
-
@matcher.matches?(wrong_nil).should
|
75
|
-
@matcher.
|
76
|
-
|
77
|
-
@matcher.matches?(wrong_non_nil).should
|
78
|
-
@matcher.
|
79
|
-
|
80
|
-
@matcher.matches?(misplaced_fields).should
|
81
|
-
@matcher.
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'correctly compares with a query result' do
|
85
|
-
@matcher.matches?(@subject).should
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'only accepts well formed query result subjects' do
|
89
|
-
expected_message = /Can perform query matches only against a well formed query result subject/
|
90
|
-
@matcher.matches?(1).should
|
91
|
-
@matcher.
|
92
|
-
|
93
|
-
@matcher.matches?('test string').should
|
94
|
-
@matcher.
|
95
|
-
|
96
|
-
@matcher.matches?(1.1).should
|
97
|
-
@matcher.
|
98
|
-
|
99
|
-
@matcher.matches?(Time.now).should
|
100
|
-
@matcher.
|
101
|
-
|
102
|
-
@matcher.matches?(nil).should
|
103
|
-
@matcher.
|
104
|
-
|
105
|
-
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x'}]).should
|
106
|
-
@matcher.
|
107
|
-
|
108
|
-
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f3 => 'y'}]).should
|
109
|
-
@matcher.
|
110
|
-
|
111
|
-
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f2 => 'y', :f3 => 'z'}]).should
|
112
|
-
@matcher.
|
113
|
-
|
114
|
-
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, 12]).should
|
115
|
-
@matcher.
|
116
|
-
|
117
|
-
@matcher.matches?([12, {:f1 => 'x', :f2 => 'y'}]).should
|
118
|
-
@matcher.
|
119
|
-
|
120
|
-
# An array with a single empty row is not a well-formed query result
|
121
|
-
@matcher.matches?([{}]).should
|
122
|
-
@matcher.
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
describe 'CSV-based golden master' do
|
128
|
-
before(:each) do
|
129
|
-
@matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/test_1.csv'))
|
130
|
-
end
|
131
|
-
|
132
|
-
it_behaves_like 'table-based matcher'
|
133
|
-
|
134
|
-
it 'correctly compares an empty subject with an empty CSV file' do
|
135
|
-
matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/no_rows.csv'))
|
136
|
-
matcher.matches?([]).should
|
137
|
-
|
138
|
-
matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/completely_blank.csv'))
|
139
|
-
matcher.matches?([]).should
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe 'Array-based golden master' do
|
144
|
-
before(:each) do
|
145
|
-
@matcher = Slacker::QueryResultMatcher.new(deep_copy(@subject))
|
146
|
-
end
|
147
|
-
|
148
|
-
it_behaves_like 'table-based matcher'
|
149
|
-
|
150
|
-
it 'only accepts well formed query result golden master' do
|
151
|
-
expected_message = /Cannot match against a non-well formed golden master array/
|
152
|
-
|
153
|
-
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x'}])
|
154
|
-
matcher.matches?([]).should
|
155
|
-
matcher.
|
156
|
-
|
157
|
-
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f3 => 'y'}])
|
158
|
-
matcher.matches?([]).should
|
159
|
-
matcher.
|
160
|
-
|
161
|
-
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f2 => 'y', :f3 => 'z'}])
|
162
|
-
matcher.matches?([]).should
|
163
|
-
matcher.
|
164
|
-
|
165
|
-
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, 12])
|
166
|
-
matcher.matches?([]).should
|
167
|
-
matcher.
|
168
|
-
|
169
|
-
matcher = Slacker::QueryResultMatcher.new([12, {:f1 => 'x', :f2 => 'y'}])
|
170
|
-
matcher.matches?([]).should
|
171
|
-
matcher.
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'correctly compares an empty subject with an empty golden master' do
|
175
|
-
matcher = Slacker::QueryResultMatcher.new([])
|
176
|
-
matcher.matches?([]).should
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
shared_examples_for 'single-value-based matcher' do
|
181
|
-
it 'should correctly match the first value in the result set' do
|
182
|
-
matcher = Slacker::QueryResultMatcher.new(@correct_golden_master)
|
183
|
-
matcher.matches?(@subject).should
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'should correctly reject a non-matching first item by value' do
|
187
|
-
if !@wrong_value_golden_master.nil? #Skip nil from value check when the master is nil
|
188
|
-
matcher = Slacker::QueryResultMatcher.new(@wrong_value_golden_master)
|
189
|
-
matcher.matches?(@subject).should
|
190
|
-
matcher.
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'should correctly reject a non-matching first item by type' do
|
195
|
-
matcher = Slacker::QueryResultMatcher.new(@wrong_type_golden_master)
|
196
|
-
matcher.matches?(@subject).should
|
197
|
-
matcher.
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
describe 'Integer-based golden master' do
|
202
|
-
before(:each) do
|
203
|
-
@subject = [{'Field 1' => 14, 'Field_2' => 'whatever'}]
|
204
|
-
@correct_golden_master = 14
|
205
|
-
@wrong_value_golden_master = 15
|
206
|
-
@wrong_type_golden_master = 'whatever'
|
207
|
-
end
|
208
|
-
|
209
|
-
it_behaves_like 'single-value-based matcher'
|
210
|
-
end
|
211
|
-
|
212
|
-
describe 'String-based golden master' do
|
213
|
-
before(:each) do
|
214
|
-
@subject = [{'Field 1' => 'test string', 'Field_2' => 12}]
|
215
|
-
@correct_golden_master = 'test string'
|
216
|
-
@wrong_value_golden_master = 'whatever'
|
217
|
-
@wrong_type_golden_master = 15
|
218
|
-
end
|
219
|
-
|
220
|
-
it_behaves_like 'single-value-based matcher'
|
221
|
-
end
|
222
|
-
|
223
|
-
describe 'Floating point-based golden master' do
|
224
|
-
before(:each) do
|
225
|
-
@subject = [{'Field 1' => 18.2, 'Field_2' => 12}]
|
226
|
-
@correct_golden_master = 18.2
|
227
|
-
@wrong_value_golden_master = 18.7
|
228
|
-
@wrong_type_golden_master = 15
|
229
|
-
end
|
230
|
-
|
231
|
-
it_behaves_like 'single-value-based matcher'
|
232
|
-
end
|
233
|
-
|
234
|
-
describe 'Date-based golden master' do
|
235
|
-
before(:each) do
|
236
|
-
@subject = [{'Field 1' => Time.parse('1/1/2011'), 'Field_2' => 12}]
|
237
|
-
@correct_golden_master = Time.parse('1/1/2011')
|
238
|
-
@wrong_value_golden_master = Time.parse('2/1/2011')
|
239
|
-
@wrong_type_golden_master = 'whatever'
|
240
|
-
end
|
241
|
-
|
242
|
-
it_behaves_like 'single-value-based matcher'
|
243
|
-
end
|
244
|
-
|
245
|
-
describe 'Nil-based golden master' do
|
246
|
-
before(:each) do
|
247
|
-
@subject = [{'Field 1' => nil, 'Field_2' => 12}]
|
248
|
-
@correct_golden_master = nil
|
249
|
-
@wrong_value_golden_master = nil # There is no wrong value for nil-based master
|
250
|
-
@wrong_type_golden_master = 'whatever'
|
251
|
-
end
|
252
|
-
|
253
|
-
it_behaves_like 'single-value-based matcher'
|
254
|
-
end
|
255
|
-
|
256
|
-
it 'correctly matches a multi-result subject' do
|
257
|
-
subject = [@subject, [{:Field_x => 12}]]
|
258
|
-
matcher = Slacker::QueryResultMatcher.new(deep_copy(@subject))
|
259
|
-
matcher.matches?(subject).should
|
260
|
-
end
|
261
|
-
|
262
|
-
it 'correctly rejects a wrong multi-result subject' do
|
263
|
-
subject = [[{:Field_x => 12}], @subject]
|
264
|
-
matcher = Slacker::QueryResultMatcher.new(deep_copy(@subject))
|
265
|
-
matcher.matches?(subject).should
|
266
|
-
matcher.
|
267
|
-
end
|
268
|
-
end
|
1
|
+
require 'slacker'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'time'
|
4
|
+
require 'odbc'
|
5
|
+
|
6
|
+
describe Slacker::QueryResultMatcher do
|
7
|
+
def deep_copy(obj)
|
8
|
+
Marshal.load(Marshal.dump(obj))
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
@subject = [{'Field 1' => 12, 'Field_2' => nil, 'b' => ''},
|
13
|
+
{'Field 1' => 'test string', 'Field_2' => ODBC::TimeStamp.new('2011-01-30'), 'b' => 8.9}]
|
14
|
+
end
|
15
|
+
|
16
|
+
shared_examples_for 'table-based matcher' do
|
17
|
+
it 'correctly rejects a non-matching query result based on wrong columns' do
|
18
|
+
one_column_too_few = deep_copy(@subject).each{|row| row.delete('b')}
|
19
|
+
one_column_too_many = deep_copy(@subject).each{|row| row['new column'] = 'val 1'}
|
20
|
+
wrong_column_name = deep_copy(@subject).each{|row| row.delete('Field_2'); row['Field_x'] = 'val x'}
|
21
|
+
|
22
|
+
@matcher.matches?(one_column_too_few).should be false
|
23
|
+
@matcher.failure_message.should == 'Expected 3 field(s), got 2'
|
24
|
+
|
25
|
+
@matcher.matches?(one_column_too_many).should be false
|
26
|
+
@matcher.failure_message.should == 'Expected 3 field(s), got 4'
|
27
|
+
|
28
|
+
@matcher.matches?(wrong_column_name).should be false
|
29
|
+
@matcher.failure_message.should == 'Expected field "Field_2", got field "b"'
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'correctly rejects a non-matching query result based on number of records' do
|
33
|
+
one_row_too_few = deep_copy(@subject)
|
34
|
+
one_row_too_few.shift
|
35
|
+
one_row_too_many = deep_copy(@subject) << @subject[0]
|
36
|
+
empty_query_result = []
|
37
|
+
|
38
|
+
@matcher.matches?(one_row_too_few).should be false
|
39
|
+
@matcher.failure_message.should == 'Expected 2 record(s), got 1'
|
40
|
+
|
41
|
+
@matcher.matches?(one_row_too_many).should be false
|
42
|
+
@matcher.failure_message.should == 'Expected 2 record(s), got 3'
|
43
|
+
|
44
|
+
@matcher.matches?(empty_query_result).should be false
|
45
|
+
@matcher.failure_message.should == 'Expected 2 record(s), got 0'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'correctly rejects a non-matching query result based on a value' do
|
49
|
+
wrong_int = deep_copy(@subject)
|
50
|
+
wrong_int[0]['Field 1'] = 14
|
51
|
+
|
52
|
+
wrong_int_type = deep_copy(@subject)
|
53
|
+
wrong_int_type[1]['Field 1'] = 14
|
54
|
+
|
55
|
+
wrong_nil = deep_copy(@subject)
|
56
|
+
wrong_nil[0]['Field 1'] = nil
|
57
|
+
|
58
|
+
wrong_non_nil = deep_copy(@subject)
|
59
|
+
wrong_non_nil[0]['Field_2'] = 'whatever'
|
60
|
+
|
61
|
+
misplaced_fields = deep_copy(@subject)
|
62
|
+
misplaced_fields[0].delete('Field 1')
|
63
|
+
misplaced_fields[1].delete('Field 1')
|
64
|
+
misplaced_fields[0]['Field 1'] = 12
|
65
|
+
misplaced_fields[1]['Field 1'] = 'test string'
|
66
|
+
|
67
|
+
@matcher.matches?(wrong_int).should be false
|
68
|
+
@matcher.failure_message.should == 'Field "Field 1", Record 1: Expected value "12", got "14"'
|
69
|
+
|
70
|
+
|
71
|
+
@matcher.matches?(wrong_int_type).should be false
|
72
|
+
@matcher.failure_message.should == 'Field "Field 1", Record 2: Expected value "test string", got "14"'
|
73
|
+
|
74
|
+
@matcher.matches?(wrong_nil).should be false
|
75
|
+
@matcher.failure_message.should == 'Field "Field 1", Record 1: Expected value "12", got <NULL>'
|
76
|
+
|
77
|
+
@matcher.matches?(wrong_non_nil).should be false
|
78
|
+
@matcher.failure_message.should == 'Field "Field_2", Record 1: Expected value <NULL>, got "whatever"'
|
79
|
+
|
80
|
+
@matcher.matches?(misplaced_fields).should be false
|
81
|
+
@matcher.failure_message.should == 'Expected field "Field 1", got field "Field_2"'
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'correctly compares with a query result' do
|
85
|
+
@matcher.matches?(@subject).should be true
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'only accepts well formed query result subjects' do
|
89
|
+
expected_message = /Can perform query matches only against a well formed query result subject/
|
90
|
+
@matcher.matches?(1).should be false
|
91
|
+
@matcher.failure_message.should =~ expected_message
|
92
|
+
|
93
|
+
@matcher.matches?('test string').should be false
|
94
|
+
@matcher.failure_message.should =~ expected_message
|
95
|
+
|
96
|
+
@matcher.matches?(1.1).should be false
|
97
|
+
@matcher.failure_message.should =~ expected_message
|
98
|
+
|
99
|
+
@matcher.matches?(Time.now).should be false
|
100
|
+
@matcher.failure_message.should =~ expected_message
|
101
|
+
|
102
|
+
@matcher.matches?(nil).should be false
|
103
|
+
@matcher.failure_message.should =~ expected_message
|
104
|
+
|
105
|
+
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x'}]).should be false
|
106
|
+
@matcher.failure_message.should =~ expected_message
|
107
|
+
|
108
|
+
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f3 => 'y'}]).should be false
|
109
|
+
@matcher.failure_message.should =~ expected_message
|
110
|
+
|
111
|
+
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f2 => 'y', :f3 => 'z'}]).should be false
|
112
|
+
@matcher.failure_message.should =~ expected_message
|
113
|
+
|
114
|
+
@matcher.matches?([{:f1 => 'x', :f2 => 'y'}, 12]).should be false
|
115
|
+
@matcher.failure_message.should =~ expected_message
|
116
|
+
|
117
|
+
@matcher.matches?([12, {:f1 => 'x', :f2 => 'y'}]).should be false
|
118
|
+
@matcher.failure_message.should =~ expected_message
|
119
|
+
|
120
|
+
# An array with a single empty row is not a well-formed query result
|
121
|
+
@matcher.matches?([{}]).should be false
|
122
|
+
@matcher.failure_message.should =~ expected_message
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'CSV-based golden master' do
|
128
|
+
before(:each) do
|
129
|
+
@matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/test_1.csv'))
|
130
|
+
end
|
131
|
+
|
132
|
+
it_behaves_like 'table-based matcher'
|
133
|
+
|
134
|
+
it 'correctly compares an empty subject with an empty CSV file' do
|
135
|
+
matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/no_rows.csv'))
|
136
|
+
matcher.matches?([]).should be true
|
137
|
+
|
138
|
+
matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/completely_blank.csv'))
|
139
|
+
matcher.matches?([]).should be true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'Array-based golden master' do
|
144
|
+
before(:each) do
|
145
|
+
@matcher = Slacker::QueryResultMatcher.new(deep_copy(@subject))
|
146
|
+
end
|
147
|
+
|
148
|
+
it_behaves_like 'table-based matcher'
|
149
|
+
|
150
|
+
it 'only accepts well formed query result golden master' do
|
151
|
+
expected_message = /Cannot match against a non-well formed golden master array/
|
152
|
+
|
153
|
+
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x'}])
|
154
|
+
matcher.matches?([]).should be false
|
155
|
+
matcher.failure_message.should =~ expected_message
|
156
|
+
|
157
|
+
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f3 => 'y'}])
|
158
|
+
matcher.matches?([]).should be false
|
159
|
+
matcher.failure_message.should =~ expected_message
|
160
|
+
|
161
|
+
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f2 => 'y', :f3 => 'z'}])
|
162
|
+
matcher.matches?([]).should be false
|
163
|
+
matcher.failure_message.should =~ expected_message
|
164
|
+
|
165
|
+
matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, 12])
|
166
|
+
matcher.matches?([]).should be false
|
167
|
+
matcher.failure_message.should =~ expected_message
|
168
|
+
|
169
|
+
matcher = Slacker::QueryResultMatcher.new([12, {:f1 => 'x', :f2 => 'y'}])
|
170
|
+
matcher.matches?([]).should be false
|
171
|
+
matcher.failure_message.should =~ expected_message
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'correctly compares an empty subject with an empty golden master' do
|
175
|
+
matcher = Slacker::QueryResultMatcher.new([])
|
176
|
+
matcher.matches?([]).should be true
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
shared_examples_for 'single-value-based matcher' do
|
181
|
+
it 'should correctly match the first value in the result set' do
|
182
|
+
matcher = Slacker::QueryResultMatcher.new(@correct_golden_master)
|
183
|
+
matcher.matches?(@subject).should be true
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should correctly reject a non-matching first item by value' do
|
187
|
+
if !@wrong_value_golden_master.nil? #Skip nil from value check when the master is nil
|
188
|
+
matcher = Slacker::QueryResultMatcher.new(@wrong_value_golden_master)
|
189
|
+
matcher.matches?(@subject).should be false
|
190
|
+
matcher.failure_message.should =~ /Expected value "#{@wrong_value_golden_master}", got "#{@subject[0].values[0]}"/
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'should correctly reject a non-matching first item by type' do
|
195
|
+
matcher = Slacker::QueryResultMatcher.new(@wrong_type_golden_master)
|
196
|
+
matcher.matches?(@subject).should be false
|
197
|
+
matcher.failure_message.should =~ /Expected type "#{@wrong_type_golden_master.class}", got \"#{@subject[0].values[0].class}\"/
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe 'Integer-based golden master' do
|
202
|
+
before(:each) do
|
203
|
+
@subject = [{'Field 1' => 14, 'Field_2' => 'whatever'}]
|
204
|
+
@correct_golden_master = 14
|
205
|
+
@wrong_value_golden_master = 15
|
206
|
+
@wrong_type_golden_master = 'whatever'
|
207
|
+
end
|
208
|
+
|
209
|
+
it_behaves_like 'single-value-based matcher'
|
210
|
+
end
|
211
|
+
|
212
|
+
describe 'String-based golden master' do
|
213
|
+
before(:each) do
|
214
|
+
@subject = [{'Field 1' => 'test string', 'Field_2' => 12}]
|
215
|
+
@correct_golden_master = 'test string'
|
216
|
+
@wrong_value_golden_master = 'whatever'
|
217
|
+
@wrong_type_golden_master = 15
|
218
|
+
end
|
219
|
+
|
220
|
+
it_behaves_like 'single-value-based matcher'
|
221
|
+
end
|
222
|
+
|
223
|
+
describe 'Floating point-based golden master' do
|
224
|
+
before(:each) do
|
225
|
+
@subject = [{'Field 1' => 18.2, 'Field_2' => 12}]
|
226
|
+
@correct_golden_master = 18.2
|
227
|
+
@wrong_value_golden_master = 18.7
|
228
|
+
@wrong_type_golden_master = 15
|
229
|
+
end
|
230
|
+
|
231
|
+
it_behaves_like 'single-value-based matcher'
|
232
|
+
end
|
233
|
+
|
234
|
+
describe 'Date-based golden master' do
|
235
|
+
before(:each) do
|
236
|
+
@subject = [{'Field 1' => Time.parse('1/1/2011'), 'Field_2' => 12}]
|
237
|
+
@correct_golden_master = Time.parse('1/1/2011')
|
238
|
+
@wrong_value_golden_master = Time.parse('2/1/2011')
|
239
|
+
@wrong_type_golden_master = 'whatever'
|
240
|
+
end
|
241
|
+
|
242
|
+
it_behaves_like 'single-value-based matcher'
|
243
|
+
end
|
244
|
+
|
245
|
+
describe 'Nil-based golden master' do
|
246
|
+
before(:each) do
|
247
|
+
@subject = [{'Field 1' => nil, 'Field_2' => 12}]
|
248
|
+
@correct_golden_master = nil
|
249
|
+
@wrong_value_golden_master = nil # There is no wrong value for nil-based master
|
250
|
+
@wrong_type_golden_master = 'whatever'
|
251
|
+
end
|
252
|
+
|
253
|
+
it_behaves_like 'single-value-based matcher'
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'correctly matches a multi-result subject' do
|
257
|
+
subject = [@subject, [{:Field_x => 12}]]
|
258
|
+
matcher = Slacker::QueryResultMatcher.new(deep_copy(@subject))
|
259
|
+
matcher.matches?(subject).should be true
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'correctly rejects a wrong multi-result subject' do
|
263
|
+
subject = [[{:Field_x => 12}], @subject]
|
264
|
+
matcher = Slacker::QueryResultMatcher.new(deep_copy(@subject))
|
265
|
+
matcher.matches?(subject).should be false
|
266
|
+
matcher.failure_message.should == 'Expected 3 field(s), got 1'
|
267
|
+
end
|
268
|
+
end
|