minitest_to_rspec 0.11.0 → 0.12.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 +5 -5
- data/.travis.yml +3 -2
- data/CHANGELOG.md +19 -0
- data/README.md +3 -0
- data/lib/minitest_to_rspec/converter.rb +2 -2
- data/lib/minitest_to_rspec/input/model/base.rb +15 -0
- data/lib/minitest_to_rspec/input/model/call.rb +185 -0
- data/lib/minitest_to_rspec/input/model/defn.rb +37 -0
- data/lib/minitest_to_rspec/input/model/hash_exp.rb +24 -0
- data/lib/minitest_to_rspec/input/model/iter.rb +89 -0
- data/lib/minitest_to_rspec/input/model/klass.rb +102 -0
- data/lib/minitest_to_rspec/input/processor.rb +40 -0
- data/lib/minitest_to_rspec/input/subprocessors/base.rb +91 -0
- data/lib/minitest_to_rspec/input/subprocessors/call.rb +279 -0
- data/lib/minitest_to_rspec/input/subprocessors/defn.rb +64 -0
- data/lib/minitest_to_rspec/input/subprocessors/iter.rb +148 -0
- data/lib/minitest_to_rspec/input/subprocessors/klass.rb +101 -0
- data/lib/minitest_to_rspec/minitest/stub.rb +85 -0
- data/lib/minitest_to_rspec/{expression_builders → rspec}/stub.rb +3 -2
- data/lib/minitest_to_rspec/type.rb +1 -1
- data/lib/minitest_to_rspec/version.rb +1 -1
- metadata +17 -18
- data/lib/minitest_to_rspec/model/base.rb +0 -13
- data/lib/minitest_to_rspec/model/call.rb +0 -165
- data/lib/minitest_to_rspec/model/calls/once.rb +0 -13
- data/lib/minitest_to_rspec/model/calls/twice.rb +0 -13
- data/lib/minitest_to_rspec/model/defn.rb +0 -27
- data/lib/minitest_to_rspec/model/hash_exp.rb +0 -20
- data/lib/minitest_to_rspec/model/iter.rb +0 -79
- data/lib/minitest_to_rspec/model/klass.rb +0 -100
- data/lib/minitest_to_rspec/processor.rb +0 -38
- data/lib/minitest_to_rspec/subprocessors/base.rb +0 -89
- data/lib/minitest_to_rspec/subprocessors/call.rb +0 -391
- data/lib/minitest_to_rspec/subprocessors/defn.rb +0 -49
- data/lib/minitest_to_rspec/subprocessors/iter.rb +0 -138
- data/lib/minitest_to_rspec/subprocessors/klass.rb +0 -99
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module MinitestToRspec
|
6
|
-
module Model
|
7
|
-
# Data object. Represents a `:defn` s-expression.
|
8
|
-
class Defn < Base
|
9
|
-
def initialize(exp)
|
10
|
-
assert_sexp_type(:defn, exp)
|
11
|
-
@exp = exp.dup
|
12
|
-
end
|
13
|
-
|
14
|
-
def body
|
15
|
-
@exp[3..-1]
|
16
|
-
end
|
17
|
-
|
18
|
-
def method_name
|
19
|
-
@exp[1].to_s
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_method?
|
23
|
-
method_name.start_with?('test_')
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MinitestToRspec
|
4
|
-
module Model
|
5
|
-
# Data object. Represents a `:hash` S-expression.
|
6
|
-
class HashExp < Base
|
7
|
-
def initialize(sexp)
|
8
|
-
assert_sexp_type(:hash, sexp)
|
9
|
-
@exp = sexp.dup
|
10
|
-
end
|
11
|
-
|
12
|
-
# A slightly nicer implementation would be:
|
13
|
-
# `@exp[1..-1].each_slice(2).to_h`
|
14
|
-
# but that would require ruby >= 2.1
|
15
|
-
def to_h
|
16
|
-
Hash[@exp[1..-1].each_slice(2).to_a]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module MinitestToRspec
|
6
|
-
module Model
|
7
|
-
# Data object. Represents an `:iter` s-expression.
|
8
|
-
class Iter < Base
|
9
|
-
def initialize(exp)
|
10
|
-
assert_sexp_type(:iter, exp)
|
11
|
-
@exp = exp.dup
|
12
|
-
end
|
13
|
-
|
14
|
-
def [](*args)
|
15
|
-
@exp[*args]
|
16
|
-
end
|
17
|
-
|
18
|
-
def assert_difference?
|
19
|
-
!empty? && Model::Call.assert_difference?(@exp[1])
|
20
|
-
end
|
21
|
-
|
22
|
-
def assert_no_difference?
|
23
|
-
!empty? && Model::Call.assert_no_difference?(@exp[1])
|
24
|
-
end
|
25
|
-
|
26
|
-
def assert_nothing_raised?
|
27
|
-
!empty? && Model::Call.assert_nothing_raised?(@exp[1])
|
28
|
-
end
|
29
|
-
|
30
|
-
def assert_raise?
|
31
|
-
!empty? && Model::Call.assert_raise?(@exp[1])
|
32
|
-
end
|
33
|
-
|
34
|
-
def assert_raises?
|
35
|
-
!empty? && Model::Call.assert_raises?(@exp[1])
|
36
|
-
end
|
37
|
-
|
38
|
-
def block
|
39
|
-
@exp[3]
|
40
|
-
end
|
41
|
-
|
42
|
-
def call
|
43
|
-
@exp[1]
|
44
|
-
end
|
45
|
-
|
46
|
-
# Not to be confused with block arguments.
|
47
|
-
def call_arguments
|
48
|
-
call_obj.arguments
|
49
|
-
end
|
50
|
-
|
51
|
-
def call_obj
|
52
|
-
Model::Call.new(call)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Enumerates children, skipping the base `call` and
|
56
|
-
# starting with the block arguments, then each `:call` in
|
57
|
-
# the block.
|
58
|
-
def each
|
59
|
-
@exp[2..-1].each do |e| yield(e) end
|
60
|
-
end
|
61
|
-
|
62
|
-
def empty?
|
63
|
-
@exp.length == 1 # just the sexp_type
|
64
|
-
end
|
65
|
-
|
66
|
-
def setup?
|
67
|
-
!empty? && Model::Call.method_name?(@exp[1], :setup)
|
68
|
-
end
|
69
|
-
|
70
|
-
def teardown?
|
71
|
-
!empty? && Model::Call.method_name?(@exp[1], :teardown)
|
72
|
-
end
|
73
|
-
|
74
|
-
def sexp
|
75
|
-
@exp
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base'
|
4
|
-
|
5
|
-
module MinitestToRspec
|
6
|
-
module Model
|
7
|
-
# Data object. Represents a `:class` S-expression.
|
8
|
-
class Klass < Base
|
9
|
-
def initialize(exp)
|
10
|
-
assert_sexp_type(:class, exp)
|
11
|
-
@exp = exp.dup
|
12
|
-
assert_valid_name
|
13
|
-
end
|
14
|
-
|
15
|
-
def action_controller_test_case?
|
16
|
-
lineage?(parent, %i[ActionController TestCase])
|
17
|
-
end
|
18
|
-
|
19
|
-
def action_mailer_test_case?
|
20
|
-
lineage?(parent, %i[ActionMailer TestCase])
|
21
|
-
end
|
22
|
-
|
23
|
-
def active_support_test_case?
|
24
|
-
lineage?(parent, %i[ActiveSupport TestCase])
|
25
|
-
end
|
26
|
-
|
27
|
-
# Raise an error if we don't know now to process the name
|
28
|
-
# of this class. Specifically, classes with module-shorthand.
|
29
|
-
def assert_valid_name
|
30
|
-
if name.is_a?(Symbol)
|
31
|
-
# Valid
|
32
|
-
elsif name.respond_to?(:sexp_type) && name.sexp_type == :colon2
|
33
|
-
raise ModuleShorthandError
|
34
|
-
else
|
35
|
-
raise ProcessingError, "Unexpected class expression: #{name}"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def block?
|
40
|
-
!block.empty?
|
41
|
-
end
|
42
|
-
|
43
|
-
def block
|
44
|
-
@_block ||= @exp[3..-1] || []
|
45
|
-
end
|
46
|
-
|
47
|
-
def draper_test_case?
|
48
|
-
lineage?(parent, %i[Draper TestCase])
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns the name of the class. Examples:
|
52
|
-
#
|
53
|
-
# - Banana #=> :Banana
|
54
|
-
# - Fruit::Banana #=> s(:colon2, s(:const, :Fruit), :Banana)
|
55
|
-
#
|
56
|
-
# Note that the latter (module shorthand) is not supported
|
57
|
-
# by MinitestToRspec. See `#assert_valid_name`.
|
58
|
-
#
|
59
|
-
def name
|
60
|
-
@exp[1]
|
61
|
-
end
|
62
|
-
|
63
|
-
# Returns the "inheritance". Examples:
|
64
|
-
#
|
65
|
-
# - Inherit nothing #=> nil
|
66
|
-
# - Inherit Foo #=> s(:const, :Foo)
|
67
|
-
# - Inherit Bar::Foo #=> s(:colon2, s(:const, :Bar), :Foo)
|
68
|
-
#
|
69
|
-
def parent
|
70
|
-
@_parent ||= @exp[2]
|
71
|
-
end
|
72
|
-
|
73
|
-
# Returns true if `@exp` inherits from, e.g. ActiveSupport::TestCase.
|
74
|
-
# TODO: Other test case parent classes.
|
75
|
-
def test_case?
|
76
|
-
return false unless sexp_type?(:colon2, parent)
|
77
|
-
active_support_test_case? ||
|
78
|
-
action_controller_test_case? ||
|
79
|
-
action_mailer_test_case? ||
|
80
|
-
draper_test_case?
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def ancestor_name(exp, index)
|
86
|
-
assert_sexp_type(:colon2, exp)
|
87
|
-
ancestor = exp[index + 1]
|
88
|
-
sexp_type?(:const, ancestor) ? ancestor[1] : ancestor
|
89
|
-
end
|
90
|
-
|
91
|
-
def lineage?(exp, names)
|
92
|
-
assert_sexp_type(:colon2, exp)
|
93
|
-
exp.length == names.length + 1 &&
|
94
|
-
names.each_with_index.all? { |name, ix|
|
95
|
-
name.to_sym == ancestor_name(exp, ix).to_sym
|
96
|
-
}
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ruby_parser'
|
4
|
-
require 'sexp_processor'
|
5
|
-
require_relative 'subprocessors/call'
|
6
|
-
require_relative 'subprocessors/defn'
|
7
|
-
require_relative 'subprocessors/klass'
|
8
|
-
require_relative 'subprocessors/iter'
|
9
|
-
|
10
|
-
module MinitestToRspec
|
11
|
-
# Consumes a `String` of minitest code and returns an S-expression
|
12
|
-
# representing equivalent RSpec code. The main method is `#process`. See
|
13
|
-
# `SexpProcessor` docs for details.
|
14
|
-
class Processor < SexpProcessor
|
15
|
-
def initialize(rails, mocha)
|
16
|
-
super()
|
17
|
-
self.strict = false
|
18
|
-
@mocha = mocha
|
19
|
-
@rails = rails
|
20
|
-
end
|
21
|
-
|
22
|
-
def process_call(exp)
|
23
|
-
Subprocessors::Call.new(exp, @rails, @mocha).process
|
24
|
-
end
|
25
|
-
|
26
|
-
def process_class(exp)
|
27
|
-
Subprocessors::Klass.new(exp, @rails, @mocha).process
|
28
|
-
end
|
29
|
-
|
30
|
-
def process_defn(exp)
|
31
|
-
Subprocessors::Defn.new(exp, @rails, @mocha).process
|
32
|
-
end
|
33
|
-
|
34
|
-
def process_iter(exp)
|
35
|
-
Subprocessors::Iter.new(exp, @rails, @mocha).process
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../sexp_assertions'
|
4
|
-
|
5
|
-
module MinitestToRspec
|
6
|
-
module Subprocessors
|
7
|
-
# Parent class of "sub-processors". There is one sub-processor for each
|
8
|
-
# `sexp_type` that `Processor` knows how to process.
|
9
|
-
#
|
10
|
-
# For example, `Subprocessors::Call` will process an `s(:call, ..)`
|
11
|
-
# expression representing minitest code, and return an S-expression
|
12
|
-
# representing equivalent RSpec code.
|
13
|
-
class Base
|
14
|
-
include SexpAssertions
|
15
|
-
|
16
|
-
def initialize(rails, mocha)
|
17
|
-
@rails = rails
|
18
|
-
@mocha = mocha
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns a s-expression representing an rspec-mocks stub.
|
22
|
-
def allow_to(msg_recipient, matcher, any_instance = false)
|
23
|
-
allow_method = any_instance ? :allow_any_instance_of : :allow
|
24
|
-
target = s(:call, nil, allow_method, msg_recipient)
|
25
|
-
s(:call, target, :to, matcher)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns a s-expression representing an RSpec expectation, i.e. the
|
29
|
-
# combination of an "expectation target" and a matcher.
|
30
|
-
def expect(target, eager, phase, matcher, any_instance)
|
31
|
-
et = expectation_target(target, eager, any_instance)
|
32
|
-
s(:call, et, phase, matcher)
|
33
|
-
end
|
34
|
-
|
35
|
-
def expect_to(matcher, target, eager, any_instance = false)
|
36
|
-
expect(target, eager, :to, matcher, any_instance)
|
37
|
-
end
|
38
|
-
|
39
|
-
def expect_to_not(matcher, target, eager)
|
40
|
-
expect(target, eager, :to_not, matcher, false)
|
41
|
-
end
|
42
|
-
|
43
|
-
# In RSpec, `expect` returns an "expectation target". This
|
44
|
-
# can be based on an expression, as in `expect(1 + 1)` or it
|
45
|
-
# can be based on a block, as in `expect { raise }`. Either
|
46
|
-
# way, it's called an "expectation target".
|
47
|
-
def expectation_target(exp, eager, any_instance)
|
48
|
-
if eager
|
49
|
-
expectation_target_eager(exp, any_instance)
|
50
|
-
else
|
51
|
-
expectation_target_lazy(exp)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def expectation_target_eager(exp, any_instance)
|
56
|
-
expect_method = any_instance ? :expect_any_instance_of : :expect
|
57
|
-
s(:call, nil, expect_method, exp)
|
58
|
-
end
|
59
|
-
|
60
|
-
def expectation_target_lazy(block)
|
61
|
-
s(:iter,
|
62
|
-
s(:call, nil, :expect),
|
63
|
-
0,
|
64
|
-
full_process(block)
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
|
-
# If it's a `Sexp`, run `obj` through a new `Processor`. Otherwise,
|
69
|
-
# return `obj`.
|
70
|
-
#
|
71
|
-
# This is useful for expressions that cannot be fully understood by a
|
72
|
-
# single subprocessor. For example, we must begin processing all :iter
|
73
|
-
# expressions, because some :iter represent calls we're interested in,
|
74
|
-
# e.g. `assert_difference`. However, if the :iter turns out to be
|
75
|
-
# uninteresting (perhaps it has no assertions) we still want to fully
|
76
|
-
# process its sub-expressions.
|
77
|
-
#
|
78
|
-
# TODO: `full_process` may not be the best name.
|
79
|
-
def full_process(obj)
|
80
|
-
obj.is_a?(Sexp) ? Processor.new(@rails, @mocha).process(obj) : obj
|
81
|
-
end
|
82
|
-
|
83
|
-
def matcher(name, *args)
|
84
|
-
exp = s(:call, nil, name)
|
85
|
-
exp.concat(args)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,391 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'minitest_to_rspec/type'
|
4
|
-
require 'minitest_to_rspec/expression_builders/stub'
|
5
|
-
require_relative '../model/call'
|
6
|
-
require_relative '../model/hash_exp'
|
7
|
-
require_relative 'base'
|
8
|
-
|
9
|
-
module MinitestToRspec
|
10
|
-
module Subprocessors
|
11
|
-
# Processes `s(:call, ..)` expressions.
|
12
|
-
class Call < Base
|
13
|
-
# Mocha methods will only be processed if `--mocha` flag was given,
|
14
|
-
# i.e. `mocha` argument in constructor is true.
|
15
|
-
MOCHA_METHODS = %i[
|
16
|
-
expects
|
17
|
-
once
|
18
|
-
returns
|
19
|
-
stub
|
20
|
-
stubs
|
21
|
-
stub_everything
|
22
|
-
twice
|
23
|
-
].freeze
|
24
|
-
|
25
|
-
def initialize(sexp, rails, mocha)
|
26
|
-
super(rails, mocha)
|
27
|
-
@exp = Model::Call.new(sexp)
|
28
|
-
sexp.clear
|
29
|
-
end
|
30
|
-
|
31
|
-
# Given a `Model::Call`, returns a `Sexp`
|
32
|
-
def process
|
33
|
-
if process?
|
34
|
-
send(name_of_processing_method)
|
35
|
-
else
|
36
|
-
@exp.original
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def process?
|
41
|
-
respond_to?(name_of_processing_method, true) &&
|
42
|
-
(@mocha || !MOCHA_METHODS.include?(@exp.method_name))
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
# - msg_rcp. Message recipient. The object to be stubbed.
|
48
|
-
# - msg. Message. The name of the stubbed method.
|
49
|
-
# - ret_vals. Return values.
|
50
|
-
# - any_ins. Any instance? True if this is an `any_instance` stub.
|
51
|
-
# - with. Allowed arguments.
|
52
|
-
def allow_receive_and_return(msg_rcp, msg, ret_vals, any_ins, with)
|
53
|
-
allow_to(
|
54
|
-
msg_rcp,
|
55
|
-
receive_and_return(msg, ret_vals, with),
|
56
|
-
any_ins
|
57
|
-
)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Given `exp`, an S-expression representing an rspec-mocks statement
|
61
|
-
# (expect or allow) apply `ordinal`, which is either `:once` or `:twice`.
|
62
|
-
# This feels like a hack. No other processing "re-opens" an "output
|
63
|
-
# sexp".
|
64
|
-
def apply_expectation_count_to(exp, ordinal)
|
65
|
-
exp[3] = s(:call, exp[3], ordinal)
|
66
|
-
exp
|
67
|
-
end
|
68
|
-
|
69
|
-
def be_falsey
|
70
|
-
matcher(:be_falsey)
|
71
|
-
end
|
72
|
-
|
73
|
-
def be_nil
|
74
|
-
matcher(:be_nil)
|
75
|
-
end
|
76
|
-
|
77
|
-
def be_truthy
|
78
|
-
matcher(:be_truthy)
|
79
|
-
end
|
80
|
-
|
81
|
-
def call_to_question_mark?(exp)
|
82
|
-
sexp_type?(:call, exp) && Model::Call.new(exp).question_mark_method?
|
83
|
-
end
|
84
|
-
|
85
|
-
def eq(exp)
|
86
|
-
matcher(:eq, exp)
|
87
|
-
end
|
88
|
-
|
89
|
-
# - msg_rcp. Message recipient. The object to be stubbed.
|
90
|
-
# - msg. Message. The name of the stubbed method.
|
91
|
-
# - ret_vals. Return values.
|
92
|
-
# - any_ins. Any instance? True if this is an `any_instance` stub.
|
93
|
-
# - with. Allowed arguments.
|
94
|
-
def expect_receive_and_return(msg_rcp, msg, ret_vals, any_ins, with)
|
95
|
-
expect_to(
|
96
|
-
receive_and_return(msg, ret_vals, with),
|
97
|
-
msg_rcp,
|
98
|
-
true,
|
99
|
-
any_ins
|
100
|
-
)
|
101
|
-
end
|
102
|
-
|
103
|
-
# Given a `Sexp` representing a `Hash` of message expectations,
|
104
|
-
# return an array of `Sexp`, each representing an expectation
|
105
|
-
# in rspec-mocks syntax.
|
106
|
-
def hash_to_expectations(sexp, receiver)
|
107
|
-
Model::HashExp.new(sexp).to_h.map { |msg, ret_val|
|
108
|
-
expect_receive_and_return(
|
109
|
-
receiver.deep_clone, msg, wrap_sexp(ret_val), false, []
|
110
|
-
)
|
111
|
-
}
|
112
|
-
end
|
113
|
-
|
114
|
-
def match(pattern)
|
115
|
-
matcher(:match, pattern)
|
116
|
-
end
|
117
|
-
|
118
|
-
def method_assert
|
119
|
-
refsert eq(s(:true)), be_truthy
|
120
|
-
end
|
121
|
-
|
122
|
-
def method_assert_equal
|
123
|
-
expected = @exp.arguments[0]
|
124
|
-
calculated = @exp.arguments[1]
|
125
|
-
expect_to(eq(expected), calculated, true)
|
126
|
-
end
|
127
|
-
|
128
|
-
def method_assert_match
|
129
|
-
pattern = @exp.arguments[0]
|
130
|
-
string = @exp.arguments[1]
|
131
|
-
expect_to(match(pattern), string, true)
|
132
|
-
end
|
133
|
-
|
134
|
-
def method_assert_nil
|
135
|
-
expect_to(be_nil, @exp.arguments[0], true)
|
136
|
-
end
|
137
|
-
|
138
|
-
def method_assert_not_nil
|
139
|
-
expect_to_not(be_nil, @exp.arguments[0], true)
|
140
|
-
end
|
141
|
-
|
142
|
-
def method_assert_not_equal
|
143
|
-
expected = @exp.arguments[0]
|
144
|
-
calculated = @exp.arguments[1]
|
145
|
-
expect_to_not(eq(expected), calculated, true)
|
146
|
-
end
|
147
|
-
|
148
|
-
def method_expects
|
149
|
-
if @exp.num_arguments == 1
|
150
|
-
mocha_expects(@exp)
|
151
|
-
else
|
152
|
-
@exp.original
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def method_once
|
157
|
-
mocha_once(@exp)
|
158
|
-
end
|
159
|
-
|
160
|
-
def method_refute
|
161
|
-
refsert eq(s(:false)), be_falsey
|
162
|
-
end
|
163
|
-
|
164
|
-
def method_refute_equal
|
165
|
-
unexpected = @exp.arguments[0]
|
166
|
-
calculated = @exp.arguments[1]
|
167
|
-
expect_to_not(eq(unexpected), calculated, true)
|
168
|
-
end
|
169
|
-
|
170
|
-
# Processes an entire line of code that ends in `.returns`
|
171
|
-
def method_returns
|
172
|
-
receiver = mocha_stub_receiver(@exp)
|
173
|
-
any_instance = rspec_any_instance?(@exp)
|
174
|
-
message_call = mocha_stub_expects(@exp)
|
175
|
-
message = message_call.arguments.first
|
176
|
-
with = mocha_stub_with(@exp)
|
177
|
-
returns = @exp.arguments.first
|
178
|
-
count = message_call.method_name == :expects ? 1 : nil
|
179
|
-
ExpressionBuilders::Stub.new(
|
180
|
-
receiver, any_instance, message, with, returns, count
|
181
|
-
).to_rspec_exp
|
182
|
-
rescue StandardError
|
183
|
-
# TODO: We used to have an `UnknownVariant` error.
|
184
|
-
# That was nice and specific.
|
185
|
-
@exp.original
|
186
|
-
end
|
187
|
-
|
188
|
-
def method_require
|
189
|
-
if @exp.require_test_helper?
|
190
|
-
require_spec_helper
|
191
|
-
else
|
192
|
-
@exp.original
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def method_should
|
197
|
-
s(:call, nil, :it, *@exp.arguments)
|
198
|
-
end
|
199
|
-
|
200
|
-
# Happily, the no-block signatures of [stub][3] are the
|
201
|
-
# same as [double][2].
|
202
|
-
#
|
203
|
-
# - (name)
|
204
|
-
# - (stubs)
|
205
|
-
# - (name, stubs)
|
206
|
-
|
207
|
-
def method_stub
|
208
|
-
mocha_stub(@exp)
|
209
|
-
end
|
210
|
-
|
211
|
-
# [stub_everything][1] responds to all messages with nil.
|
212
|
-
# [double.as_null_object][4] responds with self. Not a
|
213
|
-
# drop-in replacement, but will work in many situations.
|
214
|
-
# RSpec doesn't provide an equivalent to `stub_everything`,
|
215
|
-
# AFAIK.
|
216
|
-
|
217
|
-
def method_stub_everything
|
218
|
-
if @exp.receiver.nil?
|
219
|
-
d = s(:call, nil, :double, *@exp.arguments)
|
220
|
-
s(:call, d, :as_null_object)
|
221
|
-
else
|
222
|
-
@exp.original
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def method_test
|
227
|
-
s(:call, nil, :it, *@exp.arguments)
|
228
|
-
end
|
229
|
-
|
230
|
-
def method_twice
|
231
|
-
mocha_twice(@exp)
|
232
|
-
end
|
233
|
-
|
234
|
-
def mocha_expects(exp)
|
235
|
-
raise ArgumentError unless exp.is_a?(Model::Call)
|
236
|
-
arg = exp.arguments.first
|
237
|
-
if sexp_type?(:hash, arg)
|
238
|
-
mocha_expects_hash(exp, arg)
|
239
|
-
elsif sexp_type?(:lit, arg)
|
240
|
-
mocha_expects_lit(exp, arg)
|
241
|
-
else
|
242
|
-
exp.original
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
def mocha_expects_hash(exp, hash_sexp)
|
247
|
-
assert_sexp_type(:hash, hash_sexp)
|
248
|
-
pointless_lambda(hash_to_expectations(hash_sexp, exp.receiver))
|
249
|
-
end
|
250
|
-
|
251
|
-
def mocha_expects_lit(exp, lit_sexp)
|
252
|
-
assert_sexp_type(:lit, lit_sexp)
|
253
|
-
expect_to(receive_and_call_original(lit_sexp), exp.receiver, true)
|
254
|
-
end
|
255
|
-
|
256
|
-
# TODO: add support for
|
257
|
-
# - at_least
|
258
|
-
# - at_least_once
|
259
|
-
# - at_most
|
260
|
-
# - at_most_once
|
261
|
-
# - never
|
262
|
-
def mocha_expectation_count(exp, count)
|
263
|
-
Type.assert(Model::Call, exp)
|
264
|
-
Type.assert(Integer, count)
|
265
|
-
receiver = mocha_stub_receiver(exp)
|
266
|
-
any_instance = rspec_any_instance?(exp)
|
267
|
-
message = mocha_stub_expects(exp).arguments.first
|
268
|
-
with = mocha_stub_with(exp)
|
269
|
-
returns = exp.find_call_in_receiver_chain(:returns)&.arguments&.first
|
270
|
-
ExpressionBuilders::Stub.new(
|
271
|
-
receiver, any_instance, message, with, returns, count
|
272
|
-
).to_rspec_exp
|
273
|
-
end
|
274
|
-
|
275
|
-
# Given a mocha stub, e.g. `X.any_instance.expects(:y)`, returns `X`.
|
276
|
-
def mocha_stub_receiver(exp)
|
277
|
-
chain = exp.receiver_chain
|
278
|
-
last = chain[-1]
|
279
|
-
last.nil? ? chain[-2] : last
|
280
|
-
end
|
281
|
-
|
282
|
-
# Given an `exp` representing a chain of calls, like
|
283
|
-
# `stubs(x).returns(y).once`, finds the call to `stubs` or `expects`.
|
284
|
-
def mocha_stub_expects(exp)
|
285
|
-
exp.find_call_in_receiver_chain(%i[stubs expects])
|
286
|
-
end
|
287
|
-
|
288
|
-
def mocha_stub_with(exp)
|
289
|
-
exp.find_call_in_receiver_chain(:with)&.arguments&.first
|
290
|
-
end
|
291
|
-
|
292
|
-
def rspec_any_instance?(exp)
|
293
|
-
exp.calls_in_receiver_chain.any? { |i|
|
294
|
-
i.method_name.to_s.include?('any_instance')
|
295
|
-
}
|
296
|
-
end
|
297
|
-
|
298
|
-
def mocha_once(exp)
|
299
|
-
mocha_expectation_count(exp, 1)
|
300
|
-
end
|
301
|
-
|
302
|
-
def mocha_stub(exp)
|
303
|
-
raise ArgumentError unless exp.is_a?(Model::Call)
|
304
|
-
if exp.receiver.nil?
|
305
|
-
s(:call, nil, :double, *exp.arguments)
|
306
|
-
else
|
307
|
-
exp.original
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
def mocha_twice(exp)
|
312
|
-
mocha_expectation_count(exp, 2)
|
313
|
-
end
|
314
|
-
|
315
|
-
def name_of_processing_method
|
316
|
-
"method_#{@exp.method_name}".to_sym
|
317
|
-
end
|
318
|
-
|
319
|
-
# Given `array_of_calls`, returns a `Sexp` representing a
|
320
|
-
# self-executing lambda.
|
321
|
-
#
|
322
|
-
# This works around the fact that `sexp_processor` expects us to return
|
323
|
-
# a single `Sexp`, not an array of `Sexp`. We also can't return a
|
324
|
-
# `:block`, or else certain input would produce nested blocks (e.g.
|
325
|
-
# `s(:block, s(:block, ..))`) which `ruby2ruby` (naturally) does not know
|
326
|
-
# how to process. So, the easiest solution I could think of is a
|
327
|
-
# self-executing lambda.
|
328
|
-
#
|
329
|
-
# Currently, the only `:call` which we process into multiple calls is
|
330
|
-
# the hash form of a mocha `#expects`, thankfully uncommon.
|
331
|
-
#
|
332
|
-
# To get better output (without a pointless lambda) we would have to
|
333
|
-
# process `:block` *and* `:defn`, which we are not yet doing.
|
334
|
-
|
335
|
-
def pointless_lambda(array_of_calls)
|
336
|
-
assert_sexp_type_array(:call, array_of_calls)
|
337
|
-
s(:call,
|
338
|
-
s(:iter,
|
339
|
-
s(:call, nil, :lambda),
|
340
|
-
0,
|
341
|
-
s(:block,
|
342
|
-
s(:str, 'Sorry for the pointless lambda here.'),
|
343
|
-
*array_of_calls
|
344
|
-
)
|
345
|
-
),
|
346
|
-
:call
|
347
|
-
)
|
348
|
-
end
|
349
|
-
|
350
|
-
def receive(message, with = [])
|
351
|
-
r = s(:call, nil, :receive, message)
|
352
|
-
if with.empty?
|
353
|
-
r
|
354
|
-
else
|
355
|
-
s(:call, r, :with, *with)
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
def receive_and_call_original(message)
|
360
|
-
s(:call, s(:call, nil, :receive, message), :and_call_original)
|
361
|
-
end
|
362
|
-
|
363
|
-
def receive_and_return(message, return_values, with = [])
|
364
|
-
s(:call, receive(message, with), :and_return, *return_values)
|
365
|
-
end
|
366
|
-
|
367
|
-
# `refsert` - Code shared by refute and assert. I could also have gone
|
368
|
-
# with `assfute`. Wooo .. time for bed.
|
369
|
-
def refsert(exact, fuzzy)
|
370
|
-
actual = @exp.arguments[0]
|
371
|
-
matcher = call_to_question_mark?(actual) ? exact : fuzzy
|
372
|
-
expect_to(matcher, actual, true)
|
373
|
-
end
|
374
|
-
|
375
|
-
def require_spec_helper
|
376
|
-
prefix = @rails ? 'rails' : 'spec'
|
377
|
-
s(:call, nil, :require, s(:str, "#{prefix}_helper"))
|
378
|
-
end
|
379
|
-
|
380
|
-
# Wraps `obj` in an `Array` if it is a `Sexp`
|
381
|
-
def wrap_sexp(obj)
|
382
|
-
obj.is_a?(Sexp) ? [obj] : obj
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
end
|
387
|
-
|
388
|
-
# [1]: http://bit.ly/1yll6ND
|
389
|
-
# [2]: http://bit.ly/1CRdmP3
|
390
|
-
# [3]: http://bit.ly/1aY2mJN
|
391
|
-
# [4]: http://bit.ly/1OtwDOY
|