In Files

Parent

UnitDiff

UnitDiff makes reading Test::Unit output easy and fun. Instead of a confusing jumble of text with nearly unnoticable changes like this:

  1) Failure:
  test_to_gpoints(RouteTest) [test/unit/route_test.rb:29]:
  <"new GPolyline([\n  new GPoint(  47.00000, -122.00000),\n  new GPoint(  46.5000
  0, -122.50000),\n  new GPoint(  46.75000, -122.75000),\n  new GPoint(  46.00000,
   -123.00000)])"> expected but was
  <"new Gpolyline([\n  new GPoint(  47.00000, -122.00000),\n  new GPoint(  46.5000
  0, -122.50000),\n  new GPoint(  46.75000, -122.75000),\n  new GPoint(  46.00000,
   -123.00000)])">.

You get an easy-to-read diff output like this:

  1) Failure:
  test_to_gpoints(RouteTest) [test/unit/route_test.rb:29]:
  1c1
  < new GPolyline([
  ---
  > new Gpolyline([

Usage

  test.rb | unit_diff [options]
    options:
    -b ignore whitespace differences
    -c contextual diff
    -h show usage
    -k keep temp diff files around
    -l prefix line numbers on the diffs
    -u unified diff [default]
    -p plain diff
    -v display version

Constants

WINDOZE
DIFF

Public Class Methods

unit_diff() click to toggle source

Handy wrapper for UnitDiff#unit_diff.

    # File lib/unit_diff.rb, line 57
57:   def self.unit_diff
58:     trap 'INT' do exit 1 end
59:     puts UnitDiff.new.unit_diff
60:   end

Public Instance Methods

diff(expect, butwas) click to toggle source
     # File lib/unit_diff.rb, line 232
232:   def diff expect, butwas
233:     output = nil
234: 
235:     Tempfile.open("expect") do |a|
236:       a.write(massage(expect))
237:       a.rewind
238:       Tempfile.open("butwas") do |b|
239:         b.write(massage(butwas))
240:         b.rewind
241: 
242:         diff_flags = $p ? "" : $c ? "-c" : "-u"
243:         diff_flags += " -b" if $b
244: 
245:         result = `#{DIFF} #{diff_flags} #{a.path} #{b.path}`
246:         result.sub!(/^\-\-\- .+/, "--- expected")
247:         result.sub!(/^\+\+\+ .+/, "+++ actual")
248: 
249:         output = if result.empty? then
250:                    "[no difference--suspect ==]"
251:                  else
252:                    result.split(/\n/)
253:                  end
254: 
255:         if $k then
256:           warn "moving #{a.path} to #{a.path}.keep"
257:           File.rename a.path, a.path + ".keep"
258:           warn "moving #{b.path} to #{b.path}.keep"
259:           File.rename b.path, b.path + ".keep"
260:         end
261:       end
262:     end
263: 
264:     output
265:   end
massage(data) click to toggle source
     # File lib/unit_diff.rb, line 267
267:   def massage(data)
268:     # unescape newlines, strip <> from entire string
269:     data = data.join
270:     data = data.gsub(/\\n/, "\n").gsub(/0x[a-f0-9]+/, '0xXXXXXX') + "\n"
271:     data += "\n" unless data[1] == \n\
272:     data
273:   end
parse_diff(result) click to toggle source

Parses a single diff recording the header and what was expected, and what was actually obtained.

     # File lib/unit_diff.rb, line 121
121:   def parse_diff(result)
122:     header = []
123:     expect = []
124:     butwas = []
125:     footer = []
126:     state = :header
127: 
128:     until result.empty? do
129:       case state
130:       when :header then
131:         header << result.shift
132:         state = :expect if result.first =~ /^<|^Expected/
133:       when :expect then
134:         case result.first
135:         when /^Expected (.*?) to equal (.*?):$/ then
136:           expect << $1
137:           butwas << $2
138:           state = :footer
139:           result.shift
140:         when /^Expected (.*?), not (.*)$/ then
141:           expect << $1
142:           butwas << $2
143:           state = :footer
144:           result.shift
145:         when /^Expected (.*?)$/ then
146:           expect << "#{$1}\n"
147:           result.shift
148:         when /^to equal / then
149:           state = :spec_butwas
150:           bw = result.shift.sub(/^to equal (.*):?$/, '\1')
151:           butwas << bw
152:         else
153:           state = :butwas if result.first.sub!(/ expected( but was|, not)/, '')
154:           expect << result.shift
155:         end
156:       when :butwas then
157:         butwas = result[0..1]
158:         result.clear
159:       when :spec_butwas then
160:         if result.first =~ /^\s+\S+ at |^:\s*$/
161:           state = :footer
162:         else
163:           butwas << result.shift
164:         end
165:       when :footer then
166:         butwas.last.sub!(/:$/, '')
167:         footer = result.map {|l| l.chomp }
168:         result.clear
169:       else
170:         raise "unknown state #{state}"
171:       end
172:     end
173: 
174:     return header, expect, nil, footer if butwas.empty?
175: 
176:     expect.last.chomp!
177:     expect.first.sub!(/^<\"/, '')
178:     expect.last.sub!(/\">$/, '')
179: 
180:     butwas.last.chomp!
181:     butwas.last.chop! if butwas.last =~ /\.$/
182:     butwas.first.sub!( /^<\"/, '')
183:     butwas.last.sub!(/\">$/, '')
184: 
185:     return header, expect, butwas, footer
186:   end
parse_input(input, output) click to toggle source
     # File lib/unit_diff.rb, line 62
 62:   def parse_input(input, output)
 63:     current = []
 64:     data = []
 65:     data << current
 66:     print_lines = true
 67: 
 68:     term = "\nFinished".split(//).map { |c| c[0] }
 69:     term_length = term.size
 70: 
 71:     old_sync = output.sync
 72:     output.sync = true
 73:     while line = input.gets
 74:       case line
 75:       when /^(Loaded suite|Started|# Running tests:)/ then
 76:         print_lines = true
 77:         output.puts line
 78:         chars = []
 79:         while c = input.getc do
 80:           output.putc c
 81:           chars << c
 82:           tail = chars[-term_length..1]
 83:           break if chars.size >= term_length and tail == term
 84:         end
 85:         output.puts input.gets # the rest of "Finished in..."
 86:         output.puts
 87:         next
 88:       when /^\s*$/, /^\(?\s*\d+\) (Failure|Error):/, /^\d+\)/ then
 89:         print_lines = false
 90:         current = []
 91:         data << current
 92:       when /^Finished in \d/ then
 93:         print_lines = false
 94:       end
 95:       output.puts line if print_lines
 96:       current << line
 97:     end
 98:     output.sync = old_sync
 99:     data = data.reject { |o| o == ["\n"] or o.empty? }
100:     footer = data.pop
101: 
102:     data.map do |result|
103:       break if result.any? { |l| l =~ / expected( but was|, not)/ }
104: 
105:       header = result.find do |l|
106:         l =~ /^\(?\s*\d+\) (Failure|Error):/
107:       end
108: 
109:       break unless header
110: 
111:       message_index = result.index(header) + 2
112: 
113:       result[message_index..1] = result[message_index..1].join
114:     end
115: 
116:     return data, footer
117:   end
unit_diff(input=ARGF, output=$stdout) click to toggle source

Scans Test::Unit output input looking for comparison failures and makes them easily readable by passing them through diff.

     # File lib/unit_diff.rb, line 192
192:   def unit_diff(input=ARGF, output=$stdout)
193:     $b = false unless defined? $b
194:     $c = false unless defined? $c
195:     $k = false unless defined? $k
196:     $u = true  unless defined? $u
197:     $p = false unless defined? $p
198: 
199:     data, footer = self.parse_input(input, output)
200: 
201:     output = []
202: 
203:     # Output
204:     data.each do |result|
205:       if result.first =~ /Error/ then
206:         output.push result.join('')
207:         next
208:       end
209: 
210:       prefix, expect, butwas, result_footer = parse_diff(result)
211: 
212:       output.push prefix.compact.map {|line| line.strip}.join("\n")
213: 
214:       if butwas then
215:         output.push self.diff(expect, butwas)
216: 
217:         output.push result_footer
218:         output.push ''
219:       else
220:         output.push expect.join('')
221:       end
222:     end
223: 
224:     if footer then
225:       footer.shift if footer.first.strip.empty?
226:       output.push footer.compact.map {|line| line.strip}.join("\n")
227:     end
228: 
229:     return output.flatten.join("\n")
230:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.