class DiffuxCI::SnapshotComparer

This class is responsible for comparing two Snapshots and generating a diff.

Public Class Methods

new(png_before, png_after) click to toggle source

@param png_before [ChunkyPNG::Image] @param png_after [ChunkyPNG::Image]

# File lib/diffux_ci/snapshot_comparer.rb, line 10
def initialize(png_before, png_after)
  @png_after  = png_after
  @png_before = png_before
end

Public Instance Methods

compare!() click to toggle source

@return [Hash]

# File lib/diffux_ci/snapshot_comparer.rb, line 16
def compare!
  no_diff = {
    diff_in_percent: 0,
    diff_image: nil,
    diff_clusters: []
  }

  # If these images are totally identical, we don't need to do any more
  # work.
  return no_diff if @png_before == @png_after

  array_before = to_array_of_arrays(@png_before)
  array_after = to_array_of_arrays(@png_after)

  # If the arrays of arrays of colors are identical, we don't need to do any
  # more work. This might happen if some of the headers are different.
  return no_diff if array_before == array_after

  sdiff = Diff::LCS.sdiff(array_before, array_after)
  cluster_finder  = DiffClusterFinder.new(sdiff.size)
  sprite, all_comparisons = initialize_comparison_images(
    [@png_after.width, @png_before.width].max, sdiff.size)

  sdiff.each_with_index do |row, y|
    # each row is a Diff::LCS::ContextChange instance
    all_comparisons.each { |image| image.render_row(y, row) }
    cluster_finder.row_is_different(y) unless row.unchanged?
  end

  percent_changed = cluster_finder.percent_of_rows_different
  {
    diff_in_percent: percent_changed,
    diff_image:      (sprite if percent_changed > 0),
    diff_clusters:   cluster_finder.clusters,
  }
end

Private Instance Methods

initialize_comparison_images(width, height) click to toggle source

@param canvas [ChunkyPNG::Image] The output image to draw pixels on @return [Array<SnapshotComparisonImage>]

# File lib/diffux_ci/snapshot_comparer.rb, line 67
def initialize_comparison_images(width, height)
  gutter_width = SnapshotComparisonImage::Gutter::WIDTH
  total_width = (width * 3) + (gutter_width * 3)

  sprite = ChunkyPNG::Image.new(total_width, height)
  offset, comparison_images = 0, []
  comparison_images << SnapshotComparisonImage::Gutter.new(offset, sprite)
  offset += gutter_width
  comparison_images << SnapshotComparisonImage::Before.new(offset, sprite)
  offset += width
  comparison_images << SnapshotComparisonImage::Gutter.new(offset, sprite)
  offset += gutter_width
  comparison_images << SnapshotComparisonImage::Overlayed.new(offset, sprite)
  offset += width
  comparison_images << SnapshotComparisonImage::Gutter.new(offset, sprite)
  offset += gutter_width
  comparison_images << SnapshotComparisonImage::After.new(offset, sprite)

  [sprite, comparison_images]
end
to_array_of_arrays(chunky_png) click to toggle source

@param [ChunkyPNG::Image] @return [Array<Array<Integer>>]

# File lib/diffux_ci/snapshot_comparer.rb, line 57
def to_array_of_arrays(chunky_png)
  array_of_arrays = []
  chunky_png.height.times do |y|
    array_of_arrays << chunky_png.row(y)
  end
  array_of_arrays
end