rspec 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/CHANGES +7 -12
  2. data/Rakefile +17 -12
  3. data/TUTORIAL +1 -1
  4. data/WHY_RSPEC +115 -0
  5. data/bin/spec +17 -4
  6. data/bin/test2rspec +35 -0
  7. data/examples/airport_spec.rb +35 -0
  8. data/examples/mocking_spec.rb +16 -0
  9. data/examples/spec_framework_spec.rb +28 -0
  10. data/examples/stack.rb +36 -0
  11. data/examples/stack_spec.rb +112 -0
  12. data/lib/spec.rb +5 -18
  13. data/lib/spec/api.rb +4 -0
  14. data/lib/spec/{exceptions.rb → api/exceptions.rb} +1 -1
  15. data/lib/spec/{expectations.rb → api/expectations.rb} +5 -4
  16. data/lib/spec/api/helper.rb +10 -0
  17. data/lib/spec/{have_helper.rb → api/helper/have_helper.rb} +1 -1
  18. data/lib/spec/{instance_helper.rb → api/helper/instance_helper.rb} +0 -0
  19. data/lib/spec/{instance_negator.rb → api/helper/instance_negator.rb} +0 -0
  20. data/lib/spec/{kind_helper.rb → api/helper/kind_helper.rb} +0 -0
  21. data/lib/spec/{kind_negator.rb → api/helper/kind_negator.rb} +0 -0
  22. data/lib/spec/{respond_helper.rb → api/helper/respond_helper.rb} +0 -0
  23. data/lib/spec/{respond_negator.rb → api/helper/respond_negator.rb} +0 -0
  24. data/lib/spec/{should_base.rb → api/helper/should_base.rb} +6 -4
  25. data/lib/spec/{should_helper.rb → api/helper/should_helper.rb} +12 -0
  26. data/lib/spec/{should_negator.rb → api/helper/should_negator.rb} +11 -0
  27. data/lib/spec/api/mock.rb +184 -0
  28. data/lib/spec/rake/spectask.rb +153 -0
  29. data/lib/spec/runner.rb +9 -0
  30. data/lib/spec/runner/backtrace_tweaker.rb +17 -0
  31. data/lib/spec/runner/context.rb +47 -0
  32. data/lib/spec/runner/context_runner.rb +52 -0
  33. data/lib/spec/runner/execution_context.rb +15 -0
  34. data/lib/spec/runner/instance_exec.rb +15 -0
  35. data/lib/spec/runner/kernel_ext.rb +6 -0
  36. data/lib/spec/runner/option_parser.rb +41 -0
  37. data/lib/spec/runner/rdoc_formatter.rb +17 -0
  38. data/lib/spec/runner/simple_text_reporter.rb +92 -0
  39. data/lib/spec/runner/specification.rb +42 -0
  40. data/lib/spec/tool/command_line.rb +39 -0
  41. data/lib/spec/tool/test_unit_translator.rb +112 -0
  42. data/lib/spec/version.rb +13 -0
  43. data/test/spec/api/helper/arbitrary_predicate_test.rb +121 -0
  44. data/test/spec/api/helper/containment_test.rb +117 -0
  45. data/test/spec/api/helper/equality_test.rb +46 -0
  46. data/test/spec/api/helper/identity_test.rb +68 -0
  47. data/test/spec/api/helper/raising_test.rb +50 -0
  48. data/test/spec/api/helper/regex_matching_test.rb +38 -0
  49. data/test/spec/api/helper/should_satisfy_test.rb +37 -0
  50. data/test/spec/api/helper/throwing_test.rb +56 -0
  51. data/test/spec/api/helper/true_false_special_case_test.rb +87 -0
  52. data/test/spec/api/helper/typing_test.rb +107 -0
  53. data/test/spec/api/mock_test.rb +161 -0
  54. data/test/spec/runner/backtrace_tweaker_test.rb +20 -0
  55. data/test/spec/runner/context_runner_test.rb +19 -0
  56. data/test/spec/runner/context_test.rb +29 -0
  57. data/test/spec/runner/execution_context_test.rb +13 -0
  58. data/test/spec/runner/option_parser_test.rb +50 -0
  59. data/test/spec/runner/rdoc_formatter_test.rb +23 -0
  60. data/test/spec/runner/simple_text_reporter_test.rb +128 -0
  61. data/test/spec/runner/specification_test.rb +70 -0
  62. data/test/spec/tool/command_line_test.rb +22 -0
  63. data/test/spec/tool/test_unit_api_spec.rb +61 -0
  64. data/test/spec/tool/test_unit_api_test.rb +61 -0
  65. data/test/spec/tool/test_unit_translator_test.rb +29 -0
  66. data/test/test_helper.rb +8 -0
  67. metadata +89 -67
  68. data/examples/add_specification_spec.rb +0 -15
  69. data/examples/craps.rb +0 -15
  70. data/examples/craps_spec.rb +0 -105
  71. data/examples/dsl_spec.rb +0 -8
  72. data/examples/movie.rb +0 -7
  73. data/examples/movie_list.rb +0 -19
  74. data/examples/movie_spec.rb +0 -37
  75. data/lib/spec/collector.rb +0 -17
  76. data/lib/spec/context.rb +0 -89
  77. data/lib/spec/dsl.rb +0 -23
  78. data/lib/spec/gui_runner.rb +0 -59
  79. data/lib/spec/mock.rb +0 -183
  80. data/lib/spec/text_runner.rb +0 -75
  81. data/test/collection_owner.rb +0 -48
  82. data/test/context_fixtures_test.rb +0 -71
  83. data/test/context_run_test.rb +0 -174
  84. data/test/dsl_test.rb +0 -48
  85. data/test/error_reporting_test.rb +0 -225
  86. data/test/expectations_for_should_have_test.rb +0 -144
  87. data/test/expectations_test.rb +0 -592
  88. data/test/get_classes.rb +0 -6
  89. data/test/gui_runner_test.rb +0 -162
  90. data/test/mock_test.rb +0 -157
  91. data/test/spec_collection_test.rb +0 -39
  92. data/test/specification_addition_test.rb +0 -29
  93. data/test/specification_identification_test.rb +0 -71
  94. data/test/text_runner_test.rb +0 -146
@@ -0,0 +1,9 @@
1
+ require 'spec/runner/instance_exec'
2
+ require 'spec/runner/context'
3
+ require 'spec/runner/specification'
4
+ require 'spec/runner/execution_context'
5
+ require 'spec/runner/context_runner'
6
+ require 'spec/runner/option_parser'
7
+ require 'spec/runner/backtrace_tweaker'
8
+ require 'spec/runner/rdoc_formatter'
9
+ require 'spec/runner/simple_text_reporter'
@@ -0,0 +1,17 @@
1
+ module Spec
2
+ module Runner
3
+ class BacktraceTweaker
4
+ def tweak_backtrace error, spec_name
5
+ return if error.backtrace.nil?
6
+ tweaked_backtrace = []
7
+ error.backtrace.each do |line|
8
+ if line.include?('__instance_exec')
9
+ line = line.split(':in')[0] + ":in `#{spec_name}'"
10
+ end
11
+ tweaked_backtrace.push line
12
+ end
13
+ error.set_backtrace tweaked_backtrace
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ module Spec
2
+ module Runner
3
+ class Context
4
+ @@context_runner = nil
5
+
6
+ def self.context_runner= runner
7
+ @@context_runner = runner
8
+ end
9
+
10
+ def initialize(name, &context_block)
11
+ @setup_block = nil
12
+ @teardown_block = nil
13
+ @specifications = []
14
+ @name = name
15
+ instance_exec(&context_block)
16
+ @@context_runner.add_context(self) unless @@context_runner.nil?
17
+ ContextRunner.standalone(self) if @@context_runner.nil?
18
+ end
19
+
20
+ def run(reporter)
21
+ reporter.add_context(@name)
22
+ @specifications.each do |specification|
23
+ specification.run(reporter, @setup_block, @teardown_block)
24
+ end
25
+ end
26
+
27
+ def run_docs(reporter)
28
+ reporter.add_context(@name)
29
+ @specifications.each do |specification|
30
+ specification.run_docs(reporter)
31
+ end
32
+ end
33
+
34
+ def setup(&block)
35
+ @setup_block = block
36
+ end
37
+
38
+ def teardown(&block)
39
+ @teardown_block = block
40
+ end
41
+
42
+ def specify(spec_name, &block)
43
+ @specifications << Specification.new(spec_name, &block)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,52 @@
1
+ require File.dirname(__FILE__) + '/../../spec'
2
+
3
+ module Spec
4
+ module Runner
5
+ class ContextRunner
6
+
7
+ def self.standalone context
8
+ context_runner = ContextRunner.new(ARGV)
9
+ context_runner.add_context context
10
+ context_runner.run
11
+ end
12
+
13
+ def initialize(args)
14
+ options = OptionParser.parse(args)
15
+ @contexts = []
16
+ @out = options.out
17
+ @out = File.open(@out, 'w') if @out.is_a? String
18
+ @doc = options.doc
19
+ @listener = RDocFormatter.new(@out) if @doc
20
+ @listener = SimpleTextReporter.new(@out, options.verbose) unless @doc
21
+ end
22
+
23
+ def add_context(context)
24
+ @contexts << context
25
+ self
26
+ end
27
+
28
+ def run
29
+ run_specs unless @doc
30
+ run_docs if @doc
31
+ end
32
+
33
+ private
34
+
35
+ def run_specs
36
+ @listener.start
37
+ @contexts.each do |context|
38
+ context.run(@listener)
39
+ end
40
+ @listener.end
41
+ @listener.dump
42
+ end
43
+
44
+ def run_docs
45
+ @contexts.each do |context|
46
+ context.run_docs(@listener)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ module Spec
2
+ module Runner
3
+ class ExecutionContext
4
+ def initialize(spec)
5
+ @spec = spec
6
+ end
7
+
8
+ def mock(name)
9
+ mock = Api::Mock.new(name)
10
+ @spec.add_mock(mock)
11
+ mock
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # http://eigenclass.org/hiki.rb?cmd=view&p=instance_exec&key=instance_exec
2
+ class Object
3
+ module InstanceExecHelper; end
4
+ include InstanceExecHelper
5
+ def instance_exec(*args, &block) # !> method redefined; discarding old instance_exec
6
+ mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
7
+ InstanceExecHelper.module_eval{ define_method(mname, &block) }
8
+ begin
9
+ ret = send(mname, *args)
10
+ ensure
11
+ InstanceExecHelper.module_eval{ undef_method(mname) } rescue nil
12
+ end
13
+ ret
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Kernel
2
+ def context(name, &block)
3
+ Spec::Runner::Context.new(name, &block) unless $generating_docs
4
+ Spec::Runner::DocumentationContext.new(name, &block) if $generating_docs
5
+ end
6
+ end
@@ -0,0 +1,41 @@
1
+ require 'ostruct'
2
+ require 'optparse'
3
+ module Spec
4
+ module Runner
5
+ class OptionParser
6
+
7
+ def self.parse(args)
8
+ options = OpenStruct.new
9
+ options.out = $stdout
10
+ options.verbose = false;
11
+ options.doc = false;
12
+
13
+ opts = ::OptionParser.new do |opts|
14
+ opts.banner = "Usage: specdoc [options] FILE|DIRECTORY"
15
+ opts.separator ""
16
+
17
+ opts.on("-o", "--of [FILE]", "Set the output file (defaults to STDOUT)") do |outfile|
18
+ options.out = outfile unless outfile.nil?
19
+ exit if outfile.nil?
20
+ end
21
+
22
+ opts.on("-v", "--verbose") do
23
+ options.verbose = true
24
+ end
25
+
26
+ opts.on("-d", "--doc", "Generate documentation") do
27
+ options.doc = true
28
+ end
29
+
30
+ opts.on_tail("-h", "--help", "Show this message") do
31
+ puts opts
32
+ exit
33
+ end
34
+
35
+ end
36
+ opts.parse!(args)
37
+ options
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ module Spec
2
+ module Runner
3
+ class RDocFormatter
4
+ def initialize(output=STDOUT)
5
+ @output = output
6
+ end
7
+
8
+ def add_context(name)
9
+ @output << "# #{name}\n"
10
+ end
11
+
12
+ def add_spec(name)
13
+ @output << "# * #{name}\n"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,92 @@
1
+ module Spec
2
+ module Runner
3
+ class SimpleTextReporter
4
+ def initialize(output=STDOUT,verbose=false,backtrace_tweaker=BacktraceTweaker.new)
5
+ @output = output
6
+ @context_names = []
7
+ @errors = []
8
+ @spec_names = []
9
+ @verbose = verbose
10
+ @backtrace_tweaker = backtrace_tweaker
11
+ end
12
+
13
+ def add_context(name)
14
+ @output << "\n" if @context_names.empty? unless @verbose
15
+ @output << "\n#{name}\n" if @verbose
16
+ @context_names << name
17
+ end
18
+
19
+ def add_spec(name, errors=[])
20
+ if errors.empty?
21
+ spec_passed(name)
22
+ else
23
+ errors.each { |error| @backtrace_tweaker.tweak_backtrace(error, name) }
24
+ # only show the first one (there might be more)
25
+ spec_failed(name, errors[0])
26
+ end
27
+ end
28
+
29
+ def start
30
+ @start_time = Time.new
31
+ end
32
+
33
+ def end
34
+ @end_time = Time.new
35
+ end
36
+
37
+ def dump
38
+ unless @verbose
39
+ @output << "\n"
40
+ dump_failures
41
+ @output << "\n\n" unless @errors.empty?
42
+ end
43
+ @output << "\n" if @errors.empty?
44
+ @output << "Finished in " << (duration).to_s << " seconds\n\n"
45
+ @output << "#{@context_names.length} context#{'s' unless @context_names.length == 1 }, "
46
+ @output << "#{@spec_names.length} specification#{'s' unless @spec_names.length == 1 }, "
47
+ @output << "#{@errors.length} failure#{'s' unless @errors.length == 1 }"
48
+ @output << "\n"
49
+ end
50
+
51
+ def dump_failures
52
+ return if @errors.empty?
53
+ @output << "\n"
54
+ @errors.inject(1) do |index, error|
55
+ @output << "\n\n" if index > 1
56
+ @output << index.to_s << ") "
57
+ @output << "#{error.message} (#{error.class.name})\n"
58
+ dump_backtrace(error.backtrace)
59
+ index + 1
60
+ end
61
+ end
62
+
63
+ def dump_backtrace(trace)
64
+ @output << trace.join("\n") unless trace.nil?
65
+ end
66
+
67
+ private
68
+
69
+ def duration
70
+ return @end_time - @start_time unless (@end_time.nil? or @start_time.nil?)
71
+ return "0.0"
72
+ end
73
+
74
+ def spec_passed(name)
75
+ @spec_names << name
76
+ @output << "- #{name}\n" if @verbose
77
+ @output << '.' unless @verbose
78
+ end
79
+
80
+ def spec_failed(name, error)
81
+ @spec_names << name
82
+ @errors << error
83
+ if @verbose
84
+ @output << "- #{name} (FAILED)\n#{error.message} (#{error.class.name})\n#{error.backtrace.join("\n")}\n"
85
+ else
86
+ @output << 'F'
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,42 @@
1
+ module Spec
2
+ module Runner
3
+ class Specification
4
+
5
+ def initialize(name, &block)
6
+ @name = name
7
+ @block = block
8
+ @mocks = []
9
+ @errors = []
10
+ end
11
+
12
+ def run(reporter=nil, setup_block=nil, teardown_block=nil)
13
+ execution_context = ::Spec::Runner::ExecutionContext.new(self)
14
+ begin
15
+ execution_context.instance_exec(&setup_block) unless setup_block.nil?
16
+ execution_context.instance_exec(&@block)
17
+ rescue => e
18
+ @errors << e
19
+ end
20
+
21
+ begin
22
+ execution_context.instance_exec(&teardown_block) unless teardown_block.nil?
23
+ @mocks.each do |mock|
24
+ mock.__verify
25
+ end
26
+ rescue => e
27
+ @errors << e
28
+ end
29
+
30
+ reporter.add_spec(@name, @errors) unless reporter.nil?
31
+ end
32
+
33
+ def run_docs(reporter)
34
+ reporter.add_spec(@name)
35
+ end
36
+
37
+ def add_mock(mock)
38
+ @mocks << mock
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ require 'find'
2
+ require 'fileutils'
3
+
4
+ module Spec
5
+ module Tool
6
+ class CommandLine
7
+ def initialize(filesystem=nil)
8
+ @filesystem = filesystem.nil? ? self : filesystem
9
+ @translator = TestUnitTranslator.new
10
+ end
11
+
12
+ def run(source, dest, out)
13
+ if FileTest.directory?(source)
14
+ raise "DEST must be a directory when SOURCE is a directory" if FileTest.file?(dest)
15
+ Find.find(source) do |path|
16
+ if FileTest.file?(path) and File.extname(path) == '.rb'
17
+ relative_path = path[source.length+1..-1]
18
+ dest_path = File.join dest, relative_path
19
+ run path, dest_path, out
20
+ end
21
+ end
22
+ else
23
+ raise "DEST must be a file when SOURCE is a file" if FileTest.directory?(dest)
24
+ out.puts "Writing: #{dest}"
25
+ @filesystem.write_translation(source, dest)
26
+ end
27
+ end
28
+
29
+ def write_translation(source, dest)
30
+ dir = File.dirname(dest)
31
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
32
+ File.open(dest, "w") do |io|
33
+ translation = @translator.translate(source)
34
+ io.write(translation)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,112 @@
1
+ module Spec
2
+ module Tool
3
+ # Translates Test::Unit tests to RSpec specs.
4
+ class TestUnitTranslator
5
+ ONE_ARG_TRANSLATIONS = {
6
+ "assert" => "should.not.be nil",
7
+ "assert_nil" => "should.be nil",
8
+ "assert_not_nil" => "should.not.be nil"
9
+
10
+ }
11
+ TWO_ARG_TRANSLATIONS = {
12
+ "assert_equal" => "should.equal",
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_not_equal" => "should.not.equal",
18
+ "assert_not_same" => "should.not.be",
19
+ "assert_same" => "should.be"
20
+ }
21
+ RAISE_TRANSLATIONS = {
22
+ "assert_nothing_raised" => "should.not.raise",
23
+ "assert_nothing_thrown" => "should.not.throw",
24
+ "assert_raise" => "should.raise",
25
+ "assert_raises" => "should.raise",
26
+ "assert_throws" => "should.throw",
27
+ }
28
+
29
+ def translate(test_unit_file)
30
+ content = File.open(test_unit_file)
31
+ end_replacement = nil
32
+ translated = ""
33
+ content.each do |line|
34
+ if line =~ /^require .*test.*/
35
+ line = "require 'spec'\n"
36
+ elsif line =~ /^(\s*)def\s+setup/
37
+ spaces = $1
38
+ line = "#{spaces}setup do\n"
39
+ elsif line =~ /^(\s*)def\s+teardown/
40
+ spaces = $1
41
+ line = "#{spaces}teardown do\n"
42
+ elsif line =~ /^(\s*)class\s+(.*)\s+<\s+Test::Unit::TestCase/
43
+ spaces = $1
44
+ class_name = $2
45
+
46
+ context_name = class_name.match(/(.*)Test/)[1]
47
+ line = "#{spaces}context \"#{context_name}\" do\n"
48
+
49
+ elsif line =~ /(\s*)def\s+test_(.*)/
50
+ spaces = $1
51
+ method_meaning = $2
52
+
53
+ specification_name = method_meaning.gsub(/_/, " ").capitalize
54
+ line = "#{spaces}specify \"#{specification_name}\" do\n"
55
+
56
+ elsif line =~ /(\s*)(assert[^\s$\(]*)\s*\(?([^\)^\{]*)\)?\s*(.*)/
57
+ spaces = $1
58
+ assertion = $2
59
+ args = $3
60
+ suffix = $4
61
+
62
+ if(args =~ /^do/n and suffix =="")
63
+ # hack to handle methods taking no args and do at the end
64
+ args = ""
65
+ suffix = "do"
66
+ end
67
+
68
+ if translation = TWO_ARG_TRANSLATIONS[assertion]
69
+ expected, actual, message = args.split(",").collect{|arg| arg.strip}
70
+ line = "#{spaces}#{actual}.#{translation} #{expected}\n"
71
+
72
+ elsif assertion == "assert_respond_to"
73
+ actual, method, message = args.split(",").collect{|arg| arg.strip}
74
+ line = "#{spaces}#{actual}.should.respond.to #{method}\n"
75
+
76
+ elsif translation = ONE_ARG_TRANSLATIONS[assertion]
77
+ actual, message = args.split(",").collect{|arg| arg.strip}
78
+ line = "#{spaces}#{actual}.#{translation}\n"
79
+
80
+ elsif translation = RAISE_TRANSLATIONS[assertion] and suffix =~ /\{.*\}/
81
+ expected, message = args.split(",").collect{|arg| arg.strip}
82
+ line = "#{spaces}lambda #{suffix}.#{translation} #{expected}\n"
83
+
84
+ elsif translation = RAISE_TRANSLATIONS[assertion]
85
+ expected, message = args.split(",").collect{|arg| arg.strip}
86
+ line = "#{spaces}lambda do\n"
87
+ end_replacement = "#{translation} #{expected}\n"
88
+
89
+ elsif assertion == "assert_block" and suffix =~ /\{.*\}/
90
+ line = "#{spaces}lambda #{suffix}.should.be true\n"
91
+
92
+ elsif assertion == "assert_block"
93
+ line = "#{spaces}lambda do\n"
94
+ end_replacement = "should.be true\n"
95
+
96
+ elsif assertion == "assert_in_delta"
97
+ expected, actual, delta, message = args.split(",").collect{|arg| arg.strip}
98
+ line = "#{spaces}#{actual}.should.be.close #{expected}, #{delta}\n"
99
+ end
100
+ elsif end_replacement && line =~ /(\s+)end/
101
+ spaces = $1
102
+ line = "#{spaces}end.#{end_replacement}"
103
+ end_replacement = nil
104
+ end
105
+
106
+ translated += line unless line.nil?
107
+ end
108
+ translated
109
+ end
110
+ end
111
+ end
112
+ end