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 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
- * test2spec uses RubyInline, RubyToC and ParseTree
15
- * The spectask needs rcov if rcov is enabled.
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 => [:test]
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 :doc => :test2spec do
55
- sh %{pushd doc; webgen; popd}
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/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, :doc, :examples_specdoc, :rdoc]
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']
@@ -7,10 +7,10 @@ require 'test/unit/ui/testrunnermediator'
7
7
  require 'test/unit/autorunner'
8
8
  require 'optparse'
9
9
 
10
- $LOAD_PATH.push File.dirname(__FILE__) + '/../lib'
10
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
11
11
 
12
12
  require 'rubygems'
13
- require 'spec/tool/translation_test_runner'
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 create each file. The template",
30
- "has access toi the following variables:",
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::Tool::TranslationTestRunner }
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
@@ -11,7 +11,7 @@
11
11
  <div id="container">
12
12
  <div id="header">
13
13
  <h2>Behaviour Driven Development for <strong>Ruby</strong></h2>
14
- <h1>RSpec</h1>
14
+ <h1>RSpec {version: }</h1>
15
15
  </div>
16
16
 
17
17
  <div id="navigation">
@@ -4,7 +4,7 @@ inMenu: true
4
4
  ---
5
5
  h2. Rake Task
6
6
 
7
- RSpec coomes with a Rake task for executing specs.
7
+ RSpec comes with a Rake task for executing specs.
8
8
  See "Spec::Rake::SpecTask":../rdoc/classes/Spec/Rake/SpecTask.html for details.
9
9
 
10
10
  h3. Run specs
@@ -2,11 +2,11 @@
2
2
  title: Test::Unit Migration
3
3
  inMenu: true
4
4
  ---
5
- h2. Test::Unit migration
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/tool/test_unit_api_test.rb"/>
49
+ <ruby file="../test/spec/test_to_spec/testfiles/test_unit_api_test.rb"/>
50
50
  </td>
51
51
  <td>
52
- <ruby file="../spec/spec/tool/test_unit_api_spec.rb"/>
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 tool is based on three other tools:
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.
@@ -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, context_count, spec_count, failure_count)
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"
@@ -43,7 +43,7 @@ module Spec
43
43
  def dump
44
44
  @formatter.start_dump
45
45
  dump_failures
46
- @formatter.dump_summary(duration, @context_names.length, @spec_names.length, @failures.length)
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
- $stderr.puts "You must gem install ParseTree (and RubyInline)"
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