Skip to content

Commit f7133fe

Browse files
committed
Add specs covering uncovered code.
1 parent dca74d5 commit f7133fe

16 files changed

+266
-34
lines changed

lib/rspec/core/formatters/snippet_extractor.rb

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,30 @@ module Formatters
77
# and applies synax highlighting and line numbers using html.
88
class SnippetExtractor
99
# @private
10-
class NullConverter
11-
def convert(code)
10+
module NullConverter
11+
def self.convert(code)
1212
%Q(#{code}\n<span class="comment"># Install the coderay gem to get syntax highlighting</span>)
1313
end
1414
end
1515

1616
# @private
17-
class CoderayConverter
18-
def convert(code)
17+
module CoderayConverter
18+
def self.convert(code)
1919
CodeRay.scan(code, :ruby).html(:line_numbers => false)
2020
end
2121
end
2222

23+
# rubocop:disable Style/ClassVars
24+
@@converter = NullConverter
2325
begin
2426
require 'coderay'
25-
# rubocop:disable Style/ClassVars
26-
@@converter = CoderayConverter.new
27+
@@converter = CoderayConverter
28+
# rubocop:disable Lint/HandleExceptions
2729
rescue LoadError
28-
@@converter = NullConverter.new
30+
# it'll fall back to the NullConverter assigned above
31+
# rubocop:enable Lint/HandleExceptions
2932
end
33+
3034
# rubocop:enable Style/ClassVars
3135

3236
# @api private
@@ -43,6 +47,7 @@ def snippet(backtrace)
4347
highlighted = @@converter.convert(raw_code)
4448
post_process(highlighted, line)
4549
end
50+
# rubocop:enable Style/ClassVars
4651

4752
# @api private
4853
#

lib/rspec/core/runner.rb

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@ def self.autorun
1717
return
1818
end
1919

20-
at_exit do
21-
# Don't bother running any specs and just let the program terminate
22-
# if we got here due to an unrescued exception (anything other than
23-
# SystemExit, which is raised when somebody calls Kernel#exit).
24-
next unless $!.nil? || $!.is_a?(SystemExit)
25-
26-
# We got here because either the end of the program was reached or
27-
# somebody called Kernel#exit. Run the specs and then override any
28-
# existing exit status with RSpec's exit status if any specs failed.
29-
invoke
30-
end
20+
at_exit { perform_at_exit }
3121
@installed_at_exit = true
3222
end
3323

24+
# @private
25+
def self.perform_at_exit
26+
# Don't bother running any specs and just let the program terminate
27+
# if we got here due to an unrescued exception (anything other than
28+
# SystemExit, which is raised when somebody calls Kernel#exit).
29+
return unless $!.nil? || $!.is_a?(SystemExit)
30+
31+
# We got here because either the end of the program was reached or
32+
# somebody called Kernel#exit. Run the specs and then override any
33+
# existing exit status with RSpec's exit status if any specs failed.
34+
invoke
35+
end
36+
3437
# Runs the suite of specs and exits the process with an appropriate exit
3538
# code.
3639
def self.invoke
@@ -159,8 +162,14 @@ def self.running_in_drb?
159162

160163
# @private
161164
def self.trap_interrupt
162-
trap('INT') do
163-
exit!(1) if RSpec.world.wants_to_quit
165+
trap('INT') { handle_interrupt }
166+
end
167+
168+
# @private
169+
def self.handle_interrupt
170+
if RSpec.world.wants_to_quit
171+
exit!(1)
172+
else
164173
RSpec.world.wants_to_quit = true
165174
STDERR.puts "\nRSpec is shutting down and will print the summary report... Interrupt again to force quit."
166175
end

spec/rspec/core/backtrace_formatter_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def make_backtrace_formatter(exclusion_patterns=nil, inclusion_patterns=nil)
206206
end
207207

208208
it "deals gracefully with a security error" do
209+
Metadata.instance_eval { @relative_path_regex = nil }
209210
with_safe_set_to_level_that_triggers_security_errors do
210211
self.formatter.__send__(:backtrace_line, __FILE__)
211212
# on some rubies, this doesn't raise a SecurityError; this test just

spec/rspec/core/configuration_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,20 @@ def metadata_hash(*args)
13411341
end
13421342
end
13431343

1344+
describe "#backtrace_inclusion_patterns" do
1345+
before { config.backtrace_exclusion_patterns << /.*/ }
1346+
1347+
it 'can be assigned to' do
1348+
config.backtrace_inclusion_patterns = [/foo/]
1349+
expect(config.backtrace_formatter.exclude?("food")).to be false
1350+
end
1351+
1352+
it 'can be appended to' do
1353+
config.backtrace_inclusion_patterns << /foo/
1354+
expect(config.backtrace_formatter.exclude?("food")).to be false
1355+
end
1356+
end
1357+
13441358
describe "#filter_gems_from_backtrace" do
13451359
def exclude?(line)
13461360
config.backtrace_formatter.exclude?(line)
@@ -1357,6 +1371,22 @@ def exclude?(line)
13571371
end
13581372
end
13591373

1374+
describe "#profile_examples" do
1375+
it "defaults to false" do
1376+
expect(config.profile_examples).to be false
1377+
end
1378+
1379+
it "can be set to an integer value" do
1380+
config.profile_examples = 17
1381+
expect(config.profile_examples).to eq(17)
1382+
end
1383+
1384+
it "returns 10 when set simply enabled" do
1385+
config.profile_examples = true
1386+
expect(config.profile_examples).to eq(10)
1387+
end
1388+
end
1389+
13601390
describe "#libs=" do
13611391
it "adds directories to the LOAD_PATH" do
13621392
expect($LOAD_PATH).to receive(:unshift).with("a/dir")

spec/rspec/core/drb_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ def self.run(argv, err, out)
8282
DRb::stop_service
8383
end
8484

85+
it "falls back to `druby://:0` when `druby://localhost:0` fails" do
86+
# see https://bugs.ruby-lang.org/issues/496 for background
87+
expect(::DRb).to receive(:start_service).with("druby://localhost:0").and_raise(SocketError)
88+
expect(::DRb).to receive(:start_service).with("druby://:0").and_call_original
89+
90+
result = runner("--drb-port", @drb_port, passing_spec_filename).run(err, out)
91+
expect(result).to be(0)
92+
end
93+
8594
it "returns 0 if spec passes" do
8695
result = runner("--drb-port", @drb_port, passing_spec_filename).run(err, out)
8796
expect(result).to be(0)

spec/rspec/core/example_group_spec.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,8 +1419,7 @@ def foo; 'third value'; end
14191419
let(:group) { RSpec.describe }
14201420

14211421
before do
1422-
allow(RSpec.world).to receive(:wants_to_quit) { true }
1423-
allow(RSpec.world).to receive(:clear_remaining_example_groups)
1422+
RSpec.world.wants_to_quit = true
14241423
end
14251424

14261425
it "returns without starting the group" do
@@ -1430,16 +1429,19 @@ def foo; 'third value'; end
14301429

14311430
context "at top level" do
14321431
it "purges remaining groups" do
1433-
expect(RSpec.world).to receive(:clear_remaining_example_groups)
1434-
self.group.run(reporter)
1432+
expect {
1433+
self.group.run(reporter)
1434+
}.to change { RSpec.world.example_groups }.from([self.group]).to([])
14351435
end
14361436
end
14371437

14381438
context "in a nested group" do
14391439
it "does not purge remaining groups" do
14401440
nested_group = self.group.describe
1441-
expect(RSpec.world).not_to receive(:clear_remaining_example_groups)
1442-
nested_group.run(reporter)
1441+
1442+
expect {
1443+
nested_group.run(reporter)
1444+
}.not_to change { RSpec.world.example_groups }.from([self.group])
14431445
end
14441446
end
14451447
end

spec/rspec/core/example_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ def metadata_hash(*args)
2222
expect { ignoring_warnings { pp example_instance }}.to output(/RSpec::Core::Example/).to_stdout
2323
end
2424

25+
describe "#rerun_argument" do
26+
it "returns the location-based rerun argument" do
27+
allow(RSpec.configuration).to receive_messages(:loaded_spec_files => [__FILE__])
28+
example = RSpec.describe.example
29+
expect(example.rerun_argument).to eq("#{RSpec::Core::Metadata.relative_path(__FILE__)}:#{__LINE__ - 1}")
30+
end
31+
end
32+
2533
describe "#exception" do
2634
it "supplies the first exception raised, if any" do
2735
RSpec.configuration.output_stream = StringIO.new

spec/rspec/core/formatters/json_formatter_spec.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
RSpec.describe RSpec::Core::Formatters::JsonFormatter do
1414
include FormatterSupport
1515

16-
it "outputs json (brittle high level functional test)" do
16+
it "can be loaded via `--format json`" do
17+
formatter_output = run_example_specs_with_formatter("json", false)
18+
parsed = JSON.parse(formatter_output)
19+
expect(parsed.keys).to include("examples", "summary", "summary_line")
20+
end
21+
22+
it "outputs expected json (brittle high level functional test)" do
1723
group = RSpec.describe("one apiece") do
1824
it("succeeds") { expect(1).to eq 1 }
1925
it("fails") { fail "eek" }

spec/rspec/core/formatters/snippet_extractor_spec.rb

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ module Formatters
99
end
1010

1111
it "falls back on a default message when it doesn't find the file" do
12-
expect(RSpec::Core::Formatters::SnippetExtractor.new.lines_around("blech", 8)).to eq("# Couldn't get snippet for blech")
12+
expect(RSpec::Core::Formatters::SnippetExtractor.new.lines_around("blech", 8)).to eq("# Couldn't get snippet for blech")
1313
end
1414

1515
it "falls back on a default message when it gets a security error" do
@@ -19,6 +19,31 @@ module Formatters
1919
end
2020
expect(message).to eq("# Couldn't get snippet for blech")
2121
end
22+
23+
describe "snippet extraction" do
24+
let(:snippet) do
25+
SnippetExtractor.new.snippet(["#{__FILE__}:#{__LINE__}"])
26+
end
27+
28+
before do
29+
# `send` is required for 1.8.7...
30+
@orig_converter = SnippetExtractor.send(:class_variable_get, :@@converter)
31+
end
32+
33+
after do
34+
SnippetExtractor.send(:class_variable_set, :@@converter, @orig_converter)
35+
end
36+
37+
it 'suggests you install coderay when it cannot be loaded' do
38+
SnippetExtractor.send(:class_variable_set, :@@converter, SnippetExtractor::NullConverter)
39+
40+
expect(snippet).to include("Install the coderay gem")
41+
end
42+
43+
it 'does not suggest installing coderay normally' do
44+
expect(snippet).to exclude("Install the coderay gem")
45+
end
46+
end
2247
end
2348
end
2449
end

spec/rspec/core/metadata_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ module Core
1515
end
1616
# I have no idea what line = line.sub(/\A([^:]+:\d+)$/, '\\1') is supposed to do
1717
it "gracefully returns nil if run in a secure thread" do
18+
# Ensure our call to `File.expand_path` is not cached as that is the insecure operation.
19+
Metadata.instance_eval { @relative_path_regex = nil }
1820
with_safe_set_to_level_that_triggers_security_errors do
1921
value = Metadata.relative_path(".")
2022
# on some rubies, File.expand_path is not a security error, so accept "." as well

spec/rspec/core/notifications_spec.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@
4747
end
4848
end
4949

50+
context "when ruby reports a file that does not exist" do
51+
let(:file) { "#{__FILE__}/blah.rb" }
52+
let(:exception) { instance_double(Exception, :backtrace => [ "#{file}:1"]) }
53+
54+
it "reports the filename and that it was unable to find the matching line" do
55+
example.metadata[:absolute_file_path] = file
56+
expect(notification.send(:read_failed_line)).to include("Unable to find #{file} to read failed line")
57+
end
58+
end
59+
5060
context "when the stacktrace includes relative paths (which can happen when using `rspec/autorun` and running files through `ruby`)" do
5161
let(:relative_file) { Pathname(__FILE__).relative_path_from(Pathname(Dir.pwd)) }
5262
line = __LINE__
@@ -117,3 +127,24 @@
117127
end
118128
end
119129
end
130+
131+
module RSpec::Core::Notifications
132+
RSpec.describe ExamplesNotification do
133+
include FormatterSupport
134+
135+
describe "#notifications" do
136+
it 'returns an array of notification objects for all the examples' do
137+
reporter = RSpec::Core::Reporter.new(RSpec.configuration)
138+
example = new_example
139+
140+
reporter.example_started(example)
141+
reporter.example_passed(example)
142+
143+
notification = ExamplesNotification.new(reporter)
144+
expect(notification.notifications).to match [
145+
an_instance_of(ExampleNotification) & an_object_having_attributes(:example => example)
146+
]
147+
end
148+
end
149+
end
150+
end

spec/rspec/core/option_parser_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'rspec/core/project_initializer'
2+
13
module RSpec::Core
24
RSpec.describe OptionParser do
35
before do
@@ -59,6 +61,33 @@ def generate_help_text
5961
expect { generate_help_text }.to_not output(useless_lines).to_stdout
6062
end
6163

64+
%w[ -v --version ].each do |option|
65+
describe option do
66+
it "prints the version and exits" do
67+
parser = Parser.new
68+
expect(parser).to receive(:exit)
69+
70+
expect {
71+
parser.parse([option])
72+
}.to output("#{RSpec::Core::Version::STRING}\n").to_stdout
73+
end
74+
end
75+
end
76+
77+
describe "--init" do
78+
it "initializes a project and exits" do
79+
project_init = instance_double(ProjectInitializer)
80+
allow(ProjectInitializer).to receive_messages(:new => project_init)
81+
82+
parser = Parser.new
83+
84+
expect(project_init).to receive(:run).ordered
85+
expect(parser).to receive(:exit).ordered
86+
87+
parser.parse(["--init"])
88+
end
89+
end
90+
6291
describe "-I" do
6392
it "sets the path" do
6493
options = Parser.parse(%w[-I path/to/foo])

0 commit comments

Comments
 (0)