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