implemented bitmap checks in test framwork
authorMatthias Kramm <kramm@quiss.org>
Tue, 11 Aug 2009 10:22:52 +0000 (12:22 +0200)
committerMatthias Kramm <kramm@quiss.org>
Tue, 11 Aug 2009 10:22:52 +0000 (12:22 +0200)
spec/spec_helper.rb

index 19aaec3..78a25b3 100644 (file)
@@ -1,4 +1,6 @@
 require 'spec'
+require 'rubygems'
+require 'RMagick'
 
 class WrongColor < Exception
     def initialize(pixel)
@@ -24,58 +26,103 @@ class PixelError < Exception
        "Pixel #{@p1} #{@relation} #{@p2}"
     end
 end
+class ConversionFailed < Exception
+    def initialize(output,file)
+       @output = output
+       @file = file
+       @exists = File.exists?(file)
+    end
+    def to_s
+       puts "-"*26+" Conversion failed "+"-"*27
+       (puts @output) if @output
+       puts "file #{@file} doesn't exist" if not @exists
+       puts "-"*72
+    end
+end
 
 class Area
-    def initialize(x1,y1,x2,y2)
+    def initialize(x1,y1,x2,y2,data)
        @x1,@y1,@x2,@y2 = x1,y1,x2,y2
+       @rgb = Array.new(data.size/3) do |i| data.slice(i*3,3) end
     end
     def should_be_plain_colored
-       raise AreaError.new(self,"is not plain colored")
+       @rgb.minmax == [@rgb[0],@rgb[0]] or raise AreaError.new(self,"is not plain colored")
     end
     def should_not_be_plain_colored
-       raise AreaError.new(self,"is plain colored")
+       @rgb.minmax != [@rgb[0],@rgb[0]] or raise AreaError.new(self,"is plain colored")
     end
     def to_s
        "(#{@x1},#{@y1},#{@x2},#{@y2})"
     end
 end
+
+def rgb_to_int(rgb)
+    # ImageMagick rgb triples are 16 bit
+    (rgb.reverse+[0]).map {|c| c>>8}.pack("CCCC").unpack("i")[0]
+end
+
 class Pixel
-    def initialize(x,y)
-       @x = x
-       @y = y
+    attr :rgb
+    def initialize(x,y,rgb)
+       @x,@y,@rgb = x,y,rgb
     end
-    def should_be_of_color(color)
-       raise WrongColor.new(self)
+    def should_be_of_color(color2)
+       color1 = rgb_to_int(@rgb)
+       color1 == color2 or raise WrongColor.new(self)
     end
     def should_be_brighter_than(pixel)
-       raise PixelError.new(self,"is not brighter than",pixel)
+       gray1 = @rgb.inject(0) {|sum,e| sum+e}
+       gray2 = pixel.rgb.inject(0) {|sum,e| sum+e}
+       gray1 > gray2 or raise PixelError.new(self,"is not brighter than",pixel)
     end
     def should_be_less_bright_than(pixel)
-       raise PixelError.new(self,"is brighter than",pixel)
+       gray1 = @rgb.inject(0) {|sum,e| sum+e}
+       gray2 = pixel.rgb.inject(0) {|sum,e| sum+e}
+       gray1 < gray2 or raise PixelError.new(self,"is not less bright than",pixel)
     end
     def should_be_the_same_as(pixel)
-       raise PixelError.new(self,"is not the same as",pixel)
+       @rgb == pixel.rgb or raise PixelError.new(self,"is not the same as",pixel)
     end
     def to_s
        "(#{@x},#{@y})"
     end
 end
 class DocFile
-    def initialize(filename, options)
+    def initialize(filename, page)
        @filename = filename
-       @page = (options[:page] or 1)
+       @page = page
+    end
+    def load()
+       @swfname = @filename.gsub(/.pdf$/i,"")+".swf"
+       @pngname = @filename.gsub(/.pdf$/i,"")+".png"
+       begin
+           output = `pdf2swf --flatten -p #{@page} #{@filename} -o #{@swfname} 2>&1`
+           raise ConversionFailed.new(output,@swfname) unless File.exists?(@swfname)
+           output = `swfrender --legacy #{@swfname} -o #{@pngname} 2>&1`
+           raise ConversionFailed.new(output,@pngname) unless File.exists?(@pngname)
+           @img = Magick::Image.read(@pngname).first
+       ensure
+           `rm -f #{@swfname}`
+           `rm -f #{@pngname}`
+       end
     end
     def area_at(x1,y1,x2,y2)
-       return Area.new(x1,y1,x2,y2)
+       self.load()
+       data = @img.export_pixels(x1, y1, x2-x1, y2-y1, "RGB")
+       return Area.new(x1,y1,x2,y2,data)
     end
-    def width
-       return 300
+    def width()
+       self.load()
+       return @img.columns
     end
-    def height
-       return 200
+    def height()
+       self.load()
+       return @img.rows
     end
     def pixel_at(x,y)
-       return Pixel.new(x,y)
+       self.load()
+       data = @img.export_pixels(x, y, 1, 1, "RGB")
+       return Pixel.new(x,y,data)
     end
 end
 
@@ -95,10 +142,16 @@ module Spec
               @file.pixel_at(x,y)
           end
           def initialize(proxy,&impl)
+
+              # overriding the initialize() function saves us from having to
+              # set up the document in the test. The bad news, however, is that
+              # we have to be very careful not to raise exceptions here-
+              # rspec would miss those.
+
               @_proxy = proxy
               @_implementation = impl
               @_backtrace = caller
-              @file = DocFile.new(proxy.description, proxy.options)
+              @file = DocFile.new(proxy.description, (proxy.options[:page] or 1))
            end
        end
        module ExampleGroupMethods