rspec-core 2.8.0 → 2.9.0.rc2
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/.document +5 -0
- data/.yardopts +3 -0
- data/Changelog.md +492 -0
- data/README.md +1 -1
- data/features/mock_framework_integration/use_flexmock.feature +2 -2
- data/features/step_definitions/additional_cli_steps.rb +2 -2
- data/features/subject/attribute_of_subject.feature +4 -2
- data/features/subject/explicit_subject.feature +6 -2
- data/features/subject/implicit_receiver.feature +1 -1
- data/features/subject/implicit_subject.feature +40 -7
- data/lib/autotest/rspec2.rb +1 -1
- data/lib/rspec/core.rb +1 -1
- data/lib/rspec/core/configuration.rb +53 -5
- data/lib/rspec/core/configuration_options.rb +5 -2
- data/lib/rspec/core/drb_options.rb +3 -1
- data/lib/rspec/core/filter_manager.rb +1 -1
- data/lib/rspec/core/formatters/base_text_formatter.rb +1 -5
- data/lib/rspec/core/formatters/documentation_formatter.rb +4 -8
- data/lib/rspec/core/formatters/helpers.rb +15 -0
- data/lib/rspec/core/hooks.rb +3 -1
- data/lib/rspec/core/metadata.rb +6 -11
- data/lib/rspec/core/runner.rb +4 -14
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +7 -7
- data/spec/autotest/rspec_spec.rb +1 -1
- data/spec/rspec/core/configuration_options_spec.rb +8 -5
- data/spec/rspec/core/configuration_spec.rb +38 -10
- data/spec/rspec/core/example_group_spec.rb +16 -0
- data/spec/rspec/core/formatters/documentation_formatter_spec.rb +23 -1
- data/spec/rspec/core/formatters/helpers_spec.rb +20 -0
- data/spec/rspec/core/metadata_spec.rb +3 -4
- data/spec/rspec/core/shared_example_group_spec.rb +2 -2
- data/spec/rspec/core/world_spec.rb +11 -1
- metadata +166 -19
- data/lib/rspec/monkey.rb +0 -1
- data/lib/rspec/monkey/spork/test_framework/rspec.rb +0 -10
data/README.md
CHANGED
@@ -32,7 +32,7 @@ describe Order do
|
|
32
32
|
end
|
33
33
|
```
|
34
34
|
|
35
|
-
The `describe` method creates an [ExampleGroup](
|
35
|
+
The `describe` method creates an [ExampleGroup](http://rubydoc.info/gems/rspec-core/RSpec/Core/ExampleGroup). Within the
|
36
36
|
block passed to `describe` you can declare examples using the `it` method.
|
37
37
|
|
38
38
|
Under the hood, an example group is a class in which the block passed to
|
@@ -9,7 +9,7 @@ Feature: mock with flexmock
|
|
9
9
|
config.mock_framework = :flexmock
|
10
10
|
end
|
11
11
|
|
12
|
-
describe "mocking with
|
12
|
+
describe "mocking with Flexmock" do
|
13
13
|
it "passes when it should" do
|
14
14
|
receiver = flexmock('receiver')
|
15
15
|
receiver.should_receive(:message).once
|
@@ -27,7 +27,7 @@ Feature: mock with flexmock
|
|
27
27
|
config.mock_framework = :flexmock
|
28
28
|
end
|
29
29
|
|
30
|
-
describe "mocking with
|
30
|
+
describe "mocking with Flexmock" do
|
31
31
|
it "fails when it should" do
|
32
32
|
receiver = flexmock('receiver')
|
33
33
|
receiver.should_receive(:message).once
|
@@ -11,8 +11,8 @@ Then /^the output should not contain any of these:$/ do |table|
|
|
11
11
|
end
|
12
12
|
|
13
13
|
Then /^the example(?:s)? should(?: all)? pass$/ do
|
14
|
-
|
15
|
-
|
14
|
+
step %q{the output should contain "0 failures"}
|
15
|
+
step %q{the exit status should be 0}
|
16
16
|
end
|
17
17
|
|
18
18
|
Then /^the file "([^"]*)" should contain:$/ do |file, partial_content|
|
@@ -1,10 +1,12 @@
|
|
1
1
|
Feature: attribute of subject
|
2
2
|
|
3
|
-
|
3
|
+
WARNING: `its` will be extracted from rspec-core-3.0 into its own gem.
|
4
|
+
|
5
|
+
Use the `its` method as a short-hand to generate a nested example group with
|
4
6
|
a single example that specifies the expected value of an attribute of the
|
5
7
|
subject. This can be used with an implicit or explicit subject.
|
6
8
|
|
7
|
-
its
|
9
|
+
`its` accepts a symbol or a string, and a block representing the example.
|
8
10
|
|
9
11
|
its(:size) { should eq(1) }
|
10
12
|
its("length") { should eq(1) }
|
@@ -1,7 +1,11 @@
|
|
1
1
|
Feature: explicit subject
|
2
2
|
|
3
|
-
Use subject
|
4
|
-
returned by the subject
|
3
|
+
Use `subject` in the group scope to explicitly define the value that is
|
4
|
+
returned by the `subject` method in the example scope.
|
5
|
+
|
6
|
+
Note that while the examples below demonstrate how `subject` can be used as a
|
7
|
+
user-facing concept, we recommend that you reserve it for support of custom
|
8
|
+
matchers and/or extension libraries that hide its use from examples.
|
5
9
|
|
6
10
|
Scenario: subject in top level group
|
7
11
|
Given a file named "top_level_subject_spec.rb" with:
|
@@ -1,14 +1,18 @@
|
|
1
|
-
Feature:
|
1
|
+
Feature: implicitly defined subject
|
2
2
|
|
3
3
|
If the first argument to the outermost example group is a class, an instance
|
4
|
-
of that class is exposed to each example via the subject
|
4
|
+
of that class is exposed to each example via the `subject` method.
|
5
|
+
|
6
|
+
While the examples below demonstrate how `subject` can be used as a
|
7
|
+
user-facing concept, we recommend that you reserve it for support of custom
|
8
|
+
matchers and/or extension libraries that hide its use from examples.
|
5
9
|
|
6
|
-
Scenario: subject in top level group
|
10
|
+
Scenario: subject exposed in top level group
|
7
11
|
Given a file named "top_level_subject_spec.rb" with:
|
8
12
|
"""
|
9
|
-
describe Array
|
10
|
-
it "should be empty" do
|
11
|
-
subject.should
|
13
|
+
describe Array do
|
14
|
+
it "should be empty when first created" do
|
15
|
+
subject.should be_empty
|
12
16
|
end
|
13
17
|
end
|
14
18
|
"""
|
@@ -21,7 +25,36 @@ Feature: implicit subject
|
|
21
25
|
describe Array do
|
22
26
|
describe "when first created" do
|
23
27
|
it "should be empty" do
|
24
|
-
subject.should
|
28
|
+
subject.should be_empty
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
"""
|
33
|
+
When I run `rspec nested_subject_spec.rb`
|
34
|
+
Then the examples should all pass
|
35
|
+
|
36
|
+
Scenario: subject in a nested group with a different class (outermost wins)
|
37
|
+
Given a file named "nested_subject_spec.rb" with:
|
38
|
+
"""
|
39
|
+
class ArrayWithOneElement < Array
|
40
|
+
def initialize(*)
|
41
|
+
super
|
42
|
+
unshift "first element"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe Array do
|
47
|
+
describe ArrayWithOneElement do
|
48
|
+
context "referenced as subject" do
|
49
|
+
it "should be empty (because it is the Array declared at the top)" do
|
50
|
+
subject.should be_empty
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "created in the example" do
|
55
|
+
it "should not be empty" do
|
56
|
+
ArrayWithOneElement.new.should_not be_empty
|
57
|
+
end
|
25
58
|
end
|
26
59
|
end
|
27
60
|
end
|
data/lib/autotest/rspec2.rb
CHANGED
@@ -47,7 +47,7 @@ class Autotest::Rspec2 < Autotest
|
|
47
47
|
# Overrides Autotest's implementation to generate the rspec command to run
|
48
48
|
def make_test_cmd(files_to_test)
|
49
49
|
files_to_test.empty? ? '' :
|
50
|
-
"#{prefix}#{ruby}#{suffix} -S #{RSPEC_EXECUTABLE} --tty #{normalize(files_to_test).keys.flatten.map { |f| "'#{f}'"}.join(' ')}"
|
50
|
+
"#{prefix}#{ruby}#{suffix} -S '#{RSPEC_EXECUTABLE}' --tty #{normalize(files_to_test).keys.flatten.map { |f| "'#{f}'"}.join(' ')}"
|
51
51
|
end
|
52
52
|
|
53
53
|
# Generates a map of filenames to Arrays for Autotest
|
data/lib/rspec/core.rb
CHANGED
@@ -10,6 +10,7 @@ else
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
require 'set'
|
13
14
|
require_rspec 'core/filter_manager'
|
14
15
|
require_rspec 'core/dsl'
|
15
16
|
require_rspec 'core/extensions'
|
@@ -104,4 +105,3 @@ module RSpec
|
|
104
105
|
end
|
105
106
|
|
106
107
|
require_rspec 'core/backward_compatibility'
|
107
|
-
require_rspec 'monkey'
|
@@ -534,10 +534,26 @@ EOM
|
|
534
534
|
# or config files (e.g. `.rspec`).
|
535
535
|
#
|
536
536
|
# @example
|
537
|
-
#
|
537
|
+
# # given this declaration
|
538
|
+
# describe "something", :foo => 'bar' do
|
539
|
+
# # ...
|
540
|
+
# end
|
541
|
+
#
|
542
|
+
# # any of the following will include that group
|
543
|
+
# config.filter_run_including :foo => 'bar'
|
544
|
+
# config.filter_run_including :foo => /^ba/
|
545
|
+
# config.filter_run_including :foo => lambda {|v| v == 'bar'}
|
546
|
+
# config.filter_run_including :foo => lambda {|v,m| m[:foo] == 'bar'}
|
547
|
+
#
|
548
|
+
# # given a proc with an arity of 1, the lambda is passed the value related to the key, e.g.
|
549
|
+
# config.filter_run_including :foo => lambda {|v| v == 'bar'}
|
550
|
+
#
|
551
|
+
# # given a proc with an arity of 2, the lambda is passed the value related to the key,
|
552
|
+
# # and the metadata itself e.g.
|
553
|
+
# config.filter_run_including :foo => lambda {|v,m| m[:foo] == 'bar'}
|
538
554
|
#
|
539
555
|
# # with treat_symbols_as_metadata_keys_with_true_values = true
|
540
|
-
# filter_run_including :foo #
|
556
|
+
# filter_run_including :foo # same as filter_run_including :foo => true
|
541
557
|
def filter_run_including(*args)
|
542
558
|
filter_manager.include_with_low_priority build_metadata_hash_from(args)
|
543
559
|
end
|
@@ -576,10 +592,26 @@ EOM
|
|
576
592
|
# or config files (e.g. `.rspec`).
|
577
593
|
#
|
578
594
|
# @example
|
579
|
-
#
|
595
|
+
# # given this declaration
|
596
|
+
# describe "something", :foo => 'bar' do
|
597
|
+
# # ...
|
598
|
+
# end
|
599
|
+
#
|
600
|
+
# # any of the following will exclude that group
|
601
|
+
# config.filter_run_excluding :foo => 'bar'
|
602
|
+
# config.filter_run_excluding :foo => /^ba/
|
603
|
+
# config.filter_run_excluding :foo => lambda {|v| v == 'bar'}
|
604
|
+
# config.filter_run_excluding :foo => lambda {|v,m| m[:foo] == 'bar'}
|
605
|
+
#
|
606
|
+
# # given a proc with an arity of 1, the lambda is passed the value related to the key, e.g.
|
607
|
+
# config.filter_run_excluding :foo => lambda {|v| v == 'bar'}
|
608
|
+
#
|
609
|
+
# # given a proc with an arity of 2, the lambda is passed the value related to the key,
|
610
|
+
# # and the metadata itself e.g.
|
611
|
+
# config.filter_run_excluding :foo => lambda {|v,m| m[:foo] == 'bar'}
|
580
612
|
#
|
581
613
|
# # with treat_symbols_as_metadata_keys_with_true_values = true
|
582
|
-
# filter_run_excluding :foo #
|
614
|
+
# filter_run_excluding :foo # same as filter_run_excluding :foo => true
|
583
615
|
def filter_run_excluding(*args)
|
584
616
|
filter_manager.exclude_with_low_priority build_metadata_hash_from(args)
|
585
617
|
end
|
@@ -677,7 +709,23 @@ EOM
|
|
677
709
|
def configure_group(group)
|
678
710
|
include_or_extend_modules.each do |include_or_extend, mod, filters|
|
679
711
|
next unless filters.empty? || group.any_apply?(filters)
|
680
|
-
|
712
|
+
send("safe_#{include_or_extend}", mod, group)
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
# @private
|
717
|
+
def safe_include(mod, host)
|
718
|
+
host.send(:include,mod) unless host < mod
|
719
|
+
end
|
720
|
+
|
721
|
+
# @private
|
722
|
+
if RUBY_VERSION.to_f >= 1.9
|
723
|
+
def safe_extend(mod, host)
|
724
|
+
host.extend(mod) unless (class << host; self; end) < mod
|
725
|
+
end
|
726
|
+
else
|
727
|
+
def safe_extend(mod, host)
|
728
|
+
host.extend(mod) unless (class << host; self; end).included_modules.include?(mod)
|
681
729
|
end
|
682
730
|
end
|
683
731
|
|
@@ -33,12 +33,15 @@ module RSpec
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def filter_manager
|
36
|
-
@filter_manager ||=
|
36
|
+
@filter_manager ||= RSpec::configuration.filter_manager
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
40
40
|
|
41
|
-
NON_FORCED_OPTIONS = [
|
41
|
+
NON_FORCED_OPTIONS = [
|
42
|
+
:debug, :requires, :libs, :profile, :drb, :files_or_directories_to_run,
|
43
|
+
:line_numbers, :full_description, :full_backtrace, :tty
|
44
|
+
].to_set
|
42
45
|
|
43
46
|
def force?(key)
|
44
47
|
!NON_FORCED_OPTIONS.include?(key)
|
@@ -52,9 +52,11 @@ module RSpec::Core
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
CONDITIONAL_FILTERS = [:if, :unless]
|
56
|
+
|
55
57
|
def add_filter(argv, name, hash)
|
56
58
|
hash.each_pair do |k, v|
|
57
|
-
next if
|
59
|
+
next if CONDITIONAL_FILTERS.include?(k)
|
58
60
|
tag = name == :inclusion ? k.to_s : "~#{k}"
|
59
61
|
tag << ":#{v}" if v.is_a?(String)
|
60
62
|
argv << "--tag" << tag
|
@@ -67,7 +67,7 @@ module RSpec
|
|
67
67
|
# @see Configuration#filter_run_excluding
|
68
68
|
class FilterManager
|
69
69
|
DEFAULT_EXCLUSIONS = {
|
70
|
-
:if => lambda { |value
|
70
|
+
:if => lambda { |value| !value },
|
71
71
|
:unless => lambda { |value| value }
|
72
72
|
}
|
73
73
|
|
@@ -35,7 +35,7 @@ module RSpec
|
|
35
35
|
super(duration, example_count, failure_count, pending_count)
|
36
36
|
# Don't print out profiled info if there are failures, it just clutters the output
|
37
37
|
dump_profile if profile_examples? && failure_count == 0
|
38
|
-
output.puts "\nFinished in #{
|
38
|
+
output.puts "\nFinished in #{format_duration(duration)}\n"
|
39
39
|
output.puts colorise_summary(summary_line(example_count, failure_count, pending_count))
|
40
40
|
dump_commands_to_rerun_failed_examples
|
41
41
|
end
|
@@ -142,10 +142,6 @@ module RSpec
|
|
142
142
|
|
143
143
|
private
|
144
144
|
|
145
|
-
def pluralize(count, string)
|
146
|
-
"#{count} #{string}#{'s' unless count == 1}"
|
147
|
-
end
|
148
|
-
|
149
145
|
def format_caller(caller_info)
|
150
146
|
backtrace_line(caller_info.to_s.split(':in `block').first)
|
151
147
|
end
|
@@ -3,9 +3,7 @@ require 'rspec/core/formatters/base_text_formatter'
|
|
3
3
|
module RSpec
|
4
4
|
module Core
|
5
5
|
module Formatters
|
6
|
-
|
7
6
|
class DocumentationFormatter < BaseTextFormatter
|
8
|
-
|
9
7
|
def initialize(output)
|
10
8
|
super(output)
|
11
9
|
@group_level = 0
|
@@ -15,7 +13,7 @@ module RSpec
|
|
15
13
|
super(example_group)
|
16
14
|
|
17
15
|
output.puts if @group_level == 0
|
18
|
-
output.puts "#{current_indentation}#{example_group.description}"
|
16
|
+
output.puts "#{current_indentation}#{example_group.description.strip}"
|
19
17
|
|
20
18
|
@group_level += 1
|
21
19
|
end
|
@@ -40,7 +38,7 @@ module RSpec
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def failure_output(example, exception)
|
43
|
-
red("#{current_indentation}#{example.description} (FAILED - #{next_failure_index})")
|
41
|
+
red("#{current_indentation}#{example.description.strip} (FAILED - #{next_failure_index})")
|
44
42
|
end
|
45
43
|
|
46
44
|
def next_failure_index
|
@@ -49,11 +47,11 @@ module RSpec
|
|
49
47
|
end
|
50
48
|
|
51
49
|
def passed_output(example)
|
52
|
-
green("#{current_indentation}#{example.description}")
|
50
|
+
green("#{current_indentation}#{example.description.strip}")
|
53
51
|
end
|
54
52
|
|
55
53
|
def pending_output(example, message)
|
56
|
-
yellow("#{current_indentation}#{example.description} (PENDING: #{message})")
|
54
|
+
yellow("#{current_indentation}#{example.description.strip} (PENDING: #{message})")
|
57
55
|
end
|
58
56
|
|
59
57
|
def current_indentation
|
@@ -63,9 +61,7 @@ module RSpec
|
|
63
61
|
def example_group_chain
|
64
62
|
example_group.ancestors.reverse
|
65
63
|
end
|
66
|
-
|
67
64
|
end
|
68
|
-
|
69
65
|
end
|
70
66
|
end
|
71
67
|
end
|
@@ -6,6 +6,17 @@ module RSpec
|
|
6
6
|
SUB_SECOND_PRECISION = 5
|
7
7
|
DEFAULT_PRECISION = 2
|
8
8
|
|
9
|
+
def format_duration(duration)
|
10
|
+
if duration > 60
|
11
|
+
minutes = duration.to_i / 60
|
12
|
+
seconds = duration - minutes * 60
|
13
|
+
|
14
|
+
"#{pluralize(minutes, 'minute')} #{format_seconds(seconds)} seconds"
|
15
|
+
else
|
16
|
+
"#{format_seconds(duration)} seconds"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
9
20
|
def format_seconds(float)
|
10
21
|
precision ||= (float < 1) ? SUB_SECOND_PRECISION : DEFAULT_PRECISION
|
11
22
|
formatted = sprintf("%.#{precision}f", float)
|
@@ -17,6 +28,10 @@ module RSpec
|
|
17
28
|
stripped.empty? ? "0" : stripped
|
18
29
|
end
|
19
30
|
|
31
|
+
def pluralize(count, string)
|
32
|
+
"#{count} #{string}#{'s' unless count == 1}"
|
33
|
+
end
|
34
|
+
|
20
35
|
end
|
21
36
|
|
22
37
|
end
|
data/lib/rspec/core/hooks.rb
CHANGED
@@ -398,8 +398,10 @@ module RSpec
|
|
398
398
|
|
399
399
|
private
|
400
400
|
|
401
|
+
SCOPES = [:each, :all, :suite]
|
402
|
+
|
401
403
|
def scope_and_options_from(*args)
|
402
|
-
scope = if
|
404
|
+
scope = if SCOPES.include?(args.first)
|
403
405
|
args.shift
|
404
406
|
elsif args.any? { |a| a.is_a?(Symbol) }
|
405
407
|
raise ArgumentError.new("You must explicitly give a scope (:each, :all, or :suite) when using symbols as metadata for a hook.")
|
data/lib/rspec/core/metadata.rb
CHANGED
@@ -102,8 +102,8 @@ module RSpec
|
|
102
102
|
|
103
103
|
def described_class
|
104
104
|
container_stack.each do |g|
|
105
|
-
return g[:describes] if g.has_key?(:describes)
|
106
105
|
return g[:described_class] if g.has_key?(:described_class)
|
106
|
+
return g[:describes] if g.has_key?(:describes)
|
107
107
|
end
|
108
108
|
|
109
109
|
container_stack.reverse.each do |g|
|
@@ -174,20 +174,15 @@ module RSpec
|
|
174
174
|
return metadata.location_filter_applies?(value) if key == :locations
|
175
175
|
return metadata.filters_apply?(key, value) if Hash === value
|
176
176
|
|
177
|
+
return false unless metadata.has_key?(key)
|
178
|
+
|
177
179
|
case value
|
178
180
|
when Regexp
|
179
181
|
metadata[key] =~ value
|
180
182
|
when Proc
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
# { } # => run the example
|
185
|
-
# { :if => nil } # => exclude the example
|
186
|
-
# The value of metadata[:if] is the same in these two cases but
|
187
|
-
# they need to be treated differently.
|
188
|
-
value.call(metadata[key], metadata) rescue false
|
189
|
-
else
|
190
|
-
value.call(metadata[key]) rescue false
|
183
|
+
case value.arity
|
184
|
+
when 1 then value.call(metadata[key])
|
185
|
+
when 2 then value.call(metadata[key], metadata)
|
191
186
|
end
|
192
187
|
else
|
193
188
|
metadata[key].to_s == value.to_s
|
data/lib/rspec/core/runner.rb
CHANGED
@@ -7,7 +7,7 @@ module RSpec
|
|
7
7
|
# Register an at_exit hook that runs the suite.
|
8
8
|
def self.autorun
|
9
9
|
return if autorun_disabled? || installed_at_exit? || running_in_drb?
|
10
|
-
at_exit { exit run(ARGV, $stderr, $stdout).to_i }
|
10
|
+
at_exit { exit run(ARGV, $stderr, $stdout).to_i unless $! }
|
11
11
|
@installed_at_exit = true
|
12
12
|
end
|
13
13
|
AT_EXIT_HOOK_BACKTRACE_LINE = "#{__FILE__}:#{__LINE__ - 2}:in `autorun'"
|
@@ -60,27 +60,17 @@ module RSpec
|
|
60
60
|
|
61
61
|
if options.options[:drb]
|
62
62
|
begin
|
63
|
-
|
63
|
+
DRbCommandLine.new(options).run(err, out)
|
64
64
|
rescue DRb::DRbConnError
|
65
65
|
err.puts "No DRb server is running. Running in local process instead ..."
|
66
|
-
|
66
|
+
CommandLine.new(options).run(err, out)
|
67
67
|
end
|
68
68
|
else
|
69
|
-
|
69
|
+
CommandLine.new(options).run(err, out)
|
70
70
|
end
|
71
71
|
ensure
|
72
72
|
RSpec.reset
|
73
73
|
end
|
74
|
-
|
75
|
-
def self.run_over_drb(options, err, out)
|
76
|
-
DRbCommandLine.new(options).run(err, out)
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.run_in_process(options, err, out)
|
80
|
-
CommandLine.new(options, RSpec::configuration, RSpec::world).run(err, out)
|
81
|
-
end
|
82
|
-
|
83
74
|
end
|
84
|
-
|
85
75
|
end
|
86
76
|
end
|