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
+ 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: make 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
+ pairs = files.inject([]){ |m, f| viles.collect{ |v| m << [f,v] }; m }
25
+ pairs = pairs.reject{ |f,v| f == v }
26
+
27
+ max = files.collect{ |f| f.sub(Dir.pwd+'/','').size }.max
28
+
29
+ testruns = pairs.collect do |file1, file2|
30
+ name1 = file1.sub(Dir.pwd+'/','')
31
+ name2 = file2.sub(Dir.pwd+'/','')
32
+ name = "%-#{max}s %-#{max}s" % [name1, name2]
33
+ suite.new_case(name, file1, file2)
34
+ end
35
+
36
+ test_loop_runner(suite)
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
@@ -0,0 +1,167 @@
1
+ module Turn
2
+ require 'turn/colorize'
3
+ require 'yaml'
4
+ require 'open3'
5
+
6
+ # = IsoRunner
7
+ #
8
+ # Iso Runner provides means from running unit test
9
+ # in isolated processes. It can do this either by running
10
+ # each test in isolation (solo testing) or in pairs (cross testing).
11
+ #
12
+ # The IsoRunner proiveds some variery in ouput formats and can also
13
+ # log results to a file.
14
+ #
15
+ class IsoRunner
16
+ include Turn::Colorize
17
+
18
+ attr :reporter
19
+
20
+ private
21
+
22
+ def initialize(controller)
23
+ @controller = controller
24
+ @reporter = controller.reporter
25
+ #yield(self) if block_given?
26
+ @loadpath = controller.loadpath
27
+ @requires = controller.requires
28
+ @live = controller.live?
29
+ @minitest = controller.framework == :minitest
30
+ end
31
+
32
+ public
33
+
34
+ # Runs the list of test calls passed to it.
35
+ # This is used by #test_solo and #test_cross.
36
+ #
37
+ def start
38
+ suite = TestSuite.new
39
+ testruns = @controller.files.collect do |file|
40
+ name = file.sub(Dir.pwd+'/','')
41
+ suite.new_case(name, file)
42
+ end
43
+ test_loop_runner(suite)
44
+ end
45
+
46
+ private
47
+
48
+ # The IsoRunner actually shells out to turn in
49
+ # manifest mode, to gather results from isolated
50
+ # runs.
51
+ def test_loop_runner(suite)
52
+ reporter.start_suite(suite)
53
+
54
+ recase = []
55
+
56
+ suite.each_with_index do |kase, index|
57
+ reporter.start_case(kase)
58
+
59
+ turn_path = File.expand_path(File.dirname(__FILE__) + '/../bin.rb')
60
+
61
+ files = kase.files.map{ |f| f.sub(Dir.pwd+'/', '') }
62
+
63
+ # FRACKING GENIUS RIGHT HERE !!!!!!!!!!!!
64
+ cmd = []
65
+ cmd << "ruby"
66
+ cmd << "-I#{@loadpath.join(':')}" unless @loadpath.empty?
67
+ cmd << "-r#{@requires.join(':')}" unless @requires.empty?
68
+ cmd << "--"
69
+ cmd << turn_path
70
+ cmd << "--marshal"
71
+ cmd << %[--loadpath="#{@loadpath.join(':')}"] unless @loadpath.empty?
72
+ cmd << %[--requires="#{@requires.join(':')}"] unless @requires.empty?
73
+ cmd << "--live" if @live
74
+ cmd << "--minitest" if @minitest
75
+ cmd << files.join(' ')
76
+ cmd = cmd.join(' ')
77
+
78
+ #out = `#{cmd}`
79
+ #err = ''
80
+
81
+ out, err = nil, nil
82
+ Open3.popen3(cmd) do |stdin, stdout, stderr|
83
+ stdin.close
84
+ out = stdout.read.chomp
85
+ err = stderr.read.chomp
86
+ end
87
+
88
+ # TODO: how to report? will need to add something to reporter
89
+ # b/c it may have redirected stdout. Or use STDOUT?
90
+ #if !err.empty?
91
+ # puts err
92
+ # raise
93
+ #end
94
+
95
+ files = kase.files
96
+
97
+ # remove any unexpected output injected at the beginning
98
+ yaml = out[out.index(/^---/)..-1]
99
+ sub_suite = YAML.load(yaml)
100
+
101
+ # TODO: How to handle pairs?
102
+ #name = kase.name
103
+ kases = sub_suite.cases
104
+ suite.cases[index] = kases
105
+
106
+ kases.each do |kase|
107
+ kase.files = files
108
+ #reporter.start_case(kase)
109
+ kase.tests.each do |test|
110
+ reporter.start_test(test)
111
+ if test.error?
112
+ #reporter.error(test.message)
113
+ reporter.error(test.raised)
114
+ elsif test.fail?
115
+ #reporter.fail(test.message)
116
+ reporter.error(test.raised)
117
+ else
118
+ reporter.pass
119
+ end
120
+ reporter.finish_test(test)
121
+ end
122
+ reporter.finish_case(kase)
123
+ end
124
+ end
125
+
126
+ suite.cases.flatten!
127
+
128
+ reporter.finish_suite(suite)
129
+
130
+ # shutdown auto runner
131
+ if @minitest
132
+
133
+ else
134
+ ::Test::Unit.run=true rescue nil
135
+ end
136
+
137
+ suite
138
+ end
139
+
140
+ #
141
+ #def test_parse_result(result)
142
+ # if md = /(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/.match(result)
143
+ # count = md[1..4].collect{|q| q.to_i}
144
+ # else
145
+ # count = [1, 0, 0, 1] # SHOULD NEVER HAPPEN
146
+ # end
147
+ # return count
148
+ #end
149
+
150
+ # NOT USED YET.
151
+ def log_report(report)
152
+ if log #&& !dryrun?
153
+ #logfile = File.join('log', apply_naming_policy('testlog', 'txt'))
154
+ FileUtils.mkdir_p('log')
155
+ logfile = File.join('log', 'testlog.txt')
156
+ File.open(logfile, 'a') do |f|
157
+ f << "= #{self.class} Test @ #{Time.now}\n"
158
+ f << report
159
+ f << "\n"
160
+ end
161
+ end
162
+ end
163
+
164
+ end#class IsoRunner
165
+
166
+ end#module Turn
167
+
@@ -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
+
@@ -0,0 +1,189 @@
1
+ #
2
+
3
+ # Becuase of some wierdness in MiniTest
4
+ debug, $DEBUG = $DEBUG, false
5
+ require 'minitest/unit'
6
+ $DEBUG = debug
7
+
8
+ Test = MiniTest
9
+
10
+ module Turn
11
+
12
+ # = MiniTest TestRunner
13
+ #
14
+ class MiniRunner < ::MiniTest::Unit
15
+
16
+ #
17
+ def initialize(controller)
18
+
19
+ controller.loadpath.each{ |path| $: << path } unless controller.live?
20
+ controller.requires.each{ |path| require(path) }
21
+
22
+ [controller.files].flatten.each{ |path| require(path) }
23
+
24
+ files = [controller.files].flatten
25
+ files.each{ |path| require(path) }
26
+
27
+ # TODO: Better name ?
28
+ @turn_suite_name = files.map{ |path| File.dirname(path).sub(Dir.pwd+'/','') }.uniq.join(',')
29
+
30
+ #sub_suites = []
31
+ #ObjectSpace.each_object(Class) do |klass|
32
+ # if(Test::Unit::TestCase > klass)
33
+ # sub_suites << klass.suite
34
+ # end
35
+ #end
36
+ #suite = Test::Unit::TestSuite.new('') # FIXME: Name?
37
+ #sub_suites.sort_by{|s|s.name}.each{|s| suite << s}
38
+
39
+ #suite.tests.each do |c|
40
+ # pattern = controller.pattern
41
+ # c.tests.reject! { |t| pattern !~ t.method_name }
42
+ #end
43
+
44
+ @turn_logger = controller.reporter
45
+
46
+ super()
47
+ end
48
+
49
+ #
50
+ def start(args=[])
51
+ run(args)
52
+ return @turn_suite
53
+ end
54
+
55
+ #
56
+ def run(args = [])
57
+ @verbose = true
58
+
59
+ filter = if args.first =~ /^(-n|--name)$/ then
60
+ args.shift
61
+ arg = args.shift
62
+ arg =~ /\/(.*)\// ? Regexp.new($1) : arg
63
+ else
64
+ /./ # anything - ^test_ already filtered by #tests
65
+ end
66
+
67
+ #@@out.puts "Loaded suite #{$0.sub(/\.rb$/, '')}\nStarted"
68
+
69
+ start = Time.now
70
+
71
+ run_test_suites(filter)
72
+
73
+ return failures + errors if @test_count > 0 # or return nil...
74
+ end
75
+
76
+ #
77
+ def run_test_suites(filter = /./)
78
+ @test_count, @assertion_count = 0, 0
79
+ old_sync, @@out.sync = @@out.sync, true if @@out.respond_to? :sync=
80
+
81
+ @turn_suite = Turn::TestSuite.new(@turn_suite_name)
82
+ @turn_suite.size = ::MiniTest::Unit::TestCase.test_suites.size
83
+ @turn_logger.start_suite(@turn_suite)
84
+
85
+ ::MiniTest::Unit::TestCase.test_suites.each do |kase|
86
+
87
+ test_cases = kase.test_methods.grep(filter)
88
+
89
+ @turn_case = @turn_suite.new_case(kase.name)
90
+
91
+ turn_cases = test_cases.map do |test|
92
+ @turn_case.new_test(test)
93
+ end
94
+
95
+ @turn_logger.start_case(@turn_case)
96
+
97
+ turn_cases.each do |test|
98
+ #methname, tcase = name.scan(%r/^([^\(]+)\(([^\)]+)\)/o).flatten!
99
+ @turn_test = test #@turn_case.new_test(test)
100
+ @turn_logger.start_test(@turn_test)
101
+
102
+ inst = kase.new(test.name)
103
+ inst._assertions = 0
104
+
105
+ result = inst.run(self)
106
+ report = @report.last
107
+
108
+ case result
109
+ when :pass
110
+ @turn_logger.pass
111
+ when :error
112
+ #trace = ::MiniTest::filter_backtrace(report[:exception].backtrace).first
113
+ @turn_test.error!(report)
114
+ @turn_logger.error(report)
115
+ when :fail
116
+ #trace = ::MiniTest::filter_backtrace(report[:exception].backtrace).first
117
+ @turn_test.fail!(report)
118
+ @turn_logger.fail(report)
119
+ when :skip
120
+ @turn_test.skip! #(report)
121
+ @turn_logger.skip #(report)
122
+ end
123
+
124
+ @turn_logger.finish_test(@turn_test)
125
+
126
+ @test_count += 1
127
+ @assertion_count += inst._assertions
128
+ end
129
+ @turn_case.count_assertions = @assertion_count # for lack of a better appraoch
130
+ @turn_logger.finish_case(@turn_case)
131
+ end
132
+ @turn_logger.finish_suite(@turn_suite)
133
+ @@out.sync = old_sync if @@out.respond_to? :sync=
134
+ [@test_count, @assertion_count]
135
+ end
136
+
137
+ # Overwrite #puke method so that is stores a hash
138
+ # with :message and :exception keys.
139
+ def puke(klass, meth, e)
140
+ result = nil
141
+ msg = case e
142
+ when ::MiniTest::Skip
143
+ @skips += 1
144
+ result = :skip
145
+ e.message
146
+ when ::MiniTest::Assertion
147
+ @failures += 1
148
+ result = :fail
149
+ e.message
150
+ else
151
+ @errors += 1
152
+ result = :error
153
+ "#{e.class}: #{e.message}\n"
154
+ end
155
+
156
+ @report << e #{:message => msg, :exception => e}
157
+ result
158
+ end
159
+
160
+ end
161
+
162
+ end
163
+
164
+ class ::MiniTest::Unit::TestCase
165
+ old_verbose, $VERBOSE = $VERBOSE, false
166
+ # Overwrite #run method so that is uses symbols
167
+ # as return values rather than characters.
168
+ def run(runner)
169
+ result = :pass
170
+ begin
171
+ @passed = nil
172
+ self.setup
173
+ self.__send__(self.__name__.to_s)
174
+ @passed = true
175
+ rescue Exception => e
176
+ @passed = false
177
+ result = runner.puke(self.class, self.__name__.to_s, e)
178
+ ensure
179
+ begin
180
+ self.teardown
181
+ rescue Exception => e
182
+ result = runner.puke(self.class, self.__name__.to_s, e)
183
+ end
184
+ end
185
+ result
186
+ end
187
+ $VERBOSE = old_verbose
188
+ end
189
+