rspec 0.5.9 → 0.5.10
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.
- 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
|