diff --git a/.rubocop.yml b/.rubocop.yml index 11861ed..16d3764 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,3 +5,18 @@ AllCops: Metrics/BlockLength: CountAsOne: ['array', 'hash', 'heredoc', 'method_call'] + AllowedMethods: + - describe + - context + - shared_examples + - RSpec::Matchers.define + +Naming/MethodParameterName: + AllowedNames: + - x + - y + - cr + - x1 + - y1 + - x2 + - y2 diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index bab7153..a02d455 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -18,15 +18,6 @@ Gemspec/RequiredRubyVersion: Metrics/AbcSize: Max: 94 -# Offense count: 3 -# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. -# IgnoredMethods: refine -Metrics/BlockLength: - AllowedMethods: - - describe - - context - - shared_examples - # Offense count: 1 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: @@ -52,16 +43,6 @@ Metrics/ParameterLists: Metrics/PerceivedComplexity: Max: 17 -Naming/MethodParameterName: - AllowedNames: - - x - - y - - cr - - x1 - - y1 - - x2 - - y2 - # Offense count: 1 Naming/AccessorMethodName: Exclude: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae836f..67d3955 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Support for visual image comparison in specs - Automated visual comparison of images in specs, also serving as a record of exact rendering behaviour - Development scripts for performing benchmarks +- Basic test coverage for transparency support ### Changed - Extracted image operations to separate files within a dedicated module diff --git a/spec/fixtures/match-with-transparency.png b/spec/fixtures/match-with-transparency.png new file mode 100644 index 0000000..f9dbf6b Binary files /dev/null and b/spec/fixtures/match-with-transparency.png differ diff --git a/spec/fixtures/reference_images/match-multiple-operations-and-straighten.jpg b/spec/fixtures/reference_images/match-multiple-operations-and-straighten.jpg new file mode 100644 index 0000000..5a53df8 Binary files /dev/null and b/spec/fixtures/reference_images/match-multiple-operations-and-straighten.jpg differ diff --git a/spec/fixtures/reference_images/match-multiple-operations.jpg b/spec/fixtures/reference_images/match-multiple-operations.jpg new file mode 100644 index 0000000..e793f70 Binary files /dev/null and b/spec/fixtures/reference_images/match-multiple-operations.jpg differ diff --git a/spec/morandi_spec.rb b/spec/morandi_spec.rb index af0b734..924590b 100644 --- a/spec/morandi_spec.rb +++ b/spec/morandi_spec.rb @@ -421,6 +421,38 @@ expect(created_file_sizes.sort).to eq(files_in_increasing_quality_order) end end + + context 'with transparent png input' do + let(:file_in) { 'spec/fixtures/match-with-transparency.png' } + let(:options) do + { + 'gamma' => 1.1, + 'fx' => 'sepia', + 'crop' => [10, 2, 600, 840] + } + end + + it 'applies transformations' do + process_image + + expect(File).to exist(file_out) + expect(processed_image_type).to eq('jpeg') + expect(file_out).to match_reference_image('match-multiple-operations') + end + + context 'with straighten option' do + # Tested explicitly, because morandi happens to handle transparency differently when using straighten + let(:options) { super().merge('straighten' => 2) } + + it 'applies transformations' do + process_image + + expect(File).to exist(file_out) + expect(processed_image_type).to eq('jpeg') + expect(file_out).to match_reference_image('match-multiple-operations-and-straighten') + end + end + end end context 'pixbuf processor' do diff --git a/spec/support/match_reference_image.rb b/spec/support/match_reference_image.rb index f593eba..2dd6f26 100644 --- a/spec/support/match_reference_image.rb +++ b/spec/support/match_reference_image.rb @@ -42,19 +42,31 @@ class ImageDebugData attr_reader :exposed_reference_path, :exposed_tested_path, :exposed_diff_path - def initialize(name, file_type) - sanitised_name = name.gsub(/[^a-zA-Z0-9_-]+/, '-') - @output_dir = File.join(OUTPUT_ROOT, sanitised_name) - @exposed_reference_path = File.join(@output_dir, "reference.#{file_type}") - @exposed_tested_path = File.join(@output_dir, "tested.#{file_type}") - @exposed_diff_path = File.join(@output_dir, 'diff.png') + def initialize(name) + @name = name end - def expose_from(reference_path:, tested_path:, diff_path:) - FileUtils.mkdir_p(@output_dir) - FileUtils.cp(tested_path, @exposed_tested_path) - FileUtils.cp(reference_path, @exposed_reference_path) - FileUtils.cp(diff_path, @exposed_diff_path) + def expose_from(file_type:, tested_path: nil, reference_path: nil, diff_path: nil) + sanitised_name = @name.gsub(/[^a-zA-Z0-9_-]+/, '-') + output_dir = File.join(OUTPUT_ROOT, sanitised_name) + FileUtils.mkdir_p(output_dir) + + if reference_path + @exposed_reference_path = File.join(output_dir, "reference.#{file_type}") + FileUtils.cp(reference_path, @exposed_reference_path) + end + + if tested_path + @exposed_tested_path = File.join(output_dir, "tested.#{file_type}") + FileUtils.cp(tested_path, @exposed_tested_path) + end + + if diff_path + @exposed_diff_path = File.join(output_dir, 'diff.png') + FileUtils.cp(diff_path, @exposed_diff_path) + end + + true end end end @@ -63,7 +75,18 @@ def expose_from(reference_path:, tested_path:, diff_path:) RSpec::Matchers.define :match_reference_image do |reference_name, file_type: 'jpg', tolerance: 0| reference_path = File.join('spec/fixtures/reference_images', "#{reference_name}.#{file_type}") + def debug_data + metadata = RSpec.current_example.metadata + spec_name = "#{metadata[:absolute_file_path].split('/spec/').last}:#{metadata[:scoped_id]}" + @debug_data ||= Morandi::SpecSupport::ImageDebugData.new(spec_name) + end + match do |tested_path| + if File.file?(tested_path) && !File.file?(reference_path) + debug_data.expose_from(tested_path: tested_path, file_type: file_type) + return false + end + tmp_diff = Tempfile.new('test-diff') comparison = Morandi::SpecSupport::ImageComparison.new(reference_path: reference_path, tested_path: tested_path, @@ -72,25 +95,35 @@ def expose_from(reference_path:, tested_path:, diff_path:) @normalized_mean_error = comparison.normalized_mean_error return true if @normalized_mean_error <= tolerance - metadata = RSpec.current_example.metadata - spec_name = "#{metadata[:absolute_file_path].split('/spec/').last}:#{metadata[:scoped_id]}" - @debug_data = Morandi::SpecSupport::ImageDebugData.new(spec_name, file_type) - - @debug_data.expose_from(reference_path: reference_path, tested_path: tested_path, diff_path: tmp_diff.path) + debug_data.expose_from(reference_path: reference_path, + tested_path: tested_path, + diff_path: tmp_diff.path, + file_type: file_type) false ensure - tmp_diff.close! + tmp_diff&.close! end failure_message do - <<~TXT - The provided image and reference image do not match (error: #{@normalized_mean_error}, tolerance: #{tolerance}) - EXPECTED: #{@debug_data.exposed_reference_path} - ACTUAL: #{@debug_data.exposed_tested_path} - DIFF: #{@debug_data.exposed_diff_path} - - After manually confirming that the difference is expected, run: - cp #{@debug_data.exposed_tested_path} #{reference_path} - TXT + if debug_data.exposed_reference_path + <<~TXT + The provided image and reference image do not match (error: #{@normalized_mean_error}, tolerance: #{tolerance}) + EXPECTED: #{debug_data.exposed_reference_path} + ACTUAL: #{debug_data.exposed_tested_path} + DIFF: #{debug_data.exposed_diff_path} + + After manually confirming that the difference is expected, run: + cp #{debug_data.exposed_tested_path} #{reference_path} + + TXT + else + <<~TXT + The provided reference image does not exist. + + If there is no typo and tested image is valid, reference can be created with: + cp #{debug_data.exposed_tested_path} #{reference_path} + + TXT + end end end