tapout 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +44 -0
- data/APACHE2.txt +204 -0
- data/HISTORY.rdoc +11 -0
- data/NOTICE.rdoc +38 -0
- data/README.rdoc +73 -0
- data/TAP-YJ.rdoc +296 -0
- data/bin/tapout +3 -0
- data/lib/tapout.rb +88 -0
- data/lib/tapout/reporters.rb +6 -0
- data/lib/tapout/reporters/abstract.rb +266 -0
- data/lib/tapout/reporters/breakdown.rb +120 -0
- data/lib/tapout/reporters/dotprogress.rb +69 -0
- data/lib/tapout/reporters/progressbar.rb +89 -0
- data/lib/tapout/reporters/tap.rb +80 -0
- data/lib/tapout/reporters/verbose.rb +54 -0
- data/lib/tapout/tap_legacy_adapter.rb +168 -0
- data/lib/tapout/tap_legacy_parser.rb +25 -0
- data/lib/tapout/tapy_parser.rb +58 -0
- data/lib/tapout/version.rb +7 -0
- data/qed/applique/env.rb +5 -0
- data/qed/tap_adapter.rdoc +68 -0
- metadata +129 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'tapout/reporters/abstract'
|
2
|
+
|
3
|
+
module TapOut::Reporters
|
4
|
+
|
5
|
+
# Traditional dot progress reporter.
|
6
|
+
class Dotprogress < Abstract
|
7
|
+
|
8
|
+
#
|
9
|
+
def start_suite(entry)
|
10
|
+
@start_time = Time.now
|
11
|
+
$stdout.puts "Started\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
def pass(entry)
|
16
|
+
$stdout.print '.'
|
17
|
+
$stdout.flush
|
18
|
+
super(entry)
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
def fail(entry)
|
23
|
+
$stdout.print 'F'.ansi(:red)
|
24
|
+
$stdout.flush
|
25
|
+
super(entry)
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
def err(entry)
|
30
|
+
$stdout.print 'E'.ansi(:yellow)
|
31
|
+
$stdout.flush
|
32
|
+
super(entry)
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
def finish_suite(entry)
|
37
|
+
$stdout.puts "\n\n"
|
38
|
+
|
39
|
+
i = 1
|
40
|
+
|
41
|
+
@failed.each do |e|
|
42
|
+
#backtrace = clean_backtrace(exception.backtrace)
|
43
|
+
$stdout.puts "#{i}. " + (e['label']).ansi(:red)
|
44
|
+
$stdout.puts
|
45
|
+
$stdout.puts " #{e['message']}"
|
46
|
+
$stdout.puts " #{e['file']}:#{e['line']}" #+ backtrace[0]
|
47
|
+
$stdout.puts code_snippet(e)
|
48
|
+
$stdout.puts
|
49
|
+
i += 1
|
50
|
+
end
|
51
|
+
|
52
|
+
@raised.each do |e|
|
53
|
+
#backtrace = clean_backtrace(exception.backtrace)
|
54
|
+
$stdout.puts "#{i}. " + (e['label']).ansi(:yellow)
|
55
|
+
$stdout.puts
|
56
|
+
$stdout.puts " #{e['message']}"
|
57
|
+
$stdout.puts " #{e['file']}:#{e['line']}" #+ backtrace[0..2].join(" \n")
|
58
|
+
$stdout.puts code_snippet(e)
|
59
|
+
$stdout.puts
|
60
|
+
i += 1
|
61
|
+
end
|
62
|
+
|
63
|
+
$stdout.puts "Finished in #{Time.now - @start_time}s"
|
64
|
+
$stdout.puts tally(entry)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'tapout/reporters/abstract'
|
2
|
+
|
3
|
+
require 'ansi/progressbar'
|
4
|
+
|
5
|
+
module TapOut
|
6
|
+
|
7
|
+
module Reporters
|
8
|
+
|
9
|
+
# The progressbar report format utilises a progress bar to indicate
|
10
|
+
# elapsed progress.
|
11
|
+
class Progressbar < Abstract
|
12
|
+
|
13
|
+
def start_suite(entry)
|
14
|
+
@pbar = ::ANSI::Progressbar.new('Testing', entry['count'].to_i + 1)
|
15
|
+
@pbar.style(:bar=>:green)
|
16
|
+
@pbar.inc
|
17
|
+
end
|
18
|
+
|
19
|
+
def start_case(entry)
|
20
|
+
end
|
21
|
+
|
22
|
+
#def test(entry)
|
23
|
+
# #@pbar.inc
|
24
|
+
#end
|
25
|
+
|
26
|
+
def pass(entry)
|
27
|
+
@pbar.inc
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
def fail(entry)
|
32
|
+
@pbar.clear
|
33
|
+
|
34
|
+
puts
|
35
|
+
message = entry['message'].strip
|
36
|
+
message = message.ansi(:red)
|
37
|
+
puts(message)
|
38
|
+
puts "#{entry['file']}:#{entry['line']}"
|
39
|
+
puts
|
40
|
+
puts code_snippet(entry)
|
41
|
+
puts
|
42
|
+
|
43
|
+
@pbar.style(:bar=>:red)
|
44
|
+
@pbar.inc
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
def error(message=nil)
|
49
|
+
@pbar.clear
|
50
|
+
|
51
|
+
puts
|
52
|
+
message = entry['message'].strip
|
53
|
+
message = message.ansi(:red)
|
54
|
+
puts(message)
|
55
|
+
puts "#{entry['file']}:#{entry['line']}"
|
56
|
+
puts
|
57
|
+
puts code_snippet(entry)
|
58
|
+
puts
|
59
|
+
|
60
|
+
@pbar.style(:bar=>:yellow)
|
61
|
+
@pbar.inc
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
def omit(entry)
|
66
|
+
@pbar.inc
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
def skip(entry)
|
71
|
+
@pbar.inc
|
72
|
+
end
|
73
|
+
|
74
|
+
#def finish_case(kase)
|
75
|
+
#end
|
76
|
+
|
77
|
+
def finish_suite(entry)
|
78
|
+
@pbar.finish
|
79
|
+
#post_report(entry)
|
80
|
+
puts
|
81
|
+
puts tally(entry)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'tapout/reporters/abstract'
|
2
|
+
|
3
|
+
module TapOut::Reporters
|
4
|
+
|
5
|
+
# Tap Reporter
|
6
|
+
class Tap < Abstract
|
7
|
+
|
8
|
+
#
|
9
|
+
def start_suite(entry)
|
10
|
+
@start = Time.now
|
11
|
+
@i = 0
|
12
|
+
#n = 0
|
13
|
+
#suite.concerns.each{ |f| f.concerns.each { |s| n += s.ok.size } }
|
14
|
+
puts "1..#{entry['count']}"
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
def start_case(entry)
|
19
|
+
#$stdout.puts concern.label.ansi(:bold)
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
#def start_ok(ok)
|
24
|
+
# @i += 1
|
25
|
+
#end
|
26
|
+
|
27
|
+
#
|
28
|
+
def pass(entry)
|
29
|
+
super(entry)
|
30
|
+
|
31
|
+
#desc = entry['message'] #+ " #{ok.arguments.inspect}"
|
32
|
+
|
33
|
+
puts "ok #{entry['index']} - #{entry['label']}"
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
def fail(entry)
|
38
|
+
super(entry)
|
39
|
+
|
40
|
+
#desc = #ok.concern.label + " #{ok.arguments.inspect}"
|
41
|
+
|
42
|
+
body = []
|
43
|
+
body << "FAIL #{entry['file']}:#{entry['line']}" #clean_backtrace(exception.backtrace)[0]
|
44
|
+
body << "#{entry['message']}"
|
45
|
+
body << code_snippet(entry)
|
46
|
+
body = body.join("\n").gsub(/^/, ' # ')
|
47
|
+
|
48
|
+
puts "not ok #{entry['index']} - #{entry['label']}"
|
49
|
+
puts body
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
def error(entry)
|
54
|
+
super(entry)
|
55
|
+
|
56
|
+
#desc = ok.concern.label + " #{ok.arguments.inspect}"
|
57
|
+
|
58
|
+
body = []
|
59
|
+
body << "ERROR #{entry['file']}:#{entry['line']}" #clean_backtrace(exception.backtrace)[0..2].join(" \n")
|
60
|
+
#body << "#{exception.class}: #{entry['message']}"
|
61
|
+
body << "#{entry['message']}"
|
62
|
+
body << ""
|
63
|
+
body << code_snippet(entry)
|
64
|
+
body << ""
|
65
|
+
body = body.join("\n").gsub(/^/, ' # ')
|
66
|
+
|
67
|
+
puts "not ok #{entry['index']} - #{entry['label']}"
|
68
|
+
puts body
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
#def pending(ok, exception)
|
73
|
+
# puts "not ok #{@i} - #{unit.description}"
|
74
|
+
# puts " PENDING"
|
75
|
+
# puts " #{exception.backtrace[1]}"
|
76
|
+
#end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'tapout/reporters/abstract'
|
2
|
+
|
3
|
+
module TapOut::Reporters
|
4
|
+
|
5
|
+
# Verbose reporter.
|
6
|
+
class Verbose < Abstract
|
7
|
+
|
8
|
+
#
|
9
|
+
def start_suite(entry)
|
10
|
+
@start_time = Time.now
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
def start_case(entry)
|
15
|
+
$stdout.puts entry['label'].ansi(:bold)
|
16
|
+
end
|
17
|
+
|
18
|
+
def pass(entry)
|
19
|
+
super(entry)
|
20
|
+
$stdout.puts "* " + entry['label'].ansi(:green) + " #{entry['source']}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def fail(entry)
|
24
|
+
super(entry)
|
25
|
+
$stdout.puts "* " + entry['label'].ansi(:red) + " #{entry['source']}"
|
26
|
+
$stdout.puts
|
27
|
+
$stdout.puts " #{entry['message']}"
|
28
|
+
#$stdout.puts " " + ok.caller #clean_backtrace(exception.backtrace)[0]
|
29
|
+
$stdout.puts
|
30
|
+
$stdout.puts code_snippet(entry)
|
31
|
+
$stdout.puts
|
32
|
+
end
|
33
|
+
|
34
|
+
def err(entry)
|
35
|
+
super(entry)
|
36
|
+
$stdout.puts "* " + entry['label'].ansi(:yellow) + " #{entry['source']}"
|
37
|
+
$stdout.puts
|
38
|
+
$stdout.puts " #{entry['message']}" # error class?
|
39
|
+
#$stdout.puts " " + ok.caller #clean_backtrace(exception.backtrace)[0..2].join(" \n")
|
40
|
+
$stdout.puts
|
41
|
+
$stdout.puts code_snippet(entry)
|
42
|
+
$stdout.puts
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
def finish_suite(entry)
|
47
|
+
#$stderr.puts
|
48
|
+
$stdout.print tally(entry)
|
49
|
+
$stdout.puts " [%0.4fs] " % [Time.now - @start_time]
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'tapout/version'
|
2
|
+
|
3
|
+
module TapOut
|
4
|
+
|
5
|
+
# The TAP Legacy Adapter transforms traditional TAP format to
|
6
|
+
# modern TAP-Y format.
|
7
|
+
#
|
8
|
+
# NOTE: This is still a work in progress.
|
9
|
+
#
|
10
|
+
# TODO: Add support for TAP-J.
|
11
|
+
|
12
|
+
class TAPLegacyAdapter
|
13
|
+
|
14
|
+
#
|
15
|
+
def initialize(input)
|
16
|
+
@input = input
|
17
|
+
reset
|
18
|
+
end
|
19
|
+
|
20
|
+
# Reset state.
|
21
|
+
def reset
|
22
|
+
@head = false
|
23
|
+
@state = nil
|
24
|
+
@entries = []
|
25
|
+
@cache = []
|
26
|
+
end
|
27
|
+
|
28
|
+
# We need to keep an internal list of all entries
|
29
|
+
# in order to create a proper footer.
|
30
|
+
attr :entries
|
31
|
+
|
32
|
+
# Convert input stream to TAP-Y string.
|
33
|
+
def to_s
|
34
|
+
self | ""
|
35
|
+
end
|
36
|
+
|
37
|
+
# Route stream to an array of entires.
|
38
|
+
def to_a
|
39
|
+
self | []
|
40
|
+
end
|
41
|
+
|
42
|
+
# Convert input stream to TAP-Y and *pipe* to +output+ stream.
|
43
|
+
def |(output)
|
44
|
+
@out = output
|
45
|
+
reset
|
46
|
+
while line = @input.gets
|
47
|
+
self << line
|
48
|
+
end
|
49
|
+
self << nil
|
50
|
+
return @out
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
def <<(line)
|
55
|
+
case line
|
56
|
+
when nil
|
57
|
+
parse(@cache)
|
58
|
+
@state = :footer
|
59
|
+
finish
|
60
|
+
when /^\d+\.\.\d+/
|
61
|
+
#parse(@cache) if @state != :plan
|
62
|
+
return if @head
|
63
|
+
@head = true
|
64
|
+
@state = :plan
|
65
|
+
@cache << line
|
66
|
+
when /^ok/
|
67
|
+
parse(@cache) #if @state != :ok
|
68
|
+
@state = :ok
|
69
|
+
@cache << line
|
70
|
+
when /^not\ ok/
|
71
|
+
parse(@cache) #if @state != :not_ok
|
72
|
+
@state = :not_ok
|
73
|
+
@cache << line
|
74
|
+
when /^\#/
|
75
|
+
parse(@cache) if @state != :comment
|
76
|
+
@state = :comment
|
77
|
+
@cache << line
|
78
|
+
else
|
79
|
+
@cache << line
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
def parse(cache)
|
85
|
+
case @state
|
86
|
+
when nil
|
87
|
+
return
|
88
|
+
when :plan
|
89
|
+
line = cache[0]
|
90
|
+
md = /^(\d+)\.\.(\d+)\s*$/.match(line)
|
91
|
+
count = md[2].to_i - md[1].to_i + 1
|
92
|
+
entry = {'count'=> count, 'type'=>'header', 'version'=>TAP_Y_VERSION}
|
93
|
+
when :ok
|
94
|
+
line = cache[0]
|
95
|
+
md = /^ok\s+(\d+)\s*\-?\s*(.*?)($|#)/.match(line)
|
96
|
+
entry = {'type'=>'test','status'=>'pass','index'=>md[1].to_i, 'label'=>md[2]}
|
97
|
+
when :not_ok
|
98
|
+
line = cache[0]
|
99
|
+
yaml = cache[1..-2].join('')
|
100
|
+
data = YAML.load(yaml)
|
101
|
+
md = /^not ok\s+(\d+)\s*\-?\s*(.*?)($|#)/.match(line)
|
102
|
+
entry = convert_not_ok(md[1], md[2], data)
|
103
|
+
when :comment
|
104
|
+
desc = cache.map{ |c| c.sub(/^\#\s{0,1}/, '') }.join("\n")
|
105
|
+
entry = {'type'=>'note', 'description'=>desc.rstrip}
|
106
|
+
end
|
107
|
+
output(entry)
|
108
|
+
@cache = []
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
def output(entry)
|
113
|
+
@entries << entry
|
114
|
+
case @out
|
115
|
+
when String, IO
|
116
|
+
@out << entry.to_yaml
|
117
|
+
else
|
118
|
+
@out << entry
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
def finish
|
124
|
+
output(make_footer)
|
125
|
+
case @out
|
126
|
+
when String, IO
|
127
|
+
@out << '...'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
#
|
134
|
+
def convert_not_ok(number, label, metainfo)
|
135
|
+
entry = {}
|
136
|
+
entry['type'] = 'test'
|
137
|
+
entry['status'] = 'fail'
|
138
|
+
entry['index'] = number.to_i
|
139
|
+
entry['label'] = label
|
140
|
+
if metainfo
|
141
|
+
entry['file'] = metainfo['file']
|
142
|
+
entry['line'] = metainfo['line']
|
143
|
+
entry['expected'] = metainfo['wanted']
|
144
|
+
entry['returned'] = metainfo['found']
|
145
|
+
entry['description'] = metainfo['description']
|
146
|
+
entry['source'] = metainfo['raw_test']
|
147
|
+
entry['extra'] = metainfo['extensions']
|
148
|
+
end
|
149
|
+
entry
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
def make_footer
|
154
|
+
groups = @entries.group_by{ |e| e['status'] }
|
155
|
+
|
156
|
+
entry = {}
|
157
|
+
entry['count'] = @count
|
158
|
+
entry['type'] = 'footer'
|
159
|
+
entry['tally'] = {
|
160
|
+
'pass' => (groups['pass'] || []).size,
|
161
|
+
'fail' => (groups['fail'] || []).size
|
162
|
+
}
|
163
|
+
entry
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|