Skip to content

Commit abea2f9

Browse files
committed
Raise an exception instead of changing exit code
It think it's louder and clearer that way Also avoid checking coverage and failing after our own test case is finished by disabling exit handler via Test.uninstall And move setup/handling at_exit from Configuration to Test
1 parent fbf9ee0 commit abea2f9

4 files changed

Lines changed: 114 additions & 111 deletions

File tree

lib/openapi_first/test.rb

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Test
88
autoload :Coverage, 'openapi_first/test/coverage'
99
autoload :Methods, 'openapi_first/test/methods'
1010

11+
class CoverageError < Error; end
12+
1113
def self.minitest?(base)
1214
base.include?(::Minitest::Assertions)
1315
rescue NameError
@@ -39,13 +41,30 @@ def self.setup
3941
"OpenapiFirst::Test.setup { |test| test.register('myopenapi.yaml') }"
4042
end
4143

42-
return unless configuration.report_coverage
44+
@exit_handler = method(:handle_exit)
4345

4446
@setup ||= at_exit do
45-
configuration.handle_exit
47+
# :nocov:
48+
@exit_handler&.call
49+
# :nocov:
4650
end
4751
end
4852

53+
def self.handle_exit
54+
return unless configuration.report_coverage
55+
56+
report_coverage(
57+
formatter: configuration.coverage_formatter,
58+
**configuration.coverage_formatter_options
59+
)
60+
return unless configuration.report_coverage == true
61+
62+
coverage = Coverage.result.coverage
63+
return if coverage >= configuration.minimum_coverage
64+
65+
raise OpenapiFirst::Test::CoverageError, 'Not all described requests and responses have been tested.'
66+
end
67+
4968
# Print the coverage report
5069
# @param formatter A formatter to define the report.
5170
# @output [IO] An output where to puts the report.
@@ -87,6 +106,7 @@ def self.uninstall
87106
definitions.clear
88107
@configuration = nil
89108
@installed = nil
109+
@exit_handler = nil
90110
end
91111

92112
class NotRegisteredError < StandardError; end

lib/openapi_first/test/configuration.rb

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,6 @@ def skip_response_coverage_if(&block)
4646

4747
# TODO: Deprecate skip_response_coverage
4848
alias skip_response_coverage skip_response_coverage_if
49-
50-
# This called at_exit
51-
def handle_exit
52-
return unless report_coverage
53-
54-
Test.report_coverage(
55-
formatter: coverage_formatter,
56-
**coverage_formatter_options
57-
)
58-
coverage = Coverage.result.coverage
59-
return if coverage >= minimum_coverage
60-
61-
return unless report_coverage == true
62-
63-
warn 'OpenapiFirst::Test failed with exit 2, because not all described requests/responses have been tested.'
64-
exit 2
65-
end
6649
end
6750
end
6851
end

spec/test/configuration_spec.rb

Lines changed: 4 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,93 +3,9 @@
33
RSpec.describe OpenapiFirst::Test::Configuration do
44
subject(:configuration) { described_class.new }
55

6-
describe '#handle_exit' do
7-
it 'reports coverage and fails' do
8-
expect(OpenapiFirst::Test).to receive(:report_coverage)
9-
expect do
10-
configuration.handle_exit
11-
end.to raise_error(SystemExit)
12-
end
13-
14-
it 'raises an error with invalid option value' do
15-
expect do
16-
configuration.report_coverage = :fatal
17-
end.to raise_error(ArgumentError)
18-
end
19-
20-
context 'with full coverage' do
21-
let(:definition) do
22-
OpenapiFirst.parse(YAML.load(%(
23-
openapi: 3.1.0
24-
info:
25-
title: Dice
26-
version: 1
27-
paths:
28-
"/roll":
29-
post:
30-
responses:
31-
'200':
32-
content:
33-
application/json:
34-
schema:
35-
type: integer
36-
min: 1
37-
max:
38-
)))
39-
end
40-
41-
before do
42-
valid_request = Rack::Request.new(Rack::MockRequest.env_for('/roll', method: 'POST'))
43-
valid_response = Rack::Response[200, { 'content-type' => 'application/json' }, ['1']]
44-
OpenapiFirst::Test.setup { |test| test.register(definition) }
45-
definition.validate_request(valid_request)
46-
definition.validate_response(valid_request, valid_response)
47-
end
48-
49-
it 'reports coverage but does not fail' do
50-
expect(OpenapiFirst::Test).to receive(:report_coverage)
51-
52-
expect do
53-
configuration.handle_exit
54-
end.not_to raise_error(SystemExit)
55-
end
56-
end
57-
58-
context 'with report_coverage = true' do
59-
before do
60-
configuration.report_coverage = true
61-
end
62-
63-
it 'reports coverage' do
64-
expect(OpenapiFirst::Test).to receive(:report_coverage)
65-
expect do
66-
configuration.handle_exit
67-
end.to raise_error(SystemExit)
68-
end
69-
end
70-
71-
context 'with report_coverage = false' do
72-
before do
73-
configuration.report_coverage = false
74-
end
75-
76-
it 'does not report coverage' do
77-
expect(OpenapiFirst::Test).not_to receive(:report_coverage)
78-
79-
configuration.handle_exit
80-
end
81-
end
82-
83-
context 'with report_coverage = :warn' do
84-
before do
85-
configuration.report_coverage = :warn
86-
end
87-
88-
it 'reports coverage, but does not fail' do
89-
expect(OpenapiFirst::Test).to receive(:report_coverage)
90-
91-
configuration.handle_exit
92-
end
93-
end
6+
it 'raises an error with invalid option value' do
7+
expect do
8+
configuration.report_coverage = :fatal
9+
end.to raise_error(ArgumentError)
9410
end
9511
end

spec/test_spec.rb

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
require 'minitest'
44

55
RSpec.describe OpenapiFirst::Test do
6-
before do
7-
described_class.configuration.report_coverage = false
8-
end
9-
106
describe '.minitest?' do
117
it 'detects minitest' do
128
test_case = Class.new(Minitest::Test)
@@ -122,6 +118,94 @@
122118
end
123119
end
124120

121+
describe '#handle_exit' do
122+
let(:configuration) { described_class.configuration }
123+
124+
before do
125+
configuration.report_coverage = true
126+
end
127+
128+
it 'reports coverage and fails' do
129+
expect(OpenapiFirst::Test).to receive(:report_coverage)
130+
expect do
131+
described_class.handle_exit
132+
end.to raise_error(OpenapiFirst::Test::CoverageError)
133+
end
134+
135+
context 'with full coverage' do
136+
let(:definition) do
137+
OpenapiFirst.parse(YAML.load(%(
138+
openapi: 3.1.0
139+
info:
140+
title: Dice
141+
version: 1
142+
paths:
143+
"/roll":
144+
post:
145+
responses:
146+
'200':
147+
content:
148+
application/json:
149+
schema:
150+
type: integer
151+
min: 1
152+
max:
153+
)))
154+
end
155+
156+
before do
157+
valid_request = Rack::Request.new(Rack::MockRequest.env_for('/roll', method: 'POST'))
158+
valid_response = Rack::Response[200, { 'content-type' => 'application/json' }, ['1']]
159+
OpenapiFirst::Test.setup { |test| test.register(definition) }
160+
definition.validate_request(valid_request)
161+
definition.validate_response(valid_request, valid_response)
162+
end
163+
164+
it 'does not fail' do
165+
expect do
166+
described_class.handle_exit
167+
end.not_to raise_error
168+
end
169+
end
170+
171+
context 'with report_coverage = true' do
172+
before do
173+
configuration.report_coverage = true
174+
end
175+
176+
it 'reports coverage' do
177+
expect(OpenapiFirst::Test).to receive(:report_coverage)
178+
expect do
179+
described_class.handle_exit
180+
end.to raise_error(OpenapiFirst::Test::CoverageError)
181+
end
182+
end
183+
184+
context 'with report_coverage = false' do
185+
before do
186+
configuration.report_coverage = false
187+
end
188+
189+
it 'does not report coverage' do
190+
expect(OpenapiFirst::Test).not_to receive(:report_coverage)
191+
192+
described_class.handle_exit
193+
end
194+
end
195+
196+
context 'with report_coverage = :warn' do
197+
before do
198+
configuration.report_coverage = :warn
199+
end
200+
201+
it 'reports coverage, but does not fail' do
202+
expect(OpenapiFirst::Test).to receive(:report_coverage)
203+
204+
described_class.handle_exit
205+
end
206+
end
207+
end
208+
125209
describe '.report_coverage' do
126210
let(:output) { StringIO.new }
127211

0 commit comments

Comments
 (0)