slacker 1.0.9 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +4 -4
  3. data/README.markdown +22 -22
  4. data/Rakefile +11 -11
  5. data/bin/slacker +28 -29
  6. data/bin/slacker_new +34 -34
  7. data/lib/slacker.rb +175 -175
  8. data/lib/slacker/application.rb +211 -206
  9. data/lib/slacker/command_line_formatter.rb +59 -59
  10. data/lib/slacker/command_line_formatter2.rb +61 -0
  11. data/lib/slacker/configuration.rb +59 -59
  12. data/lib/slacker/formatter.rb +14 -19
  13. data/lib/slacker/query_result_matcher.rb +178 -178
  14. data/lib/slacker/rspec_ext.rb +49 -49
  15. data/lib/slacker/rspec_monkey.rb +7 -7
  16. data/lib/slacker/sql.rb +39 -39
  17. data/lib/slacker/sql_preprocessor.rb +23 -23
  18. data/lib/slacker/string_helper.rb +16 -16
  19. data/lib/slacker/version.rb +3 -3
  20. data/lib/slacker_new/project/data/sample_1/my_table_expected_power_results.csv +11 -11
  21. data/lib/slacker_new/project/data/sample_1/my_table_initial_data.csv +11 -11
  22. data/lib/slacker_new/project/data/sample_1/numbers_expected_output.csv +3 -3
  23. data/lib/slacker_new/project/database.yml +9 -9
  24. data/lib/slacker_new/project/lib/helpers/my_helper.rb +1 -1
  25. data/lib/slacker_new/project/spec/sample_1.rb +66 -66
  26. data/lib/slacker_new/project/sql/sample_1/my_table_on_power.sql.erb +1 -1
  27. data/lib/slacker_new/project/sql/sample_1/play_with_numbers.sql.erb +16 -16
  28. data/lib/slacker_new/project/sql/sample_1/sysobjects_with_params.sql.erb +1 -1
  29. data/slacker.gemspec +27 -26
  30. data/spec/application_spec.rb +13 -13
  31. data/spec/query_result_matcher_spec.rb +268 -268
  32. data/spec/rspec_ext_spec.rb +87 -87
  33. data/spec/slacker_spec.rb +59 -59
  34. data/spec/spec_helper.rb +9 -9
  35. data/spec/test_files/matcher/test_1.csv +3 -3
  36. data/spec/test_files/test_slacker_project/data/test_1.csv +3 -3
  37. data/spec/test_files/test_slacker_project/sql/nest/nested_1.sql.erb +1 -1
  38. data/spec/test_files/test_slacker_project/sql/no_params.sql.erb +2 -2
  39. data/spec/test_files/test_slacker_project/sql/params.sql.erb +1 -1
  40. metadata +19 -20
@@ -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] %>';
@@ -1,26 +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
-
14
- s.rubyforge_project = "slacker"
15
-
16
- s.files = ['README.markdown', 'Rakefile', 'Gemfile', 'slacker.gemspec'] + Dir.glob("{bin,lib,spec}/**/*")
17
- s.test_files = Dir.glob("spec/**/*")
18
- s.executables = ['slacker', 'slacker_new']
19
- s.require_paths = ["lib"]
20
-
21
- s.required_ruby_version = '>= 1.9.2'
22
-
23
- s.add_dependency 'bundler', '~> 1.0.15'
24
- s.add_dependency 'ruby-odbc', '= 0.99994'
25
- s.add_dependency 'rspec', '~> 2.10.0'
26
- 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.99994'
26
+ s.add_dependency 'rspec', '~> 3.0'
27
+ end
@@ -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', 'debug/passed_examples', 'debug/failed_examples', 'sql', 'spec', 'lib', 'lib/helpers']
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', '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 be_false
23
- @matcher.failure_message_for_should.should == 'Expected 3 field(s), got 2'
24
-
25
- @matcher.matches?(one_column_too_many).should be_false
26
- @matcher.failure_message_for_should.should == 'Expected 3 field(s), got 4'
27
-
28
- @matcher.matches?(wrong_column_name).should be_false
29
- @matcher.failure_message_for_should.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_for_should.should == 'Expected 2 record(s), got 1'
40
-
41
- @matcher.matches?(one_row_too_many).should be_false
42
- @matcher.failure_message_for_should.should == 'Expected 2 record(s), got 3'
43
-
44
- @matcher.matches?(empty_query_result).should be_false
45
- @matcher.failure_message_for_should.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_for_should.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_for_should.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_for_should.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_for_should.should == 'Field "Field_2", Record 1: Expected value <NULL>, got "whatever"'
79
-
80
- @matcher.matches?(misplaced_fields).should be_false
81
- @matcher.failure_message_for_should.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(@matcher.failure_message_for_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 be_false
91
- @matcher.failure_message_for_should.should =~ expected_message
92
-
93
- @matcher.matches?('test string').should be_false
94
- @matcher.failure_message_for_should.should =~ expected_message
95
-
96
- @matcher.matches?(1.1).should be_false
97
- @matcher.failure_message_for_should.should =~ expected_message
98
-
99
- @matcher.matches?(Time.now).should be_false
100
- @matcher.failure_message_for_should.should =~ expected_message
101
-
102
- @matcher.matches?(nil).should be_false
103
- @matcher.failure_message_for_should.should =~ expected_message
104
-
105
- @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x'}]).should be_false
106
- @matcher.failure_message_for_should.should =~ expected_message
107
-
108
- @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f3 => 'y'}]).should be_false
109
- @matcher.failure_message_for_should.should =~ expected_message
110
-
111
- @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f2 => 'y', :f3 => 'z'}]).should be_false
112
- @matcher.failure_message_for_should.should =~ expected_message
113
-
114
- @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, 12]).should be_false
115
- @matcher.failure_message_for_should.should =~ expected_message
116
-
117
- @matcher.matches?([12, {:f1 => 'x', :f2 => 'y'}]).should be_false
118
- @matcher.failure_message_for_should.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_for_should.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(matcher.failure_message_for_should)
137
-
138
- matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/completely_blank.csv'))
139
- matcher.matches?([]).should be_true(matcher.failure_message_for_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 be_false
155
- matcher.failure_message_for_should.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_for_should.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_for_should.should =~ expected_message
164
-
165
- matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, 12])
166
- matcher.matches?([]).should be_false
167
- matcher.failure_message_for_should.should =~ expected_message
168
-
169
- matcher = Slacker::QueryResultMatcher.new([12, {:f1 => 'x', :f2 => 'y'}])
170
- matcher.matches?([]).should be_false
171
- matcher.failure_message_for_should.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(matcher.failure_message_for_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 be_true(matcher.failure_message_for_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 be_false
190
- matcher.failure_message_for_should.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_for_should.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(matcher.failure_message_for_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 be_false
266
- matcher.failure_message_for_should.should == 'Expected 3 field(s), got 1'
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_for_should.should == 'Expected 3 field(s), got 2'
24
+
25
+ @matcher.matches?(one_column_too_many).should be_false
26
+ @matcher.failure_message_for_should.should == 'Expected 3 field(s), got 4'
27
+
28
+ @matcher.matches?(wrong_column_name).should be_false
29
+ @matcher.failure_message_for_should.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_for_should.should == 'Expected 2 record(s), got 1'
40
+
41
+ @matcher.matches?(one_row_too_many).should be_false
42
+ @matcher.failure_message_for_should.should == 'Expected 2 record(s), got 3'
43
+
44
+ @matcher.matches?(empty_query_result).should be_false
45
+ @matcher.failure_message_for_should.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_for_should.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_for_should.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_for_should.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_for_should.should == 'Field "Field_2", Record 1: Expected value <NULL>, got "whatever"'
79
+
80
+ @matcher.matches?(misplaced_fields).should be_false
81
+ @matcher.failure_message_for_should.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(@matcher.failure_message_for_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 be_false
91
+ @matcher.failure_message_for_should.should =~ expected_message
92
+
93
+ @matcher.matches?('test string').should be_false
94
+ @matcher.failure_message_for_should.should =~ expected_message
95
+
96
+ @matcher.matches?(1.1).should be_false
97
+ @matcher.failure_message_for_should.should =~ expected_message
98
+
99
+ @matcher.matches?(Time.now).should be_false
100
+ @matcher.failure_message_for_should.should =~ expected_message
101
+
102
+ @matcher.matches?(nil).should be_false
103
+ @matcher.failure_message_for_should.should =~ expected_message
104
+
105
+ @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x'}]).should be_false
106
+ @matcher.failure_message_for_should.should =~ expected_message
107
+
108
+ @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f3 => 'y'}]).should be_false
109
+ @matcher.failure_message_for_should.should =~ expected_message
110
+
111
+ @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, {:f1 => 'x', :f2 => 'y', :f3 => 'z'}]).should be_false
112
+ @matcher.failure_message_for_should.should =~ expected_message
113
+
114
+ @matcher.matches?([{:f1 => 'x', :f2 => 'y'}, 12]).should be_false
115
+ @matcher.failure_message_for_should.should =~ expected_message
116
+
117
+ @matcher.matches?([12, {:f1 => 'x', :f2 => 'y'}]).should be_false
118
+ @matcher.failure_message_for_should.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_for_should.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(matcher.failure_message_for_should)
137
+
138
+ matcher = Slacker::QueryResultMatcher.new(SpecHelper.load_csv('matcher/completely_blank.csv'))
139
+ matcher.matches?([]).should be_true(matcher.failure_message_for_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 be_false
155
+ matcher.failure_message_for_should.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_for_should.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_for_should.should =~ expected_message
164
+
165
+ matcher = Slacker::QueryResultMatcher.new([{:f1 => 'x', :f2 => 'y'}, 12])
166
+ matcher.matches?([]).should be_false
167
+ matcher.failure_message_for_should.should =~ expected_message
168
+
169
+ matcher = Slacker::QueryResultMatcher.new([12, {:f1 => 'x', :f2 => 'y'}])
170
+ matcher.matches?([]).should be_false
171
+ matcher.failure_message_for_should.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(matcher.failure_message_for_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 be_true(matcher.failure_message_for_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 be_false
190
+ matcher.failure_message_for_should.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_for_should.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(matcher.failure_message_for_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 be_false
266
+ matcher.failure_message_for_should.should == 'Expected 3 field(s), got 1'
267
+ end
268
+ end