minitest_to_rspec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c0b2d69b30e206e341a4bd6a5b036ae70469f96e
4
+ data.tar.gz: f101b5c2b968434081eff2574abda02c01c73eec
5
+ SHA512:
6
+ metadata.gz: 7574bec7773f8e050aae8326b63d699146feed31abc91abb9eac7d7ce5d609c1a11a6d9705c7bf1ce5600f936abcbe02325ba35b453a083750d2f5d22e15b5c1
7
+ data.tar.gz: 718febe6a17d6495f56423fc288131ebdc0725723cd5900512204feac01d173e515f0e947cf0bdbe946d42e1ea11ce5975356548df8722e0b52dfc3f7fe5b71f
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.1
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - "2.0.0-p598"
4
+ - "2.1.5"
5
+ - "2.2.1"
6
+ script: bundle exec rake
7
+ notifications:
8
+ email: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ Change Log
2
+ ==========
3
+
4
+ This project follows [semver 2.0.0][1] and the recommendations
5
+ of [keepachangelog.com][2].
6
+
7
+ Road Map
8
+ --------
9
+
10
+ - CLI
11
+ - More assertions
12
+
13
+ Contributions welcome.
14
+
15
+ 0.1.0
16
+ -----
17
+
18
+ Initial release. 11 assertions are supported.
19
+
20
+ [1]: http://semver.org/spec/v2.0.0.html
21
+ [2]: http://keepachangelog.com/
@@ -0,0 +1,28 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people
4
+ who contribute through reporting issues, posting feature requests, updating
5
+ documentation, submitting pull requests or patches, and other activities.
6
+
7
+ We are committed to making participation in this project a harassment-free
8
+ experience for everyone, regardless of level of experience, gender, gender
9
+ identity and expression, sexual orientation, disability, personal appearance,
10
+ body size, race, age, or religion.
11
+
12
+ Examples of unacceptable behavior by participants include the use of sexual
13
+ language or imagery, derogatory comments or personal attacks, trolling, public
14
+ or private harassment, insults, or other unprofessional conduct.
15
+
16
+ Project maintainers have the right and responsibility to remove, edit, or reject
17
+ comments, commits, code, wiki edits, issues, and other contributions that are
18
+ not aligned to this Code of Conduct. Project maintainers who do not follow the
19
+ Code of Conduct may be removed from the project team.
20
+
21
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
22
+ reported by opening an issue or contacting one or more of the project
23
+ maintainers.
24
+
25
+ This Code of Conduct is adapted from the [Contributor
26
+ Covenant](http:contributor-covenant.org), version 1.0.0, available at
27
+ [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org
28
+ /version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in minitest_to_rspec.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Jared Beck
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # MinitestToRspec
2
+
3
+ Converts [minitest][8] files to [rspec][9].
4
+
5
+ [![Build Status][1]][2] [![Code Climate][3]][4] [![Test Coverage][7]][4]
6
+
7
+ Example
8
+ -------
9
+
10
+ Input:
11
+
12
+ ```ruby
13
+ require 'test_helper'
14
+ class BananaTest < ActiveSupport::TestCase
15
+ test "is delicious" do
16
+ assert Banana.new.delicious?
17
+ end
18
+ end
19
+ ```
20
+
21
+ Output:
22
+
23
+ ```ruby
24
+ require("spec_helper")
25
+ RSpec.describe(Banana) do
26
+ it("is delicious") { expect(Banana.new.delicious?).to(be_truthy) }
27
+ end
28
+ ```
29
+
30
+ The code style is whatever [ruby2ruby][6] feels like printing,
31
+ and is not configurable. The goal is not style, but to get to
32
+ rspec quickly.
33
+
34
+ Usage
35
+ -----
36
+
37
+ No CLI executable is provided yet, but ruby usage is simple.
38
+
39
+ ```ruby
40
+ require 'minitest_to_rspec'
41
+ MinitestToRspec::Converter.new.convert("assert('banana')")
42
+ #=> "expect(\"banana\").to(be_truthy)"
43
+ ```
44
+
45
+ Supported Assertions
46
+ --------------------
47
+
48
+ Selected assertions from minitest, Test::Unit, and ActiveSupport.
49
+ See [doc/supported_assertions.md][5] for rationale. Contributions
50
+ are welcome.
51
+
52
+ Assertion | Arity
53
+ --------------------------- | -----
54
+ assert |
55
+ assert_difference | 1
56
+ assert_difference | 2
57
+ assert_equal |
58
+ assert_match |
59
+ assert_nil |
60
+ assert_no_difference |
61
+ [assert_nothing_raised][10] |
62
+ assert_raises |
63
+ refute |
64
+ refute_equal |
65
+
66
+ [1]: https://travis-ci.org/jaredbeck/minitest_to_rspec.svg
67
+ [2]: https://travis-ci.org/jaredbeck/minitest_to_rspec
68
+ [3]: https://codeclimate.com/github/jaredbeck/minitest_to_rspec/badges/gpa.svg
69
+ [4]: https://codeclimate.com/github/jaredbeck/minitest_to_rspec
70
+ [5]: https://github.com/jaredbeck/minitest_to_rspec/blob/master/doc/supported_assertions.md
71
+ [6]: https://github.com/seattlerb/ruby2ruby
72
+ [7]: https://codeclimate.com/github/jaredbeck/minitest_to_rspec/badges/coverage.svg
73
+ [8]: https://github.com/jaredbeck/minitest_to_rspec/blob/master/doc/minitest.md
74
+ [9]: https://github.com/jaredbeck/minitest_to_rspec/blob/master/doc/rspec.md
75
+ [10]: http://www.rubydoc.info/gems/test-unit/3.0.9/Test/Unit/Assertions#assert_nothing_raised-instance_method
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'cane/rake_task'
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc 'Check quality metrics'
5
+ Cane::RakeTask.new(:quality) do |cane|
6
+ cane.max_violations = 0
7
+ cane.abc_glob = 'lib/**/*.rb'
8
+ cane.abc_max = 10
9
+ cane.no_doc = true
10
+ cane.style_glob = 'lib/**/*.rb'
11
+ cane.style_measure = 80
12
+ end
13
+
14
+ task(:spec).clear
15
+ RSpec::Core::RakeTask.new(:spec) do |t|
16
+ t.verbose = false
17
+ end
18
+
19
+ task :default => [:quality, :spec]
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "minitest_to_rspec"
5
+
6
+ # You can also use a different console, if you like.
7
+ # require "irb"
8
+ # IRB.start
9
+
10
+ require "pry"
11
+ Pry.start
data/doc/minitest.md ADDED
@@ -0,0 +1,29 @@
1
+ Minitest
2
+ ========
3
+
4
+ Gem | https://rubygems.org/gems/minitest
5
+ Docs | http://www.rubydoc.info/gems/minitest/5.5.1
6
+
7
+ ActiveSupport
8
+ -------------
9
+
10
+ Rails adds some assertions to minitest.
11
+
12
+ - http://guides.rubyonrails.org/testing.html
13
+ - [active_support/testing/assertions.rb][3]
14
+
15
+ Test::Unit
16
+ ----------
17
+
18
+ - https://github.com/test-unit/test-unit
19
+ - http://www.rubydoc.info/gems/test-unit/3.0.9/Test/Unit/Assertions
20
+
21
+ Selected History
22
+ ----------------
23
+
24
+ [Minitest was removed from ruby stdlib][1] in ruby 2.2, but it is
25
+ still [packaged with ruby][2] somehow.
26
+
27
+ [1]: https://bugs.ruby-lang.org/issues/9711
28
+ [2]: https://bugs.ruby-lang.org/issues/9852
29
+ [3]: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/testing/assertions.rb
data/doc/rspec.md ADDED
@@ -0,0 +1,5 @@
1
+ RSpec
2
+ =====
3
+
4
+ Gem | https://rubygems.org/gems/rspec
5
+ Docs | https://relishapp.com/rspec
@@ -0,0 +1,60 @@
1
+ Supported Assertions
2
+ ====================
3
+
4
+ A quick survey of one mid-sized test suite (14 kilolines) found
5
+ the following assertions in use.
6
+
7
+ ```bash
8
+ find test -type f -name '*.rb' | xargs cat > all_tests;
9
+ for a in $( cat ~/Desktop/assertions ); do
10
+ echo -n $a
11
+ ggrep -E "\\b$a\\b" all_tests | wc -l
12
+ done |
13
+ awk '{print $2 " " $1}' |
14
+ sort -nr
15
+ ```
16
+
17
+ ```
18
+ 625 assert
19
+ 530 assert_equal
20
+ 84 assert_difference
21
+ 38 assert_no_difference
22
+ 10 refute
23
+ 10 assert_nil
24
+ 5 assert_nothing_raised
25
+ 4 assert_match
26
+ 2 assert_raises
27
+ 1 refute_equal
28
+ 0 refute_same
29
+ 0 refute_respond_to
30
+ 0 refute_predicate
31
+ 0 refute_operator
32
+ 0 refute_nil
33
+ 0 refute_match
34
+ 0 refute_kind_of
35
+ 0 refute_instance_of
36
+ 0 refute_includes
37
+ 0 refute_in_epsilon
38
+ 0 refute_in_delta
39
+ 0 refute_empty
40
+ 0 assert_throws
41
+ 0 assert_silent
42
+ 0 assert_send
43
+ 0 assert_same
44
+ 0 assert_respond_to
45
+ 0 assert_present
46
+ 0 assert_predicate
47
+ 0 assert_output
48
+ 0 assert_operator
49
+ 0 assert_not
50
+ 0 assert_kind_of
51
+ 0 assert_instance_of
52
+ 0 assert_includes
53
+ 0 assert_in_epsilon
54
+ 0 assert_in_delta
55
+ 0 assert_empty
56
+ 0 assert_blank
57
+ ```
58
+
59
+ Assertions which are not used in the targeted test suite
60
+ are not yet supported, but contributions are welcome.
@@ -0,0 +1,5 @@
1
+ require "minitest_to_rspec/version"
2
+ require "minitest_to_rspec/converter"
3
+
4
+ module MinitestToRspec
5
+ end
@@ -0,0 +1,57 @@
1
+ require "ruby_parser"
2
+ require "ruby2ruby"
3
+ require_relative "processor"
4
+
5
+ module MinitestToRspec
6
+ class Converter
7
+ def initialize
8
+ @processor = Processor.new
9
+ @ruby2ruby = Ruby2Ruby.new
10
+ end
11
+
12
+ def convert(input)
13
+ render process parse input
14
+ end
15
+
16
+ private
17
+
18
+ # Parses an input string using the `ruby_parser` gem, and
19
+ # returns an Abstract Syntax Tree (AST) in the form of
20
+ # S-expressions.
21
+ #
22
+ # Example of AST
23
+ # --------------
24
+ #
25
+ # s(:block,
26
+ # s(:call, nil, :require, s(:str, "test_helper")),
27
+ # s(:class,
28
+ # :BananaTest,
29
+ # s(:colon2, s(:const, :ActiveSupport), :TestCase),
30
+ # s(:iter,
31
+ # s(:call, nil, :test, s(:str, "is delicious")),
32
+ # s(:args),
33
+ # s(:call, nil, :assert,
34
+ # s(:call, s(:call, s(:const, :Banana), :new), :delicious?)
35
+ # )
36
+ # )
37
+ # )
38
+ # )
39
+ #
40
+ def parse(input)
41
+ RubyParser.new.parse(input)
42
+ end
43
+
44
+ # Processes an AST (S-expressions) representing a minitest
45
+ # file, and returns an AST (still S-expressions) representing
46
+ # an rspec file.
47
+ def process(exp)
48
+ @processor.process(exp)
49
+ end
50
+
51
+ # Given an AST representing an rspec file, returns a string
52
+ # of ruby code.
53
+ def render(exp)
54
+ @ruby2ruby.process(exp)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module MinitestToRspec
2
+ class NotImplemented < StandardError; end
3
+ end
@@ -0,0 +1,84 @@
1
+ module MinitestToRspec
2
+ module Exp
3
+
4
+ # Data object. Represents a `:call` s-expression.
5
+ class Call
6
+ attr_reader :original
7
+
8
+ def initialize(exp)
9
+ unless exp.sexp_type == :call
10
+ raise ArgumentError, "Expected call, got #{exp.sexp_type}"
11
+ end
12
+ @exp = exp.dup
13
+ @original = exp.dup
14
+ end
15
+
16
+ class << self
17
+ def assert_difference?(exp)
18
+ exp.sexp_type == :call && new(exp).assert_difference?
19
+ end
20
+
21
+ def assert_no_difference?(exp)
22
+ exp.sexp_type == :call && new(exp).assert_no_difference?
23
+ end
24
+
25
+ def assert_nothing_raised?(exp)
26
+ exp.sexp_type == :call && new(exp).assert_nothing_raised?
27
+ end
28
+
29
+ def assert_raises?(exp)
30
+ exp.sexp_type == :call && new(exp).assert_raises?
31
+ end
32
+ end
33
+
34
+ def arguments
35
+ @exp[3..-1]
36
+ end
37
+
38
+ def argument_types
39
+ arguments.map(&:sexp_type)
40
+ end
41
+
42
+ def assert_difference?
43
+ return false unless method_name == :assert_difference
44
+ [[:str], [:str, :lit]].include?(argument_types)
45
+ end
46
+
47
+ def assert_no_difference?
48
+ method_name == :assert_no_difference &&
49
+ arguments.length == 1 &&
50
+ arguments[0].sexp_type == :str
51
+ end
52
+
53
+ def assert_nothing_raised?
54
+ method_name == :assert_nothing_raised && arguments.empty?
55
+ end
56
+
57
+ def assert_raises?
58
+ method_name == :assert_raises &&
59
+ arguments.length == 1 &&
60
+ arguments[0].sexp_type == :const
61
+ end
62
+
63
+ def method_name
64
+ @exp[2]
65
+ end
66
+
67
+ def one_string_argument?
68
+ arguments.length == 1 && string?(arguments[0])
69
+ end
70
+
71
+ def require_test_helper?
72
+ method_name == :require &&
73
+ one_string_argument? &&
74
+ arguments[0][1] == "test_helper"
75
+ end
76
+
77
+ private
78
+
79
+ def string?(exp)
80
+ exp.sexp_type == :str
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,43 @@
1
+ module MinitestToRspec
2
+ module Exp
3
+
4
+ # Data object. Represents an `:iter` s-expression.
5
+ class Iter
6
+
7
+ def initialize(exp)
8
+ unless exp.sexp_type == :iter
9
+ raise ArgumentError, "Expected iter, got #{exp.sexp_type}"
10
+ end
11
+ @exp = exp.dup
12
+ end
13
+
14
+ def [](*args)
15
+ @exp[*args]
16
+ end
17
+
18
+ def assert_difference?
19
+ !empty? && Exp::Call.assert_difference?(@exp[1])
20
+ end
21
+
22
+ def assert_no_difference?
23
+ !empty? && Exp::Call.assert_no_difference?(@exp[1])
24
+ end
25
+
26
+ def assert_nothing_raised?
27
+ !empty? && Exp::Call.assert_nothing_raised?(@exp[1])
28
+ end
29
+
30
+ def assert_raises?
31
+ !empty? && Exp::Call.assert_raises?(@exp[1])
32
+ end
33
+
34
+ def empty?
35
+ @exp.length == 1 # just the sexp_type
36
+ end
37
+
38
+ def sexp
39
+ @exp
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ require "ruby_parser"
2
+ require "sexp_processor"
3
+ require_relative "subprocessors/call"
4
+ require_relative "subprocessors/class"
5
+ require_relative "subprocessors/iter"
6
+
7
+ module MinitestToRspec
8
+ class Processor < SexpProcessor
9
+ def initialize
10
+ super
11
+ self.strict = false
12
+ end
13
+
14
+ def process_call(exp)
15
+ Subprocessors::Call.process(exp)
16
+ end
17
+
18
+ def process_class(exp)
19
+ Subprocessors::Class.process(exp)
20
+ end
21
+
22
+ def process_iter(exp)
23
+ Subprocessors::Iter.process(exp)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,58 @@
1
+ module MinitestToRspec
2
+ module Subprocessors
3
+ class Base
4
+ class << self
5
+
6
+ # Returns a s-expression representing an RSpec expectation, i.e. the
7
+ # combination of an "expectation target" and a matcher.
8
+ def expect(target, eager, phase, matcher)
9
+ s(:call, expectation_target(target, eager), phase, matcher)
10
+ end
11
+
12
+ def expect_to(matcher, target, eager)
13
+ expect(target, eager, :to, matcher)
14
+ end
15
+
16
+ def expect_to_not(matcher, target, eager)
17
+ expect(target, eager, :to_not, matcher)
18
+ end
19
+
20
+ # In RSpec, `expect` returns an "expectation target". This
21
+ # can be based on an expression, as in `expect(1 + 1)` or it
22
+ # can be based on a block, as in `expect { raise }`. Either
23
+ # way, it's called an "expectation target".
24
+ def expectation_target(exp, eager = true)
25
+ m = "expectation_target_%s" % [eager ? "eager" : "lazy"]
26
+ send(m, exp)
27
+ end
28
+
29
+ def expectation_target_eager(exp)
30
+ s(:call, nil, :expect, exp)
31
+ end
32
+
33
+ def expectation_target_lazy(block)
34
+ s(:iter,
35
+ s(:call, nil, :expect),
36
+ s(:args),
37
+ full_process(block)
38
+ )
39
+ end
40
+
41
+ # Run `exp` through a new `Processor`. This is useful for expressions
42
+ # that cannot be fully understood by a single subprocessor. For
43
+ # example, we process :iter expressions, because we're interested in
44
+ # :iter that contain e.g. an `assert_difference`. However, if the :iter
45
+ # turns out to be uninteresting, we still want to fully process its
46
+ # sub-expressions. TODO: `full_process` may not be the best name.
47
+ def full_process(exp)
48
+ Processor.new.process(exp)
49
+ end
50
+
51
+ def matcher(name, *args)
52
+ exp = s(:call, nil, name)
53
+ exp.concat(args)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,109 @@
1
+ require_relative "../exp/call"
2
+ require_relative "base"
3
+
4
+ module MinitestToRspec
5
+ module Subprocessors
6
+ class Call < Base
7
+
8
+ ASSERTIONS = %i[
9
+ assert
10
+ assert_equal
11
+ assert_match
12
+ assert_nil
13
+ refute
14
+ refute_equal
15
+ ]
16
+
17
+ class << self
18
+ def process(sexp)
19
+ exp = Exp::Call.new(sexp)
20
+ sexp.clear
21
+ process_exp(exp)
22
+ end
23
+
24
+ private
25
+
26
+ def assertion?(exp)
27
+ ASSERTIONS.include?(exp.method_name)
28
+ end
29
+
30
+ def be_falsey
31
+ matcher(:be_falsey)
32
+ end
33
+
34
+ def be_nil
35
+ matcher(:be_nil)
36
+ end
37
+
38
+ def be_truthy
39
+ matcher(:be_truthy)
40
+ end
41
+
42
+ def eq(exp)
43
+ matcher(:eq, exp)
44
+ end
45
+
46
+ def match(pattern)
47
+ matcher(:match, pattern)
48
+ end
49
+
50
+ def method_assert(exp)
51
+ expect_to(be_truthy, exp.arguments[0], true)
52
+ end
53
+
54
+ def method_assert_equal(exp)
55
+ expected = exp.arguments[0]
56
+ calculated = exp.arguments[1]
57
+ expect_to(eq(expected), calculated, true)
58
+ end
59
+
60
+ def method_assert_match(exp)
61
+ pattern = exp.arguments[0]
62
+ string = exp.arguments[1]
63
+ expect_to(match(pattern), string, true)
64
+ end
65
+
66
+ def method_assert_nil(exp)
67
+ expect_to(be_nil, exp.arguments[0], true)
68
+ end
69
+
70
+ def method_refute(exp)
71
+ expect_to(be_falsey, exp.arguments[0], true)
72
+ end
73
+
74
+ def method_refute_equal(exp)
75
+ unexpected = exp.arguments[0]
76
+ calculated = exp.arguments[1]
77
+ expect_to_not(eq(unexpected), calculated, true)
78
+ end
79
+
80
+ def method_test(exp)
81
+ s(:call, nil, :it, *exp.arguments)
82
+ end
83
+
84
+ def processable?(exp)
85
+ exp.method_name == :test || assertion?(exp)
86
+ end
87
+
88
+ # Given a `Exp::Call`, returns a `Sexp`
89
+ def process_exp(exp)
90
+ if exp.require_test_helper?
91
+ require_spec_helper
92
+ elsif processable?(exp)
93
+ process_method(exp)
94
+ else
95
+ exp.original
96
+ end
97
+ end
98
+
99
+ def process_method(exp)
100
+ send("method_#{exp.method_name}".to_sym, exp)
101
+ end
102
+
103
+ def require_spec_helper
104
+ s(:call, nil, :require, s(:str, "spec_helper"))
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,105 @@
1
+ require_relative "../errors"
2
+ require_relative "base"
3
+
4
+ module MinitestToRspec
5
+ module Subprocessors
6
+ class Class < Base
7
+ class << self
8
+
9
+ # Examples of S-expressions
10
+ # -------------------------
11
+ #
12
+ # An empty class
13
+ #
14
+ # class Derp; end
15
+ # s(:class, :Derp, nil)
16
+ #
17
+ # A trivial class
18
+ #
19
+ # class Derp; puts; end
20
+ # s(:class, :Derp, nil, s(:call, nil, :puts))
21
+ #
22
+ # A TestCase
23
+ #
24
+ # s(:class,
25
+ # :BananaTest,
26
+ # s(:colon2, s(:const, :ActiveSupport), :TestCase),
27
+ # s(:iter,
28
+ # s(:call, nil, :test, s(:str, "is delicious")),
29
+ # s(:args),
30
+ # s(:call, nil, :assert,
31
+ # s(:call, s(:call, s(:const, :Banana), :new), :delicious?)
32
+ # )
33
+ # )
34
+ # )
35
+ #
36
+ def process(exp)
37
+ raise ArgumentError unless exp.shift == :class
38
+ name = exp.shift
39
+ parent = exp.shift
40
+ iter = exp.empty? ? nil : exp.shift
41
+ raise("Unexpected class expression") unless exp.empty?
42
+ result(name, parent, iter)
43
+ end
44
+
45
+ private
46
+
47
+ def active_support_test_case?(parent)
48
+ parent.length == 3 &&
49
+ parent[1] == s(:const, :ActiveSupport) &&
50
+ parent[2] == :TestCase
51
+ end
52
+
53
+ # Given a `test_class_name` like `BananaTest`, returns the
54
+ # described clas, like `Banana`.
55
+ def described_class(test_class_name)
56
+ test_class_name.to_s.gsub(/Test\Z/, "").to_sym
57
+ end
58
+
59
+ def inheritance?(exp)
60
+ exp.sexp_type == :colon2
61
+ end
62
+
63
+ # Run `exp` through a new `Processor`. This is appropriate
64
+ # for expressions like `:iter` (a block) which we're not
65
+ # interested in processing. We *are* interested in
66
+ # processing expressions within an `:iter`, but not the
67
+ # iter itself. TODO: `full_process` may not be the best name.
68
+ def full_process(exp)
69
+ Processor.new.process(exp)
70
+ end
71
+
72
+ def result(name, parent, iter)
73
+ if parent && test_case?(parent)
74
+ rspec_describe_block(name, iter)
75
+ elsif iter.nil?
76
+ s(:class, name, parent)
77
+ else
78
+ s(:class, name, parent, full_process(iter))
79
+ end
80
+ end
81
+
82
+ def rspec_describe(arg)
83
+ s(:call, s(:const, :RSpec), :describe, arg)
84
+ end
85
+
86
+ # Returns a S-expression representing a call to RSpec.describe
87
+ def rspec_describe_block(name, iter)
88
+ arg = s(:const, described_class(name))
89
+ result = s(:iter, rspec_describe(arg), s(:args))
90
+ unless iter.nil?
91
+ result << full_process(iter)
92
+ end
93
+ result
94
+ end
95
+
96
+ # TODO: Obviously, there are test case parent classes
97
+ # other than ActiveSupport::TestCase
98
+ def test_case?(parent)
99
+ raise ArgumentError unless inheritance?(parent)
100
+ active_support_test_case?(parent)
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,107 @@
1
+ require_relative "base"
2
+ require_relative "../exp/iter"
3
+
4
+ module MinitestToRspec
5
+ module Subprocessors
6
+ class Iter < Base
7
+ class << self
8
+ def process(sexp)
9
+ exp = Exp::Iter.new(sexp)
10
+ sexp.clear
11
+ process_exp(exp)
12
+ end
13
+
14
+ private
15
+
16
+ # Returns an expression representing an RSpec `change {}`
17
+ # matcher. See also `change_by` below.
18
+ def change(exp)
19
+ matcher_with_block(:change, exp)
20
+ end
21
+
22
+ # Returns an expression representing an RSpec `change {}.by()` matcher.
23
+ def change_by(diff_exp, by_exp)
24
+ s(:call,
25
+ change(diff_exp),
26
+ :by,
27
+ by_exp
28
+ )
29
+ end
30
+
31
+ def matcher_with_block(matcher_name, block)
32
+ s(:iter,
33
+ s(:call, nil, matcher_name),
34
+ s(:args),
35
+ block
36
+ )
37
+ end
38
+
39
+ def parse(str)
40
+ RubyParser.new.parse(str)
41
+ end
42
+
43
+ def process_assert_difference(exp)
44
+ call = exp[1]
45
+ block = exp[3]
46
+ by = call[4]
47
+ what = parse(call[3][1])
48
+ matcher = by.nil? ? change(what) : change_by(what, by)
49
+ expect_to(matcher, block, false)
50
+ end
51
+
52
+ def process_assert_no_difference(exp)
53
+ call = exp[1]
54
+ block = exp[3]
55
+ what = parse(call[3][1])
56
+ expect_to_not(change(what), block, false)
57
+ end
58
+
59
+ def process_assert_nothing_raised(exp)
60
+ block = exp[3]
61
+ expect_to_not(raise_error, block, false)
62
+ end
63
+
64
+ def process_assert_raises(exp)
65
+ block = exp[3]
66
+ call = Exp::Call.new(exp[1])
67
+ err = call.arguments.first
68
+ expect_to(raise_error(err), block, false)
69
+ end
70
+
71
+ # Given a `Exp::Iter`, returns a `Sexp`
72
+ def process_exp(exp)
73
+ m = processing_method(exp)
74
+ if m.nil?
75
+ process_uninteresting_iter(exp.sexp)
76
+ else
77
+ send(m, exp)
78
+ end
79
+ end
80
+
81
+ def process_uninteresting_iter(exp)
82
+ iter = s(exp.shift)
83
+ until exp.empty?
84
+ iter << full_process(exp.shift)
85
+ end
86
+ iter
87
+ end
88
+
89
+ # Returns the name of a method in this subprocessor, or nil if
90
+ # this iter is not processable.
91
+ def processing_method(iter)
92
+ if !iter.empty? && iter[1].sexp_type == :call
93
+ method_name = iter[1][2]
94
+ decision = "#{method_name}?".to_sym
95
+ if iter.respond_to?(decision) && iter.public_send(decision)
96
+ "process_#{method_name}".to_sym
97
+ end
98
+ end
99
+ end
100
+
101
+ def raise_error(*args)
102
+ matcher(:raise_error, *args)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,3 @@
1
+ module MinitestToRspec
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'minitest_to_rspec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "minitest_to_rspec"
8
+ spec.version = MinitestToRspec::VERSION
9
+ spec.authors = ["Jared Beck"]
10
+ spec.email = ["jared@jaredbeck.com"]
11
+
12
+ spec.summary = "Converts minitest files to rspec"
13
+ spec.homepage = "https://github.com/jaredbeck/minitest_to_rspec"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "ruby_parser"
22
+
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "cane"
25
+ spec.add_development_dependency "codeclimate-test-reporter"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "ruby2ruby"
29
+ spec.add_development_dependency "pry"
30
+ spec.add_development_dependency "pry-nav"
31
+ end
metadata ADDED
@@ -0,0 +1,195 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: minitest_to_rspec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jared Beck
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby_parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cane
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: codeclimate-test-reporter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: ruby2ruby
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry-nav
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description:
140
+ email:
141
+ - jared@jaredbeck.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".ruby-version"
148
+ - ".travis.yml"
149
+ - CHANGELOG.md
150
+ - CODE_OF_CONDUCT.md
151
+ - Gemfile
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - bin/console
156
+ - doc/minitest.md
157
+ - doc/rspec.md
158
+ - doc/supported_assertions.md
159
+ - lib/minitest_to_rspec.rb
160
+ - lib/minitest_to_rspec/converter.rb
161
+ - lib/minitest_to_rspec/errors.rb
162
+ - lib/minitest_to_rspec/exp/call.rb
163
+ - lib/minitest_to_rspec/exp/iter.rb
164
+ - lib/minitest_to_rspec/processor.rb
165
+ - lib/minitest_to_rspec/subprocessors/base.rb
166
+ - lib/minitest_to_rspec/subprocessors/call.rb
167
+ - lib/minitest_to_rspec/subprocessors/class.rb
168
+ - lib/minitest_to_rspec/subprocessors/iter.rb
169
+ - lib/minitest_to_rspec/version.rb
170
+ - minitest_to_rspec.gemspec
171
+ homepage: https://github.com/jaredbeck/minitest_to_rspec
172
+ licenses:
173
+ - MIT
174
+ metadata: {}
175
+ post_install_message:
176
+ rdoc_options: []
177
+ require_paths:
178
+ - lib
179
+ required_ruby_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ required_rubygems_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ requirements: []
190
+ rubyforge_project:
191
+ rubygems_version: 2.4.5
192
+ signing_key:
193
+ specification_version: 4
194
+ summary: Converts minitest files to rspec
195
+ test_files: []