openlogic-turn 0.8.2

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