transpec 1.3.1 → 1.4.0
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 +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +1 -3
- data/CHANGELOG.md +9 -0
- data/README.md +141 -24
- data/README.md.erb +136 -24
- data/lib/transpec/ast/node.rb +7 -3
- data/lib/transpec/cli.rb +1 -1
- data/lib/transpec/configuration.rb +1 -0
- data/lib/transpec/converter.rb +31 -2
- data/lib/transpec/dynamic_analyzer.rb +1 -1
- data/lib/transpec/option_parser.rb +12 -9
- data/lib/transpec/project.rb +23 -12
- data/lib/transpec/rspec_version.rb +18 -4
- data/lib/transpec/static_context_inspector.rb +0 -15
- data/lib/transpec/syntax/example.rb +83 -0
- data/lib/transpec/syntax/expect.rb +5 -0
- data/lib/transpec/syntax/have.rb +111 -54
- data/lib/transpec/syntax/method_stub.rb +58 -37
- data/lib/transpec/syntax/mixin/allow_no_message.rb +2 -0
- data/lib/transpec/syntax/mixin/any_instance.rb +2 -0
- data/lib/transpec/syntax/mixin/should_base.rb +39 -0
- data/lib/transpec/syntax/oneliner_should.rb +218 -0
- data/lib/transpec/syntax/operator_matcher.rb +1 -0
- data/lib/transpec/syntax/should.rb +3 -30
- data/lib/transpec/util.rb +54 -0
- data/lib/transpec/version.rb +2 -2
- data/spec/support/shared_context.rb +21 -29
- data/spec/transpec/ast/node_spec.rb +1 -1
- data/spec/transpec/commit_message_spec.rb +29 -23
- data/spec/transpec/configuration_spec.rb +1 -0
- data/spec/transpec/converter_spec.rb +208 -5
- data/spec/transpec/dynamic_analyzer_spec.rb +2 -2
- data/spec/transpec/option_parser_spec.rb +1 -0
- data/spec/transpec/project_spec.rb +10 -0
- data/spec/transpec/rspec_version_spec.rb +52 -28
- data/spec/transpec/static_context_inspector_spec.rb +2 -2
- data/spec/transpec/syntax/be_boolean_spec.rb +6 -13
- data/spec/transpec/syntax/be_close_spec.rb +2 -9
- data/spec/transpec/syntax/double_spec.rb +2 -9
- data/spec/transpec/syntax/example_spec.rb +249 -0
- data/spec/transpec/syntax/expect_spec.rb +1 -1
- data/spec/transpec/syntax/have_spec.rb +127 -22
- data/spec/transpec/syntax/its_spec.rb +9 -18
- data/spec/transpec/syntax/method_stub_spec.rb +193 -158
- data/spec/transpec/syntax/oneliner_should_spec.rb +653 -0
- data/spec/transpec/syntax/operator_matcher_spec.rb +7 -8
- data/spec/transpec/syntax/raise_error_spec.rb +6 -13
- data/spec/transpec/syntax/rspec_configure_spec.rb +1 -8
- data/spec/transpec/syntax/should_receive_spec.rb +19 -28
- data/spec/transpec/syntax/should_spec.rb +18 -16
- data/spec/transpec/util_spec.rb +30 -0
- data/transpec.gemspec +8 -7
- metadata +49 -28
data/lib/transpec/util.rb
CHANGED
@@ -2,12 +2,29 @@
|
|
2
2
|
|
3
3
|
module Transpec
|
4
4
|
module Util
|
5
|
+
EXAMPLE_GROUP_METHODS = %w(
|
6
|
+
describe context
|
7
|
+
shared_examples shared_context share_examples_for shared_examples_for
|
8
|
+
).map(&:to_sym).freeze
|
9
|
+
|
10
|
+
EXAMPLE_METHODS = %w(
|
11
|
+
example it specify
|
12
|
+
focus focused fit
|
13
|
+
pending xexample xit xspecify
|
14
|
+
).map(&:to_sym).freeze
|
15
|
+
|
16
|
+
HOOK_METHODS = %w(before after around).map(&:to_sym).freeze
|
17
|
+
|
18
|
+
HELPER_METHODS = %w(subject subject! let let!).map(&:to_sym).freeze
|
19
|
+
|
5
20
|
LITERAL_TYPES = %w(
|
6
21
|
true false nil
|
7
22
|
int float
|
8
23
|
str sym regexp
|
9
24
|
).map(&:to_sym).freeze
|
10
25
|
|
26
|
+
WHITESPACES = [' ', "\t"].freeze
|
27
|
+
|
11
28
|
module_function
|
12
29
|
|
13
30
|
def proc_literal?(node)
|
@@ -86,5 +103,42 @@ module Transpec
|
|
86
103
|
false
|
87
104
|
end
|
88
105
|
end
|
106
|
+
|
107
|
+
def expand_range_to_adjacent_whitespaces(range, direction = :both)
|
108
|
+
source = range.source_buffer.source
|
109
|
+
begin_pos = if [:both, :begin].include?(direction)
|
110
|
+
find_consecutive_whitespace_position(source, range.begin_pos, :downto)
|
111
|
+
else
|
112
|
+
range.begin_pos
|
113
|
+
end
|
114
|
+
|
115
|
+
end_pos = if [:both, :end].include?(direction)
|
116
|
+
find_consecutive_whitespace_position(source, range.end_pos - 1, :upto) + 1
|
117
|
+
else
|
118
|
+
range.end_pos
|
119
|
+
end
|
120
|
+
|
121
|
+
Parser::Source::Range.new(range.source_buffer, begin_pos, end_pos)
|
122
|
+
end
|
123
|
+
|
124
|
+
def find_consecutive_whitespace_position(source, origin, method)
|
125
|
+
from, to = case method
|
126
|
+
when :upto
|
127
|
+
[origin + 1, source.length - 1]
|
128
|
+
when :downto
|
129
|
+
[origin - 1, 0]
|
130
|
+
else
|
131
|
+
fail "Invalid method #{method}"
|
132
|
+
end
|
133
|
+
|
134
|
+
from.send(method, to).reduce(origin) do |previous_position, position|
|
135
|
+
character = source[position]
|
136
|
+
if WHITESPACES.include?(character)
|
137
|
+
position
|
138
|
+
else
|
139
|
+
return previous_position
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
89
143
|
end
|
90
144
|
end
|
data/lib/transpec/version.rb
CHANGED
@@ -1,30 +1,31 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require 'transpec/dynamic_analyzer'
|
4
|
-
require 'transpec/ast/builder'
|
5
|
-
require 'transpec/syntax/should'
|
6
|
-
require 'transpec/syntax/expect'
|
7
|
-
require 'parser'
|
8
|
-
require 'parser/current'
|
9
|
-
require 'tmpdir'
|
10
|
-
|
11
3
|
# This context requires `source` to be defined with #let.
|
12
4
|
shared_context 'parsed objects' do
|
13
5
|
let(:source_buffer) do
|
6
|
+
require 'parser'
|
14
7
|
buffer = Parser::Source::Buffer.new('(string)')
|
15
8
|
buffer.source = source
|
16
9
|
buffer
|
17
10
|
end
|
18
11
|
|
19
12
|
let(:ast) do
|
13
|
+
require 'transpec/ast/builder'
|
14
|
+
require 'parser/current'
|
20
15
|
builder = Transpec::AST::Builder.new
|
21
16
|
parser = Parser::CurrentRuby.new(builder)
|
22
17
|
parser.parse(source_buffer)
|
23
18
|
end
|
24
19
|
|
25
|
-
let(:source_rewriter)
|
20
|
+
let(:source_rewriter) do
|
21
|
+
require 'parser'
|
22
|
+
Parser::Source::Rewriter.new(source_buffer)
|
23
|
+
end
|
26
24
|
|
27
25
|
let(:rewritten_source) { source_rewriter.process }
|
26
|
+
|
27
|
+
# Include 'dynamic analysis objects' after this context so that this nil will be overridden.
|
28
|
+
let(:runtime_data) { nil }
|
28
29
|
end
|
29
30
|
|
30
31
|
# This context requires `source` to be defined with #let.
|
@@ -34,6 +35,7 @@ shared_context 'dynamic analysis objects' do
|
|
34
35
|
let(:source_path) { 'spec/example_spec.rb' }
|
35
36
|
|
36
37
|
let(:source_buffer) do
|
38
|
+
require 'parser'
|
37
39
|
buffer = Parser::Source::Buffer.new(source_path)
|
38
40
|
buffer.source = source
|
39
41
|
buffer
|
@@ -42,6 +44,8 @@ shared_context 'dynamic analysis objects' do
|
|
42
44
|
runtime_data_cache = {}
|
43
45
|
|
44
46
|
let(:runtime_data) do
|
47
|
+
require 'transpec/dynamic_analyzer'
|
48
|
+
|
45
49
|
if runtime_data_cache[source]
|
46
50
|
runtime_data_cache[source]
|
47
51
|
else
|
@@ -52,30 +56,16 @@ shared_context 'dynamic analysis objects' do
|
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
next unless Transpec::Syntax::Should.target_node?(node)
|
59
|
-
return Transpec::Syntax::Should.new(node, source_rewriter, runtime_data)
|
60
|
-
end
|
61
|
-
|
62
|
-
fail 'No should node is found!'
|
63
|
-
end
|
64
|
-
|
65
|
-
let(:runtime_data) { nil }
|
66
|
-
end
|
67
|
-
|
68
|
-
shared_context 'expect object' do
|
69
|
-
let(:expect_object) do
|
59
|
+
# This context depends on the context 'parsed objects'.
|
60
|
+
shared_context 'syntax object' do |syntax_class, name|
|
61
|
+
let(name) do
|
70
62
|
ast.each_node do |node|
|
71
|
-
next unless
|
72
|
-
return
|
63
|
+
next unless syntax_class.target_node?(node)
|
64
|
+
return syntax_class.new(node, source_rewriter, runtime_data)
|
73
65
|
end
|
74
66
|
|
75
|
-
fail
|
67
|
+
fail "No #{syntax_class.name} node is found!"
|
76
68
|
end
|
77
|
-
|
78
|
-
let(:runtime_data) { nil }
|
79
69
|
end
|
80
70
|
|
81
71
|
shared_context 'isolated environment' do
|
@@ -89,6 +79,8 @@ shared_context 'isolated environment' do
|
|
89
79
|
end
|
90
80
|
|
91
81
|
shared_context 'inside of git repository' do
|
82
|
+
require 'tmpdir'
|
83
|
+
|
92
84
|
around do |example|
|
93
85
|
Dir.mkdir('repo')
|
94
86
|
Dir.chdir('repo') do
|
@@ -26,37 +26,43 @@ module Transpec
|
|
26
26
|
|
27
27
|
let(:lines) { commit_message.to_s.lines.to_a }
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
describe 'first line' do
|
30
|
+
it 'has concise summary' do
|
31
|
+
lines[0].chomp.should == 'Convert specs to the latest RSpec syntax with Transpec'
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
+
describe 'second line' do
|
36
|
+
it 'has blank line' do
|
37
|
+
lines[1].chomp.should be_empty
|
38
|
+
end
|
35
39
|
end
|
36
40
|
|
37
41
|
let(:body_lines) { lines[2..-1] }
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
.
|
42
|
-
|
43
|
-
.
|
44
|
-
|
43
|
+
describe 'body' do
|
44
|
+
it 'has Transpec description at the beginning' do
|
45
|
+
body_lines[0].chomp
|
46
|
+
.should match(/^This conversion is done by Transpec \d+\.\d+\.\d+ with the following command:$/)
|
47
|
+
body_lines[1].chomp
|
48
|
+
.should == ' transpec --force --generate-commit-message'
|
49
|
+
end
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
|
51
|
+
it 'has blank line after the preface' do
|
52
|
+
body_lines[2].chomp.should be_empty
|
53
|
+
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
it 'has conversion summary' do
|
56
|
+
body_lines[3..-1].join('').should == <<-END.gsub(/^\s+\|/, '')
|
57
|
+
|* 2 conversions
|
58
|
+
| from: obj.should
|
59
|
+
| to: expect(obj).to
|
60
|
+
|
|
61
|
+
|* 1 conversion
|
62
|
+
| from: obj.stub(:message)
|
63
|
+
| to: allow(obj).to receive(:message)
|
64
|
+
END
|
65
|
+
end
|
60
66
|
end
|
61
67
|
end
|
62
68
|
end
|
@@ -210,15 +210,179 @@ module Transpec
|
|
210
210
|
end
|
211
211
|
end
|
212
212
|
|
213
|
+
describe '#process_oneliner_should' do
|
214
|
+
let(:should_object) { double('oneliner_should_object').as_null_object }
|
215
|
+
|
216
|
+
shared_examples 'does nothing' do
|
217
|
+
it 'does nothing' do
|
218
|
+
should_object.should_not_receive(:expectize!)
|
219
|
+
should_object.should_not_receive(:convert_have_items_to_standard_should!)
|
220
|
+
should_object.should_not_receive(:convert_have_items_to_standard_expect!)
|
221
|
+
converter.process_oneliner_should(should_object)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
shared_examples 'invokes OnelinerShould#expectize! if available' do
|
226
|
+
context 'when RSpecVersion#one_liner_is_expected_available? returns true' do
|
227
|
+
before { rspec_version.stub(:one_liner_is_expected_available?).and_return(true) }
|
228
|
+
|
229
|
+
it 'invokes OnelinerShould#expectize!' do
|
230
|
+
should_object.should_receive(:expectize!)
|
231
|
+
converter.process_oneliner_should(should_object)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'when RSpecVersion#one_liner_is_expected_available? returns false' do
|
236
|
+
before { rspec_version.stub(:one_liner_is_expected_available?).and_return(false) }
|
237
|
+
include_examples 'does nothing'
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
shared_examples 'converts to standard expecatations' do
|
242
|
+
context 'and Configuration#convert_should? is true' do
|
243
|
+
before { configuration.convert_should = true }
|
244
|
+
|
245
|
+
it 'invokes OnelinerShould#convert_have_items_to_standard_expect!' do
|
246
|
+
should_object.should_receive(:convert_have_items_to_standard_expect!)
|
247
|
+
converter.process_oneliner_should(should_object)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
context 'and Configuration#convert_should? is false' do
|
252
|
+
before { configuration.convert_should = false }
|
253
|
+
|
254
|
+
it 'invokes OnelinerShould#convert_have_items_to_standard_should!' do
|
255
|
+
should_object.should_receive(:convert_have_items_to_standard_should!)
|
256
|
+
converter.process_oneliner_should(should_object)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'when Configuration#convert_oneliner? is true' do
|
262
|
+
before { configuration.convert_oneliner = true }
|
263
|
+
|
264
|
+
context 'and the OnelinerShould has #have matcher' do
|
265
|
+
before do
|
266
|
+
should_object.stub(:have_matcher).and_return(double('have_matcher').as_null_object)
|
267
|
+
end
|
268
|
+
|
269
|
+
context 'and Configuration#convert_have_items? is true' do
|
270
|
+
before { configuration.convert_have_items = true }
|
271
|
+
|
272
|
+
context 'and Have#project_requires_collection_matcher? is true' do
|
273
|
+
before do
|
274
|
+
should_object.have_matcher
|
275
|
+
.stub(:project_requires_collection_matcher?).and_return(true)
|
276
|
+
end
|
277
|
+
include_examples 'invokes OnelinerShould#expectize! if available'
|
278
|
+
end
|
279
|
+
|
280
|
+
context 'and Have#project_requires_collection_matcher? is false' do
|
281
|
+
before do
|
282
|
+
should_object.have_matcher
|
283
|
+
.stub(:project_requires_collection_matcher?).and_return(false)
|
284
|
+
end
|
285
|
+
include_examples 'converts to standard expecatations'
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
context 'and Configuration#convert_have_items? is false' do
|
290
|
+
before { configuration.convert_have_items = false }
|
291
|
+
include_examples 'invokes OnelinerShould#expectize! if available'
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
context 'and the OnelinerShould does not have #have matcher' do
|
296
|
+
before do
|
297
|
+
should_object.stub(:have_matcher).and_return(nil)
|
298
|
+
end
|
299
|
+
|
300
|
+
context 'and Configuration#convert_have_items? is true' do
|
301
|
+
before { configuration.convert_have_items = true }
|
302
|
+
include_examples 'invokes OnelinerShould#expectize! if available'
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'and Configuration#convert_have_items? is false' do
|
306
|
+
before { configuration.convert_have_items = false }
|
307
|
+
include_examples 'invokes OnelinerShould#expectize! if available'
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context 'when Configuration#convert_oneliner? is false' do
|
313
|
+
before { configuration.convert_oneliner = false }
|
314
|
+
|
315
|
+
context 'and the OnelinerShould has #have matcher' do
|
316
|
+
before do
|
317
|
+
should_object.stub(:have_matcher).and_return(double('have_matcher').as_null_object)
|
318
|
+
end
|
319
|
+
|
320
|
+
context 'and Configuration#convert_have_items? is true' do
|
321
|
+
before { configuration.convert_have_items = true }
|
322
|
+
|
323
|
+
context 'and Have#project_requires_collection_matcher? is true' do
|
324
|
+
before do
|
325
|
+
should_object.have_matcher
|
326
|
+
.stub(:project_requires_collection_matcher?).and_return(true)
|
327
|
+
end
|
328
|
+
include_examples 'does nothing'
|
329
|
+
end
|
330
|
+
|
331
|
+
context 'and Have#project_requires_collection_matcher? is false' do
|
332
|
+
before do
|
333
|
+
should_object.have_matcher
|
334
|
+
.stub(:project_requires_collection_matcher?).and_return(false)
|
335
|
+
end
|
336
|
+
include_examples 'converts to standard expecatations'
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
context 'and Configuration#convert_have_items? is false' do
|
341
|
+
before { configuration.convert_have_items = false }
|
342
|
+
include_examples 'does nothing'
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context 'and the OnelinerShould does not have #have matcher' do
|
347
|
+
before do
|
348
|
+
should_object.stub(:have_matcher).and_return(nil)
|
349
|
+
end
|
350
|
+
|
351
|
+
context 'and Configuration#convert_have_items? is true' do
|
352
|
+
before { configuration.convert_have_items = true }
|
353
|
+
include_examples 'does nothing'
|
354
|
+
end
|
355
|
+
|
356
|
+
context 'and Configuration#convert_have_items? is false' do
|
357
|
+
before { configuration.convert_have_items = false }
|
358
|
+
include_examples 'does nothing'
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
213
364
|
describe '#process_expect' do
|
214
365
|
let(:expect_object) { double('expect_object').as_null_object }
|
215
366
|
|
216
367
|
context 'when Configuration#convert_have_items? is true' do
|
217
368
|
before { configuration.convert_have_items = true }
|
218
369
|
|
219
|
-
|
220
|
-
|
221
|
-
|
370
|
+
context 'and Configuration#parenthesize_matcher_arg is true' do
|
371
|
+
before { configuration.parenthesize_matcher_arg = true }
|
372
|
+
|
373
|
+
it 'invokes Have#convert_to_standard_expectation! with true' do
|
374
|
+
expect_object.have_matcher.should_receive(:convert_to_standard_expectation!).with(true)
|
375
|
+
converter.process_expect(expect_object)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
context 'and Configuration#parenthesize_matcher_arg is false' do
|
380
|
+
before { configuration.parenthesize_matcher_arg = false }
|
381
|
+
|
382
|
+
it 'invokes Have#convert_to_standard_expectation! with false' do
|
383
|
+
expect_object.have_matcher.should_receive(:convert_to_standard_expectation!).with(false)
|
384
|
+
converter.process_expect(expect_object)
|
385
|
+
end
|
222
386
|
end
|
223
387
|
end
|
224
388
|
|
@@ -394,8 +558,8 @@ module Transpec
|
|
394
558
|
let(:method_stub_object) { double('method_stub_object').as_null_object }
|
395
559
|
|
396
560
|
shared_examples 'invokes MethodStub#allowize!' do
|
397
|
-
it 'invokes MethodStub#allowize! with
|
398
|
-
method_stub_object.should_receive(:allowize!).with(rspec_version
|
561
|
+
it 'invokes MethodStub#allowize! with RSpecVersion' do
|
562
|
+
method_stub_object.should_receive(:allowize!).with(rspec_version)
|
399
563
|
converter.process_method_stub(method_stub_object)
|
400
564
|
end
|
401
565
|
end
|
@@ -627,6 +791,45 @@ module Transpec
|
|
627
791
|
end
|
628
792
|
end
|
629
793
|
|
794
|
+
describe '#process_example' do
|
795
|
+
let(:example_object) { double('example_object').as_null_object }
|
796
|
+
|
797
|
+
context 'when RSpecVersion#yielded_example_available? returns true' do
|
798
|
+
before { rspec_version.stub(:yielded_example_available?).and_return(true) }
|
799
|
+
|
800
|
+
context 'when Configuration#convert_deprecated_method? is true' do
|
801
|
+
before { configuration.convert_deprecated_method = true }
|
802
|
+
|
803
|
+
it 'invokes Example#convert!' do
|
804
|
+
example_object.should_receive(:convert!)
|
805
|
+
converter.process_example(example_object)
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
context 'when Configuration#convert_deprecated_method? is false' do
|
810
|
+
before { configuration.convert_deprecated_method = false }
|
811
|
+
|
812
|
+
it 'does not invoke Its#convert_to_describe_subject_it!' do
|
813
|
+
example_object.should_not_receive(:convert!)
|
814
|
+
converter.process_example(example_object)
|
815
|
+
end
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
context 'when RSpecVersion#yielded_example_available? returns false' do
|
820
|
+
before { rspec_version.stub(:yielded_example_available?).and_return(false) }
|
821
|
+
|
822
|
+
context 'when Configuration#convert_deprecated_method? is true' do
|
823
|
+
before { configuration.convert_deprecated_method = true }
|
824
|
+
|
825
|
+
it 'does nothing' do
|
826
|
+
example_object.should_not_receive(:convert!)
|
827
|
+
converter.process_example(example_object)
|
828
|
+
end
|
829
|
+
end
|
830
|
+
end
|
831
|
+
end
|
832
|
+
|
630
833
|
describe '#process_rspec_configure' do
|
631
834
|
let(:rspec_configure) { double('rspec_configure').as_null_object }
|
632
835
|
|