rspec 0.4.0 → 0.5.0

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.
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