turn 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ require 'yaml'
2
+
3
+ module Turn
4
+ require 'turn/reporter'
5
+
6
+ # = Marshal Reporter
7
+ #
8
+ class MarshalReporter < Reporter
9
+
10
+ #def start_suite(suite)
11
+ # #@suite = suite
12
+ # #@time = Time.now
13
+ # #files = suite.collect{ |s| s.file }.join(' ')
14
+ # #io.puts "Loaded suite #{suite.name}"
15
+ # #io.puts "Started"
16
+ #end
17
+
18
+ #def start_test(test)
19
+ # #if @file != test.file
20
+ # # @file = test.file
21
+ # # io.puts(test.file)
22
+ # #end
23
+ # io.print " %-69s" % test.name
24
+ #end
25
+
26
+ #def start_case(kase)
27
+ # io.puts(kase.name)
28
+ #end
29
+
30
+ #def pass(message=nil)
31
+ # io.puts " #{PASS}"
32
+ # if message
33
+ # message = ::ANSICode.magenta(message) if COLORIZE
34
+ # io.puts(message.to_s)
35
+ # end
36
+ #end
37
+
38
+ #def fail(message=nil)
39
+ # io.puts(" #{FAIL}")
40
+ # if message
41
+ # message = ::ANSICode.magenta(message) if COLORIZE
42
+ # io.puts(message.to_s)
43
+ # end
44
+ #end
45
+
46
+ #def error(message=nil)
47
+ # io.puts("#{ERROR}")
48
+ # io.puts(message.to_s) if message
49
+ #end
50
+
51
+ #def finish_test(test)
52
+ #end
53
+
54
+ #def finish_case(kase)
55
+ #end
56
+
57
+ def finish_suite(suite)
58
+ $stdout << suite.to_yaml
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
@@ -0,0 +1,85 @@
1
+ require 'turn/reporter'
2
+
3
+ module Turn
4
+
5
+ # = Outline Reporter (Turn's Original)
6
+ #
7
+ #--
8
+ # TODO: Should we fit reporter output to width of console?
9
+ # TODO: Running percentages?
10
+ #++
11
+ class OutlineReporter < Reporter
12
+
13
+ def start_suite(suite)
14
+ @suite = suite
15
+ @time = Time.now
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 " %-69s" % test.name
31
+ end
32
+
33
+ def pass(message=nil)
34
+ io.puts " #{PASS}"
35
+ if message
36
+ message = ::ANSICode.magenta(message) if COLORIZE
37
+ message = message.to_s.tabto(8)
38
+ io.puts(message)
39
+ end
40
+ end
41
+
42
+ def fail(message=nil)
43
+ io.puts(" #{FAIL}")
44
+ if message
45
+ message = ::ANSICode.magenta(message) if COLORIZE
46
+ message = message.to_s.tabto(8)
47
+ io.puts(message)
48
+ end
49
+ end
50
+
51
+ def error(message=nil)
52
+ io.puts("#{ERROR}")
53
+ io.puts(message.to_s) if message
54
+ end
55
+
56
+ def finish_test(test)
57
+ end
58
+
59
+ #def finish_case(kase)
60
+ #end
61
+
62
+ def finish_suite(suite)
63
+ total = suite.count_tests
64
+ failure = suite.count_failures
65
+ error = suite.count_errors
66
+ pass = total - failure - error
67
+
68
+ bar = '=' * 78
69
+ if COLORIZE
70
+ bar = if pass == total then ::ANSICode.green bar
71
+ else ::ANSICode.red bar end
72
+ end
73
+
74
+ tally = [total, suite.count_assertions]
75
+
76
+ io.puts bar
77
+ io.puts " pass: %d, fail: %d, error: %d" % [pass, failure, error]
78
+ io.puts " total: %d tests with %d assertions in #{Time.new - @time} seconds" % tally
79
+ io.puts bar
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
@@ -0,0 +1,117 @@
1
+ require 'turn/reporter'
2
+ require 'facets/progressbar'
3
+ require 'facets/string/tab'
4
+
5
+ module Turn
6
+
7
+ #
8
+ class ProgressReporter < Reporter
9
+
10
+ def start_suite(suite)
11
+ @pbar = ::ProgressBar.new('Testing', suite.size)
12
+ @pbar.inc
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
+ # #@pbar.inc
23
+ #end
24
+
25
+ #def fail(message=nil)
26
+ # #@pbar.inc
27
+ #end
28
+
29
+ #def error(message=nil)
30
+ # #@pbar.inc
31
+ #end
32
+
33
+ def finish_case(kase)
34
+ @pbar.inc
35
+ end
36
+
37
+ def finish_suite(suite)
38
+ @pbar.finish
39
+ post_report(suite)
40
+ end
41
+
42
+ #
43
+ def post_report(suite)
44
+ tally = test_tally(suite)
45
+
46
+ width = suite.collect{ |tr| tr.name.size }.max
47
+
48
+ headers = [ 'TESTCASE ', ' TESTS ', 'ASSERTIONS', ' FAILURES ', ' ERRORS ' ]
49
+ io.puts "\n%-#{width}s %10s %10s %10s %10s\n" % headers
50
+
51
+ files = nil
52
+
53
+ suite.each do |testrun|
54
+ if testrun.files != [testrun.name] && testrun.files != files
55
+ label = testrun.files.join(' ')
56
+ label = ::ANSICode.magenta(label) if COLORIZE
57
+ io.puts(label + "\n")
58
+ files = testrun.files
59
+ end
60
+ io.puts paint_line(testrun, width)
61
+ end
62
+
63
+ #puts("\n%i tests, %i assertions, %i failures, %i errors\n\n" % tally)
64
+
65
+ tally_line = "-----\n"
66
+ tally_line << "%-#{width}s " % "TOTAL"
67
+ tally_line << "%10s %10s %10s %10s" % tally
68
+
69
+ io.puts(tally_line + "\n")
70
+
71
+ fails = suite.select do |testrun|
72
+ testrun.fail? || testrun.error?
73
+ end
74
+
75
+ #if tally[2] != 0 or tally[3] != 0
76
+ unless fails.empty? # or verbose?
77
+ io.puts "\n\n-- Failures and Errors --\n\n"
78
+ fails.uniq.each do |testrun|
79
+ message = testrun.message.tabto(0).strip
80
+ message = ::ANSICode.red(message) if COLORIZE
81
+ io.puts(message+"\n\n")
82
+ end
83
+ io.puts
84
+ end
85
+ #end
86
+ end
87
+
88
+ private
89
+
90
+ def paint_line(testrun, width)
91
+ line = ''
92
+ line << "%-#{width}s " % [testrun.name]
93
+ line << "%10s %10s %10s %10s" % testrun.counts
94
+ line << " " * 8
95
+ if testrun.fail?
96
+ line << "[#{FAIL}]"
97
+ elsif testrun.error?
98
+ line << "[#{FAIL}]"
99
+ else
100
+ line << "[#{PASS}]"
101
+ end
102
+ line
103
+ end
104
+
105
+ def test_tally(suite)
106
+ counts = suite.collect{ |tr| tr.counts }
107
+ tally = [0,0,0,0]
108
+ counts.each do |count|
109
+ 4.times{ |i| tally[i] += count[i] }
110
+ end
111
+ return tally
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+
@@ -0,0 +1,40 @@
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: viles this 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
+ max = (files+viles).collect{ |f| f.size }.max
25
+
26
+ pairs = files.inject([]){ |m, f| viles.collect{ |v| m << [f,v] }; m }
27
+ pairs = pairs.reject{ |f,v| f == v }
28
+
29
+ testruns = pairs.collect do |file, versus|
30
+ name = "%-#{max}s %-#{max}s" % [file, versus]
31
+ suite.new_case(name, file, versus)
32
+ end
33
+
34
+ test_loop_runner(suite)
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,129 @@
1
+ module Turn
2
+ require 'turn/colorize'
3
+
4
+ # = IsoRunner
5
+ #
6
+ # Iso Runner provides means from running unit test
7
+ # in isolated processes. It can do this either by running
8
+ # each test in isolation (solo testing) or in pairs (cross testing).
9
+ #
10
+ # The IsoRunner proiveds some variery in ouput formats and can also
11
+ # log results to a file.
12
+ #
13
+ class IsoRunner
14
+ include Turn::Colorize
15
+
16
+ attr :reporter
17
+
18
+ private
19
+
20
+ def initialize(controller)
21
+ @controller = controller
22
+ @reporter = controller.reporter
23
+ #yield(self) if block_given?
24
+ @loadpath = controller.loadpath
25
+ @requires = controller.requires
26
+ @live = controller.live?
27
+ end
28
+
29
+ public
30
+
31
+ # Runs the list of test calls passed to it.
32
+ # This is used by #test_solo and #test_cross.
33
+ #
34
+ def start
35
+ suite = TestSuite.new
36
+ testruns = @controller.files.collect do |file|
37
+ suite.new_case(file)
38
+ end
39
+ test_loop_runner(suite)
40
+ end
41
+
42
+ private
43
+
44
+ # The IsoRunner actually shells out to turn in
45
+ # manifest mode, to gather results from isolated
46
+ # runs.
47
+ def test_loop_runner(suite)
48
+ reporter.start_suite(suite)
49
+
50
+ recase = []
51
+
52
+ suite.each_with_index do |kase, index|
53
+ reporter.start_case(kase)
54
+
55
+ # FRACKING GENIUS RIGHT HERE !!!!!!!!!!!!
56
+ cmd = []
57
+ cmd << %[turn]
58
+ cmd << %[--marshal]
59
+ cmd << %[--loadpath="#{@loadpath.join(';')}"] unless @loadpath.empty?
60
+ cmd << %[--requires="#{@requires.join(';')}"] unless @requires.empty?
61
+ cmd << %[--live] if @live
62
+ cmd << %[#{kase.files.join(' ')}]
63
+ cmd = cmd.join(' ')
64
+ result = `#{cmd}`
65
+
66
+ files = kase.files
67
+
68
+ head, yaml = *result.split('---')
69
+ sub_suite = YAML.load(yaml)
70
+
71
+ # TODO: How to handle pairs?
72
+ #name = kase.name
73
+ kases = sub_suite.cases
74
+ suite.cases[index] = kases
75
+
76
+ kases.each do |kase|
77
+ kase.files = files
78
+ #reporter.start_case(kase)
79
+ kase.tests.each do |test|
80
+ reporter.start_test(test)
81
+ if test.error?
82
+ reporter.error(test.message)
83
+ elsif test.fail?
84
+ reporter.fail(test.message)
85
+ else
86
+ reporter.pass
87
+ end
88
+ reporter.finish_test(test)
89
+ end
90
+ reporter.finish_case(kase)
91
+ end
92
+ end
93
+
94
+ suite.cases.flatten!
95
+
96
+ reporter.finish_suite(suite)
97
+
98
+ # shutdown test/unit auto runner if test/unit is loaded.
99
+ ::Test::Unit.run=true rescue nil
100
+ end
101
+
102
+ #
103
+ #def test_parse_result(result)
104
+ # if md = /(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/.match(result)
105
+ # count = md[1..4].collect{|q| q.to_i}
106
+ # else
107
+ # count = [1, 0, 0, 1] # SHOULD NEVER HAPPEN
108
+ # end
109
+ # return count
110
+ #end
111
+
112
+ # NOT USED YET.
113
+ def log_report(report)
114
+ if log #&& !dryrun?
115
+ #logfile = File.join('log', apply_naming_policy('testlog', 'txt'))
116
+ FileUtils.mkdir_p('log')
117
+ logfile = File.join('log', 'testlog.txt')
118
+ File.open(logfile, 'a') do |f|
119
+ f << "= #{self.class} Test @ #{Time.now}\n"
120
+ f << report
121
+ f << "\n"
122
+ end
123
+ end
124
+ end
125
+
126
+ end#class IsoRunner
127
+
128
+ end#module Turn
129
+
@@ -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
+