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,98 @@
|
|
1
|
+
module Turn
|
2
|
+
|
3
|
+
#
|
4
|
+
class TestCase
|
5
|
+
|
6
|
+
# Name of test case.
|
7
|
+
attr_accessor :name
|
8
|
+
|
9
|
+
# Test methods.
|
10
|
+
attr_accessor :tests
|
11
|
+
|
12
|
+
# Some runners marshal tests per file.
|
13
|
+
attr_accessor :files
|
14
|
+
|
15
|
+
#attr_accessor :count_passes
|
16
|
+
#attr_accessor :count_failures
|
17
|
+
#attr_accessor :count_errors
|
18
|
+
#attr_accessor :count_tests
|
19
|
+
|
20
|
+
# This can;t be calculated, so it must be
|
21
|
+
# assigned by the runner.
|
22
|
+
attr_accessor :count_assertions
|
23
|
+
|
24
|
+
# Holds dump of test output (optional depending on runner).
|
25
|
+
attr_accessor :message
|
26
|
+
|
27
|
+
# Command used to run test (optional depending on runner).
|
28
|
+
#attr_accessor :command
|
29
|
+
|
30
|
+
#
|
31
|
+
def initialize(name, *files)
|
32
|
+
@name = name
|
33
|
+
@files = (files.empty? ? [name] : files)
|
34
|
+
@tests = []
|
35
|
+
|
36
|
+
@message = nil
|
37
|
+
@count_assertions = 0
|
38
|
+
|
39
|
+
#@count_tests = 0
|
40
|
+
#@count_failures = 0
|
41
|
+
#@count_errors = 0
|
42
|
+
|
43
|
+
#@command = command
|
44
|
+
end
|
45
|
+
|
46
|
+
def new_test(name)
|
47
|
+
c = TestMethod.new(name)
|
48
|
+
@tests << c
|
49
|
+
c
|
50
|
+
end
|
51
|
+
|
52
|
+
# Whne used by a per-file runner.
|
53
|
+
#alias_method :file, :name
|
54
|
+
|
55
|
+
# Were there any errors?
|
56
|
+
def error?
|
57
|
+
count_errors != 0
|
58
|
+
end
|
59
|
+
|
60
|
+
# Were there any failures?
|
61
|
+
def fail?
|
62
|
+
count_failures != 0
|
63
|
+
end
|
64
|
+
|
65
|
+
# Did all tests/assertion pass?
|
66
|
+
def pass?
|
67
|
+
not(fail? or error?)
|
68
|
+
end
|
69
|
+
|
70
|
+
def count_tests
|
71
|
+
tests.size
|
72
|
+
end
|
73
|
+
|
74
|
+
def count_failures
|
75
|
+
sum = 0; tests.each{ |t| sum += 1 if t.fail? }; sum
|
76
|
+
end
|
77
|
+
|
78
|
+
def count_errors
|
79
|
+
sum = 0; tests.each{ |t| sum += 1 if t.error? }; sum
|
80
|
+
end
|
81
|
+
|
82
|
+
def count_passes
|
83
|
+
sum = 0; tests.each{ |t| sum += 1 if t.pass? }; sum
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
def counts
|
88
|
+
return count_tests, count_assertions, count_failures, count_errors
|
89
|
+
end
|
90
|
+
|
91
|
+
def message
|
92
|
+
tests.collect{ |t| t.message }.join("\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Turn
|
2
|
+
|
3
|
+
#
|
4
|
+
class TestMethod
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :file
|
7
|
+
attr_accessor :message
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
@fail = false
|
12
|
+
@error = false
|
13
|
+
@message = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def fail!(message=nil)
|
17
|
+
@fail, @error = true, false
|
18
|
+
@message = message if message
|
19
|
+
end
|
20
|
+
|
21
|
+
def error!(message=nil)
|
22
|
+
@fail, @error = false, true
|
23
|
+
@message = message if message
|
24
|
+
end
|
25
|
+
|
26
|
+
def fail? ; @fail ; end
|
27
|
+
def error? ; @error ; end
|
28
|
+
def pass? ; !(@fail or @error) ; end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Turn
|
2
|
+
|
3
|
+
#
|
4
|
+
class TestSuite
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_accessor :name
|
9
|
+
attr_accessor :size
|
10
|
+
attr_accessor :cases
|
11
|
+
|
12
|
+
# This one can be set manually since it
|
13
|
+
# is not calculatable (beyond the case level).
|
14
|
+
attr_accessor :count_assertions
|
15
|
+
|
16
|
+
#
|
17
|
+
def initialize(name=nil)
|
18
|
+
@name = name
|
19
|
+
@size = nil
|
20
|
+
@cases = []
|
21
|
+
|
22
|
+
#@count_tests = nil
|
23
|
+
#@count_assertions = nil
|
24
|
+
#@count_failures = nil
|
25
|
+
#@count_errors = nil
|
26
|
+
#@count_passes = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
def new_case(name, *files)
|
31
|
+
c = TestCase.new(name, *files)
|
32
|
+
@cases << c
|
33
|
+
c
|
34
|
+
end
|
35
|
+
|
36
|
+
def count_failures
|
37
|
+
#@count_failures ||= (
|
38
|
+
sum = 0; each{ |c| sum += c.count_failures }; sum
|
39
|
+
#)
|
40
|
+
end
|
41
|
+
|
42
|
+
def count_errors
|
43
|
+
#@count_errors ||= (
|
44
|
+
sum = 0; each{ |c| sum += c.count_errors }; sum
|
45
|
+
#)
|
46
|
+
end
|
47
|
+
|
48
|
+
def count_passes
|
49
|
+
#@count_passes ||= (
|
50
|
+
sum = 0; each{ |c| sum += c.count_passes }; sum
|
51
|
+
#)
|
52
|
+
end
|
53
|
+
|
54
|
+
def count_tests
|
55
|
+
#@count_tests ||= (
|
56
|
+
sum = 0; each{ |c| sum += c.count_tests }; sum
|
57
|
+
#)
|
58
|
+
end
|
59
|
+
|
60
|
+
def count_assertions
|
61
|
+
#@count_assertions ||= (
|
62
|
+
sum = 0; each{ |c| sum += c.count_assertions }; sum
|
63
|
+
#)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Convenience methods --this is what is typcially wanted.
|
67
|
+
def counts
|
68
|
+
return count_tests, count_assertions, count_failures, count_errors
|
69
|
+
end
|
70
|
+
|
71
|
+
def each(&block)
|
72
|
+
@cases.each(&block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def size
|
76
|
+
@size ||= @cases.size
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Turn
|
4
|
+
require 'turn/components/suite.rb'
|
5
|
+
require 'turn/components/case.rb'
|
6
|
+
require 'turn/components/method.rb'
|
7
|
+
|
8
|
+
require 'turn/reporters/outline_reporter'
|
9
|
+
require 'turn/reporters/marshal_reporter'
|
10
|
+
require 'turn/reporters/progress_reporter'
|
11
|
+
require 'turn/reporters/dot_reporter'
|
12
|
+
|
13
|
+
require 'turn/runners/testrunner'
|
14
|
+
require 'turn/runners/solorunner'
|
15
|
+
require 'turn/runners/crossrunner'
|
16
|
+
|
17
|
+
# = Controller
|
18
|
+
#
|
19
|
+
#--
|
20
|
+
# TODO: Add support to test run loggging.
|
21
|
+
#++
|
22
|
+
class Controller
|
23
|
+
|
24
|
+
# File glob pattern of tests to run.
|
25
|
+
# Can be an array of files/globs.
|
26
|
+
attr_accessor :tests
|
27
|
+
|
28
|
+
# Files globs to specially exclude.
|
29
|
+
attr_accessor :exclude
|
30
|
+
|
31
|
+
# Add these folders to the $LOAD_PATH.
|
32
|
+
attr_accessor :loadpath
|
33
|
+
|
34
|
+
# Libs to require when running tests.
|
35
|
+
attr_accessor :requires
|
36
|
+
|
37
|
+
# Instance of Reporter.
|
38
|
+
attr_accessor :reporter
|
39
|
+
|
40
|
+
# Insatance of Runner.
|
41
|
+
attr_accessor :runner
|
42
|
+
|
43
|
+
# Test against live install (i.e. Don't use loadpath option)
|
44
|
+
attr_accessor :live
|
45
|
+
|
46
|
+
# Log results? May be true/false or log file name. (TODO)
|
47
|
+
attr_accessor :log
|
48
|
+
|
49
|
+
# Verbose output?
|
50
|
+
attr_accessor :verbose
|
51
|
+
|
52
|
+
def verbose? ; @verbose ; end
|
53
|
+
def live? ; @live ; end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
yield(self) if block_given?
|
59
|
+
initialize_defaults
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
def initialize_defaults
|
64
|
+
@loadpath ||= ['lib']
|
65
|
+
@tests ||= "test/**/{test,}*{,test}"
|
66
|
+
@exclude ||= []
|
67
|
+
@reqiures ||= []
|
68
|
+
@live ||= false
|
69
|
+
@log ||= true
|
70
|
+
@reporter ||= OutlineReporter.new($stdout)
|
71
|
+
@runner ||= TestRunner.new
|
72
|
+
end
|
73
|
+
|
74
|
+
# Collect test configuation.
|
75
|
+
#def test_configuration(options={})
|
76
|
+
# #options = configure_options(options, 'test')
|
77
|
+
# #options['loadpath'] ||= metadata.loadpath
|
78
|
+
# options['tests'] ||= self.tests
|
79
|
+
# options['loadpath'] ||= self.loadpath
|
80
|
+
# options['requires'] ||= self.requires
|
81
|
+
# options['live'] ||= self.live
|
82
|
+
# options['exclude'] ||= self.exclude
|
83
|
+
# #options['tests'] = list_option(options['tests'])
|
84
|
+
# options['loadpath'] = list_option(options['loadpath'])
|
85
|
+
# options['exclude'] = list_option(options['exclude'])
|
86
|
+
# options['require'] = list_option(options['require'])
|
87
|
+
# return options
|
88
|
+
#end
|
89
|
+
|
90
|
+
#
|
91
|
+
def list_option(list)
|
92
|
+
case list
|
93
|
+
when nil
|
94
|
+
[]
|
95
|
+
when Array
|
96
|
+
list
|
97
|
+
else
|
98
|
+
list.split(/[:;]/)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
public
|
103
|
+
|
104
|
+
def loadpath=(paths)
|
105
|
+
@loadpath = list_option(paths)
|
106
|
+
end
|
107
|
+
|
108
|
+
def exclude=(paths)
|
109
|
+
@exclude = list_option(paths)
|
110
|
+
end
|
111
|
+
|
112
|
+
def requries=(paths)
|
113
|
+
@requries = list_option(paths)
|
114
|
+
end
|
115
|
+
|
116
|
+
def files
|
117
|
+
@files ||= (
|
118
|
+
fs = tests.map do |t|
|
119
|
+
File.directory?(t) ? Dir[File.join(t, '**', '*')] : Dir[t]
|
120
|
+
end
|
121
|
+
fs = fs.flatten.reject{ |f| File.directory?(f) }
|
122
|
+
ex = exclude.map do |x|
|
123
|
+
File.directory?(x) ? Dir[File.join(x, '**', '*')] : Dir[x]
|
124
|
+
end
|
125
|
+
ex = ex.flatten.reject{ |f| File.directory?(f) }
|
126
|
+
(fs - ex).uniq
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
def start
|
131
|
+
@files = nil # reset files just in case
|
132
|
+
|
133
|
+
if files.empty?
|
134
|
+
$stderr.puts "No tests."
|
135
|
+
return
|
136
|
+
end
|
137
|
+
|
138
|
+
testrun = runner.new(self)
|
139
|
+
|
140
|
+
testrun.start
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Turn
|
2
|
+
require 'turn/colorize'
|
3
|
+
|
4
|
+
# = Reporter
|
5
|
+
#
|
6
|
+
# There are two distinct way in which a report may be utilized
|
7
|
+
# by a Runner: per-call or per-file. The method #pass, #fail
|
8
|
+
# and #error are generic, and will be used in either case.
|
9
|
+
# A per-call runner will use all the methods of a Reporter,
|
10
|
+
# while a per-file runner will use start_case per file,
|
11
|
+
# and will not use the start_test and finish_test methods,
|
12
|
+
# since those are beyond it's grainularity.
|
13
|
+
#
|
14
|
+
class Reporter
|
15
|
+
|
16
|
+
include Colorize
|
17
|
+
|
18
|
+
attr :io
|
19
|
+
|
20
|
+
def initialize(io)
|
21
|
+
@io = io || $stdout
|
22
|
+
end
|
23
|
+
|
24
|
+
# These methods are called in the process of running the tests.
|
25
|
+
|
26
|
+
def start_suite(suite)
|
27
|
+
end
|
28
|
+
|
29
|
+
def start_case(kase)
|
30
|
+
end
|
31
|
+
|
32
|
+
def start_test(test)
|
33
|
+
end
|
34
|
+
|
35
|
+
def pass(message=nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
def fail(message=nil)
|
39
|
+
end
|
40
|
+
|
41
|
+
def error(message=nil)
|
42
|
+
end
|
43
|
+
|
44
|
+
def finish_test(test)
|
45
|
+
end
|
46
|
+
|
47
|
+
def finish_case(kase)
|
48
|
+
end
|
49
|
+
|
50
|
+
def finish_suite(suite)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'turn/reporter'
|
2
|
+
|
3
|
+
module Turn
|
4
|
+
|
5
|
+
# = Traditional Dot Reporter
|
6
|
+
#
|
7
|
+
class DotReporter < Reporter
|
8
|
+
|
9
|
+
def start_suite(suite)
|
10
|
+
@time = Time.now
|
11
|
+
io.puts "Loaded suite #{suite.name}"
|
12
|
+
io.puts "Started"
|
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
|
+
io.print '.'; io.flush
|
23
|
+
end
|
24
|
+
|
25
|
+
def fail(message=nil)
|
26
|
+
io.print 'F'; io.flush
|
27
|
+
end
|
28
|
+
|
29
|
+
def error(message=nil)
|
30
|
+
io.print 'E'; io.flush
|
31
|
+
end
|
32
|
+
|
33
|
+
def finish_test(test)
|
34
|
+
end
|
35
|
+
|
36
|
+
def finish_case(kase)
|
37
|
+
end
|
38
|
+
|
39
|
+
def finish_suite(suite)
|
40
|
+
io.puts("\nFinished in %.5f seconds." % [Time.now - @time])
|
41
|
+
io.puts
|
42
|
+
|
43
|
+
report = ''
|
44
|
+
|
45
|
+
fails = suite.select do |testrun|
|
46
|
+
testrun.fail? || testrun.error?
|
47
|
+
end
|
48
|
+
|
49
|
+
unless fails.empty? # or verbose?
|
50
|
+
#report << "\n\n-- Failures and Errors --\n\n"
|
51
|
+
fails.uniq.each do |testrun|
|
52
|
+
message = testrun.message.tabto(0)
|
53
|
+
message = ::ANSICode.magenta(message) if COLORIZE
|
54
|
+
report << message << "\n"
|
55
|
+
end
|
56
|
+
report << "\n"
|
57
|
+
end
|
58
|
+
|
59
|
+
io.puts report
|
60
|
+
|
61
|
+
io.puts "%s tests, %s assetions, %s failures, %s errors" % test_tally(suite)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def test_tally(suite)
|
67
|
+
counts = suite.collect{ |tr| tr.counts }
|
68
|
+
tally = [0,0,0,0]
|
69
|
+
counts.each do |count|
|
70
|
+
4.times{ |i| tally[i] += count[i] }
|
71
|
+
end
|
72
|
+
return tally
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|