openlogic-turn 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ module Turn
2
+
3
+ #
4
+ class TestMethod
5
+ attr_accessor :name
6
+ attr_accessor :file
7
+ attr_accessor :raised
8
+ attr_accessor :message
9
+ attr_accessor :backtrace
10
+
11
+ def initialize(name)
12
+ @name = name
13
+ @fail = false
14
+ @error = false
15
+ @raised = nil
16
+ @message = nil
17
+ @backtrace = []
18
+ end
19
+
20
+ def fail!(assertion)
21
+ @fail, @error = true, false
22
+ @raised = assertion
23
+ @message = assertion.message
24
+ @backtrace = assertion.backtrace
25
+ end
26
+
27
+ def error!(exception)
28
+ @fail, @error = false, true
29
+ @raised = exception
30
+ @message = exception.message
31
+ @backtrace = exception.backtrace
32
+ end
33
+
34
+ def fail? ; @fail ; end
35
+ def error? ; @error ; end
36
+ def pass? ; !(@fail or @error) ; end
37
+
38
+ def to_s ; name ; end
39
+ end
40
+
41
+ end
42
+
@@ -0,0 +1,85 @@
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_tests
37
+ #@count_tests ||= (
38
+ sum = 0; each{ |c| sum += c.count_tests }; sum
39
+ #)
40
+ end
41
+
42
+ def count_assertions
43
+ #@count_assertions ||= (
44
+ sum = 0; each{ |c| sum += c.count_assertions }; sum
45
+ #)
46
+ end
47
+
48
+ def count_failures
49
+ #@count_failures ||= (
50
+ sum = 0; each{ |c| sum += c.count_failures }; sum
51
+ #)
52
+ end
53
+
54
+ def count_errors
55
+ #@count_errors ||= (
56
+ sum = 0; each{ |c| sum += c.count_errors }; sum
57
+ #)
58
+ end
59
+
60
+ def count_passes
61
+ #@count_passes ||= (
62
+ sum = 0; each{ |c| sum += c.count_passes }; 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 #,count_skips
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
+ def passed?
80
+ (count_failures == 0 && count_errors == 0)
81
+ end
82
+ end
83
+
84
+ end
85
+
@@ -0,0 +1,204 @@
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
+ # = Controller
9
+ #
10
+ #--
11
+ # TODO: Add support to test run loggging.
12
+ #++
13
+ class Controller
14
+
15
+ # File glob pattern of tests to run.
16
+ # Can be an array of files/globs.
17
+ attr_accessor :tests
18
+
19
+ # Files globs to specially exclude.
20
+ attr_accessor :exclude
21
+
22
+ # Regexp pattern that all test name's must
23
+ # match to be eligible to run.
24
+ attr_accessor :pattern
25
+
26
+ # Add these folders to the $LOAD_PATH.
27
+ attr_accessor :loadpath
28
+
29
+ # Libs to require when running tests.
30
+ attr_accessor :requires
31
+
32
+ # Reporter type.
33
+ attr_accessor :format
34
+
35
+ # Run mode.
36
+ attr_accessor :runmode
37
+
38
+ # Test against live install (i.e. Don't use loadpath option)
39
+ attr_accessor :live
40
+
41
+ # Log results? May be true/false or log file name. (TODO)
42
+ attr_accessor :log
43
+
44
+ # Verbose output?
45
+ attr_accessor :verbose
46
+
47
+ # Test framework, either :minitest or :testunit
48
+ attr_accessor :framework
49
+
50
+ def verbose? ; @verbose ; end
51
+ def live? ; @live ; end
52
+
53
+ private
54
+
55
+ def initialize
56
+ yield(self) if block_given?
57
+ initialize_defaults
58
+ end
59
+
60
+ #
61
+ def initialize_defaults
62
+ @loadpath ||= ['lib']
63
+ @tests ||= "test/**/{test,}*{,test}"
64
+ @exclude ||= []
65
+ @requires ||= []
66
+ @live ||= false
67
+ @log ||= true
68
+ #@reporter ||= OutlineReporter.new($stdout)
69
+ #@runner ||= RUBY_VERSION >= "1.9" ? MiniRunner : TestRunner
70
+ @pattern ||= /.*/
71
+ end
72
+
73
+ # Collect test configuation.
74
+ #def test_configuration(options={})
75
+ # #options = configure_options(options, 'test')
76
+ # #options['loadpath'] ||= metadata.loadpath
77
+ # options['tests'] ||= self.tests
78
+ # options['loadpath'] ||= self.loadpath
79
+ # options['requires'] ||= self.requires
80
+ # options['live'] ||= self.live
81
+ # options['exclude'] ||= self.exclude
82
+ # #options['tests'] = list_option(options['tests'])
83
+ # options['loadpath'] = list_option(options['loadpath'])
84
+ # options['exclude'] = list_option(options['exclude'])
85
+ # options['require'] = list_option(options['require'])
86
+ # return options
87
+ #end
88
+
89
+ #
90
+ def list_option(list)
91
+ case list
92
+ when nil
93
+ []
94
+ when Array
95
+ list
96
+ else
97
+ list.split(/[:;]/)
98
+ end
99
+ end
100
+
101
+ public
102
+
103
+ def loadpath=(paths)
104
+ @loadpath = list_option(paths)
105
+ end
106
+
107
+ def exclude=(paths)
108
+ @exclude = list_option(paths)
109
+ end
110
+
111
+ def requires=(paths)
112
+ @requires = list_option(paths)
113
+ end
114
+
115
+ def files
116
+ @files ||= (
117
+ fs = tests.map do |t|
118
+ File.directory?(t) ? Dir[File.join(t, '**', '*')] : Dir[t]
119
+ end
120
+ fs = fs.flatten.reject{ |f| File.directory?(f) }
121
+ ex = exclude.map do |x|
122
+ File.directory?(x) ? Dir[File.join(x, '**', '*')] : Dir[x]
123
+ end
124
+ ex = ex.flatten.reject{ |f| File.directory?(f) }
125
+ (fs - ex).uniq.map{ |f| File.expand_path(f) }
126
+ )
127
+ end
128
+
129
+ def start
130
+ @files = nil # reset files just in case
131
+
132
+ if files.empty?
133
+ $stderr.puts "No tests."
134
+ return
135
+ end
136
+
137
+ testrun = runner.new(self)
138
+
139
+ testrun.start
140
+ end
141
+
142
+ # Select reporter based on output mode.
143
+ def reporter
144
+ @reporter ||= (
145
+ case format
146
+ when :marshal
147
+ require 'turn/reporters/marshal_reporter'
148
+ Turn::MarshalReporter.new($stdout)
149
+ when :progress
150
+ require 'turn/reporters/progress_reporter'
151
+ Turn::ProgressReporter.new($stdout)
152
+ when :dotted
153
+ require 'turn/reporters/dot_reporter'
154
+ Turn::DotReporter.new($stdout)
155
+ when :pretty
156
+ require 'turn/reporters/pretty_reporter'
157
+ Turn::PrettyReporter.new($stdout)
158
+ when :cue
159
+ require 'turn/reporters/cue_reporter'
160
+ Turn::CueReporter.new($stdout)
161
+ else
162
+ require 'turn/reporters/outline_reporter'
163
+ Turn::OutlineReporter.new($stdout)
164
+ end
165
+ )
166
+ end
167
+
168
+ # # Insatance of Runner, selected based on format and runmode.
169
+ def runner
170
+ @runner ||= (
171
+ case framework
172
+ when :minitest
173
+ require 'turn/runners/minirunner'
174
+ else
175
+ require 'turn/runners/testrunner'
176
+ end
177
+
178
+ case runmode
179
+ when :marshal
180
+ if framework == :minitest
181
+ Turn::MiniRunner
182
+ else
183
+ Turn::TestRunner
184
+ end
185
+ when :solo
186
+ require 'turn/runners/solorunner'
187
+ Turn::SoloRunner
188
+ when :cross
189
+ require 'turn/runners/crossrunner'
190
+ Turn::CrossRunner
191
+ else
192
+ if framework == :minitest
193
+ Turn::MiniRunner
194
+ else
195
+ Turn::TestRunner
196
+ end
197
+ end
198
+ )
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+
@@ -0,0 +1,31 @@
1
+ # Borrowed methods from Ruby Facets.
2
+
3
+ class String
4
+
5
+ # Aligns each line n spaces.
6
+ def tab(n)
7
+ gsub(/^ */, ' ' * n)
8
+ end
9
+
10
+ # Preserves relative tabbing.
11
+ # The first non-empty line ends up with n spaces before nonspace.
12
+ def tabto(n)
13
+ if self =~ /^( *)\S/
14
+ indent(n - $1.length)
15
+ else
16
+ self
17
+ end
18
+ end
19
+
20
+ # Indent left or right by n spaces.
21
+ # (This used to be called #tab and aliased as #indent.)
22
+ def indent(n, c=' ')
23
+ if n >= 0
24
+ gsub(/^/, c * n)
25
+ else
26
+ gsub(/^#{Regexp.escape(c)}{0,#{-n}}/, "")
27
+ end
28
+ end
29
+
30
+ end
31
+
@@ -0,0 +1,69 @@
1
+ module Turn
2
+ require 'turn/colorize'
3
+ require 'turn/core_ext'
4
+
5
+ # = Reporter
6
+ #
7
+ # There are two distinct way in which a report may be utilized
8
+ # by a Runner: per-call or per-file. The method #pass, #fail
9
+ # and #error are generic, and will be used in either case.
10
+ # A per-call runner will use all the methods of a Reporter,
11
+ # while a per-file runner will use start_case per file,
12
+ # and will not use the start_test and finish_test methods,
13
+ # since those are beyond it's grainularity.
14
+ #
15
+ class Reporter
16
+
17
+ include Colorize
18
+
19
+ attr :io
20
+
21
+ def initialize(io)
22
+ @io = io || $stdout
23
+ end
24
+
25
+ # These methods are called in the process of running the tests.
26
+
27
+ def start_suite(test_suite)
28
+ end
29
+
30
+ def start_case(test_case)
31
+ end
32
+
33
+ def start_test(test)
34
+ end
35
+
36
+ def pass(message=nil)
37
+ end
38
+
39
+ def fail(assertion, message=nil)
40
+ end
41
+
42
+ def error(exception, message=nil)
43
+ end
44
+
45
+ def finish_test(test)
46
+ end
47
+
48
+ def finish_case(test_case)
49
+ end
50
+
51
+ def finish_suite(test_suite)
52
+ end
53
+
54
+ private
55
+
56
+ # TODO: backtrace filter probably could use some refinement.
57
+ def filter_backtrace(bt)
58
+ return [] unless bt
59
+ bt.reject!{ |line| line.rindex('minitest') }
60
+ bt.reject!{ |line| line.rindex('test/unit') }
61
+ bt.reject!{ |line| line.rindex('lib/turn') }
62
+ bt.reject!{ |line| line.rindex('bin/turn') }
63
+ bt.map{ |line| line.sub(Dir.pwd+'/', '') }
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+
@@ -0,0 +1,167 @@
1
+ require 'turn/reporter'
2
+
3
+ module Turn
4
+
5
+ # = Cue Reporter
6
+ #
7
+ # Inspired by Shindo.
8
+ #
9
+ class CueReporter < Reporter
10
+
11
+ def start_suite(suite)
12
+ @suite = suite
13
+ @time = Time.now
14
+ @stdout = StringIO.new
15
+ @stderr = StringIO.new
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 Colorize.blue(" %-69s" % test.name)
31
+ $stdout = @stdout
32
+ $stderr = @stderr
33
+ $stdout.rewind
34
+ $stderr.rewind
35
+ end
36
+
37
+ def pass(message=nil)
38
+ io.puts " #{PASS}"
39
+ if message
40
+ message = Colorize.green(message)
41
+ message = message.to_s.tabto(8)
42
+ io.puts(message)
43
+ end
44
+ end
45
+
46
+ def fail(assertion, message=nil)
47
+ io.puts(" #{FAIL}")
48
+ #message = assertion.location[0] + "\n" + assertion.message #.gsub("\n","\n")
49
+ message = message || assertion.to_s
50
+ #if message
51
+ message = Colorize.red(message)
52
+ message = message.to_s.tabto(8)
53
+ io.puts(message)
54
+ #end
55
+
56
+ show_captured_output
57
+
58
+ prompt
59
+ end
60
+
61
+ def error(exception, message=nil)
62
+ #message = exception.to_s.split("\n")[2..-1].join("\n")
63
+ message = message || exception.to_s
64
+ io.puts("#{ERROR}")
65
+ io.puts(message) #if message
66
+
67
+ prompt
68
+ end
69
+
70
+ def finish_test(test)
71
+ $stdout = STDOUT
72
+ $stderr = STDERR
73
+ end
74
+
75
+ def show_captured_output
76
+ show_captured_stdout
77
+ show_captured_stderr
78
+ end
79
+
80
+ def show_captured_stdout
81
+ @stdout.rewind
82
+ return if @stdout.eof?
83
+ STDOUT.puts(<<-output.tabto(8))
84
+ \nSTDOUT:
85
+ #{@stdout.read}
86
+ output
87
+ end
88
+
89
+ def show_captured_stderr
90
+ @stderr.rewind
91
+ return if @stderr.eof?
92
+ STDOUT.puts(<<-output.tabto(8))
93
+ \nSTDERR:
94
+ #{@stderr.read}
95
+ output
96
+ end
97
+
98
+ #def finish_case(kase)
99
+ #end
100
+
101
+ def finish_suite(suite)
102
+ total = suite.count_tests
103
+ failure = suite.count_failures
104
+ error = suite.count_errors
105
+ pass = total - failure - error
106
+
107
+ bar = '=' * 78
108
+ if COLORIZE
109
+ bar = if pass == total then Colorize.green(bar)
110
+ else Colorize.red(bar) end
111
+ end
112
+
113
+ tally = [total, suite.count_assertions]
114
+
115
+ io.puts bar
116
+ io.puts " pass: %d, fail: %d, error: %d" % [pass, failure, error]
117
+ io.puts " total: %d tests with %d assertions in #{Time.new - @time} seconds" % tally
118
+ io.puts bar
119
+ end
120
+
121
+ private
122
+
123
+ def prompt
124
+ begin
125
+ io << " [c,i,q,r,t,#,?] "
126
+ io.flush
127
+ until inp = $stdin.gets ; sleep 1 ; end
128
+ answer = inp.strip
129
+ case answer
130
+ when 'c', ''
131
+ when 'r'
132
+ # how to reload and start over?
133
+ when 'i'
134
+ # how to drop into an interactive console?
135
+ when 't'
136
+ io.puts $@
137
+ raise ArgumentError
138
+ when /^\d+$/
139
+ io.puts $@[0..answer.to_i]
140
+ raise ArgumentError
141
+ when 'q'
142
+ exit -1
143
+ when '?'
144
+ io.puts HELP
145
+ raise ArgumentError #prompt
146
+ else
147
+ raise ArgumentError
148
+ end
149
+ rescue ArgumentError
150
+ retry
151
+ end
152
+ end
153
+
154
+ HELP = %{
155
+ c continue
156
+ r restart
157
+ i irb
158
+ t backtrace
159
+ # backtrace lines
160
+ q quit
161
+ ? help
162
+ }
163
+
164
+ end
165
+
166
+ end
167
+