class Zucchini::Screenshot

Constants

FILE_NAME_PATTERN

Attributes

diff[RW]
diff_path[RW]
file_name[R]
file_path[R]
mask_paths[RW]
masked_paths[RW]
original_file_path[R]
test_path[RW]

Public Class Methods

new(file_path, device, log, unmatched_pending = false) click to toggle source
# File lib/zucchini/screenshot.rb, line 7
def initialize(file_path, device, log, unmatched_pending = false)
  @file_path = file_path
  @log = log
  @device = device
  
  @file_name = File.basename(@file_path)
  match = FILE_NAME_PATTERN.match(@file_name)
  raise "Illegal screenshot name #{file_path}" unless match

  @screenshot_name      = match[:screenshot_name]
  @sequence_number      = match[:sequence_number].to_i

  @file_name = File.basename(@file_path)

  unless unmatched_pending
    run_data_path      = File.dirname(@file_path)
    support_path       = File.join(run_data_path, '../../../support')

    if @log
      metadata     = @log.screenshot_metadata(@sequence_number)
      @orientation = metadata[:orientation]
      @screen      = metadata[:screen]
      @rotated     = metadata[:rotated]
    end

    if @orientation && !@rotated
      rotate
      @log.mark_screenshot_as_rotated(@sequence_number)
      @log.save
    end

    @mask_paths = {
      :global   => mask_path(File.join(support_path,  'masks',         @device[:screen])),
      :specific => mask_path(File.join(run_data_path, '../../masks',   @device[:screen], @file_name.sub('.png', ''))),
      :screen   => mask_path(File.join(support_path,  'screens/masks', @device[:screen], @screen.to_s.underscore))
    }

    masked_path   = File.join(run_data_path, "../Masked/actual/#{@file_name}")
    @masked_paths = { :global => masked_path, :screen => masked_path, :specific => masked_path }

    @diff_path = "#{run_data_path}/../Diff/#{@file_name}"
  end
end
valid?(file_path) click to toggle source
# File lib/zucchini/screenshot.rb, line 107
def self.valid?(file_path)
  FILE_NAME_PATTERN =~ File.basename(file_path)
end

Public Instance Methods

compare() click to toggle source
# File lib/zucchini/screenshot.rb, line 64
def compare
  mask_reference

  if @test_path
    FileUtils.mkdir_p(File.dirname(@diff_path))

    compare_command = "compare -metric AE -fuzz 2% -dissimilarity-threshold 1 -subimage-search"
    out = `#{compare_command} \"#{@masked_paths[:specific]}\" \"#{@test_path}\" \"#{@diff_path}\" 2>&1`
    out.chomp!
    @diff = (out == '0') ? [:passed, nil] : [:failed, out]
    @diff = [:pending, @diff[1]] if @pending
  else
    @diff = [:failed, "no reference or pending screenshot for #{@device[:screen]}"]
  end
end
mask() click to toggle source
# File lib/zucchini/screenshot.rb, line 51
def mask
  create_masked_paths_dirs
  masked_path = apply_mask(@file_path, :global)

  if mask_present?(:screen)
    masked_path = apply_mask(masked_path, :screen)
  end

  if mask_present?(:specific)
    apply_mask(masked_path, :specific)
  end
end
mask_reference() click to toggle source
# File lib/zucchini/screenshot.rb, line 88
def mask_reference
  run_data_path = File.dirname(@file_path)
  %W(reference pending).each do |reference_type|
    reference_file_path = "#{run_data_path}/../../#{reference_type}/#{@device[:screen]}/#{@file_name}"
    output_path         = "#{run_data_path}/../Masked/#{reference_type}/#{@file_name}"

    if File.exists?(reference_file_path)
      @test_path = output_path
      @pending   = (reference_type == "pending")
      FileUtils.mkdir_p(File.dirname(output_path))

      reference = Zucchini::Screenshot.new(reference_file_path, @device, @log)
      reference.mask_paths  = @mask_paths
      reference.masked_paths = { :global => output_path, :screen => output_path, :specific => output_path }
      reference.mask
    end
  end
end
result_images() click to toggle source
# File lib/zucchini/screenshot.rb, line 80
def result_images
  @result_images ||= {
    :actual     => @masked_paths && File.exists?(@masked_paths[:specific]) ? @masked_paths[:specific] : nil,
    :expected   => @test_path    && File.exists?(@test_path) ? @test_path : nil,
    :difference => @diff_path    && File.exists?(@diff_path) ? @diff_path : nil
  }
end

Private Instance Methods

apply_mask(src_path, mask) click to toggle source
# File lib/zucchini/screenshot.rb, line 134
def apply_mask(src_path, mask)
  mask_path = @mask_paths[mask]
  dest_path = @masked_paths[mask]
  `convert -page +0+0 \"#{src_path}\" -page +0+0 \"#{mask_path}\" -flatten \"#{dest_path}\"`
  return dest_path
end
create_masked_paths_dirs() click to toggle source
# File lib/zucchini/screenshot.rb, line 130
def create_masked_paths_dirs
  @masked_paths.each { |name, path| FileUtils.mkdir_p(File.dirname(path)) }
end
mask_path(path) click to toggle source
# File lib/zucchini/screenshot.rb, line 112
def mask_path(path)
  suffix = case @orientation
  when 'LandscapeRight', 'LandscapeLeft' then '_landscape'
  when 'Portrait', 'PortraitUpsideDown'  then '_portrait'
  else
    ''
  end
  
  file_path = path + suffix + '.png'
  file_path = path + '.png' unless File.exists?(file_path)

  File.expand_path(file_path)
end
mask_present?(mask) click to toggle source
# File lib/zucchini/screenshot.rb, line 126
def mask_present?(mask)
  @mask_paths[mask] && File.exists?(@mask_paths[mask])
end
rotate() click to toggle source
# File lib/zucchini/screenshot.rb, line 141
def rotate
  degrees = case @orientation
  when 'LandscapeRight' then 90
  when 'LandscapeLeft' then 270
  when 'PortraitUpsideDown' then 180
  else
    0
  end
  
  `mogrify -rotate \"#{degrees}\" \"#{@file_path}\"` if degrees > 0
  @rotated = true
end