tack 0.0.0 → 0.0.1
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/README.rdoc +5 -1
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/bin/tack +59 -0
- data/lib/tack.rb +30 -0
- data/lib/tack/adapters/adapter.rb +25 -0
- data/lib/tack/adapters/rspec_adapter.rb +106 -0
- data/lib/tack/adapters/test_unit_adapter.rb +114 -0
- data/lib/tack/formatters/basic_summary.rb +22 -0
- data/lib/tack/formatters/print_failures.rb +43 -0
- data/lib/tack/formatters/profiler.rb +39 -0
- data/lib/tack/formatters/progress_bar.rb +36 -0
- data/lib/tack/formatters/total_time.rb +23 -0
- data/lib/tack/middleware.rb +22 -0
- data/lib/tack/runner.rb +50 -0
- data/lib/tack/test_pattern.rb +21 -0
- data/lib/tack/test_set.rb +39 -0
- data/test/acceptance/rspec_test.rb +134 -0
- data/test/acceptance/test_unit_test.rb +139 -0
- data/test/tack_test.rb +4 -2
- data/test/test_helper.rb +3 -0
- metadata +35 -6
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= tack
|
2
2
|
|
3
|
-
|
3
|
+
USE AT YOUR OWN RISK. This is highly experimental and the interface is changing rapidly.
|
4
4
|
|
5
5
|
== Note on Patches/Pull Requests
|
6
6
|
|
@@ -13,6 +13,10 @@ Description goes here.
|
|
13
13
|
bump version in a commit by itself I can ignore when I pull)
|
14
14
|
* Send me a pull request. Bonus points for topic branches.
|
15
15
|
|
16
|
+
== Acknowledgements
|
17
|
+
|
18
|
+
Tack is heavily inspired by Rack and Faraday and borrows ideas and code from both. Early versions of the Test::Unit and RSpec adapters borrowed code from Hydra.
|
19
|
+
|
16
20
|
== Copyright
|
17
21
|
|
18
22
|
Copyright (c) 2010 Ben Brinckerhoff. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -10,7 +10,9 @@ begin
|
|
10
10
|
gem.email = "ben@bbrinck.com"
|
11
11
|
gem.homepage = "http://github.com/bhb/tack"
|
12
12
|
gem.authors = ["Ben Brinckerhoff"]
|
13
|
+
gem.add_dependency "test-unit", "~> 1.0" if RUBY_VERSION=~/1\.9/
|
13
14
|
gem.add_development_dependency "shoulda"
|
15
|
+
gem.add_development_dependency "test-construct"
|
14
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
17
|
end
|
16
18
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
data/bin/tack
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
3
|
+
|
4
|
+
require 'tack'
|
5
|
+
require 'pp'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
def require_ruby_debug
|
9
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
10
|
+
require 'ruby-debug'
|
11
|
+
end
|
12
|
+
|
13
|
+
options = {}
|
14
|
+
option_parser = OptionParser.new do |opts|
|
15
|
+
opts.banner = "Usage: tack [options] [file]"
|
16
|
+
opts.on("-I","--include PATH", "specify $LOAD_PATH (may be used more than once)") do |path|
|
17
|
+
options[:include] = path.split(":")
|
18
|
+
end
|
19
|
+
opts.on("-n", "--name PATTERN", "run only tests that match pattern") do |pattern|
|
20
|
+
if pattern=~/^\/.*\/$/
|
21
|
+
options[:pattern] = Regexp.new(pattern[1..-2])
|
22
|
+
else
|
23
|
+
options[:pattern] = pattern
|
24
|
+
end
|
25
|
+
end
|
26
|
+
opts.on("-u", "--debugger", "Enable ruby-debugging.") do
|
27
|
+
require_ruby_debug
|
28
|
+
end
|
29
|
+
opts.on_tail("-h","--help", "Show this message") do
|
30
|
+
puts opts
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
args = ARGV
|
36
|
+
option_parser.parse! args
|
37
|
+
options[:paths] = ARGV
|
38
|
+
|
39
|
+
if includes = options[:include]
|
40
|
+
$LOAD_PATH.unshift *includes
|
41
|
+
end
|
42
|
+
|
43
|
+
runner = Tack::Runner.new(:root => Dir.pwd) do |runner|
|
44
|
+
runner.use Tack::Formatters::Profiler, :tests => 3
|
45
|
+
runner.use Tack::Formatters::TotalTime
|
46
|
+
runner.use Tack::Formatters::PrintFailures
|
47
|
+
runner.use Tack::Formatters::BasicSummary
|
48
|
+
runner.use Tack::Formatters::ProgressBar
|
49
|
+
end
|
50
|
+
|
51
|
+
set = Tack::TestSet.new(Dir.pwd)
|
52
|
+
tests = set.tests_for(options[:paths], Tack::TestPattern.new(options[:pattern]))
|
53
|
+
|
54
|
+
runner.run(tests)
|
55
|
+
|
56
|
+
exit 0
|
57
|
+
|
58
|
+
|
59
|
+
|
data/lib/tack.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
libdir = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
3
|
+
|
4
|
+
module Tack
|
5
|
+
|
6
|
+
autoload :Runner, 'tack/runner'
|
7
|
+
autoload :TestSet, 'tack/test_set'
|
8
|
+
autoload :Middleware, 'tack/middleware'
|
9
|
+
autoload :TestPattern, 'tack/test_pattern'
|
10
|
+
|
11
|
+
|
12
|
+
module Adapters
|
13
|
+
|
14
|
+
autoload :Adapter, 'tack/adapters/adapter'
|
15
|
+
autoload :RSpecAdapter, 'tack/adapters/rspec_adapter'
|
16
|
+
autoload :TestUnitAdapter, 'tack/adapters/test_unit_adapter'
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module Formatters
|
21
|
+
|
22
|
+
autoload :BasicSummary, 'tack/formatters/basic_summary'
|
23
|
+
autoload :ProgressBar, 'tack/formatters/progress_bar'
|
24
|
+
autoload :Profiler, 'tack/formatters/profiler'
|
25
|
+
autoload :TotalTime, 'tack/formatters/total_time'
|
26
|
+
autoload :PrintFailures, 'tack/formatters/print_failures'
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
module Adapters
|
4
|
+
|
5
|
+
class Adapter
|
6
|
+
|
7
|
+
def self.for(path)
|
8
|
+
# Using a simple path-based heuristic for now
|
9
|
+
case path
|
10
|
+
when /test.rb$/
|
11
|
+
TestUnitAdapter.new
|
12
|
+
when /spec.rb$/
|
13
|
+
RSpecAdapter.new
|
14
|
+
else
|
15
|
+
raise "Cannot determine an adapter for path #{path}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'spec/runner/formatter/base_formatter'
|
3
|
+
|
4
|
+
if defined?(Spec)
|
5
|
+
module Spec
|
6
|
+
module Runner
|
7
|
+
class << self
|
8
|
+
# stop the auto-run at_exit
|
9
|
+
def run
|
10
|
+
return 0
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Spec
|
18
|
+
module Runner
|
19
|
+
module Formatter
|
20
|
+
# Stolen from Hydra for now
|
21
|
+
class TackFormatter < BaseFormatter
|
22
|
+
|
23
|
+
attr_accessor :results
|
24
|
+
|
25
|
+
def initialize(options)
|
26
|
+
io = StringIO.new # suppress output
|
27
|
+
super(options, io)
|
28
|
+
@results = { :passed => [],
|
29
|
+
:failed => [],
|
30
|
+
:pending => []}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Stifle the output of pending examples
|
34
|
+
def example_pending(example)
|
35
|
+
@results[:pending] << {
|
36
|
+
:description => example.description,
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def example_passed(example)
|
41
|
+
@results[:passed] << {
|
42
|
+
:description => example.description,
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def example_failed(example, counter, error=nil)
|
47
|
+
@results[:failed] <<
|
48
|
+
{
|
49
|
+
:description => example.description,
|
50
|
+
:failure => build_failure(example, error)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def build_failure(example, error)
|
57
|
+
case error.exception
|
58
|
+
when Spec::Expectations::ExpectationNotMetError
|
59
|
+
{ :message => error.exception.message,
|
60
|
+
:backtrace => error.exception.backtrace}
|
61
|
+
else
|
62
|
+
{ :message => "#{error.exception.class} was raised: #{error.exception.message}",
|
63
|
+
:backtrace => error.exception.backtrace}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module Tack
|
73
|
+
|
74
|
+
module Adapters
|
75
|
+
|
76
|
+
class RSpecAdapter
|
77
|
+
|
78
|
+
def tests_for(file, pattern)
|
79
|
+
Spec::Runner.options.instance_variable_set(:@formatters, [Spec::Runner::Formatter::TackFormatter.new(Spec::Runner.options.formatter_options)])
|
80
|
+
Spec::Runner.options.instance_variable_set(:@example_groups, [])
|
81
|
+
Spec::Runner.options.instance_variable_set(:@files, [file])
|
82
|
+
Spec::Runner.options.instance_variable_set(:@files_loaded, false)
|
83
|
+
runner = Spec::Runner::ExampleGroupRunner.new(Spec::Runner.options)
|
84
|
+
runner.load_files([file])
|
85
|
+
example_groups = runner.send(:example_groups)
|
86
|
+
examples = example_groups.inject([]) do |arr, group|
|
87
|
+
arr += group.examples
|
88
|
+
end
|
89
|
+
examples.map {|example| [file, example.description]}.select {|file,description| description.match(pattern)}
|
90
|
+
end
|
91
|
+
|
92
|
+
def run(file, test)
|
93
|
+
Spec::Runner.options.instance_variable_set(:@examples, [test])
|
94
|
+
Spec::Runner.options.instance_variable_set(:@example_groups, [])
|
95
|
+
Spec::Runner.options.instance_variable_set(:@files, [file])
|
96
|
+
Spec::Runner.options.instance_variable_set(:@files_loaded, false)
|
97
|
+
formatter = Spec::Runner::Formatter::TackFormatter.new(Spec::Runner.options.formatter_options)
|
98
|
+
Spec::Runner.options.instance_variable_set(:@formatters, [formatter])
|
99
|
+
Spec::Runner.options.run_examples
|
100
|
+
formatter.results
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
if RUBY_VERSION=~/1.9/
|
2
|
+
gem 'test-unit', '~> 1.0'
|
3
|
+
end
|
4
|
+
require 'test/unit'
|
5
|
+
require 'test/unit/testresult'
|
6
|
+
|
7
|
+
Test::Unit.run = true
|
8
|
+
|
9
|
+
module Tack
|
10
|
+
|
11
|
+
module Adapters
|
12
|
+
|
13
|
+
class TestUnitAdapter
|
14
|
+
|
15
|
+
def tests_for(file, pattern)
|
16
|
+
require file
|
17
|
+
classes = test_classes_for(file)
|
18
|
+
classes.inject([]) do |tests, klass|
|
19
|
+
tests += test_methods(klass).map {|method_name| [file, method_name.to_s]}.select {|file, method_name| method_name.match(pattern)}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def run(path, description)
|
24
|
+
results = { :passed => [],
|
25
|
+
:failed => [],
|
26
|
+
:pending => []}
|
27
|
+
require(path)
|
28
|
+
# Note that this won't work if there are multiple classes in a file
|
29
|
+
klass = test_classes_for(path).first
|
30
|
+
test = klass.new(description)
|
31
|
+
result = Test::Unit::TestResult.new
|
32
|
+
|
33
|
+
result.add_listener(Test::Unit::TestResult::FAULT) do |failure|
|
34
|
+
results[:failed] << build_result(description, failure)
|
35
|
+
end
|
36
|
+
|
37
|
+
test.run(result) do |started,name|
|
38
|
+
# We do nothing here
|
39
|
+
# but this method requires a block
|
40
|
+
end
|
41
|
+
if result.passed?
|
42
|
+
results[:passed] << build_result(description)
|
43
|
+
end
|
44
|
+
results
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def build_result(description, failure=nil)
|
50
|
+
{ :description => description,
|
51
|
+
:failure => build_failure(failure) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_failure(failure)
|
55
|
+
return {} if failure.nil?
|
56
|
+
case failure
|
57
|
+
when Test::Unit::Error
|
58
|
+
{ :message => "#{failure.exception.class} was raised: #{failure.exception.message}",
|
59
|
+
:backtrace => failure.exception.backtrace }
|
60
|
+
else
|
61
|
+
{ :message => failure.message,
|
62
|
+
:backtrace => failure.location }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_classes_for(file)
|
67
|
+
# taken from from hydra
|
68
|
+
#code = ""
|
69
|
+
# File.open(file) {|buffer| code = buffer.read}
|
70
|
+
code = File.read(file)
|
71
|
+
matches = code.scan(/class\s+([\S]+)/)
|
72
|
+
klasses = matches.collect do |c|
|
73
|
+
begin
|
74
|
+
if c.first.respond_to? :constantize
|
75
|
+
c.first.constantize
|
76
|
+
else
|
77
|
+
eval(c.first)
|
78
|
+
end
|
79
|
+
rescue NameError
|
80
|
+
# means we could not load [c.first], but thats ok, its just not
|
81
|
+
# one of the classes we want to test
|
82
|
+
nil
|
83
|
+
rescue SyntaxError
|
84
|
+
# see above
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
return klasses.select{|k| k.respond_to? 'suite'}
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_methods(test_class)
|
92
|
+
test_class.instance_methods.select do |method_name|
|
93
|
+
method_name =~ /^test./ &&
|
94
|
+
(test_class.instance_method(method_name).arity == 0 ||
|
95
|
+
test_class.instance_method(method_name).arity == -1
|
96
|
+
)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_test_classes
|
101
|
+
test_classes = []
|
102
|
+
ObjectSpace.each_object(Class) do |klass|
|
103
|
+
if(Test::Unit::TestCase > klass)
|
104
|
+
test_classes << klass
|
105
|
+
end
|
106
|
+
end
|
107
|
+
test_classes
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
module Formatters
|
4
|
+
|
5
|
+
class BasicSummary
|
6
|
+
include Middleware
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_suite(tests)
|
13
|
+
returning @app.run_suite(tests) do |results|
|
14
|
+
puts "%d tests, %d failures, %d pending" % [results.values.flatten.length, results[:failed].length, results[:pending].length]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
module Formatters
|
4
|
+
|
5
|
+
class PrintFailures
|
6
|
+
include Middleware
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_suite(tests)
|
13
|
+
returning @app.run_suite(tests) do |results|
|
14
|
+
results[:failed].each_with_index do |result, index|
|
15
|
+
print_failure(index+1, result)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def format_backtrace(backtrace)
|
23
|
+
return "" if backtrace.nil?
|
24
|
+
"["+backtrace.map { |line| backtrace_line(line) }.join("\n")+"]:"
|
25
|
+
end
|
26
|
+
|
27
|
+
def backtrace_line(line)
|
28
|
+
line.sub(/\A([^:]+:\d+)$/, '\\1:')
|
29
|
+
end
|
30
|
+
|
31
|
+
def print_failure(counter, result)
|
32
|
+
puts
|
33
|
+
puts "#{counter.to_s})"
|
34
|
+
puts result[:description]
|
35
|
+
puts format_backtrace(result[:failure][:backtrace])
|
36
|
+
puts result[:failure][:message]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
module Formatters
|
4
|
+
|
5
|
+
class Profiler
|
6
|
+
include Middleware
|
7
|
+
|
8
|
+
def initialize(app, args)
|
9
|
+
@app = app
|
10
|
+
@num_tests = args.fetch(:tests) { 10 }
|
11
|
+
@times = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_suite(tests)
|
15
|
+
returning @app.run_suite(tests) do |results|
|
16
|
+
puts "\n\nTop #{@num_tests} slowest examples:\n"
|
17
|
+
@times = @times.sort_by do |description, time|
|
18
|
+
time
|
19
|
+
end.reverse
|
20
|
+
@times[0..@num_tests-1].each do |description, time|
|
21
|
+
print "%.7f" % time
|
22
|
+
puts " #{description}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run_test(file, description)
|
28
|
+
time = Time.now
|
29
|
+
returning @app.run_test(file,description) do
|
30
|
+
@times << [description, Time.now - time]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
module Formatters
|
4
|
+
|
5
|
+
class ProgressBar
|
6
|
+
include Middleware
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_suite(tests)
|
13
|
+
returning @app.run_suite(tests) do
|
14
|
+
puts
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_test(file, description)
|
19
|
+
returning @app.run_test(file, description) do |result|
|
20
|
+
result[:passed].each do
|
21
|
+
print "."
|
22
|
+
end
|
23
|
+
result[:pending].each do
|
24
|
+
print "P"
|
25
|
+
end
|
26
|
+
result[:failed].each do
|
27
|
+
print "F"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
module Formatters
|
4
|
+
|
5
|
+
class TotalTime
|
6
|
+
include Middleware
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_suite(tests)
|
13
|
+
time = Time.now
|
14
|
+
returning @app.run_suite(tests) do
|
15
|
+
puts "Finished in %.7f seconds." % (Time.now - time)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
module Middleware
|
4
|
+
|
5
|
+
def run_suite(tests)
|
6
|
+
@app.run_suite(tests)
|
7
|
+
end
|
8
|
+
|
9
|
+
def run_test(file, description)
|
10
|
+
@app.run_test(file, description)
|
11
|
+
end
|
12
|
+
|
13
|
+
# not necessary for the middleware API, but handy for implementing
|
14
|
+
# middleware methods
|
15
|
+
def returning(value)
|
16
|
+
yield(value)
|
17
|
+
value
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/tack/runner.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
class Runner
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
if(args.is_a?(Hash))
|
7
|
+
@root_dir = args.fetch(:root)
|
8
|
+
else
|
9
|
+
@root_dir = args
|
10
|
+
end
|
11
|
+
@handlers = []
|
12
|
+
yield self if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(tests)
|
16
|
+
to_app if @start_app.nil?
|
17
|
+
@start_app.run_suite(tests)
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_suite(tests)
|
21
|
+
results = { :passed => [],
|
22
|
+
:failed => [],
|
23
|
+
:pending => []}
|
24
|
+
tests.each do |path, description|
|
25
|
+
result = @start_app.run_test(path, description)
|
26
|
+
results[:passed] += result[:passed]
|
27
|
+
results[:failed] += result[:failed]
|
28
|
+
results[:pending] += result[:pending]
|
29
|
+
end
|
30
|
+
results
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_test(path, description)
|
34
|
+
adapter = Adapters::Adapter.for(path)
|
35
|
+
adapter.run(path, description)
|
36
|
+
end
|
37
|
+
|
38
|
+
def use(middleware, *args, &block)
|
39
|
+
@handlers << lambda { |app|
|
40
|
+
middleware.new(app, *args, &block) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_app
|
44
|
+
inner_app = self
|
45
|
+
@start_app = @handlers.reverse.inject(inner_app) { |a, e| e.call(a) }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
class TestPattern < Regexp
|
4
|
+
|
5
|
+
DEFAULT = /.*/
|
6
|
+
|
7
|
+
def initialize(pattern=nil)
|
8
|
+
pattern = case pattern
|
9
|
+
when nil
|
10
|
+
DEFAULT
|
11
|
+
when String, Regexp
|
12
|
+
pattern
|
13
|
+
else
|
14
|
+
DEFAULT
|
15
|
+
end
|
16
|
+
super(pattern)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Tack
|
2
|
+
|
3
|
+
class TestSet
|
4
|
+
|
5
|
+
def initialize(root_dir)
|
6
|
+
@root_dir = root_dir
|
7
|
+
end
|
8
|
+
|
9
|
+
def tests_for(paths, pattern=TestPattern.new)
|
10
|
+
paths = Array(paths).map { |path| path.to_s}
|
11
|
+
files = paths.inject([]) do |files, path|
|
12
|
+
if File.directory?(path)
|
13
|
+
files += Dir[File.join(path,"**/*")].select {|f| valid_test_file?(f)}
|
14
|
+
else
|
15
|
+
files << path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
files.inject([]) do |tests, file|
|
20
|
+
adapter = Adapters::Adapter.for(file)
|
21
|
+
tests += adapter.tests_for(file, pattern)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def valid_test_file?(path)
|
28
|
+
return false if File.directory?(path)
|
29
|
+
case path
|
30
|
+
when /_test.rb$/, /_spec.rb$/
|
31
|
+
true
|
32
|
+
else
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class RSpecTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def with_rspec_context(args)
|
6
|
+
body = args.fetch(:body)
|
7
|
+
describe = args.fetch(:describe)
|
8
|
+
within_construct(false) do |c|
|
9
|
+
file_name = 'fake_spec.rb'
|
10
|
+
c.file file_name do
|
11
|
+
<<-EOS
|
12
|
+
describe #{describe} do
|
13
|
+
|
14
|
+
#{body}
|
15
|
+
|
16
|
+
end
|
17
|
+
EOS
|
18
|
+
end
|
19
|
+
path = c+file_name.to_s
|
20
|
+
yield path
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
should "grab all specs" do
|
25
|
+
body = <<-EOS
|
26
|
+
specify "something" do
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should do something" do
|
30
|
+
end
|
31
|
+
EOS
|
32
|
+
with_rspec_context :describe => String, :body => body do |path|
|
33
|
+
set = Tack::TestSet.new(path.parent)
|
34
|
+
tests = set.tests_for(path)
|
35
|
+
assert_equal 2, tests.length
|
36
|
+
assert_equal [path.to_s, "something"], tests.sort.last
|
37
|
+
assert_equal [path.to_s, "should do something"], tests.sort.first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
should "find specs that match substring" do
|
42
|
+
body = <<-EOS
|
43
|
+
specify "something" do
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does nothing" do
|
47
|
+
end
|
48
|
+
EOS
|
49
|
+
with_rspec_context :describe => String, :body => body do |path|
|
50
|
+
set = Tack::TestSet.new(path.parent)
|
51
|
+
tests = set.tests_for(path, "some")
|
52
|
+
assert_equal 1, tests.length
|
53
|
+
assert_equal [path.to_s, "something"], tests.sort.first
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
should "find specs that match regular expression" do
|
58
|
+
body = <<-EOS
|
59
|
+
specify "something" do
|
60
|
+
end
|
61
|
+
|
62
|
+
it "does nothing" do
|
63
|
+
end
|
64
|
+
EOS
|
65
|
+
with_rspec_context :describe => String, :body => body do |path|
|
66
|
+
set = Tack::TestSet.new(path.parent)
|
67
|
+
tests = set.tests_for(path, /does/)
|
68
|
+
assert_equal 1, tests.length
|
69
|
+
assert_equal [path.to_s, "does nothing"], tests.sort.first
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
should "run failing spec" do
|
74
|
+
body = <<-EOS
|
75
|
+
specify "append length is sum of component string lengths" do
|
76
|
+
("ab"+"cd").length.should == ("ab".length - "cd".length)
|
77
|
+
end
|
78
|
+
EOS
|
79
|
+
with_rspec_context :describe => String, :body => body do |path|
|
80
|
+
set = Tack::TestSet.new(path.parent)
|
81
|
+
tests = set.tests_for(path)
|
82
|
+
runner = Tack::Runner.new(path.parent)
|
83
|
+
results = runner.run(tests)
|
84
|
+
|
85
|
+
assert_equal 0, results[:passed].length
|
86
|
+
assert_equal 1, results[:failed].length
|
87
|
+
result = results[:failed].first
|
88
|
+
assert_equal "append length is sum of component string lengths", result[:description]
|
89
|
+
assert_equal "expected: 0,\n got: 4 (using ==)", result[:failure][:message]
|
90
|
+
assert_kind_of Array, result[:failure][:backtrace]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
should "run spec that raises error" do
|
95
|
+
body = <<-EOS
|
96
|
+
specify "append length is sum of component string lengths" do
|
97
|
+
raise "failing!"
|
98
|
+
end
|
99
|
+
EOS
|
100
|
+
with_rspec_context :describe => String, :body => body do |path|
|
101
|
+
set = Tack::TestSet.new(path.parent)
|
102
|
+
tests = set.tests_for(path)
|
103
|
+
runner = Tack::Runner.new(path.parent)
|
104
|
+
results = runner.run(tests)
|
105
|
+
|
106
|
+
assert_equal 0, results[:passed].length
|
107
|
+
assert_equal 1, results[:failed].length
|
108
|
+
|
109
|
+
result = results[:failed].first
|
110
|
+
assert_equal "append length is sum of component string lengths", result[:description]
|
111
|
+
assert_match /was raised/, result[:failure][:message]
|
112
|
+
assert_kind_of Array, result[:failure][:backtrace]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
should "run successful spec" do
|
117
|
+
body = <<-EOS
|
118
|
+
specify "append length is sum of component string lengths" do
|
119
|
+
("ab"+"cd").length.should == ("ab".length + "cd".length)
|
120
|
+
end
|
121
|
+
EOS
|
122
|
+
with_rspec_context :describe => String, :body => body do |path|
|
123
|
+
set = Tack::TestSet.new(path.parent)
|
124
|
+
tests = set.tests_for(path)
|
125
|
+
runner = Tack::Runner.new(path.parent)
|
126
|
+
results = runner.run(tests)
|
127
|
+
|
128
|
+
assert_equal 1, results[:passed].length
|
129
|
+
assert_equal 0, results[:failed].length
|
130
|
+
assert_equal "append length is sum of component string lengths", results[:passed].first[:description]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestUnitTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def remove_test_class_definition(class_name)
|
6
|
+
Object.send(:remove_const, class_name) if Object.const_defined?(class_name)
|
7
|
+
end
|
8
|
+
|
9
|
+
def with_test_class(args)
|
10
|
+
body = args.fetch(:body)
|
11
|
+
class_name = args.fetch(:class_name) { :FakeTest }
|
12
|
+
within_construct(false) do |c|
|
13
|
+
begin
|
14
|
+
file = c.file 'fake_test.rb' do
|
15
|
+
<<-EOS
|
16
|
+
require 'test/unit'
|
17
|
+
|
18
|
+
class #{class_name} < Test::Unit::TestCase
|
19
|
+
|
20
|
+
#{body}
|
21
|
+
|
22
|
+
end
|
23
|
+
EOS
|
24
|
+
end
|
25
|
+
path = c + file.to_s
|
26
|
+
yield file.to_s, path
|
27
|
+
ensure
|
28
|
+
remove_test_class_definition(class_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
should "grab all tests" do
|
34
|
+
body =<<-EOS
|
35
|
+
def test_one
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_two
|
39
|
+
end
|
40
|
+
EOS
|
41
|
+
with_test_class(:body => body) do |file_name, path|
|
42
|
+
set = Tack::TestSet.new(path.parent)
|
43
|
+
tests = set.tests_for(path)
|
44
|
+
assert_equal 2, tests.length
|
45
|
+
assert_equal [file_name, "test_one"], tests.sort.first
|
46
|
+
assert_equal [file_name, "test_two"], tests.sort.last
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
should "find tests that match substring" do
|
51
|
+
body=<<-EOS
|
52
|
+
def test_one
|
53
|
+
end
|
54
|
+
def test_two
|
55
|
+
end
|
56
|
+
EOS
|
57
|
+
with_test_class(:body => body) do |file_name, path|
|
58
|
+
set = Tack::TestSet.new(path.parent)
|
59
|
+
tests = set.tests_for(path, "two")
|
60
|
+
assert_equal 1, tests.length
|
61
|
+
assert_equal [file_name, "test_two"], tests.sort.first
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
should "find tests that match regular expression" do
|
66
|
+
body=<<-EOS
|
67
|
+
def test_one
|
68
|
+
end
|
69
|
+
def test_two
|
70
|
+
end
|
71
|
+
EOS
|
72
|
+
with_test_class(:body => body) do |file_name, path|
|
73
|
+
set = Tack::TestSet.new(path.parent)
|
74
|
+
tests = set.tests_for(path, /two/)
|
75
|
+
assert_equal 1, tests.length
|
76
|
+
assert_equal [file_name, "test_two"], tests.sort.first
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
should "run failing test" do
|
81
|
+
body =<<-EOS
|
82
|
+
def test_append_length
|
83
|
+
assert_equal ("ab".length - "cd".length), ("ab"+"cd").length
|
84
|
+
end
|
85
|
+
EOS
|
86
|
+
with_test_class(:body => body) do |file_name, path|
|
87
|
+
set = Tack::TestSet.new(path.parent)
|
88
|
+
tests = set.tests_for(path)
|
89
|
+
runner = Tack::Runner.new(path.parent)
|
90
|
+
results = runner.run(tests)
|
91
|
+
|
92
|
+
assert_equal 0, results[:passed].length
|
93
|
+
assert_equal 1, results[:failed].length
|
94
|
+
result = results[:failed].first
|
95
|
+
assert_equal "test_append_length", result[:description]
|
96
|
+
assert_match /expected but was/, result[:failure][:message]
|
97
|
+
assert_kind_of Array, result[:failure][:backtrace]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
should "run test with error" do
|
102
|
+
body =<<-EOS
|
103
|
+
def test_append_length
|
104
|
+
raise "failing!"
|
105
|
+
end
|
106
|
+
EOS
|
107
|
+
with_test_class(:body => body) do |file_name, path|
|
108
|
+
set = Tack::TestSet.new(path.parent)
|
109
|
+
tests = set.tests_for(path)
|
110
|
+
runner = Tack::Runner.new(path.parent)
|
111
|
+
results = runner.run(tests)
|
112
|
+
|
113
|
+
assert_equal 0, results[:passed].length
|
114
|
+
assert_equal 1, results[:failed].length
|
115
|
+
result = results[:failed].first
|
116
|
+
assert_equal "test_append_length", result[:description]
|
117
|
+
assert_match /was raised/, result[:failure][:message]
|
118
|
+
assert_kind_of Array, result[:failure][:backtrace]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
should "run successful test" do
|
123
|
+
body =<<-EOS
|
124
|
+
def test_append_length
|
125
|
+
assert_equal ("ab".length + "cd".length), ("ab"+"cd").length
|
126
|
+
end
|
127
|
+
EOS
|
128
|
+
with_test_class(:body => body) do |file_name, path|
|
129
|
+
set = Tack::TestSet.new(path.parent)
|
130
|
+
tests = set.tests_for(path)
|
131
|
+
runner = Tack::Runner.new(path.parent)
|
132
|
+
results = runner.run(tests)
|
133
|
+
assert_equal 1, results[:passed].length
|
134
|
+
assert_equal 0, results[:failed].length
|
135
|
+
assert_equal "test_append_length", results[:passed].first[:description]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
data/test/tack_test.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class TackTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
should "do whatever" do
|
6
|
+
# nothing here for now
|
6
7
|
end
|
8
|
+
|
7
9
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'test/unit'
|
3
3
|
require 'shoulda'
|
4
|
+
require 'construct'
|
5
|
+
require 'ruby-debug'
|
4
6
|
|
5
7
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
8
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
9
|
require 'tack'
|
8
10
|
|
9
11
|
class Test::Unit::TestCase
|
12
|
+
include Construct::Helpers
|
10
13
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ben Brinckerhoff
|
@@ -14,8 +14,8 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
18
|
-
default_executable:
|
17
|
+
date: 2010-06-07 00:00:00 -06:00
|
18
|
+
default_executable: tack
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: shoulda
|
@@ -29,10 +29,22 @@ dependencies:
|
|
29
29
|
version: "0"
|
30
30
|
type: :development
|
31
31
|
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: test-construct
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
version: "0"
|
42
|
+
type: :development
|
43
|
+
version_requirements: *id002
|
32
44
|
description: A Rack-inspired interface for testing libraries
|
33
45
|
email: ben@bbrinck.com
|
34
|
-
executables:
|
35
|
-
|
46
|
+
executables:
|
47
|
+
- tack
|
36
48
|
extensions: []
|
37
49
|
|
38
50
|
extra_rdoc_files:
|
@@ -45,7 +57,22 @@ files:
|
|
45
57
|
- README.rdoc
|
46
58
|
- Rakefile
|
47
59
|
- VERSION
|
60
|
+
- bin/tack
|
48
61
|
- lib/tack.rb
|
62
|
+
- lib/tack/adapters/adapter.rb
|
63
|
+
- lib/tack/adapters/rspec_adapter.rb
|
64
|
+
- lib/tack/adapters/test_unit_adapter.rb
|
65
|
+
- lib/tack/formatters/basic_summary.rb
|
66
|
+
- lib/tack/formatters/print_failures.rb
|
67
|
+
- lib/tack/formatters/profiler.rb
|
68
|
+
- lib/tack/formatters/progress_bar.rb
|
69
|
+
- lib/tack/formatters/total_time.rb
|
70
|
+
- lib/tack/middleware.rb
|
71
|
+
- lib/tack/runner.rb
|
72
|
+
- lib/tack/test_pattern.rb
|
73
|
+
- lib/tack/test_set.rb
|
74
|
+
- test/acceptance/rspec_test.rb
|
75
|
+
- test/acceptance/test_unit_test.rb
|
49
76
|
- test/tack_test.rb
|
50
77
|
- test/test_helper.rb
|
51
78
|
has_rdoc: true
|
@@ -79,5 +106,7 @@ signing_key:
|
|
79
106
|
specification_version: 3
|
80
107
|
summary: A Rack-inspired interface for testing libraries
|
81
108
|
test_files:
|
109
|
+
- test/acceptance/rspec_test.rb
|
110
|
+
- test/acceptance/test_unit_test.rb
|
82
111
|
- test/tack_test.rb
|
83
112
|
- test/test_helper.rb
|