Last active
August 29, 2015 14:01
-
-
Save seven1m/e375bcdf2864da0022f1 to your computer and use it in GitHub Desktop.
Really dumb script for converting from MiniTest::Unit to RSpec. This will get 80% of the grunt work done for you.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# This is a crude script to convert MiniTest::Unit files to RSpec files. | |
# To use: | |
# | |
# cd path/to/your/railsapp | |
# gem install parser unparser | |
# ruby to_rspec.rb | |
# rspec spec --fail-fast | |
# | |
# Now examine the error and make changes *to this script*. | |
# You can use `custom_fixes` and `custom_fixes_before` to make manual changes. | |
# (If you were to change the spec files by hand, | |
# they'll just get overwritten next time you run this script). | |
# | |
# Further, if you do get a spec file the way you want it, you can add it to | |
# the `IGNORED` list below. | |
require 'parser/current' | |
require 'unparser' | |
require 'fileutils' | |
class ToRspec | |
IGNORED = [ | |
# paths here you don't want to overwrite, e.g.: | |
#'spec/models/verification_spec.rb' | |
] | |
def go! | |
Dir['test/**/*_test.rb'].each do |path| | |
puts path | |
body = File.read(path) | |
if path =~ /test\/unit\/helpers/ | |
new_path = path.gsub('test/unit/helpers', 'spec/helpers') | |
elsif path =~ /test\/unit/ | |
new_path = path.gsub('test/unit', 'spec/models') | |
elsif path =~ /test\/functional/ | |
new_path = path.gsub('test/functional', 'spec/controllers') | |
elsif path =~ /test\/integration/ | |
new_path = path.gsub('test/integration', 'spec/requests') | |
elsif path =~ /test\/fixtures/ | |
new_path = path.gsub('test/fixtures', 'spec/fixtures') | |
elsif path =~ /test\/factories/ | |
new_path = path.gsub('test/factories', 'spec/factories') | |
else | |
puts "don't know how change #{path}" | |
end | |
new_path.gsub!(/_test\.rb$/, '_spec.rb') | |
next if IGNORED.include?(new_path) | |
custom_fixes_before!(body, new_path) | |
spec_helper!(body, new_path) | |
describe!(body) | |
before!(body) | |
context_to_describe!(body) | |
should_to_it!(body) | |
test_to_it!(body) | |
assert_question!(body) | |
assert_cannot!(body) | |
assert_can!(body) | |
assert_equal!(body) | |
assert_include!(body) | |
assert_match!(body) | |
assert_response!(body) | |
assert_redirected_to!(body) | |
assert_nil!(body) | |
assert_not!(body) | |
assert!(body) | |
custom_fixes!(body, new_path) | |
FileUtils.mkdir_p(File.split(new_path).first) | |
File.open(new_path, 'w') { |f| f.write(body) } | |
puts | |
end | |
end | |
def spec_helper!(body, path) | |
replace_line!(body) do |line| | |
if line =~ /test_helper/ | |
levels = path.split('spec/').last.count('/') | |
"require_relative '#{'../' * levels}spec_helper'" | |
end | |
end | |
end | |
def describe!(body) | |
replace_line!(body) do |line| | |
if line =~ /class ([:\w]+)Test < .*::(TestCase|IntegrationTest)\s*$/ | |
"describe #{$1} do" | |
end | |
end | |
end | |
def before!(body) | |
replace_line!(body) do |line| | |
if line =~ /(\s*)(setup do|def setup)/ | |
"#{$1}before do" | |
end | |
end | |
end | |
def context_to_describe!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)context (['"])(\w+)(['"]) do\s*$/ | |
"#{$1}describe #{$2}#{$3}#{$4} do" | |
end | |
end | |
end | |
def should_to_it!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)should (['"])(.*)(['"]) do\s*$/ | |
"#{$1}it #{$2}should #{$3}#{$4} do" | |
end | |
end | |
end | |
def test_to_it!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)test (['"])(.*)(['"]) do\s*$/ | |
"#{$1}it #{$2}#{$3}#{$4} do" | |
end | |
end | |
end | |
def assert_question!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)assert (\!|not )(.*)\.(\w+)\?\s*$/ | |
"#{$1}expect(#{$3}).to_not be_#{$4}" | |
elsif line =~ /^(\s*)assert (.*)\.(\w+)\?\s*$/ | |
"#{$1}expect(#{$2}).to be_#{$3}" | |
end | |
end | |
end | |
def assert_equal!(body) | |
body.gsub!(/assert_equal(.*),\s*\n(.*)$/, "assert_equal\\1, \\2") | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)(assert_equal.*)$/ | |
(arg1, arg2) = get_args(line) | |
"#{$1}expect(#{arg2}).to eq(#{arg1})" | |
end | |
end | |
end | |
def assert_cannot!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)(assert_cannot.*)$/ | |
(arg1, arg2, arg3) = get_args(line) | |
"#{$1}expect(#{arg1}).to_not be_able_to(#{arg2}, #{arg3})" | |
end | |
end | |
end | |
def assert_can!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)(assert_can.*)$/ | |
(arg1, arg2, arg3) = get_args(line) | |
"#{$1}expect(#{arg1}).to be_able_to(#{arg2}, #{arg3})" | |
end | |
end | |
end | |
def assert_include!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)assert (!|not )?(.*)\.include\?\((.*)\)$/ | |
negate = $2 ? '_not' : '' | |
"#{$1}expect(#{$3}).to#{negate} include(#{$4})" | |
end | |
end | |
end | |
def assert_match!(body) | |
body.gsub!(/assert_match(.*),\s*\n(.*)$/, "assert_match\\1, \\2") | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)(assert_match.*)$/ | |
(arg1, arg2) = get_args(line) | |
"#{$1}expect(#{arg2}).to match(#{arg1})" | |
end | |
end | |
end | |
# this works for some response codes (success, redirect, error), but not others (unauthorized) | |
# for the latter, you can change to this: | |
# | |
# expect(response.status) to eq(401) | |
# | |
# ... or build a custom matcher, e.g. | |
# https://github.com/churchio/onebody/blob/390f7cbd4248c4b1678a941b1eab0770d3cc519a/spec/support/response_matchers.rb | |
def assert_response!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)assert_response :(.*)$/ | |
"#{$1}expect(response).to be_#{$2}" | |
end | |
end | |
end | |
def assert_redirected_to!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)assert_redirected_to (.*)$/ | |
"#{$1}expect(response).to redirect_to(#{$2})" | |
end | |
end | |
end | |
def assert_nil!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)assert_nil (.*)$/ | |
"#{$1}expect(#{$2}).to be_nil" | |
end | |
end | |
end | |
def assert_not!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)assert (!|not )(.*)\s*$/ | |
"#{$1}expect(#{$3}).not_to be" | |
end | |
end | |
end | |
def assert!(body) | |
replace_line!(body) do |line| | |
if line =~ /^(\s*)assert (.*)\s*$/ | |
"#{$1}expect(#{$2}).to be" | |
end | |
end | |
end | |
# custom fixes to be run _before_ all the transformations | |
def custom_fixes_before!(body, path) | |
# body.gsub!(/, 'StreamItem is (not |)shared\.'/, "") | |
end | |
# custom fixes to be run _after_ all the transformations | |
def custom_fixes!(body, path) | |
# body.gsub!(/describe MailMessage/, 'describe Mail::Message') | |
# comment_lines!(body, 7..56) if path =~ /person_spec\.rb/ | |
end | |
def comment_lines!(body, nums) | |
lines = body.split(/\n/) | |
lines.each_with_index do |line, index| | |
if nums.include?(index+1) | |
lines[index] = '#' + line | |
end | |
end | |
lines.insert(nums.to_a.first-1, '# FIXME after rspec conversion') | |
body.replace(lines.join("\n")) | |
end | |
def replace_line!(body) | |
lines = body.split(/\n/) | |
lines.each_with_index do |line, index| | |
begin | |
new_line = yield(line, index) | |
rescue | |
puts '----------------------------------------' | |
puts "line number #{index+1}:" | |
puts line.strip | |
puts '----------------------------------------' | |
raise | |
end | |
lines[index] = new_line if new_line | |
end | |
body.replace(lines.join("\n")) | |
end | |
def get_args(line) | |
ast = Parser::CurrentRuby.parse(line) | |
args = ast.to_a[2..-1] | |
args.map { |a| Unparser.unparse(a) } | |
end | |
end | |
if $0 == __FILE__ | |
ToRspec.new.go! | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment