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.
Files changed (36) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +3 -2
  3. data/CHANGELOG.md +19 -0
  4. data/README.md +3 -0
  5. data/lib/minitest_to_rspec/converter.rb +2 -2
  6. data/lib/minitest_to_rspec/input/model/base.rb +15 -0
  7. data/lib/minitest_to_rspec/input/model/call.rb +185 -0
  8. data/lib/minitest_to_rspec/input/model/defn.rb +37 -0
  9. data/lib/minitest_to_rspec/input/model/hash_exp.rb +24 -0
  10. data/lib/minitest_to_rspec/input/model/iter.rb +89 -0
  11. data/lib/minitest_to_rspec/input/model/klass.rb +102 -0
  12. data/lib/minitest_to_rspec/input/processor.rb +40 -0
  13. data/lib/minitest_to_rspec/input/subprocessors/base.rb +91 -0
  14. data/lib/minitest_to_rspec/input/subprocessors/call.rb +279 -0
  15. data/lib/minitest_to_rspec/input/subprocessors/defn.rb +64 -0
  16. data/lib/minitest_to_rspec/input/subprocessors/iter.rb +148 -0
  17. data/lib/minitest_to_rspec/input/subprocessors/klass.rb +101 -0
  18. data/lib/minitest_to_rspec/minitest/stub.rb +85 -0
  19. data/lib/minitest_to_rspec/{expression_builders → rspec}/stub.rb +3 -2
  20. data/lib/minitest_to_rspec/type.rb +1 -1
  21. data/lib/minitest_to_rspec/version.rb +1 -1
  22. metadata +17 -18
  23. data/lib/minitest_to_rspec/model/base.rb +0 -13
  24. data/lib/minitest_to_rspec/model/call.rb +0 -165
  25. data/lib/minitest_to_rspec/model/calls/once.rb +0 -13
  26. data/lib/minitest_to_rspec/model/calls/twice.rb +0 -13
  27. data/lib/minitest_to_rspec/model/defn.rb +0 -27
  28. data/lib/minitest_to_rspec/model/hash_exp.rb +0 -20
  29. data/lib/minitest_to_rspec/model/iter.rb +0 -79
  30. data/lib/minitest_to_rspec/model/klass.rb +0 -100
  31. data/lib/minitest_to_rspec/processor.rb +0 -38
  32. data/lib/minitest_to_rspec/subprocessors/base.rb +0 -89
  33. data/lib/minitest_to_rspec/subprocessors/call.rb +0 -391
  34. data/lib/minitest_to_rspec/subprocessors/defn.rb +0 -49
  35. data/lib/minitest_to_rspec/subprocessors/iter.rb +0 -138
  36. data/lib/minitest_to_rspec/subprocessors/klass.rb +0 -99
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_to_rspec/input/subprocessors/base'
4
+ require 'minitest_to_rspec/input/model/iter'
5
+
6
+ module MinitestToRspec
7
+ module Input
8
+ module Subprocessors
9
+ # Processes `s(:iter, ..)` expressions.
10
+ class Iter < Base
11
+ def initialize(sexp, rails, mocha)
12
+ super(rails, mocha)
13
+ @exp = Model::Iter.new(sexp)
14
+ sexp.clear
15
+ end
16
+
17
+ def process
18
+ process_exp(@exp)
19
+ end
20
+
21
+ private
22
+
23
+ # Returns an expression representing an RSpec `change {}`
24
+ # matcher. See also `change_by` below.
25
+ def change(exp)
26
+ matcher_with_block(:change, exp)
27
+ end
28
+
29
+ # Returns an expression representing an RSpec `change {}.by()` matcher.
30
+ def change_by(diff_exp, by_exp)
31
+ s(:call,
32
+ change(diff_exp),
33
+ :by,
34
+ by_exp
35
+ )
36
+ end
37
+
38
+ def matcher_with_block(matcher_name, block)
39
+ s(:iter,
40
+ s(:call, nil, matcher_name),
41
+ 0,
42
+ block
43
+ )
44
+ end
45
+
46
+ def method_assert_difference(exp)
47
+ call = exp[1]
48
+ block = exp[3]
49
+ by = call[4]
50
+ what = parse(call[3][1])
51
+ matcher = by.nil? ? change(what) : change_by(what, by)
52
+ expect_to(matcher, block, false)
53
+ end
54
+
55
+ def method_assert_no_difference(exp)
56
+ call = exp[1]
57
+ block = exp[3]
58
+ what = parse(call[3][1])
59
+ expect_to_not(change(what), block, false)
60
+ end
61
+
62
+ def method_assert_nothing_raised(exp)
63
+ block = exp[3]
64
+ expect_to_not(raise_error, block, false)
65
+ end
66
+
67
+ def method_assert_raise(iter)
68
+ method_assert_raises(iter)
69
+ end
70
+
71
+ def method_assert_raises(iter)
72
+ expect_to(raise_error(*iter.call_arguments), iter.block, false)
73
+ end
74
+
75
+ def method_refute_raise(iter)
76
+ method_refute_raises(iter)
77
+ end
78
+
79
+ def method_refute_raises(iter)
80
+ expect_to_not(raise_error(*iter.call_arguments), iter.block, false)
81
+ end
82
+
83
+ def method_setup(exp)
84
+ replace_method_name(exp, :before)
85
+ end
86
+
87
+ def method_teardown(exp)
88
+ replace_method_name(exp, :after)
89
+ end
90
+
91
+ def name_of_processing_method(iter)
92
+ method_name = iter[1][2]
93
+ "method_#{method_name}".to_sym
94
+ end
95
+
96
+ def parse(str)
97
+ RubyParser.new.parse(str)
98
+ end
99
+
100
+ # Given a `Model::Iter`, returns a `Sexp`
101
+ def process_exp(exp)
102
+ if processable?(exp)
103
+ send_to_processing_method(exp)
104
+ else
105
+ process_uninteresting_iter(exp.sexp)
106
+ end
107
+ end
108
+
109
+ def processable?(iter)
110
+ if !iter.empty? && iter[1].sexp_type == :call
111
+ method_name = iter[1][2]
112
+ decision = "#{method_name}?".to_sym
113
+ iter.respond_to?(decision) && iter.public_send(decision)
114
+ else
115
+ false
116
+ end
117
+ end
118
+
119
+ def process_uninteresting_iter(exp)
120
+ iter = s(exp.shift)
121
+ until exp.empty?
122
+ iter << full_process(exp.shift)
123
+ end
124
+ iter
125
+ end
126
+
127
+ # Given `args` which came from an `assert_raise` or an
128
+ # `assert_raises`, return a `raise_error` matcher.
129
+ # When the last argument is a string, it represents the
130
+ # assertion failure message, and is discarded.
131
+ def raise_error(*args)
132
+ args.pop if !args.empty? && args.last.sexp_type == :str
133
+ matcher(:raise_error, *args)
134
+ end
135
+
136
+ def replace_method_name(exp, new_method)
137
+ iter = s(:iter, s(:call, nil, new_method))
138
+ exp.each do |e| iter << full_process(e) end
139
+ iter
140
+ end
141
+
142
+ def send_to_processing_method(exp)
143
+ send(name_of_processing_method(exp), exp)
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_to_rspec/errors'
4
+ require 'minitest_to_rspec/input/model/klass'
5
+ require 'minitest_to_rspec/input/subprocessors/base'
6
+
7
+ module MinitestToRspec
8
+ module Input
9
+ module Subprocessors
10
+ # Processes `s(:class, ..)` expressions.
11
+ class Klass < Base
12
+ # Takes `sexp`, a `:class` s-expression, and `rails`, a
13
+ # boolean indicating that `rspec-rails` conventions (like
14
+ # `:type` metadata) should be used.
15
+ def initialize(sexp, rails, mocha)
16
+ super(rails, mocha)
17
+ @exp = Model::Klass.new(sexp)
18
+ sexp.clear
19
+ end
20
+
21
+ def process
22
+ sexp = head
23
+ ebk = @exp.block
24
+ if ebk.length > 1
25
+ sexp << block
26
+ elsif ebk.length == 1
27
+ sexp << full_process(ebk[0])
28
+ end
29
+ sexp
30
+ end
31
+
32
+ private
33
+
34
+ # Returns a :block S-expression, the contents of the class.
35
+ def block
36
+ processed = @exp.block.map { |line| full_process(line) }
37
+ s(:block, *processed)
38
+ end
39
+
40
+ # Given a `test_class_name` like `BananaTest`, returns the
41
+ # described class, like `Banana`.
42
+ def described_class(test_class_name)
43
+ test_class_name.to_s.gsub(/Test\Z/, '').to_sym
44
+ end
45
+
46
+ # Returns the head of the output Sexp. If it's a test case,
47
+ # an :iter representing an `RSpec.describe`. Otherwise, a :class.
48
+ def head
49
+ if @exp.test_case?
50
+ rspec_describe_block
51
+ else
52
+ s(:class, @exp.name, @exp.parent)
53
+ end
54
+ end
55
+
56
+ # Returns an S-expression representing the
57
+ # RDM (RSpec Describe Metadata) hash
58
+ def rdm
59
+ s(:hash, s(:lit, :type), s(:lit, rdm_type))
60
+ end
61
+
62
+ # Returns the RDM (RSpec Describe Metadata) type.
63
+ #
64
+ # > Model specs: type: :model
65
+ # > Controller specs: type: :controller
66
+ # > Request specs: type: :request
67
+ # > Feature specs: type: :feature
68
+ # > View specs: type: :view
69
+ # > Helper specs: type: :helper
70
+ # > Mailer specs: type: :mailer
71
+ # > Routing specs: type: :routing
72
+ # > http://bit.ly/1G5w7CJ
73
+ #
74
+ # TODO: Obviously, they're not all supported yet.
75
+ def rdm_type
76
+ if @exp.action_controller_test_case?
77
+ :controller
78
+ elsif @exp.draper_test_case?
79
+ :decorator
80
+ elsif @exp.action_mailer_test_case?
81
+ :mailer
82
+ else
83
+ :model
84
+ end
85
+ end
86
+
87
+ def rspec_describe
88
+ const = s(:const, described_class(@exp.name))
89
+ call = s(:call, s(:const, :RSpec), :describe, const)
90
+ call << rdm if @rails
91
+ call
92
+ end
93
+
94
+ # Returns a S-expression representing a call to RSpec.describe
95
+ def rspec_describe_block
96
+ s(:iter, rspec_describe, 0)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_to_rspec/errors'
4
+ require 'minitest_to_rspec/type'
5
+ require 'minitest_to_rspec/input/model/call'
6
+
7
+ module MinitestToRspec
8
+ module Minitest
9
+ # Represents an `expects` or a `stubs` from mocha.
10
+ # Conceptually the same as `Rspec::Stub`.
11
+ class Stub
12
+ def initialize(call)
13
+ Type.assert(Input::Model::Call, call)
14
+ @call = call
15
+ end
16
+
17
+ # Given e.g. `X.any_instance.expects(:y)`, returns `X`.
18
+ def receiver
19
+ chain = @call.receiver_chain
20
+ last = chain[-1]
21
+ last.nil? ? chain[-2] : last
22
+ end
23
+
24
+ # Returns true if we are stubbing any instance of `receiver`.
25
+ def any_instance?
26
+ @call.calls_in_receiver_chain.any? { |i|
27
+ i.method_name.to_s.include?('any_instance')
28
+ }
29
+ end
30
+
31
+ # Given e.g. `expects(:y)`, returns `:y`.
32
+ def message
33
+ case @call.method_name
34
+ when :expects, :stubs
35
+ @call.arguments.first
36
+ else
37
+ call = the_call_to_stubs_or_expects
38
+ if call.nil?
39
+ raise UnknownVariant, 'not a mocha stub, no stubs/expects'
40
+ else
41
+ call.arguments.first
42
+ end
43
+ end
44
+ end
45
+
46
+ def with
47
+ @call.find_call_in_receiver_chain(:with)&.arguments&.first
48
+ end
49
+
50
+ def returns
51
+ case @call.method_name
52
+ when :returns
53
+ @call.arguments.first
54
+ else
55
+ @call.find_call_in_receiver_chain(:returns)&.arguments&.first
56
+ end
57
+ end
58
+
59
+ # TODO: add support for
60
+ # - at_least
61
+ # - at_least_once
62
+ # - at_most
63
+ # - at_most_once
64
+ # - never
65
+ def count
66
+ case @call.method_name
67
+ when :expects, :once
68
+ 1
69
+ when :returns
70
+ the_call_to_stubs_or_expects.method_name == :expects ? 1 : nil
71
+ when :twice
72
+ 2
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ # Given an `exp` representing a chain of calls, like
79
+ # `stubs(x).returns(y).once`, finds the call to `stubs` or `expects`.
80
+ def the_call_to_stubs_or_expects
81
+ @call.find_call_in_receiver_chain(%i[stubs expects])
82
+ end
83
+ end
84
+ end
85
+ end
@@ -3,8 +3,9 @@
3
3
  require 'minitest_to_rspec/type'
4
4
 
5
5
  module MinitestToRspec
6
- module ExpressionBuilders
7
- # Represents an `expects` or a `stubs`
6
+ module Rspec
7
+ # Represents a `receive` matcher from RSpec.
8
+ # Conceptually the same as `Minitest::Stub`.
8
9
  class Stub
9
10
  def initialize(receiver, any_instance, message, with, returns, count)
10
11
  Type.assert(Sexp, receiver)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MinitestToRspec
4
- # Runtime type assertion function.
4
+ # Runtime type assertions.
5
5
  module Type
6
6
  class << self
7
7
  def assert(types, value)
@@ -2,7 +2,7 @@
2
2
 
3
3
  #:nodoc:
4
4
  module MinitestToRspec
5
- VERSION = '0.11.0'
5
+ VERSION = '0.12.0'
6
6
 
7
7
  def self.gem_version
8
8
  ::Gem::Version.new(VERSION)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest_to_rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared Beck
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-10 00:00:00.000000000 Z
11
+ date: 2018-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby2ruby
@@ -151,22 +151,21 @@ files:
151
151
  - lib/minitest_to_rspec/cli.rb
152
152
  - lib/minitest_to_rspec/converter.rb
153
153
  - lib/minitest_to_rspec/errors.rb
154
- - lib/minitest_to_rspec/expression_builders/stub.rb
155
- - lib/minitest_to_rspec/model/base.rb
156
- - lib/minitest_to_rspec/model/call.rb
157
- - lib/minitest_to_rspec/model/calls/once.rb
158
- - lib/minitest_to_rspec/model/calls/twice.rb
159
- - lib/minitest_to_rspec/model/defn.rb
160
- - lib/minitest_to_rspec/model/hash_exp.rb
161
- - lib/minitest_to_rspec/model/iter.rb
162
- - lib/minitest_to_rspec/model/klass.rb
163
- - lib/minitest_to_rspec/processor.rb
154
+ - lib/minitest_to_rspec/input/model/base.rb
155
+ - lib/minitest_to_rspec/input/model/call.rb
156
+ - lib/minitest_to_rspec/input/model/defn.rb
157
+ - lib/minitest_to_rspec/input/model/hash_exp.rb
158
+ - lib/minitest_to_rspec/input/model/iter.rb
159
+ - lib/minitest_to_rspec/input/model/klass.rb
160
+ - lib/minitest_to_rspec/input/processor.rb
161
+ - lib/minitest_to_rspec/input/subprocessors/base.rb
162
+ - lib/minitest_to_rspec/input/subprocessors/call.rb
163
+ - lib/minitest_to_rspec/input/subprocessors/defn.rb
164
+ - lib/minitest_to_rspec/input/subprocessors/iter.rb
165
+ - lib/minitest_to_rspec/input/subprocessors/klass.rb
166
+ - lib/minitest_to_rspec/minitest/stub.rb
167
+ - lib/minitest_to_rspec/rspec/stub.rb
164
168
  - lib/minitest_to_rspec/sexp_assertions.rb
165
- - lib/minitest_to_rspec/subprocessors/base.rb
166
- - lib/minitest_to_rspec/subprocessors/call.rb
167
- - lib/minitest_to_rspec/subprocessors/defn.rb
168
- - lib/minitest_to_rspec/subprocessors/iter.rb
169
- - lib/minitest_to_rspec/subprocessors/klass.rb
170
169
  - lib/minitest_to_rspec/type.rb
171
170
  - lib/minitest_to_rspec/version.rb
172
171
  - minitest_to_rspec.gemspec
@@ -190,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
189
  version: '0'
191
190
  requirements: []
192
191
  rubyforge_project:
193
- rubygems_version: 2.6.14
192
+ rubygems_version: 2.7.6
194
193
  signing_key:
195
194
  specification_version: 4
196
195
  summary: Converts minitest files to rspec
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../sexp_assertions'
4
-
5
- module MinitestToRspec
6
- module Model
7
- # Classes inheriting `Base` are simple data objects
8
- # representing the S-expressions they are named after.
9
- class Base
10
- include SexpAssertions
11
- end
12
- end
13
- end
@@ -1,165 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base'
4
-
5
- module MinitestToRspec
6
- module Model
7
- # Data object. Represents a `:call` s-expression.
8
- class Call < Base
9
- attr_reader :original
10
-
11
- def initialize(exp)
12
- assert_sexp_type(:call, exp)
13
- @exp = exp.dup
14
- @original = exp.dup
15
- end
16
-
17
- class << self
18
- def assert_difference?(exp)
19
- exp.sexp_type == :call && new(exp).assert_difference?
20
- end
21
-
22
- def assert_no_difference?(exp)
23
- exp.sexp_type == :call && new(exp).assert_no_difference?
24
- end
25
-
26
- def assert_nothing_raised?(exp)
27
- exp.sexp_type == :call && new(exp).assert_nothing_raised?
28
- end
29
-
30
- def assert_raise?(exp)
31
- exp.sexp_type == :call && new(exp).assert_raise?
32
- end
33
-
34
- def assert_raises?(exp)
35
- exp.sexp_type == :call && new(exp).assert_raises?
36
- end
37
-
38
- def method_name?(exp, name)
39
- exp.sexp_type == :call && new(exp).method_name.to_s == name.to_s
40
- end
41
- end
42
-
43
- def arguments
44
- @exp[3..-1] || []
45
- end
46
-
47
- def argument_types
48
- arguments.map(&:sexp_type)
49
- end
50
-
51
- def assert_difference?
52
- return false unless method_name == :assert_difference
53
- [[:str], %i[str lit]].include?(argument_types)
54
- end
55
-
56
- def assert_no_difference?
57
- method_name == :assert_no_difference &&
58
- arguments.length == 1 &&
59
- arguments[0].sexp_type == :str
60
- end
61
-
62
- def assert_nothing_raised?
63
- method_name == :assert_nothing_raised && arguments.empty?
64
- end
65
-
66
- def assert_raise?
67
- method_name == :assert_raise && raise_error_args?
68
- end
69
-
70
- def assert_raises?
71
- method_name == :assert_raises && raise_error_args?
72
- end
73
-
74
- def calls_in_receiver_chain
75
- receiver_chain.each_with_object([]) do |e, a|
76
- next unless sexp_type?(:call, e)
77
- a << self.class.new(e)
78
- end
79
- end
80
-
81
- def find_call_in_receiver_chain(method_names)
82
- name_array = [method_names].flatten
83
- calls_in_receiver_chain.find { |i| name_array.include?(i.method_name) }
84
- end
85
-
86
- def method_name
87
- @exp[2]
88
- end
89
-
90
- def num_arguments
91
- arguments.length
92
- end
93
-
94
- def one_string_argument?
95
- arguments.length == 1 && string?(arguments[0])
96
- end
97
-
98
- # Returns true if arguments can be processed into RSpec's `raise_error`
99
- # matcher. When the last argument is a string, it represents the
100
- # assertion failure message, which will be discarded later.
101
- def raise_error_args?
102
- arg_types = arguments.map(&:sexp_type)
103
- [[], [:str], [:const], %i[const str]].include?(arg_types)
104
- end
105
-
106
- def receiver
107
- @exp[1]
108
- end
109
-
110
- # Consider the following chain of method calls:
111
- #
112
- # @a.b.c
113
- #
114
- # whose S-expression is
115
- #
116
- # s(:call, s(:call, s(:call, nil, :a), :b), :c)
117
- #
118
- # the "receiver chain" is
119
- #
120
- # [
121
- # s(:call, s(:call, nil, :a), :b),
122
- # s(:call, nil, :a),
123
- # nil
124
- # ]
125
- #
126
- # The order of the returned array matches the order in which
127
- # messages are received, i.e. the order of execution.
128
- #
129
- # Note that the final receiver `nil` is included. This `nil`
130
- # represents the implicit receiver, e.g. `self` or `main`.
131
- #
132
- def receiver_chain
133
- receivers = []
134
- ptr = @exp
135
- while sexp_type?(:call, ptr)
136
- receivers << ptr[1]
137
- ptr = ptr[1]
138
- end
139
- receivers
140
- end
141
-
142
- def receiver_chain_include?(method_name)
143
- receiver_chain.compact.any? { |r|
144
- self.class.method_name?(r, method_name)
145
- }
146
- end
147
-
148
- def require_test_helper?
149
- method_name == :require &&
150
- one_string_argument? &&
151
- arguments[0][1] == 'test_helper'
152
- end
153
-
154
- def question_mark_method?
155
- method_name.to_s.end_with?('?')
156
- end
157
-
158
- private
159
-
160
- def string?(exp)
161
- exp.sexp_type == :str
162
- end
163
- end
164
- end
165
- end