rspec-core 3.0.0.beta2 → 3.0.0.rc1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.yardopts +1 -0
- data/Changelog.md +297 -57
- data/README.md +16 -13
- data/lib/rspec/core.rb +55 -84
- data/lib/rspec/core/backport_random.rb +35 -3
- data/lib/rspec/core/backtrace_formatter.rb +4 -13
- data/lib/rspec/core/configuration.rb +330 -114
- data/lib/rspec/core/configuration_options.rb +38 -22
- data/lib/rspec/core/drb.rb +111 -0
- data/lib/rspec/core/dsl.rb +8 -2
- data/lib/rspec/core/example.rb +203 -94
- data/lib/rspec/core/example_group.rb +344 -316
- data/lib/rspec/core/filter_manager.rb +135 -90
- data/lib/rspec/core/flat_map.rb +1 -0
- data/lib/rspec/core/formatters.rb +50 -14
- data/lib/rspec/core/formatters/base_formatter.rb +32 -138
- data/lib/rspec/core/formatters/base_text_formatter.rb +32 -253
- data/lib/rspec/core/formatters/console_codes.rb +65 -0
- data/lib/rspec/core/formatters/deprecation_formatter.rb +24 -15
- data/lib/rspec/core/formatters/documentation_formatter.rb +7 -10
- data/lib/rspec/core/formatters/helpers.rb +15 -9
- data/lib/rspec/core/formatters/html_formatter.rb +17 -16
- data/lib/rspec/core/formatters/html_printer.rb +1 -0
- data/lib/rspec/core/formatters/json_formatter.rb +18 -20
- data/lib/rspec/core/formatters/profile_formatter.rb +67 -0
- data/lib/rspec/core/formatters/progress_formatter.rb +6 -7
- data/lib/rspec/core/formatters/snippet_extractor.rb +8 -6
- data/lib/rspec/core/hooks.rb +131 -125
- data/lib/rspec/core/memoized_helpers.rb +31 -26
- data/lib/rspec/core/metadata.rb +277 -184
- data/lib/rspec/core/metadata_filter.rb +86 -0
- data/lib/rspec/core/minitest_assertions_adapter.rb +28 -0
- data/lib/rspec/core/mocking_adapters/flexmock.rb +1 -1
- data/lib/rspec/core/mocking_adapters/mocha.rb +1 -1
- data/lib/rspec/core/mocking_adapters/null.rb +1 -1
- data/lib/rspec/core/mocking_adapters/rr.rb +2 -1
- data/lib/rspec/core/mocking_adapters/rspec.rb +1 -1
- data/lib/rspec/core/notifications.rb +435 -24
- data/lib/rspec/core/option_parser.rb +16 -25
- data/lib/rspec/core/ordering.rb +3 -1
- data/lib/rspec/core/pending.rb +57 -33
- data/lib/rspec/core/project_initializer.rb +2 -0
- data/lib/rspec/core/project_initializer/spec_helper.rb +5 -4
- data/lib/rspec/core/rake_task.rb +45 -20
- data/lib/rspec/core/reporter.rb +50 -22
- data/lib/rspec/core/ruby_project.rb +1 -0
- data/lib/rspec/core/runner.rb +93 -39
- data/lib/rspec/core/shared_context.rb +7 -5
- data/lib/rspec/core/shared_example_group.rb +85 -77
- data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
- data/lib/rspec/core/version.rb +3 -1
- data/lib/rspec/core/warnings.rb +35 -17
- data/lib/rspec/core/world.rb +57 -5
- metadata +56 -369
- metadata.gz.sig +3 -3
- data/features/README.md +0 -13
- data/features/Upgrade.md +0 -352
- data/features/command_line/README.md +0 -25
- data/features/command_line/dry_run.feature +0 -29
- data/features/command_line/example_name_option.feature +0 -97
- data/features/command_line/exit_status.feature +0 -82
- data/features/command_line/fail_fast.feature +0 -26
- data/features/command_line/format_option.feature +0 -75
- data/features/command_line/init.feature +0 -57
- data/features/command_line/line_number_appended_to_path.feature +0 -140
- data/features/command_line/line_number_option.feature +0 -58
- data/features/command_line/order.feature +0 -25
- data/features/command_line/pattern_option.feature +0 -49
- data/features/command_line/rake_task.feature +0 -122
- data/features/command_line/randomization.feature +0 -63
- data/features/command_line/require_option.feature +0 -43
- data/features/command_line/ruby.feature +0 -23
- data/features/command_line/tag.feature +0 -98
- data/features/command_line/warnings_option.feature +0 -29
- data/features/configuration/alias_example_to.feature +0 -39
- data/features/configuration/backtrace_exclusion_patterns.feature +0 -105
- data/features/configuration/custom_settings.feature +0 -84
- data/features/configuration/default_path.feature +0 -38
- data/features/configuration/deprecation_stream.feature +0 -58
- data/features/configuration/enable_global_dsl.feature +0 -54
- data/features/configuration/fail_fast.feature +0 -77
- data/features/configuration/failure_exit_code.feature +0 -36
- data/features/configuration/order_and_seed.feature +0 -3
- data/features/configuration/output_stream.feature +0 -24
- data/features/configuration/overriding_global_ordering.feature +0 -93
- data/features/configuration/pattern.feature +0 -38
- data/features/configuration/profile.feature +0 -220
- data/features/configuration/read_options_from_file.feature +0 -90
- data/features/configuration/run_all_when_everything_filtered.feature +0 -76
- data/features/example_groups/aliasing.feature +0 -48
- data/features/example_groups/basic_structure.feature +0 -55
- data/features/example_groups/shared_context.feature +0 -74
- data/features/example_groups/shared_examples.feature +0 -286
- data/features/expectation_framework_integration/configure_expectation_framework.feature +0 -102
- data/features/filtering/exclusion_filters.feature +0 -135
- data/features/filtering/if_and_unless.feature +0 -138
- data/features/filtering/inclusion_filters.feature +0 -101
- data/features/formatters/configurable_colors.feature +0 -31
- data/features/formatters/custom_formatter.feature +0 -68
- data/features/formatters/json_formatter.feature +0 -30
- data/features/formatters/regression_tests.feature +0 -95
- data/features/formatters/text_formatter.feature +0 -46
- data/features/helper_methods/arbitrary_methods.feature +0 -40
- data/features/helper_methods/let.feature +0 -50
- data/features/helper_methods/modules.feature +0 -146
- data/features/hooks/around_hooks.feature +0 -344
- data/features/hooks/before_and_after_hooks.feature +0 -427
- data/features/hooks/filtering.feature +0 -232
- data/features/metadata/current_example.feature +0 -56
- data/features/metadata/described_class.feature +0 -17
- data/features/metadata/user_defined.feature +0 -100
- data/features/mock_framework_integration/use_any_framework.feature +0 -106
- data/features/mock_framework_integration/use_flexmock.feature +0 -94
- data/features/mock_framework_integration/use_mocha.feature +0 -95
- data/features/mock_framework_integration/use_rr.feature +0 -96
- data/features/mock_framework_integration/use_rspec.feature +0 -95
- data/features/pending_and_skipped_examples/README.md +0 -3
- data/features/pending_and_skipped_examples/pending_examples.feature +0 -118
- data/features/pending_and_skipped_examples/skipped_examples.feature +0 -106
- data/features/spec_files/arbitrary_file_suffix.feature +0 -13
- data/features/step_definitions/additional_cli_steps.rb +0 -83
- data/features/subject/explicit_subject.feature +0 -101
- data/features/subject/implicit_subject.feature +0 -63
- data/features/subject/one_liner_syntax.feature +0 -71
- data/features/support/env.rb +0 -21
- data/features/support/require_expect_syntax_in_aruba_specs.rb +0 -16
- data/features/support/rubinius.rb +0 -6
- data/lib/rspec/core/command_line.rb +0 -35
- data/lib/rspec/core/drb_command_line.rb +0 -26
- data/lib/rspec/core/drb_options.rb +0 -87
- data/lib/rspec/core/formatters/legacy_formatter.rb +0 -227
- data/lib/rspec/core/shared_example_group/collection.rb +0 -27
- data/spec/command_line/order_spec.rb +0 -211
- data/spec/rspec/core/backtrace_formatter_spec.rb +0 -230
- data/spec/rspec/core/command_line_spec.rb +0 -112
- data/spec/rspec/core/command_line_spec_output.txt +0 -0
- data/spec/rspec/core/configuration_options_spec.rb +0 -409
- data/spec/rspec/core/configuration_spec.rb +0 -1479
- data/spec/rspec/core/drb_command_line_spec.rb +0 -102
- data/spec/rspec/core/drb_options_spec.rb +0 -193
- data/spec/rspec/core/dsl_spec.rb +0 -88
- data/spec/rspec/core/example_group_spec.rb +0 -1533
- data/spec/rspec/core/example_spec.rb +0 -642
- data/spec/rspec/core/filter_manager_spec.rb +0 -229
- data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -64
- data/spec/rspec/core/formatters/base_text_formatter_spec.rb +0 -303
- data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +0 -208
- data/spec/rspec/core/formatters/documentation_formatter_spec.rb +0 -75
- data/spec/rspec/core/formatters/helpers_spec.rb +0 -104
- data/spec/rspec/core/formatters/html_formatted-2.1.0.html +0 -392
- data/spec/rspec/core/formatters/html_formatted.html +0 -397
- data/spec/rspec/core/formatters/html_formatter_spec.rb +0 -122
- data/spec/rspec/core/formatters/json_formatter_spec.rb +0 -206
- data/spec/rspec/core/formatters/legacy_formatter_spec.rb +0 -137
- data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -43
- data/spec/rspec/core/formatters/snippet_extractor_spec.rb +0 -26
- data/spec/rspec/core/formatters_spec.rb +0 -120
- data/spec/rspec/core/hooks_filtering_spec.rb +0 -227
- data/spec/rspec/core/hooks_spec.rb +0 -294
- data/spec/rspec/core/memoized_helpers_spec.rb +0 -495
- data/spec/rspec/core/metadata_spec.rb +0 -491
- data/spec/rspec/core/option_parser_spec.rb +0 -262
- data/spec/rspec/core/ordering_spec.rb +0 -102
- data/spec/rspec/core/pending_example_spec.rb +0 -117
- data/spec/rspec/core/pending_spec.rb +0 -8
- data/spec/rspec/core/project_initializer_spec.rb +0 -73
- data/spec/rspec/core/rake_task_spec.rb +0 -146
- data/spec/rspec/core/random_spec.rb +0 -47
- data/spec/rspec/core/reporter_spec.rb +0 -155
- data/spec/rspec/core/resources/a_bar.rb +0 -0
- data/spec/rspec/core/resources/a_foo.rb +0 -0
- data/spec/rspec/core/resources/a_spec.rb +0 -1
- data/spec/rspec/core/resources/custom_example_group_runner.rb +0 -14
- data/spec/rspec/core/resources/formatter_specs.rb +0 -58
- data/spec/rspec/core/resources/utf8_encoded.rb +0 -8
- data/spec/rspec/core/rspec_matchers_spec.rb +0 -45
- data/spec/rspec/core/ruby_project_spec.rb +0 -26
- data/spec/rspec/core/runner_spec.rb +0 -151
- data/spec/rspec/core/shared_context_spec.rb +0 -102
- data/spec/rspec/core/shared_example_group/collection_spec.rb +0 -57
- data/spec/rspec/core/shared_example_group_spec.rb +0 -114
- data/spec/rspec/core/warnings_spec.rb +0 -29
- data/spec/rspec/core/world_spec.rb +0 -142
- data/spec/rspec/core_spec.rb +0 -91
- data/spec/spec_helper.rb +0 -160
- data/spec/support/config_options_helper.rb +0 -13
- data/spec/support/formatter_support.rb +0 -83
- data/spec/support/helper_methods.rb +0 -26
- data/spec/support/isolate_load_path_mutation.rb +0 -5
- data/spec/support/isolated_directory.rb +0 -10
- data/spec/support/isolated_home_directory.rb +0 -16
- data/spec/support/legacy_formatter_using_sub_classing_example.rb +0 -87
- data/spec/support/matchers.rb +0 -85
- data/spec/support/mathn_integration_support.rb +0 -12
- data/spec/support/old_style_formatter_example.rb +0 -69
- data/spec/support/shared_example_groups.rb +0 -13
- data/spec/support/spec_files.rb +0 -44
- data/spec/support/stderr_splitter.rb +0 -36
@@ -12,199 +12,287 @@ module RSpec
|
|
12
12
|
# The object returned by `it "does something"` is an instance of Example,
|
13
13
|
# which serves as a wrapper for an instance of the ExampleGroup in which it
|
14
14
|
# is declared.
|
15
|
+
#
|
16
|
+
# Example group bodies (e.g. `describe` or `context` blocks) are evaluated
|
17
|
+
# in the context of a new subclass of ExampleGroup. Individual examples are
|
18
|
+
# evalutaed in the context of an instance of the specific ExampleGroup subclass
|
19
|
+
# to which they belong.
|
20
|
+
#
|
21
|
+
# Besides the class methods defined here, there are other interesting macros
|
22
|
+
# defined in {Hooks}, {MemoizedHelpers::ClassMethods} and {SharedExampleGroup}.
|
23
|
+
# There are additional instance methods available to your examples defined in
|
24
|
+
# {MemoizedHelpers} and {Pending}.
|
15
25
|
class ExampleGroup
|
16
26
|
extend Hooks
|
17
27
|
|
18
28
|
include MemoizedHelpers
|
29
|
+
extend MemoizedHelpers::ClassMethods
|
19
30
|
include Pending
|
20
|
-
extend
|
31
|
+
extend SharedExampleGroup
|
21
32
|
|
22
|
-
|
23
|
-
|
24
|
-
|
33
|
+
unless respond_to?(:define_singleton_method)
|
34
|
+
# @private
|
35
|
+
def self.define_singleton_method(*a, &b)
|
36
|
+
(class << self; self; end).__send__(:define_method, *a, &b)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @!group Metadata
|
41
|
+
|
42
|
+
# The [Metadata](Metadata) object associated with this group.
|
43
|
+
# @see Metadata
|
44
|
+
def self.metadata
|
45
|
+
@metadata if defined?(@metadata)
|
25
46
|
end
|
26
47
|
|
27
48
|
# @private
|
28
|
-
|
29
|
-
|
49
|
+
# @return [Metadata] belonging to the parent of a nested {ExampleGroup}
|
50
|
+
def self.superclass_metadata
|
51
|
+
@superclass_metadata ||= self.superclass.respond_to?(:metadata) ? self.superclass.metadata : nil
|
30
52
|
end
|
31
53
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
define_method name do
|
37
|
-
metadata[:example_group][name]
|
38
|
-
end
|
39
|
-
end
|
54
|
+
# @private
|
55
|
+
def self.delegate_to_metadata(*names)
|
56
|
+
names.each do |name|
|
57
|
+
define_singleton_method(name) { metadata.fetch(name) }
|
40
58
|
end
|
59
|
+
end
|
41
60
|
|
42
|
-
|
43
|
-
description = metadata[:example_group][:description]
|
44
|
-
RSpec.configuration.format_docstrings_block.call(description)
|
45
|
-
end
|
61
|
+
delegate_to_metadata :described_class, :file_path, :location
|
46
62
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
63
|
+
# @return [String] the current example group description
|
64
|
+
def self.description
|
65
|
+
description = metadata[:description]
|
66
|
+
RSpec.configuration.format_docstrings_block.call(description)
|
67
|
+
end
|
51
68
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
69
|
+
# Returns the class or module passed to the `describe` method (or alias).
|
70
|
+
# Returns nil if the subject is not a class or module.
|
71
|
+
# @example
|
72
|
+
# describe Thing do
|
73
|
+
# it "does something" do
|
74
|
+
# described_class == Thing
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
#
|
79
|
+
def described_class
|
80
|
+
self.class.described_class
|
81
|
+
end
|
82
|
+
|
83
|
+
# @!endgroup
|
75
84
|
|
76
|
-
|
77
|
-
|
85
|
+
# @!group Defining Examples
|
86
|
+
|
87
|
+
# @private
|
88
|
+
# @macro [attach] define_example_method
|
89
|
+
# @!scope class
|
90
|
+
# @param name [String]
|
91
|
+
# @param extra_options [Hash]
|
92
|
+
# @param implementation [Block]
|
93
|
+
# @yield [Example] the example object
|
94
|
+
# @example
|
95
|
+
# $1 do
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# $1 "does something" do
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# $1 "does something", :with => 'additional metadata' do
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# $1 "does something" do |ex|
|
105
|
+
# # ex is the Example object that contains metadata about the example
|
106
|
+
# end
|
107
|
+
def self.define_example_method(name, extra_options={})
|
108
|
+
define_singleton_method(name) do |*all_args, &block|
|
109
|
+
desc, *args = *all_args
|
110
|
+
options = Metadata.build_hash_from(args)
|
111
|
+
options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
|
112
|
+
options.update(extra_options)
|
113
|
+
|
114
|
+
# Metadata inheritance normally happens in `Example#initialize`,
|
115
|
+
# but for `:pending` specifically we need it earlier.
|
116
|
+
pending_metadata = options[:pending] || metadata[:pending]
|
117
|
+
|
118
|
+
if pending_metadata
|
119
|
+
options, block = ExampleGroup.pending_metadata_and_block_for(
|
120
|
+
options.merge(:pending => pending_metadata),
|
121
|
+
block
|
122
|
+
)
|
78
123
|
end
|
124
|
+
|
125
|
+
examples << RSpec::Core::Example.new(self, desc, options, block)
|
126
|
+
examples.last
|
79
127
|
end
|
128
|
+
end
|
80
129
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
130
|
+
# Defines an example within a group.
|
131
|
+
define_example_method :example
|
132
|
+
# Defines an example within a group.
|
133
|
+
# This is the primary API to define a code example.
|
134
|
+
define_example_method :it
|
135
|
+
# Defines an example within a group.
|
136
|
+
# Useful for when your docstring does not read well off of `it`.
|
137
|
+
# @example
|
138
|
+
# RSpec.describe MyClass do
|
139
|
+
# specify "#do_something is deprecated" do
|
140
|
+
# # ...
|
141
|
+
# end
|
142
|
+
# end
|
143
|
+
define_example_method :specify
|
144
|
+
|
145
|
+
# Shortcut to define an example with `:focus => true`
|
146
|
+
# @see example
|
147
|
+
define_example_method :focus, :focus => true
|
148
|
+
# Shortcut to define an example with `:focus => true`
|
149
|
+
# @see example
|
150
|
+
define_example_method :fexample, :focus => true
|
151
|
+
# Shortcut to define an example with `:focus => true`
|
152
|
+
# @see example
|
153
|
+
define_example_method :fit, :focus => true
|
154
|
+
# Shortcut to define an example with `:focus => true`
|
155
|
+
# @see example
|
156
|
+
define_example_method :fspecify, :focus => true
|
157
|
+
# Shortcut to define an example with `:skip => 'Temporarily skipped with xexample'`
|
158
|
+
# @see example
|
159
|
+
define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
|
160
|
+
# Shortcut to define an example with `:skip => 'Temporarily skipped with xit'`
|
161
|
+
# @see example
|
162
|
+
define_example_method :xit, :skip => 'Temporarily skipped with xit'
|
163
|
+
# Shortcut to define an example with `:skip => 'Temporarily skipped with xspecify'`
|
164
|
+
# @see example
|
165
|
+
define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
|
166
|
+
# Shortcut to define an example with `:skip => true`
|
167
|
+
# @see example
|
168
|
+
define_example_method :skip, :skip => true
|
169
|
+
# Shortcut to define an example with `:pending => true`
|
170
|
+
# @see example
|
171
|
+
define_example_method :pending, :pending => true
|
172
|
+
|
173
|
+
# @!endgroup
|
174
|
+
|
175
|
+
# @!group Defining Example Groups
|
88
176
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
177
|
+
# @private
|
178
|
+
# @macro [attach] alias_example_group_to
|
179
|
+
# @!scope class
|
180
|
+
# @param name [String] The example group doc string
|
181
|
+
# @param metadata [Hash] Additional metadata to attach to the example group
|
182
|
+
# @yield The example group definition
|
183
|
+
#
|
184
|
+
# Generates a subclass of this example group which inherits
|
185
|
+
# everything except the examples themselves.
|
186
|
+
#
|
187
|
+
# @example
|
188
|
+
#
|
189
|
+
# RSpec.describe "something" do # << This describe method is defined in
|
190
|
+
# # << RSpec::Core::DSL, included in the
|
191
|
+
# # << global namespace (optional)
|
192
|
+
# before do
|
193
|
+
# do_something_before
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# let(:thing) { Thing.new }
|
197
|
+
#
|
198
|
+
# $1 "attribute (of something)" do
|
199
|
+
# # examples in the group get the before hook
|
200
|
+
# # declared above, and can access `thing`
|
201
|
+
# end
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# @see DSL#describe
|
205
|
+
def self.define_example_group_method(name, metadata={})
|
206
|
+
define_singleton_method(name) do |*args, &example_group_block|
|
207
|
+
thread_data = RSpec.thread_local_metadata
|
208
|
+
top_level = self == ExampleGroup
|
209
|
+
|
210
|
+
if top_level
|
211
|
+
if thread_data[:in_example_group]
|
212
|
+
raise "Creating an isolated context from within a context is " +
|
213
|
+
"not allowed. Change `RSpec.#{name}` to `#{name}` or " +
|
214
|
+
"move this to a top-level scope."
|
215
|
+
end
|
93
216
|
|
94
|
-
|
95
|
-
|
217
|
+
thread_data[:in_example_group] = true
|
218
|
+
end
|
96
219
|
|
97
|
-
|
98
|
-
# @example
|
99
|
-
# example do
|
100
|
-
# end
|
101
|
-
#
|
102
|
-
# example "does something" do
|
103
|
-
# end
|
104
|
-
#
|
105
|
-
# example "does something", :with => 'additional metadata' do
|
106
|
-
# end
|
107
|
-
#
|
108
|
-
# example "does something" do |ex|
|
109
|
-
# # ex is the Example object that evals this block
|
110
|
-
# end
|
111
|
-
define_example_method :example
|
112
|
-
# Defines an example within a group.
|
113
|
-
# @example
|
114
|
-
define_example_method :it
|
115
|
-
# Defines an example within a group.
|
116
|
-
# This is here primarily for backward compatibility with early versions
|
117
|
-
# of RSpec which used `context` and `specify` instead of `describe` and
|
118
|
-
# `it`.
|
119
|
-
define_example_method :specify
|
120
|
-
|
121
|
-
# Shortcut to define an example with `:focus` => true
|
122
|
-
# @see example
|
123
|
-
define_example_method :focus, :focused => true, :focus => true
|
124
|
-
# Shortcut to define an example with `:focus` => true
|
125
|
-
# @see example
|
126
|
-
define_example_method :focused, :focused => true, :focus => true
|
127
|
-
# Shortcut to define an example with `:focus` => true
|
128
|
-
# @see example
|
129
|
-
define_example_method :fit, :focused => true, :focus => true
|
130
|
-
|
131
|
-
# Shortcut to define an example with :skip => 'Temporarily skipped with xexample'
|
132
|
-
# @see example
|
133
|
-
define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
|
134
|
-
# Shortcut to define an example with :skip => 'Temporarily skipped with xit'
|
135
|
-
# @see example
|
136
|
-
define_example_method :xit, :skip => 'Temporarily skipped with xit'
|
137
|
-
# Shortcut to define an example with :skip => 'Temporarily skipped with xspecify'
|
138
|
-
# @see example
|
139
|
-
define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
|
140
|
-
# Shortcut to define an example with :skip => true
|
141
|
-
# @see example
|
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
|
146
|
-
|
147
|
-
# Works like `alias_method :name, :example` with the added benefit of
|
148
|
-
# assigning default metadata to the generated example.
|
149
|
-
#
|
150
|
-
# @note Use with caution. This extends the language used in your
|
151
|
-
# specs, but does not add any additional documentation. We use this
|
152
|
-
# in rspec to define methods like `focus` and `xit`, but we also add
|
153
|
-
# docs for those methods.
|
154
|
-
def alias_example_to name, extra={}
|
155
|
-
(class << self; self; end).define_example_method name, extra
|
156
|
-
end
|
220
|
+
begin
|
157
221
|
|
158
|
-
|
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|
|
222
|
+
description = args.shift
|
166
223
|
combined_metadata = metadata.dup
|
167
224
|
combined_metadata.merge!(args.pop) if args.last.is_a? Hash
|
168
225
|
args << combined_metadata
|
169
|
-
example_group(*args, &block)
|
170
|
-
end
|
171
|
-
|
172
|
-
RSpec::Core::DSL.expose_example_group_alias(name)
|
173
|
-
end
|
174
226
|
|
175
|
-
|
176
|
-
|
177
|
-
#
|
178
|
-
# @see SharedExampleGroup
|
179
|
-
def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
|
180
|
-
define_method(new_name) do |name, *args, &customization_block|
|
181
|
-
group = example_group("#{report_label} #{name}") do
|
182
|
-
find_and_eval_shared("examples", name, *args, &customization_block)
|
227
|
+
subclass(self, description, args, &example_group_block).tap do |child|
|
228
|
+
children << child
|
183
229
|
end
|
184
|
-
|
185
|
-
|
230
|
+
|
231
|
+
ensure
|
232
|
+
thread_data.delete(:in_example_group) if top_level
|
186
233
|
end
|
187
234
|
end
|
188
235
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
236
|
+
RSpec::Core::DSL.expose_example_group_alias(name)
|
237
|
+
end
|
238
|
+
|
239
|
+
define_example_group_method :example_group
|
240
|
+
|
241
|
+
# An alias of `example_group`. Generally used when grouping
|
242
|
+
# examples by a thing you are describing (e.g. an object, class or method).
|
243
|
+
# @see example_group
|
244
|
+
define_example_group_method :describe
|
245
|
+
|
246
|
+
# An alias of `example_group`. Generally used when grouping examples
|
247
|
+
# contextually (e.g. "with xyz", "when xyz" or "if xyz").
|
248
|
+
# @see example_group
|
249
|
+
define_example_group_method :context
|
250
|
+
|
251
|
+
# Shortcut to temporarily make an example group skipped.
|
252
|
+
# @see example_group
|
253
|
+
define_example_group_method :xdescribe, :skip => "Temporarily skipped with xdescribe"
|
254
|
+
|
255
|
+
# Shortcut to temporarily make an example group skipped.
|
256
|
+
# @see example_group
|
257
|
+
define_example_group_method :xcontext, :skip => "Temporarily skipped with xcontext"
|
258
|
+
|
259
|
+
# Shortcut to define an example group with `:focus => true`.
|
260
|
+
# @see example_group
|
261
|
+
define_example_group_method :fdescribe, :focus => true
|
262
|
+
|
263
|
+
# Shortcut to define an example group with `:focus => true`.
|
264
|
+
# @see example_group
|
265
|
+
define_example_group_method :fcontext, :focus => true
|
266
|
+
|
267
|
+
# @!endgroup
|
268
|
+
|
269
|
+
# @!group Including Shared Example Groups
|
270
|
+
|
271
|
+
# @private
|
272
|
+
# @macro [attach] define_nested_shared_group_method
|
273
|
+
# @!scope class
|
274
|
+
#
|
275
|
+
# @see SharedExampleGroup
|
276
|
+
def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
|
277
|
+
define_singleton_method(new_name) do |name, *args, &customization_block|
|
278
|
+
# Pass :caller so the :location metadata is set properly...
|
279
|
+
# otherwise, it'll be set to the next line because that's
|
280
|
+
# the block's source_location.
|
281
|
+
group = example_group("#{report_label} #{name}", :caller => caller) do
|
282
|
+
find_and_eval_shared("examples", name, *args, &customization_block)
|
283
|
+
end
|
284
|
+
group.metadata[:shared_group_name] = name
|
285
|
+
group
|
205
286
|
end
|
206
287
|
end
|
207
288
|
|
289
|
+
# Generates a nested example group and includes the shared content
|
290
|
+
# mapped to `name` in the nested group.
|
291
|
+
define_nested_shared_group_method :it_behaves_like, "behaves like"
|
292
|
+
# Generates a nested example group and includes the shared content
|
293
|
+
# mapped to `name` in the nested group.
|
294
|
+
define_nested_shared_group_method :it_should_behave_like
|
295
|
+
|
208
296
|
# Includes shared content mapped to `name` directly in the group in which
|
209
297
|
# it is declared, as opposed to `it_behaves_like`, which creates a nested
|
210
298
|
# group. If given a block, that block is also eval'd in the current context.
|
@@ -225,110 +313,68 @@ module RSpec
|
|
225
313
|
|
226
314
|
# @private
|
227
315
|
def self.find_and_eval_shared(label, name, *args, &customization_block)
|
228
|
-
|
229
|
-
|
316
|
+
unless shared_block = RSpec.world.shared_example_group_registry.find(parent_groups, name)
|
317
|
+
raise ArgumentError, "Could not find shared #{label} #{name.inspect}"
|
318
|
+
end
|
230
319
|
|
231
320
|
module_exec(*args, &shared_block)
|
232
|
-
|
321
|
+
module_exec(&customization_block) if customization_block
|
233
322
|
end
|
234
323
|
|
235
|
-
#
|
236
|
-
def self.examples
|
237
|
-
@examples ||= []
|
238
|
-
end
|
324
|
+
# @!endgroup
|
239
325
|
|
240
326
|
# @private
|
241
|
-
def self.
|
242
|
-
|
243
|
-
|
327
|
+
def self.subclass(parent, description, args, &example_group_block)
|
328
|
+
subclass = Class.new(parent)
|
329
|
+
subclass.set_it_up(description, *args, &example_group_block)
|
330
|
+
ExampleGroups.assign_const(subclass)
|
331
|
+
subclass.module_exec(&example_group_block) if example_group_block
|
244
332
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
333
|
+
# The LetDefinitions module must be included _after_ other modules
|
334
|
+
# to ensure that it takes precedence when there are name collisions.
|
335
|
+
# Thus, we delay including it until after the example group block
|
336
|
+
# has been eval'd.
|
337
|
+
MemoizedHelpers.define_helpers_on(subclass)
|
249
338
|
|
250
|
-
|
251
|
-
# @see Metadata
|
252
|
-
def self.metadata
|
253
|
-
@metadata if defined?(@metadata)
|
339
|
+
subclass
|
254
340
|
end
|
255
341
|
|
256
342
|
# @private
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
#
|
267
|
-
# describe "something" do # << This describe method is defined in
|
268
|
-
# # << RSpec::Core::DSL, included in the
|
269
|
-
# # << global namespace (optional)
|
270
|
-
# before do
|
271
|
-
# do_something_before
|
272
|
-
# end
|
273
|
-
#
|
274
|
-
# let(:thing) { Thing.new }
|
275
|
-
#
|
276
|
-
# describe "attribute (of something)" do
|
277
|
-
# # examples in the group get the before hook
|
278
|
-
# # declared above, and can access `thing`
|
279
|
-
# end
|
280
|
-
# end
|
281
|
-
#
|
282
|
-
# @see DSL#describe
|
283
|
-
def self.example_group(*args, &example_group_block)
|
284
|
-
args << {} unless args.last.is_a?(Hash)
|
285
|
-
args.last.update(:example_group_block => example_group_block)
|
286
|
-
|
287
|
-
child = subclass(self, args, &example_group_block)
|
288
|
-
children << child
|
289
|
-
child
|
290
|
-
end
|
291
|
-
|
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"
|
343
|
+
def self.set_it_up(*args, &example_group_block)
|
344
|
+
# Ruby 1.9 has a bug that can lead to infinite recursion and a
|
345
|
+
# SystemStackError if you include a module in a superclass after
|
346
|
+
# including it in a subclass: https://gist.github.com/845896
|
347
|
+
# To prevent this, we must include any modules in RSpec::Core::ExampleGroup
|
348
|
+
# before users create example groups and have a chance to include
|
349
|
+
# the same module in a subclass of RSpec::Core::ExampleGroup.
|
350
|
+
# So we need to configure example groups here.
|
351
|
+
ensure_example_groups_are_configured
|
305
352
|
|
306
|
-
|
307
|
-
|
308
|
-
|
353
|
+
description = args.shift
|
354
|
+
user_metadata = Metadata.build_hash_from(args)
|
355
|
+
args.unshift(description)
|
309
356
|
|
310
|
-
|
311
|
-
|
312
|
-
|
357
|
+
@metadata = Metadata::ExampleGroupHash.create(
|
358
|
+
superclass_metadata || {}, user_metadata, *args, &example_group_block
|
359
|
+
)
|
313
360
|
|
314
|
-
|
315
|
-
|
316
|
-
|
361
|
+
hooks.register_globals(self, RSpec.configuration.hooks)
|
362
|
+
RSpec.world.configure_group(self)
|
363
|
+
end
|
317
364
|
|
318
365
|
# @private
|
319
|
-
def self.
|
320
|
-
|
321
|
-
|
322
|
-
ExampleGroups.assign_const(subclass)
|
323
|
-
subclass.module_eval(&example_group_block) if example_group_block
|
366
|
+
def self.examples
|
367
|
+
@examples ||= []
|
368
|
+
end
|
324
369
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
MemoizedHelpers.define_helpers_on(subclass)
|
370
|
+
# @private
|
371
|
+
def self.filtered_examples
|
372
|
+
RSpec.world.filtered_examples[self]
|
373
|
+
end
|
330
374
|
|
331
|
-
|
375
|
+
# @private
|
376
|
+
def self.descendant_filtered_examples
|
377
|
+
@descendant_filtered_examples ||= filtered_examples + children.inject([]){|l,c| l + c.descendant_filtered_examples}
|
332
378
|
end
|
333
379
|
|
334
380
|
# @private
|
@@ -361,84 +407,64 @@ module RSpec
|
|
361
407
|
end
|
362
408
|
|
363
409
|
# @private
|
364
|
-
def self.
|
365
|
-
|
366
|
-
# SystemStackError if you include a module in a superclass after
|
367
|
-
# including it in a subclass: https://gist.github.com/845896
|
368
|
-
# To prevent this, we must include any modules in RSpec::Core::ExampleGroup
|
369
|
-
# before users create example groups and have a chance to include
|
370
|
-
# the same module in a subclass of RSpec::Core::ExampleGroup.
|
371
|
-
# So we need to configure example groups here.
|
372
|
-
ensure_example_groups_are_configured
|
373
|
-
|
374
|
-
symbol_description = args.shift if args.first.is_a?(Symbol)
|
375
|
-
args << Metadata.build_hash_from(args)
|
376
|
-
args.unshift(symbol_description) if symbol_description
|
377
|
-
@metadata = RSpec::Core::Metadata.new(superclass_metadata).process(*args)
|
378
|
-
@order = nil
|
379
|
-
hooks.register_globals(self, RSpec.configuration.hooks)
|
380
|
-
world.configure_group(self)
|
381
|
-
end
|
382
|
-
|
383
|
-
# @private
|
384
|
-
def self.before_all_ivars
|
385
|
-
@before_all_ivars ||= {}
|
410
|
+
def self.before_context_ivars
|
411
|
+
@before_context_ivars ||= {}
|
386
412
|
end
|
387
413
|
|
388
414
|
# @private
|
389
|
-
def self.
|
415
|
+
def self.store_before_context_ivars(example_group_instance)
|
390
416
|
return if example_group_instance.instance_variables.empty?
|
391
417
|
|
392
418
|
example_group_instance.instance_variables.each { |ivar|
|
393
|
-
|
419
|
+
before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar)
|
394
420
|
}
|
395
421
|
end
|
396
422
|
|
397
423
|
# @private
|
398
|
-
def self.
|
424
|
+
def self.run_before_context_hooks(example_group_instance)
|
399
425
|
return if descendant_filtered_examples.empty?
|
400
426
|
begin
|
401
|
-
set_ivars(example_group_instance, superclass.
|
427
|
+
set_ivars(example_group_instance, superclass.before_context_ivars)
|
402
428
|
|
403
|
-
|
404
|
-
hooks.run(:before, :
|
429
|
+
ContextHookMemoizedHash::Before.isolate_for_context_hook(example_group_instance) do
|
430
|
+
hooks.run(:before, :context, example_group_instance)
|
405
431
|
end
|
406
432
|
ensure
|
407
|
-
|
433
|
+
store_before_context_ivars(example_group_instance)
|
408
434
|
end
|
409
435
|
end
|
410
436
|
|
411
437
|
# @private
|
412
|
-
def self.
|
438
|
+
def self.run_after_context_hooks(example_group_instance)
|
413
439
|
return if descendant_filtered_examples.empty?
|
414
|
-
set_ivars(example_group_instance,
|
440
|
+
set_ivars(example_group_instance, before_context_ivars)
|
415
441
|
|
416
|
-
|
417
|
-
hooks.run(:after, :
|
442
|
+
ContextHookMemoizedHash::After.isolate_for_context_hook(example_group_instance) do
|
443
|
+
hooks.run(:after, :context, example_group_instance)
|
418
444
|
end
|
419
445
|
end
|
420
446
|
|
421
447
|
# Runs all the examples in this group
|
422
448
|
def self.run(reporter)
|
423
|
-
if RSpec.wants_to_quit
|
424
|
-
RSpec.clear_remaining_example_groups if top_level?
|
449
|
+
if RSpec.world.wants_to_quit
|
450
|
+
RSpec.world.clear_remaining_example_groups if top_level?
|
425
451
|
return
|
426
452
|
end
|
427
453
|
reporter.example_group_started(self)
|
428
454
|
|
429
455
|
begin
|
430
|
-
|
456
|
+
run_before_context_hooks(new)
|
431
457
|
result_for_this_group = run_examples(reporter)
|
432
458
|
results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
|
433
459
|
result_for_this_group && results_for_descendants
|
434
460
|
rescue Pending::SkipDeclaredInExample => ex
|
435
461
|
for_filtered_examples(reporter) {|example| example.skip_with_exception(reporter, ex) }
|
436
462
|
rescue Exception => ex
|
437
|
-
RSpec.wants_to_quit = true if fail_fast?
|
463
|
+
RSpec.world.wants_to_quit = true if fail_fast?
|
438
464
|
for_filtered_examples(reporter) {|example| example.fail_with_exception(reporter, ex) }
|
439
465
|
ensure
|
440
|
-
|
441
|
-
|
466
|
+
run_after_context_hooks(new)
|
467
|
+
before_context_ivars.clear
|
442
468
|
reporter.example_group_finished(self)
|
443
469
|
end
|
444
470
|
end
|
@@ -452,7 +478,7 @@ module RSpec
|
|
452
478
|
warn <<-WARNING.gsub(/^ +\|/, '')
|
453
479
|
|WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata.
|
454
480
|
| Falling back to configured global ordering.
|
455
|
-
| Unrecognized ordering specified at: #{
|
481
|
+
| Unrecognized ordering specified at: #{location}
|
456
482
|
WARNING
|
457
483
|
|
458
484
|
registry.fetch(:global)
|
@@ -462,11 +488,11 @@ module RSpec
|
|
462
488
|
# @private
|
463
489
|
def self.run_examples(reporter)
|
464
490
|
ordering_strategy.order(filtered_examples).map do |example|
|
465
|
-
next if RSpec.wants_to_quit
|
491
|
+
next if RSpec.world.wants_to_quit
|
466
492
|
instance = new
|
467
|
-
set_ivars(instance,
|
493
|
+
set_ivars(instance, before_context_ivars)
|
468
494
|
succeeded = example.run(instance, reporter)
|
469
|
-
RSpec.wants_to_quit = true if fail_fast? && !succeeded
|
495
|
+
RSpec.world.wants_to_quit = true if fail_fast? && !succeeded
|
470
496
|
succeeded
|
471
497
|
end.all?
|
472
498
|
end
|
@@ -490,17 +516,17 @@ module RSpec
|
|
490
516
|
|
491
517
|
# @private
|
492
518
|
def self.any_apply?(filters)
|
493
|
-
|
519
|
+
MetadataFilter.any_apply?(filters, metadata)
|
494
520
|
end
|
495
521
|
|
496
522
|
# @private
|
497
523
|
def self.all_apply?(filters)
|
498
|
-
|
524
|
+
MetadataFilter.all_apply?(filters, metadata)
|
499
525
|
end
|
500
526
|
|
501
527
|
# @private
|
502
528
|
def self.declaration_line_numbers
|
503
|
-
@declaration_line_numbers ||= [metadata[:
|
529
|
+
@declaration_line_numbers ||= [metadata[:line_number]] +
|
504
530
|
examples.collect {|e| e.metadata[:line_number]} +
|
505
531
|
children.inject([]) {|l,c| l + c.declaration_line_numbers}
|
506
532
|
end
|
@@ -515,37 +541,39 @@ module RSpec
|
|
515
541
|
ivars.each {|name, value| instance.instance_variable_set(name, value)}
|
516
542
|
end
|
517
543
|
|
518
|
-
# Returns the class or module passed to the `describe` method (or alias).
|
519
|
-
# Returns nil if the subject is not a class or module.
|
520
|
-
# @example
|
521
|
-
# describe Thing do
|
522
|
-
# it "does something" do
|
523
|
-
# described_class == Thing
|
524
|
-
# end
|
525
|
-
# end
|
526
|
-
#
|
527
|
-
#
|
528
|
-
def described_class
|
529
|
-
self.class.described_class
|
530
|
-
end
|
531
|
-
|
532
544
|
# @private
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
if RSpec.current_example
|
540
|
-
RSpec.current_example.set_exception(e, context)
|
541
|
-
else
|
542
|
-
raise
|
543
|
-
end
|
545
|
+
def self.pending_metadata_and_block_for(options, block)
|
546
|
+
if String === options[:pending]
|
547
|
+
reason = options[:pending]
|
548
|
+
else
|
549
|
+
options[:pending] = true
|
550
|
+
reason = RSpec::Core::Pending::NO_REASON_GIVEN
|
544
551
|
end
|
552
|
+
|
553
|
+
# Assign :caller so that the callback's source_location isn't used
|
554
|
+
# as the example location.
|
555
|
+
options[:caller] ||= Metadata.backtrace_from(block)
|
556
|
+
|
557
|
+
# This will fail if no block is provided, which is effectively the
|
558
|
+
# same as failing the example so it will be marked correctly as
|
559
|
+
# pending.
|
560
|
+
callback = Proc.new { pending(reason); instance_exec(&block) }
|
561
|
+
|
562
|
+
return options, callback
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
# @private
|
567
|
+
# Unnamed example group used by `SuiteHookContext`.
|
568
|
+
class AnonymousExampleGroup < ExampleGroup
|
569
|
+
def self.metadata
|
570
|
+
{}
|
545
571
|
end
|
546
572
|
end
|
547
573
|
end
|
548
574
|
|
575
|
+
# @private
|
576
|
+
#
|
549
577
|
# Namespace for the example group subclasses generated by top-level `describe`.
|
550
578
|
module ExampleGroups
|
551
579
|
def self.assign_const(group)
|