rspec 0.5.9 → 0.5.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +5 -0
- data/README +4 -3
- data/Rakefile +12 -8
- data/bin/test2spec +6 -8
- data/doc/plugin/version.rb +19 -0
- data/doc/src/default.template +1 -1
- data/doc/src/tools/rake.page +1 -1
- data/doc/src/tools/test2spec.page +12 -9
- data/lib/spec/rake/spectask.rb +1 -1
- data/lib/spec/runner/base_text_formatter.rb +1 -2
- data/lib/spec/runner/reporter.rb +1 -1
- data/lib/spec/{tool → test_to_spec}/ruby2ruby.rb +6 -2
- data/lib/spec/test_to_spec/sexp_transformer.rb +189 -0
- data/lib/spec/test_to_spec/test_case_ext.rb +22 -0
- data/lib/spec/{tool → test_to_spec}/translation_test_runner.rb +3 -4
- data/lib/spec/version.rb +1 -1
- data/test/spec/runner/progress_bar_formatter_test.rb +3 -3
- data/test/spec/runner/rdoc_formatter_test.rb +2 -2
- data/test/spec/runner/reporter_test.rb +15 -8
- data/test/spec/runner/specdoc_formatter_test.rb +3 -3
- data/test/spec/{tool → test_to_spec}/ruby_to_ruby_test.rb +2 -2
- data/test/spec/test_to_spec/sexp_transformer_assertion_test.rb +207 -0
- data/test/spec/test_to_spec/sexp_transformer_test.rb +232 -0
- data/test/spec/test_to_spec/test_case_ext_test.rb +25 -0
- data/test/spec/{tool → test_to_spec/testfiles}/test_unit_api_spec.rb +1 -1
- data/test/spec/test_to_spec/testfiles/test_unit_api_test.rb +64 -0
- data/test/test_helper.rb +24 -1
- metadata +14 -10
- data/lib/spec/tool/test_unit_translator.rb +0 -143
- data/test/spec/tool/test_unit_api_test.rb +0 -68
- data/test/spec/tool/test_unit_translator_test.rb +0 -34
data/CHANGES
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
= RSpec Changelog
|
2
2
|
|
3
|
+
== Version 0.5.10
|
4
|
+
This version features a second rewrite of test2spec - hopefully better than the previous one.
|
5
|
+
|
6
|
+
* Improved test2spec's internals. It now transforms the syntax tree before writing out the code.
|
7
|
+
|
3
8
|
== Version 0.5.9
|
4
9
|
This release improves test2spec by allowing more control over the output
|
5
10
|
|
data/README
CHANGED
@@ -3,15 +3,16 @@ Then you must install the following gems:
|
|
3
3
|
|
4
4
|
* rake
|
5
5
|
* rcov
|
6
|
-
* RubyInline
|
7
6
|
* ParseTree (Ignore the message: test/test_parse_tree.rb:190:38: ':' not followed by identified or operator)
|
7
|
+
* RubyInline
|
8
8
|
* webgen
|
9
9
|
* RedCloth
|
10
10
|
* syntax
|
11
11
|
|
12
12
|
Note that RSpec itself - once built - doesn't have any dependencies outside the Ruby core
|
13
13
|
and stdlib - with a few exceptions:
|
14
|
-
|
15
|
-
* The
|
14
|
+
|
15
|
+
* The test2spec command line uses ParseTree and RubyInline
|
16
|
+
* The Spec::Rake::SpecTask needs RCov if RCov is enabled in the task.
|
16
17
|
|
17
18
|
See http://rspec.rubyforge.org for further documentation.
|
data/Rakefile
CHANGED
@@ -6,8 +6,6 @@ require 'rake/clean'
|
|
6
6
|
require 'rake/testtask'
|
7
7
|
require 'rake/rdoctask'
|
8
8
|
require 'spec/version'
|
9
|
-
require 'spec/rake/spectask'
|
10
|
-
require 'spec/rake/rcov_verify'
|
11
9
|
require 'rcov/rcovtask'
|
12
10
|
|
13
11
|
# Some of the tasks are in separate files since they are also part of the website documentation
|
@@ -27,7 +25,7 @@ PKG_FILES = FileList[
|
|
27
25
|
'doc/**/*'
|
28
26
|
]
|
29
27
|
|
30
|
-
task :default =>
|
28
|
+
task :default => :test
|
31
29
|
|
32
30
|
desc "Run all failing examples"
|
33
31
|
Spec::Rake::SpecTask.new('failing_examples') do |t|
|
@@ -47,12 +45,18 @@ end
|
|
47
45
|
|
48
46
|
desc 'Translate our own tests to specs'
|
49
47
|
task :test2spec do
|
50
|
-
`bin/test2spec --template spec/test2spec.erb --specdir spec test`
|
48
|
+
`bin/test2spec --force --template spec/test2spec.erb --specdir spec/translated test`
|
51
49
|
end
|
52
50
|
|
53
51
|
desc 'Generate HTML documentation'
|
54
|
-
task :
|
55
|
-
|
52
|
+
task :webgen => :test2spec do
|
53
|
+
Dir.chdir 'doc' do
|
54
|
+
output = nil
|
55
|
+
IO.popen('webgen 2>&1') do |io|
|
56
|
+
output = io.read
|
57
|
+
end
|
58
|
+
raise "ERROR while running webgen: #{output}" if output =~ /ERROR/n || $? != 0
|
59
|
+
end
|
56
60
|
end
|
57
61
|
|
58
62
|
desc 'Generate RDoc'
|
@@ -119,7 +123,7 @@ end
|
|
119
123
|
|
120
124
|
task :clobber do
|
121
125
|
rm_rf 'doc/output'
|
122
|
-
rm_rf 'spec/
|
126
|
+
rm_rf 'spec/translated'
|
123
127
|
end
|
124
128
|
|
125
129
|
task :release => [:clobber, :verify_committed, :verify_user, :verify_password, :test, :publish_packages, :tag, :publish_website, :publish_news]
|
@@ -141,7 +145,7 @@ task :tag do
|
|
141
145
|
end
|
142
146
|
|
143
147
|
desc "Build the website with rdoc and rcov, but do not publish it"
|
144
|
-
task :website => [:clobber, :rcov_verify, :
|
148
|
+
task :website => [:clobber, :rcov_verify, :webgen, :examples_specdoc, :rdoc]
|
145
149
|
|
146
150
|
task :verify_user do
|
147
151
|
raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
|
data/bin/test2spec
CHANGED
@@ -7,10 +7,10 @@ require 'test/unit/ui/testrunnermediator'
|
|
7
7
|
require 'test/unit/autorunner'
|
8
8
|
require 'optparse'
|
9
9
|
|
10
|
-
$LOAD_PATH.
|
10
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
11
11
|
|
12
12
|
require 'rubygems'
|
13
|
-
require 'spec/
|
13
|
+
require 'spec/test_to_spec/translation_test_runner'
|
14
14
|
require 'spec/version'
|
15
15
|
|
16
16
|
$test2spec_options = {
|
@@ -26,13 +26,11 @@ opts = OptionParser.new do |opts|
|
|
26
26
|
end
|
27
27
|
|
28
28
|
opts.on("-t", "--template FILE",
|
29
|
-
"ERB template that will be used to
|
30
|
-
"has access
|
29
|
+
"ERB template that will be used to decorate each translated file.",
|
30
|
+
"The template has access to the following variables:",
|
31
31
|
" translation : the translated source code",
|
32
32
|
" depth : the directory depth of the file to be written",
|
33
|
-
" relative_path : the relative name of the file to be written"
|
34
|
-
"Example:",
|
35
|
-
"<%= @translation %>"
|
33
|
+
" relative_path : the relative name of the file to be written"
|
36
34
|
) do |file|
|
37
35
|
$test2spec_options[:template] = file
|
38
36
|
end
|
@@ -87,7 +85,7 @@ module Test
|
|
87
85
|
class AutoRunner
|
88
86
|
def initialize(standalone)
|
89
87
|
@standalone = standalone
|
90
|
-
@runner = proc { |r| Spec::
|
88
|
+
@runner = proc { |r| Spec::TestToSpec::TranslationTestRunner }
|
91
89
|
@collector = COLLECTORS[(standalone ? :dir : :objectspace)]
|
92
90
|
@filters = []
|
93
91
|
@to_run = []
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'webgen/plugins/tags/tags'
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/spec/version'
|
3
|
+
|
4
|
+
module Tags
|
5
|
+
|
6
|
+
class VersionTag < DefaultTag
|
7
|
+
|
8
|
+
summary "Puts the version on the page"
|
9
|
+
depends_on 'Tags'
|
10
|
+
|
11
|
+
tag 'version'
|
12
|
+
|
13
|
+
def process_tag(tag, node, refNode)
|
14
|
+
return Spec::VERSION::STRING
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/doc/src/default.template
CHANGED
data/doc/src/tools/rake.page
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
title: Test::Unit Migration
|
3
3
|
inMenu: true
|
4
4
|
---
|
5
|
-
h2.
|
5
|
+
h2. Overview of test2spec
|
6
6
|
|
7
7
|
RSpec's test2spec command line tool translates existing Test::Unit classes to RSpec.
|
8
8
|
|
9
|
-
Before you can use test2spec you must gem install ParseTree and RubyInline.
|
9
|
+
Before you can use test2spec you must gem install ParseTree (and RubyInline).
|
10
10
|
RubyInline only works on systems that have a C compiler - i.e. most anything except Windows.
|
11
11
|
|
12
12
|
If you're stuck on Windows, ask a friend who has a POSIX system to translate your specs.
|
@@ -46,10 +46,10 @@ h2. Sample translation
|
|
46
46
|
<tbody>
|
47
47
|
<tr>
|
48
48
|
<td>
|
49
|
-
<ruby file="../test/spec/
|
49
|
+
<ruby file="../test/spec/test_to_spec/testfiles/test_unit_api_test.rb"/>
|
50
50
|
</td>
|
51
51
|
<td>
|
52
|
-
<ruby file="../spec/
|
52
|
+
<ruby file="../spec/translated/test_unit_api_spec.rb"/>
|
53
53
|
</td>
|
54
54
|
</tr>
|
55
55
|
</tbody>
|
@@ -73,17 +73,20 @@ at RSpec's bug report system along with some code so we can reproduce (and hope
|
|
73
73
|
|
74
74
|
h2. Internals
|
75
75
|
|
76
|
-
The test2spec
|
76
|
+
The test2spec commandline 'runs' the tests with a special test runner - one that translates and writes out
|
77
|
+
the translations to disk instead of actually executing the tests.
|
78
|
+
|
79
|
+
The translation is done by the <tt>Test::Unit::TestCase#to_rspec</tt> method (which test2spec adds to all
|
80
|
+
test classes). This method will load the parse tree for the class, transform that tree to an RSpec context
|
81
|
+
and return the source code (using RubyToRuby).
|
82
|
+
|
83
|
+
test2spec is based directly on two other tools:
|
77
84
|
|
78
85
|
* "RubyToRuby":http://blog.zenspider.com/archives/2005/02/rubytoruby.html
|
79
86
|
* "ParseTree":http://rubyforge.org/projects/parsetree/
|
80
|
-
* "RubyInline":http://rubyforge.org/projects/rubyinline/
|
81
87
|
|
82
88
|
In fact, it's based on a modified version of "George Moschovitis' RubyToRuby enhancement":http://dark.fhtr.org/ruby2ruby.rb
|
83
89
|
of "Ryan Davis' original RubyToRuby":http://blog.zenspider.com/archives/2005/02/rubytoruby.html.
|
84
90
|
|
85
91
|
It has been modified to fix some subtle bugs that were not found by Gerorge's tests. The modified RubyToRuby
|
86
92
|
currently lives in RSpec's subversion repository.
|
87
|
-
|
88
|
-
The translation is done by TestUnitTranslator - subclass of RubyToRuby that writes out the syntax tree a little differently than
|
89
|
-
its superclass. TestUnitTranslator looks for certain Test::Unit patterns and writes out an RSpec translation instead.
|
data/lib/spec/rake/spectask.rb
CHANGED
@@ -85,7 +85,7 @@ module Rake
|
|
85
85
|
specs = file_list
|
86
86
|
raise "No spec files found." if specs.empty?
|
87
87
|
|
88
|
-
spec = File.dirname(__FILE__) + '/../../../bin/spec'
|
88
|
+
spec = File.expand_path(File.dirname(__FILE__) + '/../../../bin/spec')
|
89
89
|
file_prefix = @rcov ? " -- " : ""
|
90
90
|
interpreter = @rcov ? "rcov" : "ruby"
|
91
91
|
redirect = @out.nil? ? "" : " > #{@out}"
|
@@ -62,11 +62,10 @@ module Spec
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# This method is invoked at the very end.
|
65
|
-
def dump_summary(duration,
|
65
|
+
def dump_summary(duration, spec_count, failure_count)
|
66
66
|
return if @dry_run
|
67
67
|
@output << "\n"
|
68
68
|
@output << "Finished in " << (duration).to_s << " seconds\n\n"
|
69
|
-
@output << "#{context_count} context#{'s' unless context_count == 1}, "
|
70
69
|
@output << "#{spec_count} specification#{'s' unless spec_count == 1}, "
|
71
70
|
@output << "#{failure_count} failure#{'s' unless failure_count == 1}"
|
72
71
|
@output << "\n"
|
data/lib/spec/runner/reporter.rb
CHANGED
@@ -43,7 +43,7 @@ module Spec
|
|
43
43
|
def dump
|
44
44
|
@formatter.start_dump
|
45
45
|
dump_failures
|
46
|
-
@formatter.dump_summary(duration, @
|
46
|
+
@formatter.dump_summary(duration, @spec_names.length, @failures.length)
|
47
47
|
@failures.length
|
48
48
|
end
|
49
49
|
|
@@ -5,7 +5,7 @@ begin
|
|
5
5
|
require 'parse_tree'
|
6
6
|
require 'sexp_processor'
|
7
7
|
rescue LoadError
|
8
|
-
|
8
|
+
raise "You must gem install ParseTree (and RubyInline)"
|
9
9
|
end
|
10
10
|
|
11
11
|
class RubySource < String
|
@@ -482,5 +482,9 @@ class RubyToRuby < SexpProcessor
|
|
482
482
|
end
|
483
483
|
code.join("\n")
|
484
484
|
end
|
485
|
-
|
485
|
+
|
486
|
+
def process_bmethod(exp)
|
487
|
+
raise "FIXME"
|
488
|
+
end
|
489
|
+
|
486
490
|
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'sexp_processor'
|
2
|
+
|
3
|
+
module Spec
|
4
|
+
module TestToSpec
|
5
|
+
# Transforms a Sexp tree (produced by ParseTree) for a Test::Unit class
|
6
|
+
# to an Sexp tree representing an RSpec context
|
7
|
+
class SexpTransformer < SexpProcessor
|
8
|
+
TRANSLATIONS = {
|
9
|
+
:assert_equal => :should_equal,
|
10
|
+
:assert_not_equal => :should_not_equal,
|
11
|
+
:assert_same => :should_be,
|
12
|
+
:assert_not_same => :should_not_be,
|
13
|
+
:assert_instance_of => :should_be_instance_of,
|
14
|
+
:assert_kind_of => :should_be_kind_of,
|
15
|
+
:assert_match => :should_match,
|
16
|
+
:assert_no_match => :should_not_match,
|
17
|
+
:assert_respond_to => :should_respond_to,
|
18
|
+
:assert => :should_be,
|
19
|
+
:assert_nil => :should_be,
|
20
|
+
:assert_not_nil => :should_not_be,
|
21
|
+
:assert_in_delta => :should_be_close,
|
22
|
+
:assert_block => :should_be,
|
23
|
+
:assert_raise => :should_raise,
|
24
|
+
:assert_raises => :should_raise,
|
25
|
+
:assert_nothing_raised => :should_not_raise,
|
26
|
+
:assert_throws => :should_throw,
|
27
|
+
:assert_nothing_thrown => :should_not_throw,
|
28
|
+
}
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
super
|
32
|
+
self.expected = Array
|
33
|
+
end
|
34
|
+
|
35
|
+
def process(exp)
|
36
|
+
#puts "PROCESS:#{exp[0]}"
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def process_class(exp)
|
41
|
+
# Get the class header
|
42
|
+
exp.shift
|
43
|
+
class_name = exp.shift.to_s.split("::").last
|
44
|
+
context_name = class_name.match(/(.*)Test/)[1]
|
45
|
+
exp.shift
|
46
|
+
|
47
|
+
# Partition all methods (and other stuff) into chunks, as we're
|
48
|
+
# going to handle them a bit differently
|
49
|
+
rest = exp
|
50
|
+
setup, rest = rest.partition{|e| e[0] == :defn && e[1].to_s == "setup"}
|
51
|
+
teardown, rest = rest.partition{|e| e[0] == :defn && e[1].to_s == "teardown"}
|
52
|
+
tests, rest = rest.partition{|e| e[0] == :defn && e[1].to_s =~ /^test/}
|
53
|
+
methods, rest = rest.partition{|e| e[0] == :defn}
|
54
|
+
|
55
|
+
if !methods.empty? && setup.empty?
|
56
|
+
# We have some methods, but no setup to put them in. Create empty setup
|
57
|
+
setup[0] = [:defn, :setup, [:scope, [:block, [:args], [:nil]]]]
|
58
|
+
end
|
59
|
+
|
60
|
+
context_body = []
|
61
|
+
unless setup.empty?
|
62
|
+
setup_block = process(setup.shift)
|
63
|
+
unless methods.empty?
|
64
|
+
if setup_block.length == 3
|
65
|
+
setup_block += methods
|
66
|
+
else
|
67
|
+
setup_block[3] += methods
|
68
|
+
end
|
69
|
+
end
|
70
|
+
context_body << setup_block
|
71
|
+
end
|
72
|
+
context_body << process(teardown.shift) until teardown.empty?
|
73
|
+
context_body << process(tests.shift) until tests.empty?
|
74
|
+
context_body << process(rest.shift) until rest.empty?
|
75
|
+
exp.clear
|
76
|
+
|
77
|
+
result = [:iter, [:fcall, :context, [:array, [:str, context_name]]], nil]
|
78
|
+
if context_body.length > 1
|
79
|
+
result << [:block] + context_body
|
80
|
+
else
|
81
|
+
result += context_body
|
82
|
+
end
|
83
|
+
[result]
|
84
|
+
end
|
85
|
+
|
86
|
+
def process_defn(exp)
|
87
|
+
method_name = exp[1].to_s
|
88
|
+
if method_name =~ /^test_(.*)/
|
89
|
+
spec_name = $1.gsub(/_/, " ")
|
90
|
+
|
91
|
+
test_body = exp[2][1][2..-1]
|
92
|
+
exp.clear
|
93
|
+
block_body = []
|
94
|
+
@dasgn_decl = []
|
95
|
+
block_body << process(test_body.shift) until test_body.empty?
|
96
|
+
result = [:iter, [:fcall, :specify, [:array, [:str, spec_name]]], nil]
|
97
|
+
result << [:block] unless block_body == [[:nil]]
|
98
|
+
result[-1] += @dasgn_decl unless @dasgn_decl.empty?
|
99
|
+
result[-1] += block_body unless block_body == [[:nil]]
|
100
|
+
result
|
101
|
+
elsif method_name == "setup" || method_name == "teardown"
|
102
|
+
test_body = exp[2][1][2..-1]
|
103
|
+
exp.clear
|
104
|
+
block_body = []
|
105
|
+
@dasgn_decl = []
|
106
|
+
block_body << process(test_body.shift) until test_body.empty?
|
107
|
+
result = [:iter, [:fcall, method_name.to_sym], nil]
|
108
|
+
result << [:block] unless block_body == [[:nil]]
|
109
|
+
result[-1] += @dasgn_decl unless @dasgn_decl.empty?
|
110
|
+
result[-1] += block_body unless block_body == [[:nil]]
|
111
|
+
result
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def process_lasgn(exp)
|
116
|
+
result = exp.dup
|
117
|
+
result[0] = :dasgn_curr
|
118
|
+
decl = result[0..1].dup
|
119
|
+
if @dasgn_decl.empty?
|
120
|
+
@dasgn_decl += [decl]
|
121
|
+
else
|
122
|
+
@dasgn_decl_tail << decl
|
123
|
+
end
|
124
|
+
@dasgn_decl_tail = decl
|
125
|
+
exp.clear
|
126
|
+
result
|
127
|
+
end
|
128
|
+
|
129
|
+
# Handles 'block' assert_ calls
|
130
|
+
def process_iter(exp)
|
131
|
+
test_unit_fcall = exp[1][1]
|
132
|
+
rspec_should = TRANSLATIONS[test_unit_fcall]
|
133
|
+
unless rspec_should.nil?
|
134
|
+
body = exp[3]
|
135
|
+
args = exp[1][2]
|
136
|
+
args.delete_at(2) unless args.nil? # get rid of the message arg
|
137
|
+
result = [:call, [:iter, [:fcall, :lambda], nil, body], rspec_should]
|
138
|
+
result << args unless args.nil?
|
139
|
+
result << [:array, [:true]] if test_unit_fcall == :assert_block
|
140
|
+
exp.clear
|
141
|
+
result
|
142
|
+
else
|
143
|
+
exp.shift
|
144
|
+
result = [:iter]
|
145
|
+
result << process(exp.shift) until exp.empty?
|
146
|
+
result
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Handles regular assert_ calls
|
151
|
+
def process_fcall(exp)
|
152
|
+
test_unit_fcall = exp[1]
|
153
|
+
rspec_should = TRANSLATIONS[test_unit_fcall]
|
154
|
+
unless rspec_should.nil?
|
155
|
+
args = exp[2]
|
156
|
+
actual_index = [:assert, :assert_not_nil, :assert_nil, :assert_respond_to].index(test_unit_fcall) ? 1 : 2
|
157
|
+
actual = args.delete_at(actual_index)
|
158
|
+
expected = args
|
159
|
+
if test_unit_fcall == :assert_in_delta
|
160
|
+
expected.delete_at(3)
|
161
|
+
expected << args.delete_at(2)
|
162
|
+
else
|
163
|
+
msg_index = (test_unit_fcall == :assert_respond_to) ? 2 : actual_index
|
164
|
+
expected.delete_at(msg_index)
|
165
|
+
end
|
166
|
+
expected << [:true] if test_unit_fcall == :assert
|
167
|
+
expected << [:nil] if [:assert_not_nil, :assert_nil].index(test_unit_fcall)
|
168
|
+
|
169
|
+
actual = process(actual)
|
170
|
+
|
171
|
+
result = [:call, actual, rspec_should, expected]
|
172
|
+
exp.clear
|
173
|
+
result
|
174
|
+
else
|
175
|
+
result = exp.dup
|
176
|
+
exp.clear
|
177
|
+
result
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def process_lvar(exp)
|
182
|
+
result = exp.dup
|
183
|
+
result[0] = :dvar
|
184
|
+
exp.clear
|
185
|
+
result
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|