tapout 0.1.0 → 0.2.0

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.
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ = TODO
2
+
3
+ * Add version or revision field to suite entry.
4
+
5
+
data/lib/tapout.rb CHANGED
@@ -1,12 +1,10 @@
1
- require 'tapout/tapy_parser'
2
- require 'tapout/tap_legacy_parser'
3
-
4
1
  require 'optparse'
2
+ require 'tapout/parsers'
5
3
 
6
4
  module TapOut
7
5
 
8
- #
9
- PARSERS = %w{breakdown dotprogress progressbar tap verbose}
6
+ # Usable formats.
7
+ FORMATS = %w{breakdown dotprogress html outline progressbar tap}
10
8
 
11
9
  #
12
10
  def self.cli(*argv)
@@ -34,7 +32,7 @@ module TapOut
34
32
  $DEBUG = true
35
33
  end
36
34
 
37
- opt.separator("\nFORMATS:\n " + PARSERS.join("\n "))
35
+ opt.separator("\nFORMATS:\n " + FORMATS.join("\n "))
38
36
  end
39
37
 
40
38
  parser.parse!(argv)
@@ -51,19 +49,24 @@ module TapOut
51
49
 
52
50
  case stdin.line1
53
51
  when /^\d/
54
- type = :legacy
52
+ type = :perl
55
53
  when /^\-/
56
- type = :modern
54
+ type = :yaml
55
+ when /^\{/
56
+ type = :json
57
57
  else
58
58
  raise "Not a recognized TAP stream!"
59
59
  end
60
60
 
61
61
  case type
62
- when :legacy
63
- stream_parser = TAPLegacyParser.new(options)
62
+ when :perl
63
+ stream_parser = PerlParser.new(options)
64
64
  stream_parser.consume(stdin)
65
- else
66
- stream_parser = TAPYParser.new(options)
65
+ when :yaml
66
+ stream_parser = YamlParser.new(options)
67
+ stream_parser.consume(stdin)
68
+ when :json
69
+ stream_parser = JsonParser.new(options)
67
70
  stream_parser.consume(stdin)
68
71
  end
69
72
  end
@@ -5,11 +5,9 @@ module TapOut
5
5
  # The TAP Legacy Adapter transforms traditional TAP format to
6
6
  # modern TAP-Y format.
7
7
  #
8
- # NOTE: This is still a work in progress.
9
- #
10
- # TODO: Add support for TAP-J.
8
+ # IMPORTANT: This is still very much a work in progress.
11
9
 
12
- class TAPLegacyAdapter
10
+ class PerlAdapter
13
11
 
14
12
  #
15
13
  def initialize(input)
@@ -89,7 +87,7 @@ module TapOut
89
87
  line = cache[0]
90
88
  md = /^(\d+)\.\.(\d+)\s*$/.match(line)
91
89
  count = md[2].to_i - md[1].to_i + 1
92
- entry = {'count'=> count, 'type'=>'header', 'version'=>TAP_Y_VERSION}
90
+ entry = {'count'=>count, 'type'=>'suite', 'rev'=>REVISION}
93
91
  when :ok
94
92
  line = cache[0]
95
93
  md = /^ok\s+(\d+)\s*\-?\s*(.*?)($|#)/.match(line)
@@ -102,7 +100,7 @@ module TapOut
102
100
  entry = convert_not_ok(md[1], md[2], data)
103
101
  when :comment
104
102
  desc = cache.map{ |c| c.sub(/^\#\s{0,1}/, '') }.join("\n")
105
- entry = {'type'=>'note', 'description'=>desc.rstrip}
103
+ entry = {'type'=>'note', 'text'=>desc.rstrip}
106
104
  end
107
105
  output(entry)
108
106
  @cache = []
@@ -131,20 +129,23 @@ module TapOut
131
129
  private
132
130
 
133
131
  #
134
- def convert_not_ok(number, label, metainfo)
132
+ # TODO: Any way to distinguish fail vs error?
133
+ def convert_not_ok(number, label, data)
135
134
  entry = {}
136
135
  entry['type'] = 'test'
137
136
  entry['status'] = 'fail'
138
137
  entry['index'] = number.to_i
139
138
  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']
139
+ if data
140
+ entry['exception'] = {}
141
+ entry['exception']['file'] = data['file']
142
+ entry['exception']['line'] = data['line']
143
+ entry['exception']['message'] = data['description']
144
+
145
+ entry['expected'] = data['wanted']
146
+ entry['returned'] = data['found']
147
+ entry['source'] = data['raw_test']
148
+ entry['extra'] = data['extensions']
148
149
  end
149
150
  entry
150
151
  end
@@ -154,11 +155,11 @@ module TapOut
154
155
  groups = @entries.group_by{ |e| e['status'] }
155
156
 
156
157
  entry = {}
157
- entry['count'] = @count
158
- entry['type'] = 'footer'
159
- entry['tally'] = {
160
- 'pass' => (groups['pass'] || []).size,
161
- 'fail' => (groups['fail'] || []).size
158
+ entry['type'] = 'tally'
159
+ entry['counts'] = {
160
+ 'total' => @count,
161
+ 'pass' => (groups['pass'] || []).size,
162
+ 'fail' => (groups['fail'] || []).size
162
163
  }
163
164
  entry
164
165
  end
@@ -0,0 +1,4 @@
1
+ require 'tapout/parsers/yaml'
2
+ require 'tapout/parsers/json'
3
+ require 'tapout/parsers/perl'
4
+
@@ -0,0 +1,38 @@
1
+ require 'tapout/reporters'
2
+ require 'json'
3
+
4
+ module TapOut
5
+
6
+ # The TAP-J Parser takes a TAP-J stream and routes it through
7
+ # a TapOut report format.
8
+ #
9
+ class JsonParser
10
+
11
+ #
12
+ def initialize(options={})
13
+ format = options[:format] || 'dotprogress'
14
+ @reporter = Reporters.factory(format).new
15
+ end
16
+
17
+ #
18
+ def consume(input)
19
+ while line = input.gets
20
+ self << line
21
+ end
22
+ end
23
+
24
+ #
25
+ def <<(line)
26
+ handle(line)
27
+ end
28
+
29
+ #
30
+ def handle(doc)
31
+ return if doc == ''
32
+ entry = JSON.load(doc)
33
+ @reporter << entry
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -1,12 +1,12 @@
1
1
  require 'tapout/version'
2
- require 'tapout/tap_legacy_adapter'
2
+ require 'tapout/perl_adapter'
3
3
  require 'tapout/reporters'
4
4
 
5
5
  module TapOut
6
6
 
7
7
  # The TAPLegacy Parser takes a traditional TAP stream and routes
8
8
  # it through a Tap Out report format.
9
- class TAPLegacyParser
9
+ class perlParser
10
10
 
11
11
  # options[:format] - the report format to use
12
12
  def initialize(options={})
@@ -16,7 +16,7 @@ module TapOut
16
16
 
17
17
  # input - any object that responds to #gets
18
18
  def consume(input)
19
- parser = TAPLegacyAdapter.new(input)
19
+ parser = PerlAdapter.new(input)
20
20
  parser | @reporter
21
21
  end
22
22
 
@@ -1,12 +1,11 @@
1
1
  require 'tapout/reporters'
2
-
3
2
  require 'yaml'
4
3
 
5
4
  module TapOut
6
5
 
7
6
  # The TAP-Y Parser takes a TAP-Y stream and routes it through
8
- # a Tap Out report format.
9
- class TAPYParser
7
+ # a TapOut report format.
8
+ class YamlParser
10
9
 
11
10
  #
12
11
  def initialize(options={})
@@ -1,6 +1,7 @@
1
1
  require 'tapout/reporters/abstract'
2
+ require 'tapout/reporters/breakdown'
2
3
  require 'tapout/reporters/dotprogress'
3
- require 'tapout/reporters/verbose'
4
- require 'tapout/reporters/tap'
4
+ require 'tapout/reporters/html'
5
+ require 'tapout/reporters/outline'
5
6
  require 'tapout/reporters/progressbar'
6
- require 'tapout/reporters/breakdown'
7
+ require 'tapout/reporters/tap'
@@ -49,7 +49,7 @@ module TapOut
49
49
  # report methods.
50
50
  def handle(entry)
51
51
  case entry['type']
52
- when 'header'
52
+ when 'suite'
53
53
  start_suite(entry)
54
54
  when 'case'
55
55
  finish_case(@previous_case) if @previous_case
@@ -68,10 +68,10 @@ module TapOut
68
68
  err(entry)
69
69
  when 'omit'
70
70
  omit(entry)
71
- when 'pending', 'skip'
71
+ when 'todo', 'skip', 'pending'
72
72
  skip(entry)
73
73
  end
74
- when 'footer'
74
+ when 'tally'
75
75
  finish_case(@previous_case) if @previous_case
76
76
  finish_suite(entry)
77
77
  end
@@ -128,30 +128,32 @@ module TapOut
128
128
 
129
129
  # TODO: get the tally's from the footer entry ?
130
130
  def tally(entry)
131
- total = entry['count'] || (@passed.size + @failed.size + @raised.size)
131
+ total = @passed.size + @failed.size + @raised.size #+ @skipped.size + @omitted.size
132
132
 
133
- if entry['tally']
134
- count_fail = entry['tally']['fail'] || 0
135
- count_error = entry['tally']['error'] || 0
133
+ if entry['counts']
134
+ total = entry['counts']['total'] || total
135
+ count_fail = entry['counts']['fail'] || 0
136
+ count_error = entry['counts']['error'] || 0
136
137
  else
137
138
  count_fail = @failed.size
138
139
  count_error = @raised.size
139
140
  end
140
141
 
141
- if tally = entry['tally']
142
- sums = %w{pass fail error skip}.map{ |e| tally[e] || 0 }
142
+ if tally = entry['counts']
143
+ sums = %w{pass fail error todo omit}.map{ |e| tally[e] || 0 }
143
144
  else
144
- sums = [@passed, @failed, @raised, @skipped].map{ |e| e.size }
145
+ sums = [@passed, @failed, @raised, @skipped, @omitted].map{ |e| e.size }
145
146
  end
146
147
 
148
+ # ???
147
149
  assertions = entry['assertions']
148
150
  failures = entry['failures']
149
151
 
150
152
  if assertions
151
- text = "%s tests: %s pass, %s fail, %s err, %s pending (%s/%s assertions)"
153
+ text = "%s tests: %s pass, %s fail, %s err, %s todo, %omit (%s/%s assertions)"
152
154
  text = text % [total, *sums] + [assertions - failures, assertions]
153
155
  else
154
- text = "%s tests: %s pass, %s fail, %s err, %s pending"
156
+ text = "%s tests: %s pass, %s fail, %s err, %s todo, %s omit"
155
157
  text = text % [total, *sums]
156
158
  end
157
159
 
@@ -165,7 +167,7 @@ module TapOut
165
167
  end
166
168
 
167
169
  #
168
- INTERNALS = /(lib|bin)#{Regexp.escape(File::SEPARATOR)}ko/
170
+ INTERNALS = /(lib|bin)#{Regexp.escape(File::SEPARATOR)}tapout/
169
171
 
170
172
  # Clean the backtrace of any reference to ko/ paths and code.
171
173
  def clean_backtrace(backtrace)
@@ -200,7 +202,7 @@ module TapOut
200
202
  end
201
203
  when Array
202
204
  snippet.each do |h|
203
- s << [h.key, h.value]
205
+ s << [h.keys.first, h.values.first]
204
206
  end
205
207
  else
206
208
  ##backtrace = exception.backtrace.reject{ |bt| bt =~ INTERNALS }
@@ -208,17 +210,18 @@ module TapOut
208
210
  #caller =~ /(.+?):(\d+(?=:|\z))/ or return ""
209
211
  #source_file, source_line = $1, $2.to_i
210
212
 
211
- if File.file?(file)
213
+ if file && File.file?(file)
212
214
  source = source(file)
213
215
 
214
216
  radius = 3 # number of surrounding lines to show
215
- region = [source_line - radius, 1].max ..
216
- [source_line + radius, source.length].min
217
+ region = [line - radius, 1].max ..
218
+ [line + radius, source.length].min
217
219
 
218
220
  #len = region.last.to_s.length
219
221
 
220
222
  s = region.map do |n|
221
- format % [n, source[n-1].chomp]
223
+ #format % [n, source[n-1].chomp]
224
+ [n, source[n-1].chomp]
222
225
  end
223
226
  end
224
227
  end
@@ -98,12 +98,13 @@ module TapOut
98
98
  #puts "\n-- Failures and Errors --\n"
99
99
  puts
100
100
  bad.each do |e|
101
- message = e['message'].strip
101
+ x = e['exception']
102
+ message = x['message'].strip
102
103
  message = message.ansi(:red)
103
104
  puts(message)
104
- puts "#{e['file']}:#{e['line']}"
105
+ puts "#{x['file']}:#{x['line']}"
105
106
  puts
106
- puts code_snippet(e)
107
+ puts code_snippet(x)
107
108
  end
108
109
  puts
109
110
  end
@@ -42,9 +42,9 @@ module TapOut::Reporters
42
42
  #backtrace = clean_backtrace(exception.backtrace)
43
43
  $stdout.puts "#{i}. " + (e['label']).ansi(:red)
44
44
  $stdout.puts
45
- $stdout.puts " #{e['message']}"
46
- $stdout.puts " #{e['file']}:#{e['line']}" #+ backtrace[0]
47
- $stdout.puts code_snippet(e)
45
+ $stdout.puts " #{e['exception']['message']}"
46
+ $stdout.puts " #{e['exception']['file']}:#{e['exception']['line']}" #+ backtrace[0]
47
+ $stdout.puts code_snippet(e['exception'])
48
48
  $stdout.puts
49
49
  i += 1
50
50
  end
@@ -53,9 +53,9 @@ module TapOut::Reporters
53
53
  #backtrace = clean_backtrace(exception.backtrace)
54
54
  $stdout.puts "#{i}. " + (e['label']).ansi(:yellow)
55
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)
56
+ $stdout.puts " #{e['exception']['message']}"
57
+ $stdout.puts " #{e['exception']['file']}:#{e['exception']['line']}" #+ backtrace[0..2].join(" \n")
58
+ $stdout.puts code_snippet(e['exception'])
59
59
  $stdout.puts
60
60
  i += 1
61
61
  end
@@ -0,0 +1,152 @@
1
+ require 'test/reporters/abstract'
2
+
3
+ module TapOut::Reporters
4
+
5
+ # HTML Test Reporter
6
+ #
7
+ # This reporter is rather simplistic and rough at this point --in needs
8
+ # of some TLC.
9
+ #--
10
+ # TODO: Make this more like a microformat and add timer info.
11
+ #++
12
+ class Html < Abstract
13
+
14
+ #
15
+ def start_suite(entry)
16
+ timer_reset
17
+
18
+ puts %[<html>]
19
+ puts %[<head>]
20
+ puts %[<title>Test Report</title>]
21
+ puts %[ <style>]
22
+ puts %[ html{ background: #fff; margin: 0; padding: 0; font-family: helvetica; }]
23
+ puts %[ body{ margin: 0; padding: 0;}]
24
+ puts %[ h3{color:#555;}]
25
+ puts %[ #main{ margin: 0 auto; color: #110; width: 600px; ]
26
+ puts %[ border-right: 1px solid #ddd; border-left: 1px solid #ddd; ]
27
+ puts %[ padding: 10px 30px; width: 500px; } ]
28
+ puts %[ .title{ color: gold; font-size: 22px; font-weight: bold; ]
29
+ puts %[ font-family: courier; margin-bottom: -15px;}]
30
+ puts %[ .tally{ font-weight: bold; margin-bottom: 10px; }]
31
+ puts %[ .omit{ color: cyan; }]
32
+ puts %[ .pass{ color: green; }]
33
+ puts %[ .fail{ color: red; }]
34
+ puts %[ .footer{ font-size: 0.7em; color: #666; margin: 20px 0; }]
35
+ puts %[ </style>]
36
+ puts %[</head>]
37
+ puts %[<body>]
38
+ puts %[<div id="main">]
39
+ puts %[<div class="title">R U B Y - T E S T</div>]
40
+ puts %[<h1>Test Report</h1>]
41
+ end
42
+
43
+ #
44
+ def start_case(entry)
45
+ body = []
46
+
47
+ puts "<h2>"
48
+ puts entry['label']
49
+ puts "</h2>"
50
+
51
+ puts body.join("\n")
52
+ end
53
+
54
+ #
55
+ def start_test(entry)
56
+ if subtext = entry['subtext']
57
+ if @subtext != subtext
58
+ @subtext = subtext
59
+ puts "<h3>#{subtext}</h3>"
60
+ end
61
+ end
62
+ end
63
+
64
+ #
65
+ def pass(entry)
66
+ puts %[<li class="pass">]
67
+ puts "%s %s" % [ "PASS", entry['label'] ]
68
+ puts %[</li>]
69
+ end
70
+
71
+ #
72
+ def fail(entry)
73
+ e = entry['exception']
74
+
75
+ puts %[<li class="fail">]
76
+ puts "FAIL #{e['message']}"
77
+ puts "<pre>"
78
+ puts clean_backtrace(e['backtrace']).join("\n")
79
+ puts "</pre>"
80
+ puts %[</li>]
81
+ end
82
+
83
+ #
84
+ def err(entry)
85
+ e = entry['exception']
86
+
87
+ puts %[<li class="error">]
88
+ puts "ERROR "
89
+ puts e['message'].to_s
90
+ puts "<pre>"
91
+ puts clean_backtrace(e['backtrace']).join("\n")
92
+ puts "</pre>"
93
+ puts %[</li>]
94
+ end
95
+
96
+ #
97
+ def todo(entry)
98
+ e = entry['exception']
99
+
100
+ puts %[<li class="pending">]
101
+ puts "TODO "
102
+ puts e['message'].to_s
103
+ puts %[</li>]
104
+ end
105
+
106
+ #
107
+ def omit(entry)
108
+ e = entry['exception']
109
+
110
+ puts %[<li class="omit">]
111
+ puts "OMIT "
112
+ puts e['message'].to_s
113
+ puts %[</li>]
114
+ end
115
+
116
+ #
117
+ def finish_suite(entry)
118
+ puts ""
119
+ puts %[<div class="tally">]
120
+ puts tally(entry)
121
+ puts %[</div>]
122
+ puts ""
123
+ puts ""
124
+ puts %[<div class="footer">]
125
+ puts %[Generated by <a href="http://rubyworks.github.com/tapout">TAPOUT</a>]
126
+ puts %[on #{Time.now}.]
127
+ puts %[</div>]
128
+ puts ""
129
+ puts %[</div>]
130
+ puts %[</div>]
131
+ puts ""
132
+ puts %[</body>]
133
+ puts %[</html>]
134
+ end
135
+
136
+ private
137
+
138
+ #
139
+ def timer
140
+ secs = Time.now - @time
141
+ @time = Time.now
142
+ return "%0.5fs" % [secs.to_s]
143
+ end
144
+
145
+ #
146
+ def timer_reset
147
+ @time = Time.now
148
+ end
149
+
150
+ end
151
+
152
+ end