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
@@ -0,0 +1,61 @@
1
+ require 'slacker/formatter'
2
+ require 'rspec/core/formatters/progress_formatter'
3
+
4
+ module Slacker
5
+ class CommandLineFormatter2 < RSpec::Core::Formatters::ProgressFormatter
6
+ include Slacker::Formatter
7
+ RSpec::Core::Formatters.register self, :example_passed, :example_failed
8
+
9
+ def initialize(output)
10
+ super(output)
11
+ @failed_examples_count = 0
12
+ @passed_examples_count = 0
13
+ end
14
+
15
+ def example_passed(notification)
16
+ super(notification)
17
+ process_example_debug_output(notification, false)
18
+ end
19
+
20
+ def example_failed(notification)
21
+ super(notification)
22
+ process_example_debug_output(notification, true)
23
+ end
24
+
25
+ private
26
+
27
+ def process_example_debug_output(notification, example_failed)
28
+ if example_failed
29
+ @failed_examples_count += 1
30
+ debug_output(notification, Slacker.configuration.expand_path('debug/failed_examples'), @failed_examples_count, example_failed)
31
+ else
32
+ @passed_examples_count += 1
33
+ debug_output(notification, Slacker.configuration.expand_path('debug/passed_examples'), @passed_examples_count, example_failed)
34
+ end
35
+ end
36
+
37
+ def debug_output(notification, out_folder, file_number, example_failed)
38
+ # Write out the SQL
39
+ File.open("#{out_folder}/example_#{'%03d' % file_number}.sql", 'w') do |out_file|
40
+ out_file.write(get_formatted_example_sql(notification, example_failed))
41
+ end
42
+ end
43
+
44
+ def get_formatted_example_sql(notification, example_failed)
45
+ example = notification.example
46
+ sql = <<EOF
47
+ -- Example "#{example.metadata[:full_description]}"
48
+ -- #{example.metadata[:location]}
49
+ -- Executed at #{example.execution_result.started_at}
50
+
51
+ #{example.metadata[:sql]}
52
+
53
+ -- SLACKER RESULTS
54
+ -- *******************************************
55
+ #{example_failed ? example_failure_text(notification).split("\n").collect{|line| '-- ' + line}.join("\n") : '-- Example Passed OK'}
56
+ -- *******************************************
57
+ EOF
58
+ sql.strip
59
+ end
60
+ end
61
+ end
@@ -1,59 +1,59 @@
1
- module Slacker
2
- class Configuration
3
- attr_accessor :base_dir, :error_stream, :output_stream, :formatter, :db_server, :db_name, :db_user, :db_password, :console_enabled
4
-
5
- def initialize
6
- @console_enabled = true
7
- @base_dir = Dir.pwd
8
- @error_stream = nil
9
- @output_stream = nil
10
- @rspec_args = nil
11
- @formatter = nil
12
- @db_server = nil
13
- @db_name = nil
14
- @db_user = nil
15
- @db_password = nil
16
- end
17
-
18
- def expand_path(path)
19
- File.expand_path("#{@base_dir}/#{path}")
20
- end
21
-
22
- def console_enabled
23
- @console_enabled
24
- end
25
-
26
- def console_enabled=(value)
27
- @console_enabled = value
28
- if @console_enabled
29
- @error_stream = $stderr
30
- @output_stream = $stdout
31
- @rspec_args = ARGV
32
- else
33
- @error_stream = nil
34
- @output_stream = nil
35
- @rspec_args = []
36
- end
37
- end
38
-
39
- def rspec_args
40
- if @rspec_args.nil? || @rspec_args.empty?
41
- Dir.glob(expand_path("spec/**/*.rb"))
42
- else
43
- @rspec_args
44
- end
45
- end
46
-
47
- def rspec_args=(value)
48
- @rspec_args = value
49
- end
50
-
51
- def dsn_string
52
- "Driver={SQL Server};Server=#{@db_server};Database=#{@db_name};Uid=#{@db_user};Pwd=#{@db_password}"
53
- end
54
-
55
- def db_config
56
- {:adapter => 'sqlserver', :mode => 'odbc', :dsn => dsn_string}
57
- end
58
- end
59
- end
1
+ module Slacker
2
+ class Configuration
3
+ attr_accessor :base_dir, :error_stream, :output_stream, :formatter, :db_server, :db_name, :db_user, :db_password, :console_enabled
4
+
5
+ def initialize
6
+ @console_enabled = true
7
+ @base_dir = Dir.pwd
8
+ @error_stream = nil
9
+ @output_stream = nil
10
+ @rspec_args = nil
11
+ @formatter = nil
12
+ @db_server = nil
13
+ @db_name = nil
14
+ @db_user = nil
15
+ @db_password = nil
16
+ end
17
+
18
+ def expand_path(path)
19
+ File.expand_path("#{@base_dir}/#{path}")
20
+ end
21
+
22
+ def console_enabled
23
+ @console_enabled
24
+ end
25
+
26
+ def console_enabled=(value)
27
+ @console_enabled = value
28
+ if @console_enabled
29
+ @error_stream = $stderr
30
+ @output_stream = $stdout
31
+ @rspec_args = ARGV
32
+ else
33
+ @error_stream = nil
34
+ @output_stream = nil
35
+ @rspec_args = []
36
+ end
37
+ end
38
+
39
+ def rspec_args
40
+ if @rspec_args.nil? || @rspec_args.empty?
41
+ Dir.glob(expand_path("spec/**/*.rb"))
42
+ else
43
+ @rspec_args
44
+ end
45
+ end
46
+
47
+ def rspec_args=(value)
48
+ @rspec_args = value
49
+ end
50
+
51
+ def dsn_string
52
+ "Driver={SQL Server};Server=#{@db_server};Database=#{@db_name};Uid=#{@db_user};Pwd=#{@db_password}"
53
+ end
54
+
55
+ def db_config
56
+ {:adapter => 'sqlserver', :mode => 'odbc', :dsn => dsn_string}
57
+ end
58
+ end
59
+ end
@@ -1,19 +1,14 @@
1
- require 'slacker'
2
-
3
- module Slacker
4
- module Formatter
5
- def example_failure_text(example)
6
- text = ''
7
- exception = example.execution_result[:exception]
8
- text << "Failure/Error: #{read_failed_line(exception, example).strip}\n"
9
- text << "#{long_padding}#{exception.class.name << ":"}\n" unless exception.class.name =~ /RSpec/
10
- exception.message.split("\n").each { |line| text << "#{line}\n" }
11
-
12
- format_backtrace(example.execution_result[:exception].backtrace, example).each do |backtrace_info|
13
- text << "# #{backtrace_info}\n"
14
- end
15
-
16
- text
17
- end
18
- end
19
- end
1
+ require 'slacker'
2
+
3
+ module Slacker
4
+ module Formatter
5
+ def example_failure_text(notification)
6
+ text = ''
7
+ exception = notification.example.execution_result.exception
8
+ text << notification.message_lines.join("\n").strip << "\n"
9
+ text << notification.formatted_backtrace.join("\n")
10
+
11
+ text
12
+ end
13
+ end
14
+ end
@@ -1,178 +1,178 @@
1
- require 'csv'
2
-
3
- module Slacker
4
- DATE_FORMAT = "%m/%d/%Y"
5
-
6
- class QueryResultMatcher
7
- def initialize(golden_master)
8
- @golden_master = golden_master
9
- @failure_message = ''
10
- end
11
-
12
- def matches?(subject)
13
- does_match = false
14
-
15
- subject = normalize_query_result_subject(subject)
16
-
17
- catch :no_match do
18
- test_type_match(subject)
19
- test_value_match(subject)
20
- does_match = true
21
- end
22
-
23
- does_match
24
- end
25
-
26
- def failure_message_for_should
27
- @failure_message
28
- end
29
-
30
- private
31
-
32
- #test if the subject type is consistent with the golden master
33
- def test_type_match(subject)
34
- if !is_well_formed_query_result?(subject)
35
- throw_no_match "Can perform query matches only against a well formed query result subject"
36
- end
37
-
38
- if (@golden_master.kind_of? Array) && !is_well_formed_query_result?(@golden_master)
39
- throw_no_match "Cannot match against a non-well formed golden master array"
40
- end
41
- end
42
-
43
- def test_value_match(subject)
44
- case @golden_master
45
- when CSV::Table
46
- test_csv_table_match(subject)
47
- when Array
48
- test_array_match(subject)
49
- else
50
- test_single_value_match(subject)
51
- end
52
- end
53
-
54
- # Compare the golden master CSV table with the subject query result
55
- def test_csv_table_match(subject)
56
- # Compare the fields
57
- if !subject.empty?
58
- subject_fields = subject[0].keys
59
- master_fields = @golden_master.headers
60
-
61
- if subject_fields.count != master_fields.count
62
- throw_no_match "Expected #{master_fields.count} field(s), got #{subject_fields.count}"
63
- end
64
-
65
- master_fields.each_with_index do |column, index|
66
- if column != subject_fields[index]
67
- throw_no_match "Expected field \"#{column}\", got field \"#{subject_fields[index]}\""
68
- end
69
- end
70
- end
71
-
72
- # Compare the number of records
73
- subject_record_count = subject.count
74
- master_record_count = @golden_master.inject(0){|count| count += 1}
75
- if subject_record_count != master_record_count
76
- throw_no_match "Expected #{master_record_count} record(s), got #{subject_record_count}"
77
- end
78
-
79
- # Compare the values of the golden master with the subject
80
- current_row = 0
81
- @golden_master.each do |row|
82
- row.each do |field, master_string|
83
- subject_value = subject[current_row][field]
84
- if !match_values?(master_string, subject_value)
85
- throw_no_match "Field \"#{field}\", Record #{current_row + 1}: Expected value #{master_string.nil? ? '<NULL>' : "\"#{master_string}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
86
- end
87
- end
88
- current_row += 1
89
- end
90
- end
91
-
92
- def match_types?(master_val, subject_val)
93
- subject_val.kind_of? master_val.class
94
- end
95
-
96
- def match_values?(master_val, subject_val)
97
- if master_val.nil?
98
- master_val == subject_val
99
- elsif master_val.kind_of?(String)
100
- case subject_val
101
- when ODBC::TimeStamp
102
- (!!Time.strptime(master_val, DATE_FORMAT) rescue false) && Time.strptime(master_val, DATE_FORMAT) == ODBC::to_time(subject_val)
103
- when Float
104
- (!!Float(master_val) rescue false) && Float(master_val) == subject_val
105
- else
106
- subject_val.to_s == master_val.to_s
107
- end
108
- else
109
- subject_val.to_s == master_val.to_s
110
- end
111
- end
112
-
113
- def test_array_match(subject)
114
- # Compare the fields
115
- if !(subject.empty? || @golden_master.empty?)
116
- subject_fields = subject[0].keys
117
- master_fields = @golden_master[0].keys
118
-
119
- if subject_fields.count != master_fields.count
120
- throw_no_match "Expected #{master_fields.count} field(s), got #{subject_fields.count}"
121
- end
122
-
123
- master_fields.each_with_index do |column, index|
124
- if column != subject_fields[index]
125
- throw_no_match "Expected field \"#{column}\", got field \"#{subject_fields[index]}\""
126
- end
127
- end
128
- end
129
-
130
- # Compare the number of records
131
- subject_record_count = subject.count
132
- master_record_count = @golden_master.count
133
- if subject_record_count != master_record_count
134
- throw_no_match "Expected #{master_record_count} record(s), got #{subject_record_count}"
135
- end
136
-
137
- # Compare the values of the golden master with the subject
138
- current_row = 0
139
- @golden_master.each do |row|
140
- row.each do |field, master_value|
141
- subject_value = subject[current_row][field]
142
- if !match_values?(master_value, subject_value)
143
- throw_no_match "Field \"#{field}\", Record #{current_row + 1}: Expected value #{master_value.nil? ? '<NULL>' : "\"#{master_value}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
144
- end
145
- end
146
- current_row += 1
147
- end
148
- end
149
-
150
- def is_well_formed_query_result?(arr)
151
- return false unless arr.kind_of? Array
152
- header =[]
153
- arr.find{|row| !row.kind_of?(Hash) || (header = header.empty? ? row.keys : header) != row.keys || row.keys.empty?}.nil?
154
- end
155
-
156
- def test_single_value_match(subject)
157
- subject_value = subject[0].values[0]
158
- subject_field = subject[0].keys[0]
159
- if !match_types?(@golden_master, subject_value)
160
- throw_no_match "Field \"#{subject_field}\", Record 1: Expected type \"#{@golden_master.class}\", got \"#{subject_value.class}\""
161
- end
162
-
163
- if !match_values?(@golden_master, subject_value)
164
- throw_no_match "Field \"#{subject_field}\", Record 1: Expected value #{@golden_master.nil? ? '<NULL>' : "\"#{@golden_master}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
165
- end
166
- end
167
-
168
- # In case of a multi-resultset subject, extract the first result set
169
- def normalize_query_result_subject(subject)
170
- subject.kind_of?(Array) && !subject.empty? && is_well_formed_query_result?(subject[0]) ? subject[0] : subject
171
- end
172
-
173
- def throw_no_match(message)
174
- @failure_message = message
175
- throw :no_match
176
- end
177
- end
178
- end
1
+ require 'csv'
2
+
3
+ module Slacker
4
+ DATE_FORMAT = "%m/%d/%Y"
5
+
6
+ class QueryResultMatcher
7
+ def initialize(golden_master)
8
+ @golden_master = golden_master
9
+ @failure_message = ''
10
+ end
11
+
12
+ def matches?(subject)
13
+ does_match = false
14
+
15
+ subject = normalize_query_result_subject(subject)
16
+
17
+ catch :no_match do
18
+ test_type_match(subject)
19
+ test_value_match(subject)
20
+ does_match = true
21
+ end
22
+
23
+ does_match
24
+ end
25
+
26
+ def failure_message
27
+ @failure_message
28
+ end
29
+
30
+ private
31
+
32
+ #test if the subject type is consistent with the golden master
33
+ def test_type_match(subject)
34
+ if !is_well_formed_query_result?(subject)
35
+ throw_no_match "Can perform query matches only against a well formed query result subject"
36
+ end
37
+
38
+ if (@golden_master.kind_of? Array) && !is_well_formed_query_result?(@golden_master)
39
+ throw_no_match "Cannot match against a non-well formed golden master array"
40
+ end
41
+ end
42
+
43
+ def test_value_match(subject)
44
+ case @golden_master
45
+ when CSV::Table
46
+ test_csv_table_match(subject)
47
+ when Array
48
+ test_array_match(subject)
49
+ else
50
+ test_single_value_match(subject)
51
+ end
52
+ end
53
+
54
+ # Compare the golden master CSV table with the subject query result
55
+ def test_csv_table_match(subject)
56
+ # Compare the fields
57
+ if !subject.empty?
58
+ subject_fields = subject[0].keys
59
+ master_fields = @golden_master.headers
60
+
61
+ if subject_fields.count != master_fields.count
62
+ throw_no_match "Expected #{master_fields.count} field(s), got #{subject_fields.count}"
63
+ end
64
+
65
+ master_fields.each_with_index do |column, index|
66
+ if column != subject_fields[index]
67
+ throw_no_match "Expected field \"#{column}\", got field \"#{subject_fields[index]}\""
68
+ end
69
+ end
70
+ end
71
+
72
+ # Compare the number of records
73
+ subject_record_count = subject.count
74
+ master_record_count = @golden_master.inject(0){|count| count += 1}
75
+ if subject_record_count != master_record_count
76
+ throw_no_match "Expected #{master_record_count} record(s), got #{subject_record_count}"
77
+ end
78
+
79
+ # Compare the values of the golden master with the subject
80
+ current_row = 0
81
+ @golden_master.each do |row|
82
+ row.each do |field, master_string|
83
+ subject_value = subject[current_row][field]
84
+ if !match_values?(master_string, subject_value)
85
+ throw_no_match "Field \"#{field}\", Record #{current_row + 1}: Expected value #{master_string.nil? ? '<NULL>' : "\"#{master_string}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
86
+ end
87
+ end
88
+ current_row += 1
89
+ end
90
+ end
91
+
92
+ def match_types?(master_val, subject_val)
93
+ subject_val.kind_of? master_val.class
94
+ end
95
+
96
+ def match_values?(master_val, subject_val)
97
+ if master_val.nil?
98
+ master_val == subject_val
99
+ elsif master_val.kind_of?(String)
100
+ case subject_val
101
+ when ODBC::TimeStamp
102
+ (!!Time.strptime(master_val, DATE_FORMAT) rescue false) && Time.strptime(master_val, DATE_FORMAT) == ODBC::to_time(subject_val)
103
+ when Float
104
+ (!!Float(master_val) rescue false) && Float(master_val) == subject_val
105
+ else
106
+ subject_val.to_s == master_val.to_s
107
+ end
108
+ else
109
+ subject_val.to_s == master_val.to_s
110
+ end
111
+ end
112
+
113
+ def test_array_match(subject)
114
+ # Compare the fields
115
+ if !(subject.empty? || @golden_master.empty?)
116
+ subject_fields = subject[0].keys
117
+ master_fields = @golden_master[0].keys
118
+
119
+ if subject_fields.count != master_fields.count
120
+ throw_no_match "Expected #{master_fields.count} field(s), got #{subject_fields.count}"
121
+ end
122
+
123
+ master_fields.each_with_index do |column, index|
124
+ if column != subject_fields[index]
125
+ throw_no_match "Expected field \"#{column}\", got field \"#{subject_fields[index]}\""
126
+ end
127
+ end
128
+ end
129
+
130
+ # Compare the number of records
131
+ subject_record_count = subject.count
132
+ master_record_count = @golden_master.count
133
+ if subject_record_count != master_record_count
134
+ throw_no_match "Expected #{master_record_count} record(s), got #{subject_record_count}"
135
+ end
136
+
137
+ # Compare the values of the golden master with the subject
138
+ current_row = 0
139
+ @golden_master.each do |row|
140
+ row.each do |field, master_value|
141
+ subject_value = subject[current_row][field]
142
+ if !match_values?(master_value, subject_value)
143
+ throw_no_match "Field \"#{field}\", Record #{current_row + 1}: Expected value #{master_value.nil? ? '<NULL>' : "\"#{master_value}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
144
+ end
145
+ end
146
+ current_row += 1
147
+ end
148
+ end
149
+
150
+ def is_well_formed_query_result?(arr)
151
+ return false unless arr.kind_of? Array
152
+ header =[]
153
+ arr.find{|row| !row.kind_of?(Hash) || (header = header.empty? ? row.keys : header) != row.keys || row.keys.empty?}.nil?
154
+ end
155
+
156
+ def test_single_value_match(subject)
157
+ subject_value = subject[0].values[0]
158
+ subject_field = subject[0].keys[0]
159
+ if !match_types?(@golden_master, subject_value)
160
+ throw_no_match "Field \"#{subject_field}\", Record 1: Expected type \"#{@golden_master.class}\", got \"#{subject_value.class}\""
161
+ end
162
+
163
+ if !match_values?(@golden_master, subject_value)
164
+ throw_no_match "Field \"#{subject_field}\", Record 1: Expected value #{@golden_master.nil? ? '<NULL>' : "\"#{@golden_master}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
165
+ end
166
+ end
167
+
168
+ # In case of a multi-resultset subject, extract the first result set
169
+ def normalize_query_result_subject(subject)
170
+ subject.kind_of?(Array) && !subject.empty? && is_well_formed_query_result?(subject[0]) ? subject[0] : subject
171
+ end
172
+
173
+ def throw_no_match(message)
174
+ @failure_message = message
175
+ throw :no_match
176
+ end
177
+ end
178
+ end