rspec-core 3.0.0.beta1 → 3.0.0.beta2
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.
- data.tar.gz.sig +0 -0
- data/Changelog.md +137 -0
- data/README.md +2 -2
- data/exe/rspec +2 -23
- data/features/README.md +1 -5
- data/features/command_line/README.md +7 -10
- data/features/command_line/exit_status.feature +1 -1
- data/features/command_line/format_option.feature +1 -1
- data/features/command_line/init.feature +40 -1
- data/features/command_line/line_number_option.feature +2 -2
- data/features/command_line/ruby.feature +5 -4
- data/features/configuration/enable_global_dsl.feature +54 -0
- data/features/example_groups/aliasing.feature +48 -0
- data/features/example_groups/basic_structure.feature +1 -1
- data/features/expectation_framework_integration/configure_expectation_framework.feature +1 -1
- data/features/filtering/if_and_unless.feature +0 -30
- data/features/formatters/custom_formatter.feature +32 -0
- data/features/formatters/regression_tests.feature +95 -0
- data/features/hooks/around_hooks.feature +1 -0
- data/features/hooks/before_and_after_hooks.feature +2 -2
- data/features/mock_framework_integration/use_flexmock.feature +11 -13
- data/features/mock_framework_integration/use_mocha.feature +11 -13
- data/features/mock_framework_integration/use_rr.feature +11 -13
- data/features/mock_framework_integration/use_rspec.feature +11 -13
- data/features/pending_and_skipped_examples/README.md +3 -0
- data/features/pending_and_skipped_examples/pending_examples.feature +118 -0
- data/features/pending_and_skipped_examples/skipped_examples.feature +106 -0
- data/features/step_definitions/additional_cli_steps.rb +34 -0
- data/features/subject/explicit_subject.feature +1 -1
- data/features/subject/one_liner_syntax.feature +71 -0
- data/lib/rspec/core.rb +6 -14
- data/lib/rspec/core/backtrace_formatter.rb +16 -4
- data/lib/rspec/core/command_line.rb +2 -3
- data/lib/rspec/core/configuration.rb +114 -125
- data/lib/rspec/core/configuration_options.rb +32 -18
- data/lib/rspec/core/dsl.rb +80 -18
- data/lib/rspec/core/example.rb +84 -33
- data/lib/rspec/core/example_group.rb +95 -43
- data/lib/rspec/core/filter_manager.rb +31 -40
- data/lib/rspec/core/formatters.rb +137 -0
- data/lib/rspec/core/formatters/base_formatter.rb +28 -41
- data/lib/rspec/core/formatters/base_text_formatter.rb +26 -37
- data/lib/rspec/core/formatters/deprecation_formatter.rb +48 -27
- data/lib/rspec/core/formatters/documentation_formatter.rb +27 -22
- data/lib/rspec/core/formatters/html_formatter.rb +48 -56
- data/lib/rspec/core/formatters/html_printer.rb +11 -18
- data/lib/rspec/core/formatters/json_formatter.rb +18 -22
- data/lib/rspec/core/formatters/legacy_formatter.rb +227 -0
- data/lib/rspec/core/formatters/progress_formatter.rb +7 -10
- data/lib/rspec/core/hooks.rb +250 -217
- data/lib/rspec/core/memoized_helpers.rb +43 -9
- data/lib/rspec/core/mocking_adapters/flexmock.rb +29 -0
- data/lib/rspec/core/{mocking/with_mocha.rb → mocking_adapters/mocha.rb} +19 -16
- data/lib/rspec/core/mocking_adapters/null.rb +12 -0
- data/lib/rspec/core/mocking_adapters/rr.rb +28 -0
- data/lib/rspec/core/mocking_adapters/rspec.rb +30 -0
- data/lib/rspec/core/notifications.rb +100 -0
- data/lib/rspec/core/option_parser.rb +11 -18
- data/lib/rspec/core/pending.rb +78 -47
- data/lib/rspec/core/project_initializer.rb +2 -49
- data/lib/rspec/core/project_initializer/dot_rspec +3 -0
- data/lib/rspec/core/project_initializer/spec_helper.rb +82 -0
- data/lib/rspec/core/rake_task.rb +5 -14
- data/lib/rspec/core/reporter.rb +24 -32
- data/lib/rspec/core/ruby_project.rb +1 -1
- data/lib/rspec/core/runner.rb +14 -4
- data/lib/rspec/core/shared_example_group.rb +40 -13
- data/lib/rspec/core/version.rb +1 -1
- data/spec/command_line/order_spec.rb +15 -15
- data/spec/rspec/core/backtrace_formatter_spec.rb +15 -1
- data/spec/rspec/core/command_line_spec.rb +18 -17
- data/spec/rspec/core/configuration_options_spec.rb +57 -34
- data/spec/rspec/core/configuration_spec.rb +162 -184
- data/spec/rspec/core/drb_command_line_spec.rb +5 -7
- data/spec/rspec/core/drb_options_spec.rb +2 -2
- data/spec/rspec/core/dsl_spec.rb +79 -15
- data/spec/rspec/core/example_group_spec.rb +253 -39
- data/spec/rspec/core/example_spec.rb +149 -33
- data/spec/rspec/core/filter_manager_spec.rb +9 -26
- data/spec/rspec/core/formatters/base_formatter_spec.rb +2 -5
- data/spec/rspec/core/formatters/base_text_formatter_spec.rb +42 -145
- data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +64 -34
- data/spec/rspec/core/formatters/documentation_formatter_spec.rb +15 -28
- data/spec/rspec/core/formatters/helpers_spec.rb +2 -2
- data/spec/rspec/core/formatters/{html_formatted-1.8.7.html → html_formatted-2.1.0.html} +22 -44
- data/spec/rspec/core/formatters/{html_formatted-1.8.7-jruby.html → html_formatted.html} +30 -49
- data/spec/rspec/core/formatters/html_formatter_spec.rb +35 -19
- data/spec/rspec/core/formatters/json_formatter_spec.rb +42 -40
- data/spec/rspec/core/formatters/legacy_formatter_spec.rb +137 -0
- data/spec/rspec/core/formatters/progress_formatter_spec.rb +38 -25
- data/spec/rspec/core/formatters/snippet_extractor_spec.rb +1 -1
- data/spec/rspec/core/formatters_spec.rb +120 -0
- data/spec/rspec/core/hooks_filtering_spec.rb +1 -1
- data/spec/rspec/core/hooks_spec.rb +13 -2
- data/spec/rspec/core/memoized_helpers_spec.rb +17 -8
- data/spec/rspec/core/metadata_spec.rb +3 -3
- data/spec/rspec/core/option_parser_spec.rb +53 -46
- data/spec/rspec/core/ordering_spec.rb +4 -4
- data/spec/rspec/core/pending_example_spec.rb +23 -126
- data/spec/rspec/core/pending_spec.rb +8 -0
- data/spec/rspec/core/project_initializer_spec.rb +8 -41
- data/spec/rspec/core/rake_task_spec.rb +15 -4
- data/spec/rspec/core/random_spec.rb +1 -1
- data/spec/rspec/core/reporter_spec.rb +50 -37
- data/spec/rspec/core/resources/formatter_specs.rb +9 -11
- data/spec/rspec/core/rspec_matchers_spec.rb +1 -1
- data/spec/rspec/core/ruby_project_spec.rb +3 -3
- data/spec/rspec/core/runner_spec.rb +65 -23
- data/spec/rspec/core/shared_context_spec.rb +4 -4
- data/spec/rspec/core/shared_example_group/collection_spec.rb +1 -1
- data/spec/rspec/core/shared_example_group_spec.rb +20 -11
- data/spec/rspec/core/warnings_spec.rb +1 -1
- data/spec/rspec/core/world_spec.rb +10 -10
- data/spec/rspec/core_spec.rb +2 -2
- data/spec/spec_helper.rb +12 -24
- data/spec/support/config_options_helper.rb +1 -3
- data/spec/support/formatter_support.rb +83 -0
- data/spec/support/isolate_load_path_mutation.rb +1 -2
- data/spec/support/isolated_directory.rb +1 -1
- data/spec/support/isolated_home_directory.rb +1 -1
- data/spec/support/legacy_formatter_using_sub_classing_example.rb +87 -0
- data/spec/support/matchers.rb +20 -0
- data/spec/support/mathn_integration_support.rb +2 -2
- data/spec/support/old_style_formatter_example.rb +69 -0
- data/spec/support/shared_example_groups.rb +1 -1
- data/spec/support/spec_files.rb +3 -3
- metadata +192 -69
- metadata.gz.sig +3 -1
- checksums.yaml +0 -15
- checksums.yaml.gz.sig +0 -2
- data/features/configuration/show_failures_in_pending_blocks.feature +0 -61
- data/features/pending/pending_examples.feature +0 -229
- data/features/subject/implicit_receiver.feature +0 -29
- data/lib/rspec/core/mocking/with_absolutely_nothing.rb +0 -11
- data/lib/rspec/core/mocking/with_flexmock.rb +0 -27
- data/lib/rspec/core/mocking/with_rr.rb +0 -27
- data/lib/rspec/core/mocking/with_rspec.rb +0 -27
- data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +0 -477
- data/spec/rspec/core/formatters/html_formatted-1.9.2.html +0 -425
- data/spec/rspec/core/formatters/html_formatted-1.9.3-jruby.html +0 -416
- data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +0 -477
- data/spec/rspec/core/formatters/html_formatted-1.9.3.html +0 -419
- data/spec/rspec/core/formatters/html_formatted-2.0.0.html +0 -425
- data/spec/support/in_sub_process.rb +0 -37
- data/spec/support/sandboxed_mock_space.rb +0 -100
|
@@ -5,31 +5,24 @@ module RSpec
|
|
|
5
5
|
module Core
|
|
6
6
|
# @private
|
|
7
7
|
class ConfigurationOptions
|
|
8
|
-
attr_reader :options
|
|
9
|
-
|
|
10
8
|
def initialize(args)
|
|
11
|
-
@args = args.
|
|
12
|
-
a.sub("default_path", "default-path").sub("line_number", "line-number")
|
|
13
|
-
}
|
|
9
|
+
@args = args.dup
|
|
14
10
|
end
|
|
15
11
|
|
|
16
12
|
def configure(config)
|
|
17
13
|
config.filter_manager = filter_manager
|
|
18
14
|
|
|
19
|
-
config.libs = options[:libs] || []
|
|
20
|
-
config.setup_load_path_and_require(options[:requires] || [])
|
|
21
|
-
|
|
22
15
|
process_options_into config
|
|
23
16
|
load_formatters_into config
|
|
24
17
|
end
|
|
25
18
|
|
|
26
|
-
def
|
|
27
|
-
@options
|
|
19
|
+
def options
|
|
20
|
+
@options ||= (file_options << command_line_options << env_options).
|
|
28
21
|
each {|opts|
|
|
29
22
|
filter_manager.include opts.delete(:inclusion_filter) if opts.has_key?(:inclusion_filter)
|
|
30
23
|
filter_manager.exclude opts.delete(:exclusion_filter) if opts.has_key?(:exclusion_filter)
|
|
31
24
|
}.
|
|
32
|
-
inject {|h, opts|
|
|
25
|
+
inject(:libs => [], :requires => []) {|h, opts|
|
|
33
26
|
h.merge(opts) {|k, oldval, newval|
|
|
34
27
|
[:libs, :requires].include?(k) ? oldval + newval : newval
|
|
35
28
|
}
|
|
@@ -51,24 +44,45 @@ module RSpec
|
|
|
51
44
|
:line_numbers, :full_description, :full_backtrace, :tty
|
|
52
45
|
].to_set
|
|
53
46
|
|
|
54
|
-
UNPROCESSABLE_OPTIONS = [:
|
|
47
|
+
UNPROCESSABLE_OPTIONS = [:formatters].to_set
|
|
55
48
|
|
|
56
49
|
def force?(key)
|
|
57
50
|
!UNFORCED_OPTIONS.include?(key)
|
|
58
51
|
end
|
|
59
52
|
|
|
60
|
-
def order(keys
|
|
61
|
-
|
|
53
|
+
def order(keys)
|
|
54
|
+
OPTIONS_ORDER.reverse.each do |key|
|
|
62
55
|
keys.unshift(key) if keys.delete(key)
|
|
63
56
|
end
|
|
64
57
|
keys
|
|
65
58
|
end
|
|
66
59
|
|
|
60
|
+
OPTIONS_ORDER = [
|
|
61
|
+
# load paths depend on nothing, but must be set before `requires`
|
|
62
|
+
# to support load-path-relative requires.
|
|
63
|
+
:libs,
|
|
64
|
+
|
|
65
|
+
# `files_or_directories_to_run` uses `default_path` so it must be
|
|
66
|
+
# set before it.
|
|
67
|
+
:default_path,
|
|
68
|
+
|
|
69
|
+
# must be set before `requires` to support checking `config.files_to_run`
|
|
70
|
+
# from within `spec_helper.rb` when a `-rspec_helper` option is used.
|
|
71
|
+
:files_or_directories_to_run,
|
|
72
|
+
|
|
73
|
+
# In general, we want to require the specified files as early as possible.
|
|
74
|
+
# The `--require` option is specifically intended to allow early requires.
|
|
75
|
+
# For later requires, they can just put the require in their spec files, but
|
|
76
|
+
# `--require` provides a unique opportunity for users to instruct RSpec to
|
|
77
|
+
# load an extension file early for maximum flexibility.
|
|
78
|
+
:requires
|
|
79
|
+
]
|
|
80
|
+
|
|
67
81
|
def process_options_into(config)
|
|
68
82
|
opts = options.reject { |k, _| UNPROCESSABLE_OPTIONS.include? k }
|
|
69
83
|
|
|
70
|
-
order(opts.keys
|
|
71
|
-
force?(key) ? config.force(key => opts[key]) : config.
|
|
84
|
+
order(opts.keys).each do |key|
|
|
85
|
+
force?(key) ? config.force(key => opts[key]) : config.__send__("#{key}=", opts[key])
|
|
72
86
|
end
|
|
73
87
|
end
|
|
74
88
|
|
|
@@ -81,11 +95,11 @@ module RSpec
|
|
|
81
95
|
end
|
|
82
96
|
|
|
83
97
|
def env_options
|
|
84
|
-
ENV["SPEC_OPTS"] ? Parser.parse
|
|
98
|
+
ENV["SPEC_OPTS"] ? Parser.parse(Shellwords.split(ENV["SPEC_OPTS"])) : {}
|
|
85
99
|
end
|
|
86
100
|
|
|
87
101
|
def command_line_options
|
|
88
|
-
@command_line_options ||= Parser.parse
|
|
102
|
+
@command_line_options ||= Parser.parse(@args).merge :files_or_directories_to_run => @args
|
|
89
103
|
end
|
|
90
104
|
|
|
91
105
|
def custom_options
|
data/lib/rspec/core/dsl.rb
CHANGED
|
@@ -1,26 +1,88 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Core
|
|
3
|
-
#
|
|
3
|
+
# DSL defines methods to group examples, most notably `describe`,
|
|
4
|
+
# and exposes them as class methods of {RSpec}. They can also be
|
|
5
|
+
# exposed globally (on `main` and instances of `Module`) through
|
|
6
|
+
# the {Configuration} option `expose_dsl_globally`.
|
|
7
|
+
#
|
|
8
|
+
# By default the methods `describe`, `context` and `example_group`
|
|
9
|
+
# are exposed. These methods define a named context for one or
|
|
10
|
+
# more examples. The given block is evaluated in the context of
|
|
11
|
+
# a generated subclass of {RSpec::Core::ExampleGroup}
|
|
12
|
+
#
|
|
13
|
+
# ## Examples:
|
|
14
|
+
#
|
|
15
|
+
# RSpec.describe "something" do
|
|
16
|
+
# context "when something is a certain way" do
|
|
17
|
+
# it "does something" do
|
|
18
|
+
# # example code goes here
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# @see ExampleGroup
|
|
24
|
+
# @see ExampleGroup.example_group
|
|
4
25
|
module DSL
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
# describe "something" do
|
|
10
|
-
# it "does something" do
|
|
11
|
-
# # example code goes here
|
|
12
|
-
# end
|
|
13
|
-
# end
|
|
14
|
-
#
|
|
15
|
-
# @see ExampleGroup
|
|
16
|
-
# @see ExampleGroup.describe
|
|
17
|
-
def describe(*args, &example_group_block)
|
|
18
|
-
RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
|
|
26
|
+
# @private
|
|
27
|
+
def self.example_group_aliases
|
|
28
|
+
@example_group_aliases ||= []
|
|
19
29
|
end
|
|
30
|
+
|
|
31
|
+
# @private
|
|
32
|
+
def self.exposed_globally?
|
|
33
|
+
@exposed_globally ||= false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.expose_example_group_alias(name)
|
|
37
|
+
example_group_aliases << name
|
|
38
|
+
|
|
39
|
+
(class << RSpec; self; end).__send__(:define_method, name) do |*args, &example_group_block|
|
|
40
|
+
RSpec::Core::ExampleGroup.__send__(name, *args, &example_group_block).register
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
expose_example_group_alias_globally(name) if exposed_globally?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class << self
|
|
47
|
+
# @private
|
|
48
|
+
attr_accessor :top_level
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Add's the describe method to Module and the top level binding
|
|
52
|
+
def self.expose_globally!
|
|
53
|
+
return if exposed_globally?
|
|
54
|
+
|
|
55
|
+
example_group_aliases.each do |method_name|
|
|
56
|
+
expose_example_group_alias_globally(method_name)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@exposed_globally = true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.remove_globally!
|
|
63
|
+
return unless exposed_globally?
|
|
64
|
+
|
|
65
|
+
example_group_aliases.each do |method_name|
|
|
66
|
+
change_global_dsl { undef_method method_name }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
@exposed_globally = false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.expose_example_group_alias_globally(method_name)
|
|
73
|
+
change_global_dsl do
|
|
74
|
+
define_method(method_name) { |*a, &b| ::RSpec.__send__(method_name, *a, &b) }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.change_global_dsl(&changes)
|
|
79
|
+
(class << top_level; self; end).class_exec(&changes)
|
|
80
|
+
Module.class_exec(&changes)
|
|
81
|
+
end
|
|
82
|
+
|
|
20
83
|
end
|
|
21
84
|
end
|
|
22
85
|
end
|
|
23
86
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
87
|
+
# capture main without an eval
|
|
88
|
+
::RSpec::Core::DSL.top_level = self
|
data/lib/rspec/core/example.rb
CHANGED
|
@@ -41,15 +41,18 @@ module RSpec
|
|
|
41
41
|
keys.each { |key| define_method(key) { @metadata[key] } }
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
delegate_to_metadata :
|
|
44
|
+
delegate_to_metadata :execution_result, :file_path, :full_description,
|
|
45
|
+
:location, :pending, :skip
|
|
45
46
|
|
|
46
47
|
# Returns the string submitted to `example` or its aliases (e.g.
|
|
47
|
-
# `specify`, `it`, etc). If no string is submitted (e.g. `it {
|
|
48
|
+
# `specify`, `it`, etc). If no string is submitted (e.g. `it { is_expected.to
|
|
48
49
|
# do_something }`) it returns the message generated by the matcher if
|
|
49
50
|
# there is one, otherwise returns a message including the location of the
|
|
50
51
|
# example.
|
|
51
52
|
def description
|
|
52
|
-
description = metadata[:description].to_s.empty? ?
|
|
53
|
+
description = metadata[:description].to_s.empty? ?
|
|
54
|
+
"example at #{location}" :
|
|
55
|
+
metadata[:description]
|
|
53
56
|
RSpec.configuration.format_docstrings_block.call(description)
|
|
54
57
|
end
|
|
55
58
|
|
|
@@ -71,6 +74,10 @@ module RSpec
|
|
|
71
74
|
# running this example.
|
|
72
75
|
attr_reader :example_group_instance
|
|
73
76
|
|
|
77
|
+
# @attr_accessor
|
|
78
|
+
# @private
|
|
79
|
+
attr_accessor :clock
|
|
80
|
+
|
|
74
81
|
# Creates a new instance of Example.
|
|
75
82
|
# @param example_group_class the subclass of ExampleGroup in which this Example is declared
|
|
76
83
|
# @param description the String passed to the `it` method (or alias)
|
|
@@ -80,7 +87,7 @@ module RSpec
|
|
|
80
87
|
@example_group_class, @options, @example_block = example_group_class, metadata, example_block
|
|
81
88
|
@metadata = @example_group_class.metadata.for_example(description, metadata)
|
|
82
89
|
@example_group_instance = @exception = nil
|
|
83
|
-
@
|
|
90
|
+
@clock = RSpec::Core::Time
|
|
84
91
|
end
|
|
85
92
|
|
|
86
93
|
# @deprecated access options via metadata instead
|
|
@@ -95,6 +102,7 @@ module RSpec
|
|
|
95
102
|
end
|
|
96
103
|
|
|
97
104
|
alias_method :pending?, :pending
|
|
105
|
+
alias_method :skipped?, :skip
|
|
98
106
|
|
|
99
107
|
# @api private
|
|
100
108
|
# instance_evals the block passed to the constructor in the context of
|
|
@@ -107,13 +115,24 @@ module RSpec
|
|
|
107
115
|
start(reporter)
|
|
108
116
|
|
|
109
117
|
begin
|
|
110
|
-
|
|
118
|
+
if skipped?
|
|
119
|
+
Pending.mark_pending! self, skip
|
|
120
|
+
elsif !RSpec.configuration.dry_run?
|
|
111
121
|
with_around_each_hooks do
|
|
112
122
|
begin
|
|
113
123
|
run_before_each
|
|
114
124
|
@example_group_instance.instance_exec(self, &@example_block)
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
|
|
126
|
+
if pending?
|
|
127
|
+
Pending.mark_fixed! self
|
|
128
|
+
|
|
129
|
+
raise Pending::PendingExampleFixedError,
|
|
130
|
+
'Expected example to fail since it is pending, but it passed.',
|
|
131
|
+
metadata[:caller]
|
|
132
|
+
end
|
|
133
|
+
rescue Pending::SkipDeclaredInExample
|
|
134
|
+
# no-op, required metadata has already been set by the `skip`
|
|
135
|
+
# method.
|
|
117
136
|
rescue Exception => e
|
|
118
137
|
set_exception(e)
|
|
119
138
|
ensure
|
|
@@ -190,7 +209,7 @@ module RSpec
|
|
|
190
209
|
|
|
191
210
|
# @private
|
|
192
211
|
def around_each_hooks
|
|
193
|
-
@around_each_hooks ||= example_group.around_each_hooks_for(self)
|
|
212
|
+
@around_each_hooks ||= example_group.hooks.around_each_hooks_for(self)
|
|
194
213
|
end
|
|
195
214
|
|
|
196
215
|
# @private
|
|
@@ -198,20 +217,24 @@ module RSpec
|
|
|
198
217
|
# Used internally to set an exception in an after hook, which
|
|
199
218
|
# captures the exception but doesn't raise it.
|
|
200
219
|
def set_exception(exception, context=nil)
|
|
201
|
-
if
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
220
|
+
if pending?
|
|
221
|
+
metadata[:execution_result][:pending_exception] = exception
|
|
222
|
+
else
|
|
223
|
+
if @exception && context != :dont_print
|
|
224
|
+
# An error has already been set; we don't want to override it,
|
|
225
|
+
# but we also don't want silence the error, so let's print it.
|
|
226
|
+
msg = <<-EOS
|
|
205
227
|
|
|
206
|
-
An error occurred #{context}
|
|
207
|
-
|
|
208
|
-
|
|
228
|
+
An error occurred #{context}
|
|
229
|
+
#{exception.class}: #{exception.message}
|
|
230
|
+
occurred at #{exception.backtrace.first}
|
|
209
231
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
232
|
+
EOS
|
|
233
|
+
RSpec.configuration.reporter.message(msg)
|
|
234
|
+
end
|
|
213
235
|
|
|
214
|
-
|
|
236
|
+
@exception ||= exception
|
|
237
|
+
end
|
|
215
238
|
end
|
|
216
239
|
|
|
217
240
|
# @private
|
|
@@ -224,6 +247,16 @@ An error occurred #{context}
|
|
|
224
247
|
finish(reporter)
|
|
225
248
|
end
|
|
226
249
|
|
|
250
|
+
# @private
|
|
251
|
+
#
|
|
252
|
+
# Used internally to skip without actually executing the example when
|
|
253
|
+
# skip is used in before(:all)
|
|
254
|
+
def skip_with_exception(reporter, exception)
|
|
255
|
+
start(reporter)
|
|
256
|
+
Pending.mark_skipped! self, exception.argument
|
|
257
|
+
finish(reporter)
|
|
258
|
+
end
|
|
259
|
+
|
|
227
260
|
# @private
|
|
228
261
|
def instance_exec_with_rescue(context = nil, &block)
|
|
229
262
|
@example_group_instance.instance_exec_with_rescue(self, context, &block)
|
|
@@ -240,7 +273,7 @@ An error occurred #{context}
|
|
|
240
273
|
if around_each_hooks.empty?
|
|
241
274
|
yield
|
|
242
275
|
else
|
|
243
|
-
@example_group_class.
|
|
276
|
+
@example_group_class.hooks.run(:around, :each, self, Procsy.new(metadata, &block))
|
|
244
277
|
end
|
|
245
278
|
rescue Exception => e
|
|
246
279
|
set_exception(e, "in an around(:each) hook")
|
|
@@ -248,20 +281,18 @@ An error occurred #{context}
|
|
|
248
281
|
|
|
249
282
|
def start(reporter)
|
|
250
283
|
reporter.example_started(self)
|
|
251
|
-
record :started_at =>
|
|
284
|
+
record :started_at => clock.now
|
|
252
285
|
end
|
|
253
286
|
|
|
254
287
|
def finish(reporter)
|
|
288
|
+
pending_message = metadata[:execution_result][:pending_message]
|
|
289
|
+
|
|
255
290
|
if @exception
|
|
256
291
|
record_finished 'failed', :exception => @exception
|
|
257
292
|
reporter.example_failed self
|
|
258
293
|
false
|
|
259
|
-
elsif
|
|
260
|
-
record_finished 'pending', :pending_message =>
|
|
261
|
-
reporter.example_pending self
|
|
262
|
-
true
|
|
263
|
-
elsif pending
|
|
264
|
-
record_finished 'pending', :pending_message => String === pending ? pending : Pending::NO_REASON_GIVEN
|
|
294
|
+
elsif pending_message
|
|
295
|
+
record_finished 'pending', :pending_message => pending_message
|
|
265
296
|
reporter.example_pending self
|
|
266
297
|
true
|
|
267
298
|
else
|
|
@@ -272,17 +303,21 @@ An error occurred #{context}
|
|
|
272
303
|
end
|
|
273
304
|
|
|
274
305
|
def record_finished(status, results={})
|
|
275
|
-
finished_at =
|
|
276
|
-
record results.merge(
|
|
306
|
+
finished_at = clock.now
|
|
307
|
+
record results.merge(
|
|
308
|
+
:status => status,
|
|
309
|
+
:finished_at => finished_at,
|
|
310
|
+
:run_time => (finished_at - execution_result[:started_at]).to_f
|
|
311
|
+
)
|
|
277
312
|
end
|
|
278
313
|
|
|
279
314
|
def run_before_each
|
|
280
315
|
@example_group_instance.setup_mocks_for_rspec
|
|
281
|
-
@example_group_class.
|
|
316
|
+
@example_group_class.hooks.run(:before, :each, self)
|
|
282
317
|
end
|
|
283
318
|
|
|
284
319
|
def run_after_each
|
|
285
|
-
@example_group_class.
|
|
320
|
+
@example_group_class.hooks.run(:after, :each, self)
|
|
286
321
|
verify_mocks
|
|
287
322
|
rescue Exception => e
|
|
288
323
|
set_exception(e, "in an after(:each) hook")
|
|
@@ -293,20 +328,36 @@ An error occurred #{context}
|
|
|
293
328
|
def verify_mocks
|
|
294
329
|
@example_group_instance.verify_mocks_for_rspec
|
|
295
330
|
rescue Exception => e
|
|
296
|
-
|
|
331
|
+
if metadata[:execution_result][:pending_message]
|
|
332
|
+
metadata[:execution_result][:pending_fixed] = false
|
|
333
|
+
metadata[:pending] = true
|
|
334
|
+
@exception = nil
|
|
335
|
+
else
|
|
336
|
+
set_exception(e, :dont_print)
|
|
337
|
+
end
|
|
297
338
|
end
|
|
298
339
|
|
|
299
340
|
def assign_generated_description
|
|
300
341
|
return unless RSpec.configuration.expecting_with_rspec?
|
|
301
|
-
|
|
342
|
+
|
|
343
|
+
if metadata[:description_args].empty?
|
|
302
344
|
metadata[:description_args] << RSpec::Matchers.generated_description
|
|
303
345
|
end
|
|
346
|
+
|
|
304
347
|
RSpec::Matchers.clear_generated_description
|
|
305
348
|
end
|
|
306
349
|
|
|
307
350
|
def record(results={})
|
|
308
351
|
execution_result.update(results)
|
|
309
352
|
end
|
|
353
|
+
|
|
354
|
+
def skip_message
|
|
355
|
+
if String === skip
|
|
356
|
+
skip
|
|
357
|
+
else
|
|
358
|
+
Pending::NO_REASON_GIVEN
|
|
359
|
+
end
|
|
360
|
+
end
|
|
310
361
|
end
|
|
311
362
|
end
|
|
312
363
|
end
|
|
@@ -59,13 +59,41 @@ module RSpec
|
|
|
59
59
|
define_method(name) do |*all_args, &block|
|
|
60
60
|
desc, *args = *all_args
|
|
61
61
|
options = Metadata.build_hash_from(args)
|
|
62
|
-
options.update(:
|
|
62
|
+
options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
|
|
63
63
|
options.update(extra_options)
|
|
64
|
+
|
|
65
|
+
# Metadata inheritance normally happens in `Example#initialize`,
|
|
66
|
+
# but for `:pending` specifically we need it earlier.
|
|
67
|
+
pending_metadata = options[:pending] || metadata[:pending]
|
|
68
|
+
|
|
69
|
+
if pending_metadata
|
|
70
|
+
options, block = ExampleGroup.pending_metadata_and_block_for(
|
|
71
|
+
options.merge(:pending => pending_metadata),
|
|
72
|
+
block
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
64
76
|
examples << RSpec::Core::Example.new(self, desc, options, block)
|
|
65
77
|
examples.last
|
|
66
78
|
end
|
|
67
79
|
end
|
|
68
80
|
|
|
81
|
+
def pending_metadata_and_block_for(options, block)
|
|
82
|
+
if String === options[:pending]
|
|
83
|
+
reason = options[:pending]
|
|
84
|
+
else
|
|
85
|
+
options[:pending] = true
|
|
86
|
+
reason = RSpec::Core::Pending::NO_REASON_GIVEN
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# This will fail if no block is provided, which is effectively the
|
|
90
|
+
# same as failing the example so it will be marked correctly as
|
|
91
|
+
# pending.
|
|
92
|
+
callback = Proc.new { pending(reason); instance_exec(&block) }
|
|
93
|
+
|
|
94
|
+
return options, callback
|
|
95
|
+
end
|
|
96
|
+
|
|
69
97
|
# Defines an example within a group.
|
|
70
98
|
# @example
|
|
71
99
|
# example do
|
|
@@ -100,18 +128,21 @@ module RSpec
|
|
|
100
128
|
# @see example
|
|
101
129
|
define_example_method :fit, :focused => true, :focus => true
|
|
102
130
|
|
|
103
|
-
# Shortcut to define an example with :
|
|
131
|
+
# Shortcut to define an example with :skip => 'Temporarily skipped with xexample'
|
|
104
132
|
# @see example
|
|
105
|
-
define_example_method :
|
|
106
|
-
# Shortcut to define an example with :
|
|
133
|
+
define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
|
|
134
|
+
# Shortcut to define an example with :skip => 'Temporarily skipped with xit'
|
|
107
135
|
# @see example
|
|
108
|
-
define_example_method :
|
|
109
|
-
# Shortcut to define an example with :
|
|
136
|
+
define_example_method :xit, :skip => 'Temporarily skipped with xit'
|
|
137
|
+
# Shortcut to define an example with :skip => 'Temporarily skipped with xspecify'
|
|
110
138
|
# @see example
|
|
111
|
-
define_example_method :
|
|
112
|
-
# Shortcut to define an example with :
|
|
139
|
+
define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
|
|
140
|
+
# Shortcut to define an example with :skip => true
|
|
113
141
|
# @see example
|
|
114
|
-
define_example_method :
|
|
142
|
+
define_example_method :skip, :skip => true
|
|
143
|
+
# Shortcut to define an example with :pending => true
|
|
144
|
+
# @see example
|
|
145
|
+
define_example_method :pending, :pending => true
|
|
115
146
|
|
|
116
147
|
# Works like `alias_method :name, :example` with the added benefit of
|
|
117
148
|
# assigning default metadata to the generated example.
|
|
@@ -124,13 +155,30 @@ module RSpec
|
|
|
124
155
|
(class << self; self; end).define_example_method name, extra
|
|
125
156
|
end
|
|
126
157
|
|
|
158
|
+
# @private
|
|
159
|
+
# @macro [attach] alias_example_group_to
|
|
160
|
+
# @scope class
|
|
161
|
+
# @param [String] docstring The example group doc string
|
|
162
|
+
# @param [Hash] metadata Additional metadata to attach to the example group
|
|
163
|
+
# @yield The example group definition
|
|
164
|
+
def alias_example_group_to(name, metadata={})
|
|
165
|
+
(class << self; self; end).__send__(:define_method, name) do |*args, &block|
|
|
166
|
+
combined_metadata = metadata.dup
|
|
167
|
+
combined_metadata.merge!(args.pop) if args.last.is_a? Hash
|
|
168
|
+
args << combined_metadata
|
|
169
|
+
example_group(*args, &block)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
RSpec::Core::DSL.expose_example_group_alias(name)
|
|
173
|
+
end
|
|
174
|
+
|
|
127
175
|
# @private
|
|
128
176
|
# @macro [attach] define_nested_shared_group_method
|
|
129
177
|
#
|
|
130
178
|
# @see SharedExampleGroup
|
|
131
179
|
def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
|
|
132
180
|
define_method(new_name) do |name, *args, &customization_block|
|
|
133
|
-
group =
|
|
181
|
+
group = example_group("#{report_label} #{name}") do
|
|
134
182
|
find_and_eval_shared("examples", name, *args, &customization_block)
|
|
135
183
|
end
|
|
136
184
|
group.metadata[:shared_group_name] = name
|
|
@@ -218,7 +266,7 @@ module RSpec
|
|
|
218
266
|
#
|
|
219
267
|
# describe "something" do # << This describe method is defined in
|
|
220
268
|
# # << RSpec::Core::DSL, included in the
|
|
221
|
-
# # << global namespace
|
|
269
|
+
# # << global namespace (optional)
|
|
222
270
|
# before do
|
|
223
271
|
# do_something_before
|
|
224
272
|
# end
|
|
@@ -232,7 +280,7 @@ module RSpec
|
|
|
232
280
|
# end
|
|
233
281
|
#
|
|
234
282
|
# @see DSL#describe
|
|
235
|
-
def self.
|
|
283
|
+
def self.example_group(*args, &example_group_block)
|
|
236
284
|
args << {} unless args.last.is_a?(Hash)
|
|
237
285
|
args.last.update(:example_group_block => example_group_block)
|
|
238
286
|
|
|
@@ -241,9 +289,31 @@ module RSpec
|
|
|
241
289
|
child
|
|
242
290
|
end
|
|
243
291
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
292
|
+
# An alias of `example_group`. Generally used when grouping
|
|
293
|
+
# examples by a thing you are describing (e.g. an object, class or method).
|
|
294
|
+
# @see example_group
|
|
295
|
+
alias_example_group_to :describe
|
|
296
|
+
|
|
297
|
+
# An alias of `example_group`. Generally used when grouping examples
|
|
298
|
+
# contextually.
|
|
299
|
+
# @see example_group
|
|
300
|
+
alias_example_group_to :context
|
|
301
|
+
|
|
302
|
+
# Shortcut to temporarily make an example group pending.
|
|
303
|
+
# @see example_group
|
|
304
|
+
alias_example_group_to :xdescribe, :skip => "Temporarily skipped with xdescribe"
|
|
305
|
+
|
|
306
|
+
# Shortcut to temporarily make an example group pending.
|
|
307
|
+
# @see example_group
|
|
308
|
+
alias_example_group_to :xcontext, :skip => "Temporarily skipped with xcontext"
|
|
309
|
+
|
|
310
|
+
# Shortcut to define an example group with `:focus` => true
|
|
311
|
+
# @see example_group
|
|
312
|
+
alias_example_group_to :fdescribe, :focus => true, :focused => true
|
|
313
|
+
|
|
314
|
+
# Shortcut to define an example group with `:focus` => true
|
|
315
|
+
# @see example_group
|
|
316
|
+
alias_example_group_to :fcontext, :focus => true, :focused => true
|
|
247
317
|
|
|
248
318
|
# @private
|
|
249
319
|
def self.subclass(parent, args, &example_group_block)
|
|
@@ -324,47 +394,27 @@ module RSpec
|
|
|
324
394
|
}
|
|
325
395
|
end
|
|
326
396
|
|
|
327
|
-
# @private
|
|
328
|
-
def self.assign_before_all_ivars(ivars, example_group_instance)
|
|
329
|
-
ivars.each { |ivar, val| example_group_instance.instance_variable_set(ivar, val) }
|
|
330
|
-
end
|
|
331
|
-
|
|
332
397
|
# @private
|
|
333
398
|
def self.run_before_all_hooks(example_group_instance)
|
|
334
399
|
return if descendant_filtered_examples.empty?
|
|
335
400
|
begin
|
|
336
|
-
|
|
401
|
+
set_ivars(example_group_instance, superclass.before_all_ivars)
|
|
337
402
|
|
|
338
403
|
AllHookMemoizedHash::Before.isolate_for_all_hook(example_group_instance) do
|
|
339
|
-
|
|
404
|
+
hooks.run(:before, :all, example_group_instance)
|
|
340
405
|
end
|
|
341
406
|
ensure
|
|
342
407
|
store_before_all_ivars(example_group_instance)
|
|
343
408
|
end
|
|
344
409
|
end
|
|
345
410
|
|
|
346
|
-
# @private
|
|
347
|
-
def self.run_around_each_hooks(example, initial_procsy)
|
|
348
|
-
run_hook(:around, :each, example, initial_procsy)
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
# @private
|
|
352
|
-
def self.run_before_each_hooks(example)
|
|
353
|
-
run_hook(:before, :each, example)
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
# @private
|
|
357
|
-
def self.run_after_each_hooks(example)
|
|
358
|
-
run_hook(:after, :each, example)
|
|
359
|
-
end
|
|
360
|
-
|
|
361
411
|
# @private
|
|
362
412
|
def self.run_after_all_hooks(example_group_instance)
|
|
363
413
|
return if descendant_filtered_examples.empty?
|
|
364
|
-
|
|
414
|
+
set_ivars(example_group_instance, before_all_ivars)
|
|
365
415
|
|
|
366
416
|
AllHookMemoizedHash::After.isolate_for_all_hook(example_group_instance) do
|
|
367
|
-
|
|
417
|
+
hooks.run(:after, :all, example_group_instance)
|
|
368
418
|
end
|
|
369
419
|
end
|
|
370
420
|
|
|
@@ -381,9 +431,11 @@ module RSpec
|
|
|
381
431
|
result_for_this_group = run_examples(reporter)
|
|
382
432
|
results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
|
|
383
433
|
result_for_this_group && results_for_descendants
|
|
434
|
+
rescue Pending::SkipDeclaredInExample => ex
|
|
435
|
+
for_filtered_examples(reporter) {|example| example.skip_with_exception(reporter, ex) }
|
|
384
436
|
rescue Exception => ex
|
|
385
437
|
RSpec.wants_to_quit = true if fail_fast?
|
|
386
|
-
|
|
438
|
+
for_filtered_examples(reporter) {|example| example.fail_with_exception(reporter, ex) }
|
|
387
439
|
ensure
|
|
388
440
|
run_after_all_hooks(new)
|
|
389
441
|
before_all_ivars.clear
|
|
@@ -420,12 +472,12 @@ module RSpec
|
|
|
420
472
|
end
|
|
421
473
|
|
|
422
474
|
# @private
|
|
423
|
-
def self.
|
|
424
|
-
filtered_examples.each
|
|
475
|
+
def self.for_filtered_examples(reporter, &block)
|
|
476
|
+
filtered_examples.each(&block)
|
|
425
477
|
|
|
426
478
|
children.each do |child|
|
|
427
479
|
reporter.example_group_started(child)
|
|
428
|
-
child.
|
|
480
|
+
child.for_filtered_examples(reporter, &block)
|
|
429
481
|
reporter.example_group_finished(child)
|
|
430
482
|
end
|
|
431
483
|
false
|