rspec-core 2.11.1 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/Changelog.md +59 -0
  2. data/README.md +22 -0
  3. data/features/command_line/example_name_option.feature +5 -5
  4. data/features/command_line/exit_status.feature +6 -6
  5. data/features/command_line/format_option.feature +2 -2
  6. data/features/command_line/line_number_appended_to_path.feature +2 -2
  7. data/features/command_line/line_number_option.feature +2 -2
  8. data/features/command_line/pattern_option.feature +2 -2
  9. data/features/command_line/rake_task.feature +62 -8
  10. data/features/command_line/ruby.feature +1 -1
  11. data/features/command_line/tag.feature +1 -1
  12. data/features/configuration/alias_example_to.feature +2 -2
  13. data/features/configuration/custom_settings.feature +3 -3
  14. data/features/configuration/default_path.feature +3 -3
  15. data/features/configuration/fail_fast.feature +5 -5
  16. data/features/configuration/read_options_from_file.feature +4 -4
  17. data/features/example_groups/basic_structure.feature +2 -2
  18. data/features/example_groups/shared_context.feature +3 -3
  19. data/features/example_groups/shared_examples.feature +25 -7
  20. data/features/expectation_framework_integration/configure_expectation_framework.feature +6 -6
  21. data/features/filtering/exclusion_filters.feature +5 -5
  22. data/features/filtering/if_and_unless.feature +5 -5
  23. data/features/filtering/inclusion_filters.feature +5 -5
  24. data/features/filtering/run_all_when_everything_filtered.feature +3 -3
  25. data/features/formatters/custom_formatter.feature +2 -2
  26. data/features/formatters/json_formatter.feature +30 -0
  27. data/features/formatters/text_formatter.feature +5 -5
  28. data/features/helper_methods/arbitrary_methods.feature +2 -2
  29. data/features/helper_methods/let.feature +2 -2
  30. data/features/helper_methods/modules.feature +6 -6
  31. data/features/hooks/around_hooks.feature +11 -11
  32. data/features/hooks/before_and_after_hooks.feature +15 -11
  33. data/features/hooks/filtering.feature +6 -6
  34. data/features/metadata/current_example.feature +1 -1
  35. data/features/metadata/described_class.feature +1 -1
  36. data/features/metadata/user_defined.feature +4 -4
  37. data/features/mock_framework_integration/use_any_framework.feature +6 -6
  38. data/features/mock_framework_integration/use_flexmock.feature +5 -5
  39. data/features/mock_framework_integration/use_mocha.feature +5 -5
  40. data/features/mock_framework_integration/use_rr.feature +5 -5
  41. data/features/mock_framework_integration/use_rspec.feature +5 -5
  42. data/features/pending/pending_examples.feature +11 -11
  43. data/features/spec_files/arbitrary_file_suffix.feature +1 -1
  44. data/features/step_definitions/additional_cli_steps.rb +2 -0
  45. data/features/subject/attribute_of_subject.feature +5 -5
  46. data/features/subject/explicit_subject.feature +5 -5
  47. data/features/subject/implicit_receiver.feature +2 -2
  48. data/features/subject/implicit_subject.feature +3 -3
  49. data/lib/autotest/rspec2.rb +1 -1
  50. data/lib/rspec/core.rb +53 -32
  51. data/lib/rspec/core/configuration.rb +123 -15
  52. data/lib/rspec/core/configuration_options.rb +17 -2
  53. data/lib/rspec/core/example.rb +5 -4
  54. data/lib/rspec/core/example_group.rb +19 -9
  55. data/lib/rspec/core/extensions/ordered.rb +12 -6
  56. data/lib/rspec/core/formatters.rb +55 -0
  57. data/lib/rspec/core/formatters/base_formatter.rb +43 -38
  58. data/lib/rspec/core/formatters/base_text_formatter.rb +9 -5
  59. data/lib/rspec/core/formatters/documentation_formatter.rb +1 -1
  60. data/lib/rspec/core/formatters/helpers.rb +30 -5
  61. data/lib/rspec/core/formatters/html_formatter.rb +58 -368
  62. data/lib/rspec/core/formatters/html_printer.rb +407 -0
  63. data/lib/rspec/core/formatters/json_formatter.rb +73 -0
  64. data/lib/rspec/core/formatters/snippet_extractor.rb +3 -1
  65. data/lib/rspec/core/hooks.rb +4 -4
  66. data/lib/rspec/core/metadata.rb +14 -6
  67. data/lib/rspec/core/mocking/with_mocha.rb +25 -2
  68. data/lib/rspec/core/mocking/with_rspec.rb +6 -2
  69. data/lib/rspec/core/option_parser.rb +28 -7
  70. data/lib/rspec/core/project_initializer.rb +0 -1
  71. data/lib/rspec/core/rake_task.rb +49 -38
  72. data/lib/rspec/core/reporter.rb +2 -2
  73. data/lib/rspec/core/shared_example_group.rb +89 -41
  74. data/lib/rspec/core/subject.rb +6 -2
  75. data/lib/rspec/core/version.rb +1 -1
  76. data/lib/rspec/core/world.rb +2 -2
  77. data/spec/autotest/rspec_spec.rb +6 -1
  78. data/spec/command_line/order_spec.rb +67 -0
  79. data/spec/rspec/core/configuration_options_spec.rb +45 -38
  80. data/spec/rspec/core/configuration_spec.rb +219 -44
  81. data/spec/rspec/core/deprecations_spec.rb +9 -0
  82. data/spec/rspec/core/drb_command_line_spec.rb +1 -7
  83. data/spec/rspec/core/drb_options_spec.rb +1 -1
  84. data/spec/rspec/core/dsl_spec.rb +17 -9
  85. data/spec/rspec/core/example_group_spec.rb +51 -5
  86. data/spec/rspec/core/example_spec.rb +39 -7
  87. data/spec/rspec/core/filter_manager_spec.rb +20 -30
  88. data/spec/rspec/core/formatters/base_formatter_spec.rb +29 -1
  89. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +6 -2
  90. data/spec/rspec/core/formatters/helpers_spec.rb +12 -0
  91. data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +462 -0
  92. data/spec/rspec/core/formatters/html_formatted-1.9.2-jruby.html +410 -0
  93. data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +462 -0
  94. data/spec/rspec/core/formatters/html_formatter_spec.rb +11 -3
  95. data/spec/rspec/core/formatters/json_formatter_spec.rb +110 -0
  96. data/spec/rspec/core/formatters/snippet_extractor_spec.rb +8 -0
  97. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-rbx.html +462 -0
  98. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2-jruby.html +410 -0
  99. data/spec/rspec/core/formatters/text_mate_formatted-1.9.3-rbx.html +462 -0
  100. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +11 -3
  101. data/spec/rspec/core/hooks_filtering_spec.rb +6 -6
  102. data/spec/rspec/core/metadata_spec.rb +29 -0
  103. data/spec/rspec/core/option_parser_spec.rb +42 -0
  104. data/spec/rspec/core/project_initializer_spec.rb +2 -2
  105. data/spec/rspec/core/rake_task_spec.rb +60 -17
  106. data/spec/rspec/core/reporter_spec.rb +17 -0
  107. data/spec/rspec/core/runner_spec.rb +1 -0
  108. data/spec/rspec/core/shared_example_group_spec.rb +17 -5
  109. data/spec/rspec/core/subject_spec.rb +11 -0
  110. data/spec/spec_helper.rb +32 -2
  111. data/spec/support/config_options_helper.rb +1 -10
  112. data/spec/support/helper_methods.rb +13 -0
  113. data/spec/support/isolated_directory.rb +10 -0
  114. data/spec/support/isolated_home_directory.rb +16 -0
  115. metadata +145 -148
  116. data/lib/rspec/core/extensions.rb +0 -4
@@ -405,17 +405,21 @@ MESSAGE
405
405
  @backtrace_clean_patterns = true_or_false ? [] : DEFAULT_BACKTRACE_PATTERNS
406
406
  end
407
407
 
408
- def color
409
- return false unless output_to_tty?
408
+ def color(output=output_stream)
409
+ # rspec's built-in formatters all call this with the output argument,
410
+ # but defaulting to output_stream for backward compatibility with
411
+ # formatters in extension libs
412
+ return false unless output_to_tty?(output)
410
413
  value_for(:color, @color)
411
414
  end
412
415
 
413
416
  def color=(bool)
414
417
  if bool
415
- @color = true
416
418
  if RSpec.windows_os? and not ENV['ANSICON']
417
- warn "You must use ANSICON 1.31 or later (http://adoxa.110mb.com/ansicon/) to use colour on Windows"
419
+ warn "You must use ANSICON 1.31 or later (http://adoxa.3eeweb.com/ansicon/) to use colour on Windows"
418
420
  @color = false
421
+ else
422
+ @color = true
419
423
  end
420
424
  end
421
425
  end
@@ -500,7 +504,7 @@ EOM
500
504
  # @private
501
505
  def files_or_directories_to_run=(*files)
502
506
  files = files.flatten
503
- files << default_path if command == 'rspec' && default_path && files.empty?
507
+ files << default_path if (command == 'rspec' || Runner.running_in_drb?) && default_path && files.empty?
504
508
  self.files_to_run = get_files_to_run(files)
505
509
  end
506
510
 
@@ -777,10 +781,29 @@ EOM
777
781
 
778
782
  # @private
779
783
  def load_spec_files
780
- files_to_run.uniq.map {|f| load File.expand_path(f) }
784
+ files_to_run.uniq.each {|f| load File.expand_path(f) }
781
785
  raise_if_rspec_1_is_loaded
782
786
  end
783
787
 
788
+ # @private
789
+ DEFAULT_FORMATTER = lambda { |string| string }
790
+
791
+ # Formats the docstring output using the block provided.
792
+ #
793
+ # @example
794
+ # # This will strip the descriptions of both examples and example groups.
795
+ # RSpec.configure do |config|
796
+ # config.format_docstrings { |s| s.strip }
797
+ # end
798
+ def format_docstrings(&block)
799
+ @format_docstrings_block = block_given? ? block : DEFAULT_FORMATTER
800
+ end
801
+
802
+ # @private
803
+ def format_docstrings_block
804
+ @format_docstrings_block ||= DEFAULT_FORMATTER
805
+ end
806
+
784
807
  # @api
785
808
  #
786
809
  # Sets the seed value and sets `order='rand'`
@@ -799,6 +822,79 @@ EOM
799
822
  order.to_s.match(/rand/)
800
823
  end
801
824
 
825
+ # @private
826
+ DEFAULT_ORDERING = lambda { |list| list }
827
+
828
+ # @private
829
+ RANDOM_ORDERING = lambda do |list|
830
+ Kernel.srand RSpec.configuration.seed
831
+ list.sort_by { Kernel.rand(list.size) }
832
+ end
833
+
834
+ # Sets a strategy by which to order examples.
835
+ #
836
+ # @example
837
+ # RSpec.configure do |config|
838
+ # config.order_examples do |examples|
839
+ # examples.reverse
840
+ # end
841
+ # end
842
+ #
843
+ # @see #order_groups
844
+ # @see #order_groups_and_examples
845
+ # @see #order=
846
+ # @see #seed=
847
+ def order_examples(&block)
848
+ @example_ordering_block = block
849
+ @order = "custom" unless built_in_orderer?(block)
850
+ end
851
+
852
+ # @private
853
+ def example_ordering_block
854
+ @example_ordering_block ||= DEFAULT_ORDERING
855
+ end
856
+
857
+ # Sets a strategy by which to order groups.
858
+ #
859
+ # @example
860
+ # RSpec.configure do |config|
861
+ # config.order_groups do |groups|
862
+ # groups.reverse
863
+ # end
864
+ # end
865
+ #
866
+ # @see #order_examples
867
+ # @see #order_groups_and_examples
868
+ # @see #order=
869
+ # @see #seed=
870
+ def order_groups(&block)
871
+ @group_ordering_block = block
872
+ @order = "custom" unless built_in_orderer?(block)
873
+ end
874
+
875
+ # @private
876
+ def group_ordering_block
877
+ @group_ordering_block ||= DEFAULT_ORDERING
878
+ end
879
+
880
+ # Sets a strategy by which to order groups and examples.
881
+ #
882
+ # @example
883
+ # RSpec.configure do |config|
884
+ # config.order_groups_and_examples do |groups_or_examples|
885
+ # groups_or_examples.reverse
886
+ # end
887
+ # end
888
+ #
889
+ # @see #order_groups
890
+ # @see #order_examples
891
+ # @see #order=
892
+ # @see #seed=
893
+ def order_groups_and_examples(&block)
894
+ order_groups(&block)
895
+ order_examples(&block)
896
+ end
897
+
802
898
  private
803
899
 
804
900
  def get_files_to_run(paths)
@@ -806,12 +902,12 @@ EOM
806
902
  paths.map do |path|
807
903
  path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
808
904
  File.directory?(path) ? gather_directories(path, patterns) : extract_location(path)
809
- end.flatten
905
+ end.flatten.sort
810
906
  end
811
907
 
812
908
  def gather_directories(path, patterns)
813
909
  patterns.map do |pattern|
814
- pattern =~ /^#{path}/ ? Dir[pattern.strip] : Dir["#{path}/{#{pattern.strip}}"]
910
+ pattern =~ /^#{path}/ ? Dir[pattern.strip].sort : Dir["#{path}/{#{pattern.strip}}"].sort
815
911
  end
816
912
  end
817
913
 
@@ -856,12 +952,8 @@ MESSAGE
856
952
  end
857
953
  end
858
954
 
859
- def output_to_tty?
860
- begin
861
- output_stream.tty? || tty?
862
- rescue NoMethodError
863
- false
864
- end
955
+ def output_to_tty?(output=output_stream)
956
+ tty? || (output.respond_to?(:tty?) && output.tty?)
865
957
  end
866
958
 
867
959
  def built_in_formatter(key)
@@ -878,6 +970,9 @@ MESSAGE
878
970
  when 'p', 'progress'
879
971
  require 'rspec/core/formatters/progress_formatter'
880
972
  RSpec::Core::Formatters::ProgressFormatter
973
+ when 'j', 'json'
974
+ require 'rspec/core/formatters/json_formatter'
975
+ RSpec::Core::Formatters::JsonFormatter
881
976
  end
882
977
  end
883
978
 
@@ -923,7 +1018,9 @@ MESSAGE
923
1018
  end
924
1019
 
925
1020
  def order_and_seed_from_seed(value)
1021
+ order_groups_and_examples(&RANDOM_ORDERING)
926
1022
  @order, @seed = 'rand', value.to_i
1023
+ [@order, @seed]
927
1024
  end
928
1025
 
929
1026
  def set_order_and_seed(hash)
@@ -935,10 +1032,21 @@ MESSAGE
935
1032
  order, seed = type.to_s.split(':')
936
1033
  @order = order
937
1034
  @seed = seed = seed.to_i if seed
938
- @order, @seed = nil, nil if order == 'default'
1035
+
1036
+ if randomize?
1037
+ order_groups_and_examples(&RANDOM_ORDERING)
1038
+ elsif order == 'default'
1039
+ @order, @seed = nil, nil
1040
+ order_groups_and_examples(&DEFAULT_ORDERING)
1041
+ end
1042
+
939
1043
  return order, seed
940
1044
  end
941
1045
 
1046
+ def built_in_orderer?(block)
1047
+ [DEFAULT_ORDERING, RANDOM_ORDERING].include?(block)
1048
+ end
1049
+
942
1050
  end
943
1051
  end
944
1052
  end
@@ -9,6 +9,13 @@ module RSpec
9
9
 
10
10
  def initialize(args)
11
11
  @args = args
12
+ if args.include?("--default_path")
13
+ args[args.index("--default_path")] = "--default-path"
14
+ end
15
+
16
+ if args.include?("--line_number")
17
+ args[args.index("--line_number")] = "--line-number"
18
+ end
12
19
  end
13
20
 
14
21
  def configure(config)
@@ -71,7 +78,7 @@ module RSpec
71
78
  end
72
79
 
73
80
  def file_options
74
- custom_options_file ? [custom_options] : [global_options, local_options]
81
+ custom_options_file ? [custom_options] : [global_options, project_options, local_options]
75
82
  end
76
83
 
77
84
  def env_options
@@ -90,6 +97,10 @@ module RSpec
90
97
  @local_options ||= options_from(local_options_file)
91
98
  end
92
99
 
100
+ def project_options
101
+ @project_options ||= options_from(project_options_file)
102
+ end
103
+
93
104
  def global_options
94
105
  @global_options ||= options_from(global_options_file)
95
106
  end
@@ -112,10 +123,14 @@ module RSpec
112
123
  command_line_options[:custom_options_file]
113
124
  end
114
125
 
115
- def local_options_file
126
+ def project_options_file
116
127
  ".rspec"
117
128
  end
118
129
 
130
+ def local_options_file
131
+ ".rspec-local"
132
+ end
133
+
119
134
  def global_options_file
120
135
  begin
121
136
  File.join(File.expand_path("~"), ".rspec")
@@ -49,7 +49,8 @@ module RSpec
49
49
  # there is one, otherwise returns a message including the location of the
50
50
  # example.
51
51
  def description
52
- metadata[:description].to_s.empty? ? "example at #{location}" : metadata[:description]
52
+ description = metadata[:description].to_s.empty? ? "example at #{location}" : metadata[:description]
53
+ RSpec.configuration.format_docstrings_block.call(description)
53
54
  end
54
55
 
55
56
  # @attr_reader
@@ -260,7 +261,7 @@ An error occurred #{context}
260
261
 
261
262
  def start(reporter)
262
263
  reporter.example_started(self)
263
- record :started_at => Time.now
264
+ record :started_at => RSpec::Core::Time.now
264
265
  end
265
266
 
266
267
  # @private
@@ -290,8 +291,8 @@ An error occurred #{context}
290
291
  end
291
292
 
292
293
  def record_finished(status, results={})
293
- finished_at = Time.now
294
- record results.merge(:status => status, :finished_at => finished_at, :run_time => (finished_at - execution_result[:started_at]))
294
+ finished_at = RSpec::Core::Time.now
295
+ record results.merge(:status => status, :finished_at => finished_at, :run_time => (finished_at - execution_result[:started_at]).to_f)
295
296
  end
296
297
 
297
298
  def run_before_each
@@ -22,6 +22,7 @@ module RSpec
22
22
  include Subject::ExampleMethods
23
23
  include Pending
24
24
  include Let
25
+ include SharedExampleGroup
25
26
 
26
27
  # @private
27
28
  def self.world
@@ -43,7 +44,12 @@ module RSpec
43
44
  end
44
45
  end
45
46
 
46
- delegate_to_metadata :description, :described_class, :file_path
47
+ def description
48
+ description = metadata[:example_group][:description]
49
+ RSpec.configuration.format_docstrings_block.call(description)
50
+ end
51
+
52
+ delegate_to_metadata :described_class, :file_path
47
53
  alias_method :display_name, :description
48
54
  # @private
49
55
  alias_method :describes, :described_class
@@ -241,7 +247,7 @@ module RSpec
241
247
 
242
248
  # @private
243
249
  def self.children
244
- @children ||= [].extend(Extensions::Ordered)
250
+ @children ||= [].extend(Extensions::Ordered::ExampleGroups)
245
251
  end
246
252
 
247
253
  # @private
@@ -249,9 +255,9 @@ module RSpec
249
255
  @_descendants ||= [self] + children.inject([]) {|list, c| list + c.descendants}
250
256
  end
251
257
 
252
- # @private
253
- def self.ancestors
254
- @_ancestors ||= super().select {|a| a < RSpec::Core::ExampleGroup}
258
+ ## @private
259
+ def self.parent_groups
260
+ @parent_groups ||= ancestors.select {|a| a < RSpec::Core::ExampleGroup}
255
261
  end
256
262
 
257
263
  # @private
@@ -308,9 +314,12 @@ module RSpec
308
314
  # @private
309
315
  def self.run_before_all_hooks(example_group_instance)
310
316
  return if descendant_filtered_examples.empty?
311
- assign_before_all_ivars(superclass.before_all_ivars, example_group_instance)
312
- run_hook(:before, :all, example_group_instance)
313
- store_before_all_ivars(example_group_instance)
317
+ begin
318
+ assign_before_all_ivars(superclass.before_all_ivars, example_group_instance)
319
+ run_hook(:before, :all, example_group_instance)
320
+ ensure
321
+ store_before_all_ivars(example_group_instance)
322
+ end
314
323
  end
315
324
 
316
325
  # @private
@@ -361,6 +370,7 @@ An error occurred in an after(:all) hook.
361
370
  results_for_descendants = children.ordered.map {|child| child.run(reporter)}.all?
362
371
  result_for_this_group && results_for_descendants
363
372
  rescue Exception => ex
373
+ RSpec.wants_to_quit = true if fail_fast?
364
374
  fail_filtered_examples(ex, reporter)
365
375
  ensure
366
376
  run_after_all_hooks(new)
@@ -417,7 +427,7 @@ An error occurred in an after(:all) hook.
417
427
 
418
428
  # @private
419
429
  def self.top_level_description
420
- ancestors.last.description
430
+ parent_groups.last.description
421
431
  end
422
432
 
423
433
  # @private
@@ -7,12 +7,18 @@ module RSpec
7
7
  # strategies like randomization.
8
8
  module Ordered
9
9
  # @private
10
- def ordered
11
- if RSpec.configuration.randomize?
12
- Kernel.srand RSpec.configuration.seed
13
- sort_by { Kernel.rand size }
14
- else
15
- self
10
+ module ExampleGroups
11
+ # @private
12
+ def ordered
13
+ RSpec.configuration.group_ordering_block.call(self)
14
+ end
15
+ end
16
+
17
+ # @private
18
+ module Examples
19
+ # @private
20
+ def ordered
21
+ RSpec.configuration.example_ordering_block.call(self)
16
22
  end
17
23
  end
18
24
  end
@@ -0,0 +1,55 @@
1
+ # ## Built-in Formatters
2
+ #
3
+ # * progress (default) - prints dots for passing examples, `F` for failures, `*` for pending
4
+ # * documentation - prints the docstrings passed to `describe` and `it` methods (and their aliases)
5
+ # * html
6
+ # * textmate - html plus links to editor
7
+ # * json - useful for archiving data for subsequent analysis
8
+ #
9
+ # The progress formatter is the default, but you can choose any one or more of
10
+ # the other formatters by passing with the `--format` (or `-f` for short)
11
+ # command-line option, e.g.
12
+ #
13
+ # rspec --format documentation
14
+ #
15
+ # You can also send the output of multiple formatters to different streams, e.g.
16
+ #
17
+ # rspec --format documentation --format html --out results.html
18
+ #
19
+ # This example sends the output of the documentation formatter to `STDOUT`, and
20
+ # the output of the html formatter to results.html.
21
+ #
22
+ # ## Custom Formatters
23
+ #
24
+ # You can tell RSpec to use a custom formatter by passing its path and name to
25
+ # the `rspec` commmand. For example, if you define MyCustomFormatter in
26
+ # path/to/my_custom_formatter.rb, you would type this command:
27
+ #
28
+ # rspec --require path/to/my_custom_formatter.rb --format MyCustomFormatter
29
+ #
30
+ # The reporter calls every formatter with this protocol:
31
+ #
32
+ # * `start(expected_example_count)`
33
+ # * zero or more of the following
34
+ # * `example_group_started(group)`
35
+ # * `example_started(example)`
36
+ # * `example_passed(example)`
37
+ # * `example_failed(example)`
38
+ # * `example_pending(example)`
39
+ # * `message(string)`
40
+ # * `stop`
41
+ # * `start_dump`
42
+ # * `dump_pending`
43
+ # * `dump_failures`
44
+ # * `dump_summary(duration, example_count, failure_count, pending_count)`
45
+ # * `seed(value)`
46
+ # * `close`
47
+ #
48
+ # You can either implement all of those methods or subclass
49
+ # `RSpec::Core::Formatters::BaseTextFormatter` and override the methods you want
50
+ # to enhance.
51
+ #
52
+ # @see RSpec::Core::Formatters::BaseTextFormatter
53
+ # @see RSpec::Core::Reporter
54
+ module RSpec::Core::Formatters
55
+ end