minitest_to_rspec 0.1.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 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: []