summaryrefslogtreecommitdiff
path: root/spec/spec_helper.rb
blob: 4d74ee1c9962c636650012f47a06bf4af68a4be1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
require 'spec'
require 'rubygems'
require 'RMagick'

class WrongColor < Exception
  def initialize(pixel, is_color, desired_color)
    @pixel = pixel
    @is_color = is_color
    @desired_color = desired_color
  end
  def to_s
    "Wrong color at %s (is: %06x should be: %06x)" % [@pixel.to_s, @is_color, @desired_color]
  end
end
class AreaError < Exception
  def initialize(area,problem)
    @area,@problem = area,problem
  end
  def to_s
    "Area at #{@area} #{@problem}"
  end
end
class PixelError < Exception
  def initialize(p1, relation,p2)
    @p1,@p2,@relation = p1,p2,relation
  end
  def to_s
    "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,file)
    @x1,@y1,@x2,@y2,@file = x1,y1,x2,y2,file
  end
  def should_be_plain_colored
    @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
    @rgb.min == @rgb.max or raise AreaError.new(self,"is not plain colored: colors go from %06x to %06x" % [rgb_to_int(@rgb.min), rgb_to_int(@rgb.max)])
  end
  def should_not_be_plain_colored
    @rgb = @file.get_area(@x1,@y1,@x2,@y2) unless @rgb
    @rgb.min != @rgb.max or raise AreaError.new(self,"is plain colored")
  end
  def should_contain_text(text)
    text2 = @file.get_text(@x1,@y1,@x2,@y2) 
    text2 == text or raise AreaError.new(self, "doesn't contain text \"#{text}\" (found: \"#{text2}\")")
  end
  def should_contain_link(url)
    links = @file.get_links(@x1,@y1,@x2,@y2) 
    (links & [url]).empty? and raise AreaError.new(self, "doesn't contain url \"#{url}\"")
  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
  attr :rgb
  def initialize(x,y,rgb)
    @x,@y,@rgb = x,y,rgb
  end
  def should_be_of_color(color2)
    color1 = rgb_to_int(@rgb)
    color1 == color2 or raise WrongColor.new(self, color1, color2)
  end
  def should_be_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_darker_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)
    @rgb == pixel.rgb or raise PixelError.new(self,"is not the same as",pixel)
  end
  def to_s
    "(#{@x},#{@y})"
  end
end

$tempfiles = []
Kernel.at_exit do
  $tempfiles.each do |file|
    `rm -f #{file}`
  end
end

class DocFile
  def initialize(filename, page)
    @filename = filename
    @page = page
  end
  def convert()
    return if @swfname
    @swfname = @filename.gsub(/.pdf$/i,"")+".swf"
    $tempfiles += [@swfname]
    `pdfinfo #{@filename}` =~ /Page size:\s*([0-9]+) x ([0-9]+) pts/
    width,height = $1,$2
    dpi = (72.0 * 612 / width.to_i).to_i
    output = `pdf2swf -f -s poly2bitmap -s zoom=#{dpi} -p #{@page} #{@filename} -o #{@swfname} 2>&1`
    #output = `pdf2swf -s zoom=#{dpi} --flatten -p #{@page} #{@filename} -o #{@swfname} 2>&1`
    raise ConversionFailed.new(output,@swfname) unless File.exists?(@swfname)
  end
  def render()
    return if @img
    convert()
    @pngname = @filename.gsub(/.pdf$/i,"")+".png"
    begin
      output = `swfrender #{@swfname} -o #{@pngname} 2>&1`
      raise ConversionFailed.new(output,@pngname) unless File.exists?(@pngname)
      @img = Magick::Image.read(@pngname).first
    ensure
      `rm -f #{@pngname}`
    end
  end
  def get_text(x1,y1,x2,y2)
    self.convert()
    #puts "swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}"
    #puts `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`
    `swfstrings -x #{x1} -y #{y1} -W #{x2-x1} -H #{y2-y1} #{@swfname}`.chomp
  end
  def get_links(x1,y1,x2,y2)
    self.convert()
	t = `swfdump -a #{@swfname}`
	links = t.scan(/GetUrl2? URL:"([^"]*)"/).inject([]) do |a,u| a + u end
	t.scan(/name "url:([^"]*)"/).inject(links) do |a,u| a + u end
  end
  def get_area(x1,y1,x2,y2)
    self.render()
    data = @img.export_pixels(x1, y1, x2-x1, y2-y1, "RGB")
    Array.new(data.size/3) { |i| data.slice(i*3,3) }
  end
  def area_at(x1,y1,x2,y2)
    return Area.new(x1,y1,x2,y2,self)
  end
  def width()
    self.render()
    return @img.columns
  end
  def height()
    self.render()
    return @img.rows
  end
  def pixel_at(x,y)
    self.render()
    data = @img.export_pixels(x, y, 1, 1, "RGB")
    return Pixel.new(x,y,data)
  end
end

module  Spec::Example::ExampleGroupMethods 
  alias :convert_file :example
end

class FileExampleGroup < Spec::Example::ExampleGroup
  def area_at(x1,y1,x2,y2)
    @file.area_at(x1,y1,x2,y2)
  end
  def width
    @file.width
  end
  def height
    @file.height
  end
  def pixel_at(x,y)
    @file.pixel_at(x,y)
  end  
end

Spec::Example::ExampleGroupFactory.default(FileExampleGroup)

Spec::Runner.configure do |config|
  config.before do
    input_file = File.join(File.dirname(__FILE__), description)
    raise "Cannot find input file #{input_file}" unless File.exists?(input_file)
    @file = DocFile.new(input_file, 1)
  end
end