rspec-core 2.4.0 → 2.5.0

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.
Files changed (78) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +9 -4
  3. data/Guardfile +3 -3
  4. data/README.md +1 -1
  5. data/features/.nav +7 -2
  6. data/features/{README.markdown → Autotest.md} +17 -20
  7. data/features/Changelog.md +57 -2
  8. data/features/README.md +17 -0
  9. data/features/Upgrade.md +8 -66
  10. data/features/command_line/configure.feature +2 -2
  11. data/features/command_line/example_name_option.feature +10 -10
  12. data/features/command_line/exit_status.feature +4 -4
  13. data/features/command_line/line_number_appended_to_path.feature +11 -11
  14. data/features/command_line/line_number_option.feature +9 -9
  15. data/features/command_line/tag.feature +9 -9
  16. data/features/configuration/custom_settings.feature +3 -3
  17. data/features/configuration/fail_fast.feature +3 -3
  18. data/features/configuration/read_options_from_file.feature +4 -4
  19. data/features/example_groups/shared_example_group.feature +4 -4
  20. data/features/expectation_framework_integration/configure_expectation_framework.feature +8 -9
  21. data/features/filtering/exclusion_filters.feature +1 -1
  22. data/features/filtering/run_all_when_everything_filtered.feature +1 -1
  23. data/features/formatters/custom_formatter.feature +17 -13
  24. data/features/helper_methods/arbitrary_methods.feature +40 -0
  25. data/features/helper_methods/let.feature +50 -0
  26. data/features/hooks/before_and_after_hooks.feature +10 -10
  27. data/features/hooks/filtering.feature +37 -20
  28. data/features/metadata/described_class.feature +1 -1
  29. data/features/mock_framework_integration/use_flexmock.feature +1 -1
  30. data/features/mock_framework_integration/use_mocha.feature +1 -1
  31. data/features/mock_framework_integration/use_rr.feature +1 -1
  32. data/features/mock_framework_integration/use_rspec.feature +1 -1
  33. data/features/spec_files/arbitrary_file_suffix.feature +1 -1
  34. data/features/step_definitions/additional_cli_steps.rb +1 -1
  35. data/features/subject/attribute_of_subject.feature +2 -2
  36. data/features/subject/explicit_subject.feature +5 -5
  37. data/features/subject/implicit_receiver.feature +2 -2
  38. data/features/subject/implicit_subject.feature +2 -2
  39. data/lib/autotest/rspec2.rb +63 -13
  40. data/lib/rspec/core/configuration.rb +0 -1
  41. data/lib/rspec/core/configuration_options.rb +15 -12
  42. data/lib/rspec/core/example.rb +14 -6
  43. data/lib/rspec/core/example_group.rb +5 -4
  44. data/lib/rspec/core/formatters/base_formatter.rb +1 -1
  45. data/lib/rspec/core/formatters/documentation_formatter.rb +1 -1
  46. data/lib/rspec/core/formatters/html_formatter.rb +131 -32
  47. data/lib/rspec/core/formatters/snippet_extractor.rb +1 -1
  48. data/lib/rspec/core/hooks.rb +16 -1
  49. data/lib/rspec/core/option_parser.rb +6 -6
  50. data/lib/rspec/core/rake_task.rb +1 -1
  51. data/lib/rspec/core/subject.rb +7 -7
  52. data/lib/rspec/core/version.rb +1 -1
  53. data/rspec-core.gemspec +0 -12
  54. data/script/FullBuildRakeFile +63 -0
  55. data/script/cucumber +1 -0
  56. data/script/full_build +1 -0
  57. data/script/spec +1 -0
  58. data/spec/autotest/failed_results_re_spec.rb +22 -5
  59. data/spec/autotest/rspec_spec.rb +132 -16
  60. data/spec/rspec/core/configuration_options_spec.rb +38 -6
  61. data/spec/rspec/core/example_group_spec.rb +15 -64
  62. data/spec/rspec/core/formatters/base_formatter_spec.rb +23 -0
  63. data/spec/rspec/core/formatters/html_formatted-1.8.6.html +150 -48
  64. data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +151 -49
  65. data/spec/rspec/core/formatters/html_formatted-1.8.7.html +150 -48
  66. data/spec/rspec/core/formatters/html_formatted-1.9.1.html +150 -48
  67. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +150 -48
  68. data/spec/rspec/core/formatters/text_mate_formatted-1.8.6.html +150 -48
  69. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +151 -49
  70. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +150 -48
  71. data/spec/rspec/core/formatters/text_mate_formatted-1.9.1.html +150 -48
  72. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +150 -48
  73. data/spec/rspec/core/hooks_filtering_spec.rb +49 -0
  74. data/spec/rspec/core/rake_task_spec.rb +3 -3
  75. data/spec/rspec/core/subject_spec.rb +81 -0
  76. metadata +20 -22
  77. data/History.markdown +0 -186
  78. data/Upgrade.markdown +0 -345
@@ -58,7 +58,8 @@ module RSpec
58
58
 
59
59
  alias_example_to :it
60
60
  alias_example_to :specify
61
- alias_example_to :focused, :focused => true
61
+ alias_example_to :focused, :focused => true, :focus => true
62
+ alias_example_to :focus, :focused => true, :focus => true
62
63
  alias_example_to :pending, :pending => true
63
64
  alias_example_to :xit, :pending => true
64
65
 
@@ -172,14 +173,14 @@ module RSpec
172
173
  def self.eval_before_alls(example_group_instance)
173
174
  return if descendant_filtered_examples.empty?
174
175
  assign_before_all_ivars(superclass.before_all_ivars, example_group_instance)
175
- world.run_hook_filtered(:before, :all, self, example_group_instance) if top_level?
176
+ world.run_hook_filtered(:before, :all, self, example_group_instance)
176
177
  run_hook!(:before, :all, example_group_instance)
177
178
  store_before_all_ivars(example_group_instance)
178
179
  end
179
180
 
180
181
  def self.eval_around_eachs(example, initial_procsy)
181
182
  example.around_hooks.reverse.inject(initial_procsy) do |procsy, around_hook|
182
- Example::Procsy.new(procsy.metadata) do
183
+ Example.procsy(procsy.metadata) do
183
184
  example.example_group_instance.instance_eval_with_args(procsy, &around_hook)
184
185
  end
185
186
  end
@@ -212,7 +213,7 @@ An error occurred in an after(:all) hook.
212
213
  EOS
213
214
  end
214
215
 
215
- world.run_hook_filtered(:after, :all, self, example_group_instance) if top_level?
216
+ world.run_hook_filtered(:after, :all, self, example_group_instance)
216
217
  end
217
218
 
218
219
  def self.around_hooks_for(example)
@@ -121,7 +121,7 @@ module RSpec
121
121
  file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2]
122
122
 
123
123
  if File.exist?(file_path)
124
- open(file_path, 'r') { |f| f.readlines[line_number.to_i - 1] }
124
+ File.readlines(file_path)[line_number.to_i - 1]
125
125
  else
126
126
  "Unable to find #{file_path} to read failed line"
127
127
  end
@@ -15,7 +15,7 @@ module RSpec
15
15
  super(example_group)
16
16
 
17
17
  output.puts if @group_level == 0
18
- output.puts "#{' ' * @group_level}#{example_group.description}"
18
+ output.puts "#{current_indentation}#{example_group.description}"
19
19
 
20
20
  @group_level += 1
21
21
  end
@@ -48,9 +48,9 @@ module RSpec
48
48
  @output.puts " </dl>"
49
49
  @output.puts "</div>"
50
50
  end
51
- @output.puts "<div class=\"example_group\">"
51
+ @output.puts "<div id=\"div_group_#{example_group_number}\" class=\"example_group passed\">"
52
52
  @output.puts " <dl #{current_indentation}>"
53
- @output.puts " <dt id=\"example_group_#{example_group_number}\">#{h(example_group.description)}</dt>"
53
+ @output.puts " <dt id=\"example_group_#{example_group_number}\" class=\"passed\">#{h(example_group.description)}</dt>"
54
54
  @output.flush
55
55
  end
56
56
 
@@ -67,24 +67,24 @@ module RSpec
67
67
 
68
68
  def example_passed(example)
69
69
  move_progress
70
- @output.puts " <dd class=\"spec passed\"><span class=\"passed_spec_name\">#{h(example.description)}</span></dd>"
70
+ @output.puts " <dd class=\"example passed\"><span class=\"passed_spec_name\">#{h(example.description)}</span></dd>"
71
71
  @output.flush
72
72
  end
73
73
 
74
74
  def example_failed(example)
75
- counter = 0
75
+ super(example)
76
76
  exception = example.metadata[:execution_result][:exception]
77
77
  extra = extra_failure_content(exception)
78
- failure_style = 'failed'
79
78
  failure_style = RSpec::Core::PendingExampleFixedError === exception ? 'pending_fixed' : 'failed'
80
79
  @output.puts " <script type=\"text/javascript\">makeRed('rspec-header');</script>" unless @header_red
81
80
  @header_red = true
81
+ @output.puts " <script type=\"text/javascript\">makeRed('div_group_#{example_group_number}');</script>" unless @example_group_red
82
82
  @output.puts " <script type=\"text/javascript\">makeRed('example_group_#{example_group_number}');</script>" unless @example_group_red
83
83
  @example_group_red = true
84
84
  move_progress
85
- @output.puts " <dd class=\"spec #{failure_style}\">"
85
+ @output.puts " <dd class=\"example #{failure_style}\">"
86
86
  @output.puts " <span class=\"failed_spec_name\">#{h(example.description)}</span>"
87
- @output.puts " <div class=\"failure\" id=\"failure_#{counter}\">"
87
+ @output.puts " <div class=\"failure\" id=\"failure_#{@failed_examples.size}\">"
88
88
  @output.puts " <div class=\"message\"><pre>#{h(exception.message)}</pre></div>" unless exception.nil?
89
89
  @output.puts " <div class=\"backtrace\"><pre>#{format_backtrace(exception.backtrace, example).join("\n")}</pre></div>" if exception
90
90
  @output.puts extra unless extra == ""
@@ -96,9 +96,10 @@ module RSpec
96
96
  def example_pending(example)
97
97
  message = example.metadata[:execution_result][:pending_message]
98
98
  @output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>" unless @header_red
99
+ @output.puts " <script type=\"text/javascript\">makeYellow('div_group_#{example_group_number}');</script>" unless @example_group_red
99
100
  @output.puts " <script type=\"text/javascript\">makeYellow('example_group_#{example_group_number}');</script>" unless @example_group_red
100
101
  move_progress
101
- @output.puts " <dd class=\"spec not_implemented\"><span class=\"not_implemented_spec_name\">#{h(example.description)} (PENDING: #{h(message)})</span></dd>"
102
+ @output.puts " <dd class=\"example not_implemented\"><span class=\"not_implemented_spec_name\">#{h(example.description)} (PENDING: #{h(message)})</span></dd>"
102
103
  @output.flush
103
104
  end
104
105
 
@@ -135,7 +136,8 @@ module RSpec
135
136
  if dry_run?
136
137
  totals = "This was a dry-run"
137
138
  else
138
- totals = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
139
+ totals = "#{example_count} example#{'s' unless example_count == 1}, "
140
+ totals << "#{failure_count} failure#{'s' unless failure_count == 1}"
139
141
  totals << ", #{pending_count} pending" if pending_count > 0
140
142
  end
141
143
  @output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{duration} seconds</strong>\";</script>"
@@ -193,36 +195,97 @@ EOF
193
195
  <h1>RSpec Code Examples</h1>
194
196
  </div>
195
197
 
198
+ <div id="display-filters">
199
+ <input id="passed_checkbox" name="passed_checkbox" type="checkbox" checked onchange="apply_filters()" value="1"> <label for="passed_checkbox">Passed</label>
200
+ <input id="failed_checkbox" name="failed_checkbox" type="checkbox" checked onchange="apply_filters()" value="2"> <label for="failed_checkbox">Failed</label>
201
+ <input id="pending_checkbox" name="pending_checkbox" type="checkbox" checked onchange="apply_filters()" value="3"> <label for="pending_checkbox">Pending</label>
202
+ </div>
203
+
196
204
  <div id="summary">
197
205
  <p id="totals">&nbsp;</p>
198
206
  <p id="duration">&nbsp;</p>
199
207
  </div>
200
208
  </div>
201
209
 
210
+
202
211
  <div class="results">
203
212
  EOF
204
213
  end
205
214
 
206
215
  def global_scripts
207
216
  <<-EOF
217
+
218
+ function addClass(element_id, classname) {
219
+ document.getElementById(element_id).className += (" " + classname);
220
+ }
221
+
222
+ function removeClass(element_id, classname) {
223
+ var elem = document.getElementById(element_id);
224
+ var classlist = elem.className.replace(classname,'');
225
+ elem.className = classlist;
226
+ }
227
+
208
228
  function moveProgressBar(percentDone) {
209
229
  document.getElementById("rspec-header").style.width = percentDone +"%";
210
230
  }
231
+
211
232
  function makeRed(element_id) {
212
- document.getElementById(element_id).style.background = '#C40D0D';
213
- document.getElementById(element_id).style.color = '#FFFFFF';
233
+ removeClass(element_id, 'passed');
234
+ removeClass(element_id, 'not_implemented');
235
+ addClass(element_id,'failed');
214
236
  }
215
237
 
216
238
  function makeYellow(element_id) {
217
- if (element_id == "rspec-header" && document.getElementById(element_id).style.background != '#C40D0D')
218
- {
219
- document.getElementById(element_id).style.background = '#FAF834';
220
- document.getElementById(element_id).style.color = '#000000';
239
+ var elem = document.getElementById(element_id);
240
+ if (elem.className.indexOf("failed") == -1) { // class doesn't includes failed
241
+ if (elem.className.indexOf("not_implemented") == -1) { // class doesn't include not_implemented
242
+ removeClass(element_id, 'passed');
243
+ addClass(element_id,'not_implemented');
244
+ }
245
+ }
246
+ }
247
+
248
+ function apply_filters() {
249
+ var passed_filter = document.getElementById('passed_checkbox').checked;
250
+ var failed_filter = document.getElementById('failed_checkbox').checked;
251
+ var pending_filter = document.getElementById('pending_checkbox').checked;
252
+
253
+ assign_display_style("example passed", passed_filter);
254
+ assign_display_style("example failed", failed_filter);
255
+ assign_display_style("example not_implemented", pending_filter);
256
+
257
+ assign_display_style_for_group("example_group passed", passed_filter);
258
+ assign_display_style_for_group("example_group not_implemented", pending_filter, pending_filter || passed_filter);
259
+ assign_display_style_for_group("example_group failed", failed_filter, failed_filter || pending_filter || passed_filter);
260
+ }
261
+
262
+ function get_display_style(display_flag) {
263
+ var style_mode = 'none';
264
+ if (display_flag == true) {
265
+ style_mode = 'block';
221
266
  }
222
- else
223
- {
224
- document.getElementById(element_id).style.background = '#FAF834';
225
- document.getElementById(element_id).style.color = '#000000';
267
+ return style_mode;
268
+ }
269
+
270
+ function assign_display_style(classname, display_flag) {
271
+ var style_mode = get_display_style(display_flag);
272
+ var elems = document.getElementsByClassName(classname)
273
+ for (var i=0; i<elems.length;i++) {
274
+ elems[i].style.display = style_mode;
275
+ }
276
+ }
277
+
278
+ function assign_display_style_for_group(classname, display_flag, subgroup_flag) {
279
+ var display_style_mode = get_display_style(display_flag);
280
+ var subgroup_style_mode = get_display_style(subgroup_flag);
281
+ var elems = document.getElementsByClassName(classname)
282
+ for (var i=0; i<elems.length;i++) {
283
+ var style_mode = display_style_mode;
284
+ if ((display_flag != subgroup_flag) && (elems[i].getElementsByTagName('dt')[0].innerHTML.indexOf(", ") != -1)) {
285
+ elems[i].style.display = subgroup_style_mode;
286
+ } else {
287
+ elems[i].style.display = display_style_mode;
288
+ }
226
289
  }
227
290
  }
228
291
  EOF
@@ -242,13 +305,21 @@ EOF
242
305
  position: absolute;
243
306
  }
244
307
 
308
+ #label {
309
+ float:left;
310
+ }
311
+
312
+ #display-filters {
313
+ float:left;
314
+ padding: 28px 0 0 40%;
315
+ font-family: "Lucida Grande", Helvetica, sans-serif;
316
+ }
317
+
245
318
  #summary {
246
- margin: 0; padding: 5px 10px;
319
+ float:right;
320
+ padding: 5px 10px;
247
321
  font-family: "Lucida Grande", Helvetica, sans-serif;
248
322
  text-align: right;
249
- top: 0px;
250
- right: 0px;
251
- float:right;
252
323
  }
253
324
 
254
325
  #summary p {
@@ -281,30 +352,58 @@ dd {
281
352
  padding: 3px 3px 3px 18px;
282
353
  }
283
354
 
284
- dd.spec.passed {
355
+
356
+ dd.example.passed {
285
357
  border-left: 5px solid #65C400;
286
358
  border-bottom: 1px solid #65C400;
287
359
  background: #DBFFB4; color: #3D7700;
288
360
  }
289
361
 
290
- dd.spec.failed {
291
- border-left: 5px solid #C20000;
292
- border-bottom: 1px solid #C20000;
293
- color: #C20000; background: #FFFBD3;
294
- }
295
-
296
- dd.spec.not_implemented {
362
+ dd.example.not_implemented {
297
363
  border-left: 5px solid #FAF834;
298
364
  border-bottom: 1px solid #FAF834;
299
365
  background: #FCFB98; color: #131313;
300
366
  }
301
367
 
302
- dd.spec.pending_fixed {
368
+ dd.example.pending_fixed {
303
369
  border-left: 5px solid #0000C2;
304
370
  border-bottom: 1px solid #0000C2;
305
371
  color: #0000C2; background: #D3FBFF;
306
372
  }
307
373
 
374
+ dd.example.failed {
375
+ border-left: 5px solid #C20000;
376
+ border-bottom: 1px solid #C20000;
377
+ color: #C20000; background: #FFFBD3;
378
+ }
379
+
380
+
381
+ dt.not_implemented {
382
+ color: #000000; background: #FAF834;
383
+ }
384
+
385
+ dt.pending_fixed {
386
+ color: #FFFFFF; background: #C40D0D;
387
+ }
388
+
389
+ dt.failed {
390
+ color: #FFFFFF; background: #C40D0D;
391
+ }
392
+
393
+
394
+ #rspec-header.not_implemented {
395
+ color: #000000; background: #FAF834;
396
+ }
397
+
398
+ #rspec-header.pending_fixed {
399
+ color: #FFFFFF; background: #C40D0D;
400
+ }
401
+
402
+ #rspec-header.failed {
403
+ color: #FFFFFF; background: #C40D0D;
404
+ }
405
+
406
+
308
407
  .backtrace {
309
408
  color: #000;
310
409
  font-size: 12px;
@@ -25,7 +25,7 @@ module RSpec
25
25
 
26
26
  def lines_around(file, line)
27
27
  if File.file?(file)
28
- lines = File.open(file).read.split("\n")
28
+ lines = File.read(file).split("\n")
29
29
  min = [0, line-3].max
30
30
  max = [line+1, lines.length-1].min
31
31
  selected_lines = []
@@ -53,6 +53,10 @@ module RSpec
53
53
  def find_hooks_for(example_or_group)
54
54
  self.class.new(select {|hook| hook.options_apply?(example_or_group)})
55
55
  end
56
+
57
+ def without_hooks_for(example_or_group)
58
+ self.class.new(reject {|hook| hook.options_apply?(example_or_group)})
59
+ end
56
60
  end
57
61
 
58
62
  class BeforeHooks < HookCollection
@@ -117,7 +121,18 @@ module RSpec
117
121
  end
118
122
 
119
123
  def find_hook(hook, scope, example_group_class, example = nil)
120
- hooks[hook][scope].find_hooks_for(example || example_group_class)
124
+ found_hooks = hooks[hook][scope].find_hooks_for(example || example_group_class)
125
+
126
+ # ensure we don't re-run :all hooks that were applied to any of the parent groups
127
+ if scope == :all
128
+ super_klass = example_group_class.superclass
129
+ while super_klass != RSpec::Core::ExampleGroup
130
+ found_hooks = found_hooks.without_hooks_for(super_klass)
131
+ super_klass = super_klass.superclass
132
+ end
133
+ end
134
+
135
+ found_hooks
121
136
  end
122
137
 
123
138
  private
@@ -23,7 +23,7 @@ module RSpec::Core
23
23
 
24
24
  def parser(options)
25
25
  OptionParser.new do |parser|
26
- parser.banner = "Usage: rspec [options] [files or directories]"
26
+ parser.banner = "Usage: rspec [options] [files or directories]\n\n"
27
27
 
28
28
  parser.on('-b', '--backtrace', 'Enable full backtrace') do |o|
29
29
  options[:full_backtrace] = true
@@ -106,11 +106,7 @@ module RSpec::Core
106
106
  options[:drb_port] = o.to_i
107
107
  end
108
108
 
109
- parser.on('--tty') do |o|
110
- options[:tty] = true
111
- end
112
-
113
- parser.on('--fail-fast', 'Use the fail_fast option to tell RSpec to abort the run on first failure.') do |o|
109
+ parser.on('--fail-fast', 'Abort the run on first failure.') do |o|
114
110
  options[:fail_fast] = true
115
111
  end
116
112
 
@@ -126,6 +122,10 @@ module RSpec::Core
126
122
  options[filter_type] ||= {}
127
123
  options[filter_type][name] = value
128
124
  end
125
+
126
+ parser.on('--tty', 'Used internally by rspec when sending commands to other processes') do |o|
127
+ options[:tty] = true
128
+ end
129
129
  end
130
130
  end
131
131
  end
@@ -161,7 +161,7 @@ module RSpec
161
161
  cmd_parts << "bundle exec" if gemfile? unless skip_bundler
162
162
  cmd_parts << runner
163
163
  if rcov
164
- cmd_parts << ["-Ispec:lib", rcov_opts]
164
+ cmd_parts << ["-Ispec#{File::PATH_SEPARATOR}lib", rcov_opts]
165
165
  else
166
166
  cmd_parts << rspec_opts
167
167
  end
@@ -124,13 +124,13 @@ module RSpec
124
124
  example do
125
125
  self.class.class_eval do
126
126
  define_method(:subject) do
127
- if super().is_a?(Hash) && attribute.is_a?(Array)
128
- OpenStruct.new(super()).send(attribute.first)
129
- else
130
- attribute.to_s.split('.').inject(super()) do |target, method|
131
- target.send(method)
132
- end
133
- end
127
+ @_subject ||= if super().is_a?(Hash) && attribute.is_a?(Array)
128
+ OpenStruct.new(super()).send(attribute.first)
129
+ else
130
+ attribute.to_s.split('.').inject(super()) do |target, method|
131
+ target.send(method)
132
+ end
133
+ end
134
134
  end
135
135
  end
136
136
  instance_eval(&block)
@@ -1,7 +1,7 @@
1
1
  module RSpec # :nodoc:
2
2
  module Core # :nodoc:
3
3
  module Version # :nodoc:
4
- STRING = '2.4.0'
4
+ STRING = '2.5.0'
5
5
  end
6
6
  end
7
7
  end
@@ -22,17 +22,5 @@ Gem::Specification.new do |s|
22
22
  s.extra_rdoc_files = [ "README.md" ]
23
23
  s.rdoc_options = ["--charset=UTF-8"]
24
24
  s.require_path = "lib"
25
-
26
- s.post_install_message = %Q{**************************************************
27
-
28
- Thank you for installing #{s.summary}
29
-
30
- Please be sure to look at the upgrade instructions to see what might have
31
- changed since the last release:
32
-
33
- http://github.com/rspec/rspec-core/blob/master/Upgrade.markdown
34
-
35
- **************************************************
36
- }
37
25
  end
38
26