rspec-core 2.8.0 → 2.9.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|