TwP-turn 0.5.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/History.txt +23 -0
- data/README.txt +117 -0
- data/Rakefile +32 -0
- data/Release.txt +29 -0
- data/VERSION +1 -0
- data/bin/turn +4 -0
- data/lib/turn.rb +80 -0
- data/lib/turn/colorize.rb +29 -0
- data/lib/turn/command.rb +159 -0
- data/lib/turn/components/case.rb +98 -0
- data/lib/turn/components/method.rb +32 -0
- data/lib/turn/components/suite.rb +82 -0
- data/lib/turn/controller.rb +146 -0
- data/lib/turn/reporter.rb +56 -0
- data/lib/turn/reporters/dot_reporter.rb +78 -0
- data/lib/turn/reporters/marshal_reporter.rb +64 -0
- data/lib/turn/reporters/outline_reporter.rb +85 -0
- data/lib/turn/reporters/progress_reporter.rb +117 -0
- data/lib/turn/runners/crossrunner.rb +40 -0
- data/lib/turn/runners/isorunner.rb +129 -0
- data/lib/turn/runners/loadrunner.rb +48 -0
- data/lib/turn/runners/solorunner.rb +8 -0
- data/lib/turn/runners/testrunner.rb +154 -0
- data/test/test_example.rb +15 -0
- data/test/test_sample.rb +15 -0
- data/turn.gemspec +37 -0
- data/work/quicktest.rb +42 -0
- data/work/turn.rb +119 -0
- metadata +94 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Turn
|
4
|
+
require 'turn/reporter'
|
5
|
+
|
6
|
+
# = Marshal Reporter
|
7
|
+
#
|
8
|
+
class MarshalReporter < Reporter
|
9
|
+
|
10
|
+
#def start_suite(suite)
|
11
|
+
# #@suite = suite
|
12
|
+
# #@time = Time.now
|
13
|
+
# #files = suite.collect{ |s| s.file }.join(' ')
|
14
|
+
# #io.puts "Loaded suite #{suite.name}"
|
15
|
+
# #io.puts "Started"
|
16
|
+
#end
|
17
|
+
|
18
|
+
#def start_test(test)
|
19
|
+
# #if @file != test.file
|
20
|
+
# # @file = test.file
|
21
|
+
# # io.puts(test.file)
|
22
|
+
# #end
|
23
|
+
# io.print " %-69s" % test.name
|
24
|
+
#end
|
25
|
+
|
26
|
+
#def start_case(kase)
|
27
|
+
# io.puts(kase.name)
|
28
|
+
#end
|
29
|
+
|
30
|
+
#def pass(message=nil)
|
31
|
+
# io.puts " #{PASS}"
|
32
|
+
# if message
|
33
|
+
# message = ::ANSICode.magenta(message) if COLORIZE
|
34
|
+
# io.puts(message.to_s)
|
35
|
+
# end
|
36
|
+
#end
|
37
|
+
|
38
|
+
#def fail(message=nil)
|
39
|
+
# io.puts(" #{FAIL}")
|
40
|
+
# if message
|
41
|
+
# message = ::ANSICode.magenta(message) if COLORIZE
|
42
|
+
# io.puts(message.to_s)
|
43
|
+
# end
|
44
|
+
#end
|
45
|
+
|
46
|
+
#def error(message=nil)
|
47
|
+
# io.puts("#{ERROR}")
|
48
|
+
# io.puts(message.to_s) if message
|
49
|
+
#end
|
50
|
+
|
51
|
+
#def finish_test(test)
|
52
|
+
#end
|
53
|
+
|
54
|
+
#def finish_case(kase)
|
55
|
+
#end
|
56
|
+
|
57
|
+
def finish_suite(suite)
|
58
|
+
$stdout << suite.to_yaml
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'turn/reporter'
|
2
|
+
|
3
|
+
module Turn
|
4
|
+
|
5
|
+
# = Outline Reporter (Turn's Original)
|
6
|
+
#
|
7
|
+
#--
|
8
|
+
# TODO: Should we fit reporter output to width of console?
|
9
|
+
# TODO: Running percentages?
|
10
|
+
#++
|
11
|
+
class OutlineReporter < Reporter
|
12
|
+
|
13
|
+
def start_suite(suite)
|
14
|
+
@suite = suite
|
15
|
+
@time = Time.now
|
16
|
+
#files = suite.collect{ |s| s.file }.join(' ')
|
17
|
+
io.puts "Loaded suite #{suite.name}"
|
18
|
+
#io.puts "Started"
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_case(kase)
|
22
|
+
io.puts(kase.name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_test(test)
|
26
|
+
#if @file != test.file
|
27
|
+
# @file = test.file
|
28
|
+
# io.puts(test.file)
|
29
|
+
#end
|
30
|
+
io.print " %-69s" % test.name
|
31
|
+
end
|
32
|
+
|
33
|
+
def pass(message=nil)
|
34
|
+
io.puts " #{PASS}"
|
35
|
+
if message
|
36
|
+
message = ::ANSICode.magenta(message) if COLORIZE
|
37
|
+
message = message.to_s.tabto(8)
|
38
|
+
io.puts(message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def fail(message=nil)
|
43
|
+
io.puts(" #{FAIL}")
|
44
|
+
if message
|
45
|
+
message = ::ANSICode.magenta(message) if COLORIZE
|
46
|
+
message = message.to_s.tabto(8)
|
47
|
+
io.puts(message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def error(message=nil)
|
52
|
+
io.puts("#{ERROR}")
|
53
|
+
io.puts(message.to_s) if message
|
54
|
+
end
|
55
|
+
|
56
|
+
def finish_test(test)
|
57
|
+
end
|
58
|
+
|
59
|
+
#def finish_case(kase)
|
60
|
+
#end
|
61
|
+
|
62
|
+
def finish_suite(suite)
|
63
|
+
total = suite.count_tests
|
64
|
+
failure = suite.count_failures
|
65
|
+
error = suite.count_errors
|
66
|
+
pass = total - failure - error
|
67
|
+
|
68
|
+
bar = '=' * 78
|
69
|
+
if COLORIZE
|
70
|
+
bar = if pass == total then ::ANSICode.green bar
|
71
|
+
else ::ANSICode.red bar end
|
72
|
+
end
|
73
|
+
|
74
|
+
tally = [total, suite.count_assertions]
|
75
|
+
|
76
|
+
io.puts bar
|
77
|
+
io.puts " pass: %d, fail: %d, error: %d" % [pass, failure, error]
|
78
|
+
io.puts " total: %d tests with %d assertions in #{Time.new - @time} seconds" % tally
|
79
|
+
io.puts bar
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'turn/reporter'
|
2
|
+
require 'facets/progressbar'
|
3
|
+
require 'facets/string/tab'
|
4
|
+
|
5
|
+
module Turn
|
6
|
+
|
7
|
+
#
|
8
|
+
class ProgressReporter < Reporter
|
9
|
+
|
10
|
+
def start_suite(suite)
|
11
|
+
@pbar = ::ProgressBar.new('Testing', suite.size)
|
12
|
+
@pbar.inc
|
13
|
+
end
|
14
|
+
|
15
|
+
#def start_case(kase)
|
16
|
+
#end
|
17
|
+
|
18
|
+
#def start_test(test)
|
19
|
+
#end
|
20
|
+
|
21
|
+
#def pass(message=nil)
|
22
|
+
# #@pbar.inc
|
23
|
+
#end
|
24
|
+
|
25
|
+
#def fail(message=nil)
|
26
|
+
# #@pbar.inc
|
27
|
+
#end
|
28
|
+
|
29
|
+
#def error(message=nil)
|
30
|
+
# #@pbar.inc
|
31
|
+
#end
|
32
|
+
|
33
|
+
def finish_case(kase)
|
34
|
+
@pbar.inc
|
35
|
+
end
|
36
|
+
|
37
|
+
def finish_suite(suite)
|
38
|
+
@pbar.finish
|
39
|
+
post_report(suite)
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
def post_report(suite)
|
44
|
+
tally = test_tally(suite)
|
45
|
+
|
46
|
+
width = suite.collect{ |tr| tr.name.size }.max
|
47
|
+
|
48
|
+
headers = [ 'TESTCASE ', ' TESTS ', 'ASSERTIONS', ' FAILURES ', ' ERRORS ' ]
|
49
|
+
io.puts "\n%-#{width}s %10s %10s %10s %10s\n" % headers
|
50
|
+
|
51
|
+
files = nil
|
52
|
+
|
53
|
+
suite.each do |testrun|
|
54
|
+
if testrun.files != [testrun.name] && testrun.files != files
|
55
|
+
label = testrun.files.join(' ')
|
56
|
+
label = ::ANSICode.magenta(label) if COLORIZE
|
57
|
+
io.puts(label + "\n")
|
58
|
+
files = testrun.files
|
59
|
+
end
|
60
|
+
io.puts paint_line(testrun, width)
|
61
|
+
end
|
62
|
+
|
63
|
+
#puts("\n%i tests, %i assertions, %i failures, %i errors\n\n" % tally)
|
64
|
+
|
65
|
+
tally_line = "-----\n"
|
66
|
+
tally_line << "%-#{width}s " % "TOTAL"
|
67
|
+
tally_line << "%10s %10s %10s %10s" % tally
|
68
|
+
|
69
|
+
io.puts(tally_line + "\n")
|
70
|
+
|
71
|
+
fails = suite.select do |testrun|
|
72
|
+
testrun.fail? || testrun.error?
|
73
|
+
end
|
74
|
+
|
75
|
+
#if tally[2] != 0 or tally[3] != 0
|
76
|
+
unless fails.empty? # or verbose?
|
77
|
+
io.puts "\n\n-- Failures and Errors --\n\n"
|
78
|
+
fails.uniq.each do |testrun|
|
79
|
+
message = testrun.message.tabto(0).strip
|
80
|
+
message = ::ANSICode.red(message) if COLORIZE
|
81
|
+
io.puts(message+"\n\n")
|
82
|
+
end
|
83
|
+
io.puts
|
84
|
+
end
|
85
|
+
#end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def paint_line(testrun, width)
|
91
|
+
line = ''
|
92
|
+
line << "%-#{width}s " % [testrun.name]
|
93
|
+
line << "%10s %10s %10s %10s" % testrun.counts
|
94
|
+
line << " " * 8
|
95
|
+
if testrun.fail?
|
96
|
+
line << "[#{FAIL}]"
|
97
|
+
elsif testrun.error?
|
98
|
+
line << "[#{FAIL}]"
|
99
|
+
else
|
100
|
+
line << "[#{PASS}]"
|
101
|
+
end
|
102
|
+
line
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_tally(suite)
|
106
|
+
counts = suite.collect{ |tr| tr.counts }
|
107
|
+
tally = [0,0,0,0]
|
108
|
+
counts.each do |count|
|
109
|
+
4.times{ |i| tally[i] += count[i] }
|
110
|
+
end
|
111
|
+
return tally
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Turn
|
2
|
+
require 'turn/runners/isorunner'
|
3
|
+
|
4
|
+
# = Cross Runner
|
5
|
+
#
|
6
|
+
# Cross Runner runs test in pairs.
|
7
|
+
#
|
8
|
+
# TODO: This needs work in the test_loop_runner.
|
9
|
+
# It needs to show the files being cross tested.
|
10
|
+
#
|
11
|
+
# TODO: Cross runner output needs to be fixed
|
12
|
+
class CrossRunner < IsoRunner
|
13
|
+
|
14
|
+
#
|
15
|
+
def start
|
16
|
+
suite = TestSuite.new
|
17
|
+
|
18
|
+
files = @controller.files
|
19
|
+
viles = @controller.files # TODO: viles this selectable
|
20
|
+
|
21
|
+
#files = files.select{ |f| File.extname(f) == '.rb' and File.file?(f) }
|
22
|
+
#viles = viles.select{ |f| File.extname(f) == '.rb' and File.file?(f) }
|
23
|
+
|
24
|
+
max = (files+viles).collect{ |f| f.size }.max
|
25
|
+
|
26
|
+
pairs = files.inject([]){ |m, f| viles.collect{ |v| m << [f,v] }; m }
|
27
|
+
pairs = pairs.reject{ |f,v| f == v }
|
28
|
+
|
29
|
+
testruns = pairs.collect do |file, versus|
|
30
|
+
name = "%-#{max}s %-#{max}s" % [file, versus]
|
31
|
+
suite.new_case(name, file, versus)
|
32
|
+
end
|
33
|
+
|
34
|
+
test_loop_runner(suite)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module Turn
|
2
|
+
require 'turn/colorize'
|
3
|
+
|
4
|
+
# = IsoRunner
|
5
|
+
#
|
6
|
+
# Iso Runner provides means from running unit test
|
7
|
+
# in isolated processes. It can do this either by running
|
8
|
+
# each test in isolation (solo testing) or in pairs (cross testing).
|
9
|
+
#
|
10
|
+
# The IsoRunner proiveds some variery in ouput formats and can also
|
11
|
+
# log results to a file.
|
12
|
+
#
|
13
|
+
class IsoRunner
|
14
|
+
include Turn::Colorize
|
15
|
+
|
16
|
+
attr :reporter
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def initialize(controller)
|
21
|
+
@controller = controller
|
22
|
+
@reporter = controller.reporter
|
23
|
+
#yield(self) if block_given?
|
24
|
+
@loadpath = controller.loadpath
|
25
|
+
@requires = controller.requires
|
26
|
+
@live = controller.live?
|
27
|
+
end
|
28
|
+
|
29
|
+
public
|
30
|
+
|
31
|
+
# Runs the list of test calls passed to it.
|
32
|
+
# This is used by #test_solo and #test_cross.
|
33
|
+
#
|
34
|
+
def start
|
35
|
+
suite = TestSuite.new
|
36
|
+
testruns = @controller.files.collect do |file|
|
37
|
+
suite.new_case(file)
|
38
|
+
end
|
39
|
+
test_loop_runner(suite)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# The IsoRunner actually shells out to turn in
|
45
|
+
# manifest mode, to gather results from isolated
|
46
|
+
# runs.
|
47
|
+
def test_loop_runner(suite)
|
48
|
+
reporter.start_suite(suite)
|
49
|
+
|
50
|
+
recase = []
|
51
|
+
|
52
|
+
suite.each_with_index do |kase, index|
|
53
|
+
reporter.start_case(kase)
|
54
|
+
|
55
|
+
# FRACKING GENIUS RIGHT HERE !!!!!!!!!!!!
|
56
|
+
cmd = []
|
57
|
+
cmd << %[turn]
|
58
|
+
cmd << %[--marshal]
|
59
|
+
cmd << %[--loadpath="#{@loadpath.join(';')}"] unless @loadpath.empty?
|
60
|
+
cmd << %[--requires="#{@requires.join(';')}"] unless @requires.empty?
|
61
|
+
cmd << %[--live] if @live
|
62
|
+
cmd << %[#{kase.files.join(' ')}]
|
63
|
+
cmd = cmd.join(' ')
|
64
|
+
result = `#{cmd}`
|
65
|
+
|
66
|
+
files = kase.files
|
67
|
+
|
68
|
+
head, yaml = *result.split('---')
|
69
|
+
sub_suite = YAML.load(yaml)
|
70
|
+
|
71
|
+
# TODO: How to handle pairs?
|
72
|
+
#name = kase.name
|
73
|
+
kases = sub_suite.cases
|
74
|
+
suite.cases[index] = kases
|
75
|
+
|
76
|
+
kases.each do |kase|
|
77
|
+
kase.files = files
|
78
|
+
#reporter.start_case(kase)
|
79
|
+
kase.tests.each do |test|
|
80
|
+
reporter.start_test(test)
|
81
|
+
if test.error?
|
82
|
+
reporter.error(test.message)
|
83
|
+
elsif test.fail?
|
84
|
+
reporter.fail(test.message)
|
85
|
+
else
|
86
|
+
reporter.pass
|
87
|
+
end
|
88
|
+
reporter.finish_test(test)
|
89
|
+
end
|
90
|
+
reporter.finish_case(kase)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
suite.cases.flatten!
|
95
|
+
|
96
|
+
reporter.finish_suite(suite)
|
97
|
+
|
98
|
+
# shutdown test/unit auto runner if test/unit is loaded.
|
99
|
+
::Test::Unit.run=true rescue nil
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
#def test_parse_result(result)
|
104
|
+
# if md = /(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/.match(result)
|
105
|
+
# count = md[1..4].collect{|q| q.to_i}
|
106
|
+
# else
|
107
|
+
# count = [1, 0, 0, 1] # SHOULD NEVER HAPPEN
|
108
|
+
# end
|
109
|
+
# return count
|
110
|
+
#end
|
111
|
+
|
112
|
+
# NOT USED YET.
|
113
|
+
def log_report(report)
|
114
|
+
if log #&& !dryrun?
|
115
|
+
#logfile = File.join('log', apply_naming_policy('testlog', 'txt'))
|
116
|
+
FileUtils.mkdir_p('log')
|
117
|
+
logfile = File.join('log', 'testlog.txt')
|
118
|
+
File.open(logfile, 'a') do |f|
|
119
|
+
f << "= #{self.class} Test @ #{Time.now}\n"
|
120
|
+
f << report
|
121
|
+
f << "\n"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end#class IsoRunner
|
127
|
+
|
128
|
+
end#module Turn
|
129
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# TODO
|
2
|
+
|
3
|
+
# Load each test independently to ensure there are no
|
4
|
+
# require dependency issues. This is actually a bit redundant
|
5
|
+
# as test-solo will also cover these results. So we may deprecate
|
6
|
+
# this in the future. This does not generate a test log entry.
|
7
|
+
|
8
|
+
def test_load(options={})
|
9
|
+
options = test_configuration(options)
|
10
|
+
|
11
|
+
tests = options['tests']
|
12
|
+
loadpath = options['loadpath']
|
13
|
+
requires = options['requires']
|
14
|
+
live = options['live']
|
15
|
+
exclude = options['exclude']
|
16
|
+
|
17
|
+
files = Dir.multiglob_r(*tests) - Dir.multiglob_r(*exclude)
|
18
|
+
|
19
|
+
return puts("No tests.") if files.empty?
|
20
|
+
|
21
|
+
max = files.collect{ |f| f.size }.max
|
22
|
+
list = []
|
23
|
+
|
24
|
+
files.each do |f|
|
25
|
+
next unless File.file?(f)
|
26
|
+
if r = system("ruby -I#{loadpath.join(':')} #{f} > /dev/null 2>&1")
|
27
|
+
puts "%-#{max}s [PASS]" % [f] #if verbose?
|
28
|
+
else
|
29
|
+
puts "%-#{max}s [FAIL]" % [f] #if verbose?
|
30
|
+
list << f
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
puts " #{list.size} Load Failures"
|
35
|
+
|
36
|
+
if verbose?
|
37
|
+
unless list.empty?
|
38
|
+
puts "\n-- Load Failures --\n"
|
39
|
+
list.each do |f|
|
40
|
+
print "* "
|
41
|
+
system "ruby -I#{loadpath} #{f} 2>&1"
|
42
|
+
#puts
|
43
|
+
end
|
44
|
+
puts
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|