fixed bug in links spec
[swftools.git] / spec / spec_helper.rb
1 require 'spec'
2 require 'rubygems'
3 require 'RMagick'
4
5 class WrongColor < Exception
6     def initialize(pixel)
7         @pixel = pixel
8     end
9     def to_s
10         "Wrong color at #{@pixel}"
11     end
12 end
13 class AreaError < Exception
14     def initialize(area,problem)
15         @area,@problem = area,problem
16     end
17     def to_s
18         "Area at #{@area} #{@problem}"
19     end
20 end
21 class PixelError < Exception
22     def initialize(p1, relation,p2)
23         @p1,@p2,@relation = p1,p2,relation
24     end
25     def to_s
26         "Pixel #{@p1} #{@relation} #{@p2}"
27     end
28 end
29 class ConversionFailed < Exception
30     def initialize(output,file)
31         @output = output
32         @file = file
33         @exists = File.exists?(file)
34     end
35     def to_s
36         puts "-"*26+" Conversion failed "+"-"*27
37         (puts @output) if @output
38         puts "file #{@file} doesn't exist" if not @exists
39         puts "-"*72
40     end
41 end
42
43 class Area
44     def initialize(x1,y1,x2,y2,file)
45         @x1,@y1,@x2,@y2,@file = x1,y1,x2,y2,file
46     end
47     def should_be_plain_colored
48         @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
49         @rgb.minmax == [@rgb[0],@rgb[0]] or raise AreaError.new(self,"is not plain colored")
50     end
51     def should_not_be_plain_colored
52         @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
53         @rgb.minmax != [@rgb[0],@rgb[0]] or raise AreaError.new(self,"is plain colored")
54     end
55     def should_contain_text(text)
56         text2 = @file.get_text(@x1,@y1,@x2,@y2) 
57         text2 == text or raise AreaError.new(self, "doesn't contain text \"#{text}\" (found: \"#{text2}\")")
58     end
59     def should_contain_link(url)
60         links = @file.get_links(@x1,@y1,@x2,@y2) 
61         (links & [url]).empty? and raise AreaError.new(self, "doesn't contain url \"#{url}\"")
62     end
63     def to_s
64         "(#{@x1},#{@y1},#{@x2},#{@y2})"
65     end
66 end
67
68 def rgb_to_int(rgb)
69     # ImageMagick rgb triples are 16 bit
70     (rgb.reverse+[0]).map {|c| c>>8}.pack("CCCC").unpack("i")[0]
71 end
72
73 class Pixel
74     attr :rgb
75     def initialize(x,y,rgb)
76         @x,@y,@rgb = x,y,rgb
77     end
78     def should_be_of_color(color2)
79         color1 = rgb_to_int(@rgb)
80         color1 == color2 or raise WrongColor.new(self)
81     end
82     def should_be_brighter_than(pixel)
83         gray1 = @rgb.inject(0) {|sum,e| sum+e}
84         gray2 = pixel.rgb.inject(0) {|sum,e| sum+e}
85         gray1 > gray2 or raise PixelError.new(self,"is not brighter than",pixel)
86     end
87     def should_be_darker_than(pixel)
88         gray1 = @rgb.inject(0) {|sum,e| sum+e}
89         gray2 = pixel.rgb.inject(0) {|sum,e| sum+e}
90         gray1 < gray2 or raise PixelError.new(self,"is not less bright than",pixel)
91     end
92     def should_be_the_same_as(pixel)
93         @rgb == pixel.rgb or raise PixelError.new(self,"is not the same as",pixel)
94     end
95     def to_s
96         "(#{@x},#{@y})"
97     end
98 end
99
100 $tempfiles = []
101 Kernel.at_exit do
102     $tempfiles.each do |file|
103         `rm -f #{file}`
104     end
105 end
106
107 class DocFile
108     def initialize(filename, page)
109         @filename = filename
110         @page = page
111     end
112     def convert()
113         return if @swfname
114         @swfname = @filename.gsub(/.pdf$/i,"")+".swf"
115         $tempfiles += [@swfname]
116         `pdfinfo #{@filename}` =~ /Page size:\s*([0-9]+) x ([0-9]+) pts/
117         width,height = $1,$2
118         dpi = (72.0 * 612 / width.to_i).to_i
119         output = `pdf2swf -f --flatten -s zoom=#{dpi} -p #{@page} #{@filename} -o #{@swfname} 2>&1`
120         #output = `pdf2swf -s zoom=#{dpi} --flatten -p #{@page} #{@filename} -o #{@swfname} 2>&1`
121         raise ConversionFailed.new(output,@swfname) unless File.exists?(@swfname)
122     end
123     def render()
124         return if @img
125         convert()
126         @pngname = @filename.gsub(/.pdf$/i,"")+".png"
127         begin
128             output = `swfrender --legacy #{@swfname} -o #{@pngname} 2>&1`
129             raise ConversionFailed.new(output,@pngname) unless File.exists?(@pngname)
130             @img = Magick::Image.read(@pngname).first
131         ensure
132             `rm -f #{@pngname}`
133         end
134     end
135     def get_text(x1,y1,x2,y2)
136         self.convert()
137         #puts "swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}"
138         #puts `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`
139         `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`.chomp
140     end
141     def get_links(x1,y1,x2,y2)
142         self.convert()
143         `swfdump -a #{@swfname}`.scan(/GetUrl2? URL:"([^"]*)"/).inject([]) do |a,u| a + u end
144     end
145     def get_area(x1,y1,x2,y2)
146         self.render()
147         data = @img.export_pixels(x1, y1, x2-x1, y2-y1, "RGB")
148         Array.new(data.size/3) do |i| data.slice(i*3,3) end
149     end
150     def area_at(x1,y1,x2,y2)
151         return Area.new(x1,y1,x2,y2,self)
152     end
153     def width()
154         self.render()
155         return @img.columns
156     end
157     def height()
158         self.render()
159         return @img.rows
160     end
161     def pixel_at(x,y)
162         self.render()
163         data = @img.export_pixels(x, y, 1, 1, "RGB")
164         return Pixel.new(x,y,data)
165     end
166 end
167
168 module Spec
169     module Example
170         module ExampleMethods
171            def area_at(x1,y1,x2,y2)
172                @file.area_at(x1,y1,x2,y2)
173            end
174            def width
175                @file.width
176            end
177            def height
178                @file.height
179            end
180            def pixel_at(x,y)
181                @file.pixel_at(x,y)
182            end
183            def initialize(proxy,&impl)
184
185                # overriding the initialize() function saves us from having to
186                # set up the document in the test. The bad news, however, is that
187                # we have to be very careful not to raise exceptions here-
188                # rspec would miss those.
189
190                @_proxy = proxy
191                @_implementation = impl
192                @_backtrace = caller
193                @file = DocFile.new(proxy.description, (proxy.options[:page] or 1))
194            end
195         end
196         module ExampleGroupMethods
197             alias :convert_file :example
198             def page(nr)
199                 nr
200             end
201         end
202     end
203 end
204
205