ojo 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1507dfd7d37a94f8869aedfad8a794085050ded5
4
- data.tar.gz: d76df5592c3427e336c82ac0aa7bd78640bc2a14
3
+ metadata.gz: 9fb122efa0d57d0f24c768e2ddd60877062746bf
4
+ data.tar.gz: 372a6fdbe461d6aa7b519bf4bbd4182a2df03e4f
5
5
  SHA512:
6
- metadata.gz: 64b39c3507560aebbb5af6da31ae2c59e7f912b531ce55bb47c740ba0bacc833583aaeb481ff4532f03ab5ad3e994a66dbb084e495abb631e3c410a18bdfa767
7
- data.tar.gz: acdf69ac9f811cfa2ab18ed741c2d967d14162776797f02b55e8dd786b9fc6584d83975e07b0fa6b1d03ad66ce3c665a2e8ce5f8190e6b5125f070f47832dba8
6
+ metadata.gz: 336ea819a2118e57a750a404a8ed0256aaa8c5c1c3970d7c958be4d3cc065e1e42c3518294472fe92686aaf68046949d277215d8cc772b81393a58fabd337ca0
7
+ data.tar.gz: b63f2c1b6cbcb0ead4b42404f1411839963d88ab5be0e4cf18d161c02b8a2814813a4e7050782091903010f38c8a8068a134fb5257d07cf2a44986585b5c669c
data/.gitignore CHANGED
@@ -14,3 +14,4 @@
14
14
  mkmf.log
15
15
 
16
16
  /test/test_app/tmp
17
+ /test/test_app/log
@@ -1 +1 @@
1
- ruby-2.1.2
1
+ ruby-2.1.5
@@ -1,3 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "2.1.2"
3
+ - "2.1.5"
4
+ addons:
5
+ code_climate:
6
+ repo_token: f0b4c444b697cf8dd7fb56fe8f02fda41af6699511ca954e4c51a9ba33163abb
data/Gemfile CHANGED
@@ -12,3 +12,7 @@ gem 'poltergeist'
12
12
  gem 'capybara'
13
13
  gem 'ae_page_objects', '1.3.0'
14
14
  gem 'sqlite3'
15
+
16
+ group :test do
17
+ gem 'codeclimate-test-reporter', require: nil
18
+ end
data/README.md CHANGED
@@ -4,6 +4,7 @@ Ojo is not fancy. it just does a simple comparison of two sets of screenshots. t
4
4
 
5
5
  [![Build Status](https://travis-ci.org/QuantumGeordie/ojo.svg)](https://travis-ci.org/QuantumGeordie/ojo)
6
6
  [![Code Climate](https://codeclimate.com/github/QuantumGeordie/ojo/badges/gpa.svg)](https://codeclimate.com/github/QuantumGeordie/ojo)
7
+ [![Test Coverage](https://codeclimate.com/github/QuantumGeordie/ojo/badges/coverage.svg)](https://codeclimate.com/github/QuantumGeordie/ojo)
7
8
 
8
9
  ## Installation
9
10
 
@@ -25,7 +26,9 @@ Or install it yourself as:
25
26
 
26
27
  in a rails initializer do something like this to tell `Ojo` where the files to compare are.
27
28
 
28
- `Ojo.location = '/path/to/screenshots'`
29
+ Ojo.configure do |config|
30
+ config.location = '/path/to/screenshots'
31
+ end
29
32
 
30
33
  ### Screenshotter
31
34
 
data/lib/ojo.rb CHANGED
@@ -1,13 +1,17 @@
1
+ require 'collimator'
2
+
1
3
  require 'ojo/rails/engine' if defined?(Rails)
2
4
  require 'ojo/version'
3
5
  require 'ojo/comparison'
4
6
  require 'ojo/locations'
5
7
  require 'ojo/output'
6
8
  require 'ojo/screenshot'
7
-
8
- require 'collimator'
9
+ require 'ojo/configuration'
10
+ require 'ojo/file_sizer'
11
+ require 'ojo/image_magician'
12
+ require 'ojo/data_sets'
13
+ require 'ojo/manager'
9
14
 
10
15
  module Ojo
11
16
  include Collimator
12
-
13
17
  end
@@ -1,88 +1,66 @@
1
1
  module Ojo
2
- require 'open4'
3
- require 'fileutils'
2
+ class Ojo
3
+ def compare(branch_1, branch_2)
4
+ all_files = compile_file_lists(get_branch_files(branch_1), get_branch_files(branch_2))
4
5
 
5
- def self.compare(branch_1, branch_2)
6
- all_files = compile_file_lists(get_branch_files(branch_1), get_branch_files(branch_2))
6
+ FileUtils.mkdir_p(File.join(::Ojo.configuration.location, 'diff'))
7
7
 
8
- FileUtils.mkdir_p(File.join(self.location, 'diff'))
8
+ all_same = true
9
+ results = { :location => ::Ojo.configuration.location, :branch_1 => branch_1, :branch_2 => branch_2, :results => {} }
9
10
 
10
- all_same = true
11
- results = { :location => self.location, :branch_1 => branch_1, :branch_2 => branch_2, :results => {} }
11
+ ::Ojo::ProgressBar.start({:min => 0, :max => all_files.count, :method => :percent, :step_size => 1})
12
12
 
13
- ProgressBar.start({:min => 0, :max => all_files.count, :method => :percent, :step_size => 1})
13
+ all_files.each do |file|
14
+ diff_file = File.join(::Ojo.configuration.location, 'diff', File.basename(file))
14
15
 
15
- all_files.each do |file|
16
- diff_file = File.join(self.location, 'diff', File.basename(file))
16
+ file_1 = make_comparable_filename(branch_1, file)
17
+ file_2 = make_comparable_filename(branch_2, file)
17
18
 
18
- file_1 = File.join(location, branch_1, file)
19
- file_2 = File.join(location, branch_2, file)
19
+ this_same = compare_one_set(file_1, file_2, diff_file)
20
+ results[:results][file] = { :same => this_same, :file_1 => file_1, :file_2 => file_2 }
21
+ all_same = all_same && (this_same != false)
20
22
 
21
- file_1 = nil unless File.exist?(file_1)
22
- file_2 = nil unless File.exist?(file_2)
23
+ File.delete(diff_file) if this_same
23
24
 
24
- this_same = compare_one_set(file_1, file_2, diff_file)
25
- results[:results][file] = { :same => this_same, :file_1 => file_1, :file_2 => file_2 }
26
- all_same = all_same && (this_same != false)
25
+ ::Ojo::ProgressBar.increment
26
+ end
27
27
 
28
- File.delete(diff_file) if this_same
29
-
30
- ProgressBar.increment
28
+ ::Ojo::ProgressBar.complete
29
+ [all_same, results]
31
30
  end
32
31
 
33
- ProgressBar.complete
34
- [all_same, results]
35
- end
36
-
37
- private
32
+ private
38
33
 
39
- def self.compare_one_set(file_1, file_2, diff_file)
40
- same = nil
41
- if file_1 && file_2
42
- comparison_results = run_comparison(file_1, file_2, 'ae', '2%', diff_file)
43
- same = unpack_comparison_results(comparison_results)
34
+ def make_comparable_filename(branch, file_base)
35
+ name = File.join(::Ojo.configuration.location, branch, file_base)
36
+ name = nil unless File.exist?(name)
37
+ name
44
38
  end
45
- same
46
- end
47
-
48
- def self.get_branch_files(branch_name)
49
- Dir[File.join(self.location, branch_name, '*.png')].map{ |f| File.basename(f) }
50
- end
51
-
52
- def self.compile_file_lists(files_1, files_2)
53
- all_files = files_1.dup
54
- all_files + files_2.select{ |f2| !files_1.include?(f2) }
55
- end
56
-
57
- def self.unpack_comparison_results(packed)
58
- return false if packed.include?('image widths or heights differ')
59
39
 
60
- outputs = packed.split(/\n/)
40
+ def compare_one_set(file_1, file_2, diff_file)
41
+ same = nil
42
+ if file_1 && file_2
43
+ ::Ojo::FileSizer.new.make_files_same_size(file_1, file_2)
61
44
 
62
- outputs.map! do |o|
63
- o.strip if o.strip.start_with?('red', 'green', 'blue', 'alpha', 'all')
45
+ same = compare_files(file_1, file_2, ::Ojo.configuration.metric, ::Ojo.configuration.fuzz, diff_file)
46
+ end
47
+ same
64
48
  end
65
- outputs.compact!
66
49
 
67
- same = true
68
-
69
- outputs.each do |o|
70
- parts = o.split(' ')
71
- same = same && parts[1].to_f == 0
50
+ def get_branch_files(branch_name)
51
+ Dir[File.join(::Ojo.configuration.location, branch_name, '*.png')].map{ |f| File.basename(f) }
72
52
  end
73
53
 
74
- return same
75
- end
54
+ def compile_file_lists(files_1, files_2)
55
+ all_files = files_1.dup
56
+ all_files + files_2.select{ |f2| !files_1.include?(f2) }
57
+ end
76
58
 
77
- def self.run_comparison(file_1, file_2, metric, fuzz_factor, resulting_file)
78
- imagemagick_command = "compare -verbose -metric #{metric} -fuzz #{fuzz_factor} #{file_1} #{file_2} #{resulting_file}"
59
+ def compare_files(file_1, file_2, metric, fuzz_factor, resulting_file)
60
+ im = "compare -verbose -metric #{metric} -fuzz #{fuzz_factor} #{file_1} #{file_2} #{resulting_file}"
61
+ raw_result = ::Ojo::ImageMagician.new.make_magic(im)
79
62
 
80
- output = nil
81
- status = Open4::popen4(imagemagick_command) do |pid, stdin, stdout, stderr|
82
- output = stderr.read
63
+ ::Ojo::ImageMagician.new.unpack_comparison_result raw_result
83
64
  end
84
-
85
- output
86
65
  end
87
-
88
66
  end
@@ -0,0 +1,22 @@
1
+ module Ojo
2
+ class << self
3
+ attr_accessor :configuration
4
+ end
5
+
6
+ def self.configure
7
+ self.configuration ||= Configuration.new
8
+ yield(configuration) if block_given?
9
+ end
10
+
11
+ class Configuration
12
+ attr_accessor :fuzz
13
+ attr_accessor :location
14
+ attr_accessor :metric
15
+
16
+ def initialize
17
+ @location = nil
18
+ @fuzz = '2%'
19
+ @metric = 'ae'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module Ojo
2
+ class DataSets
3
+ def sets_available
4
+ data_sets = []
5
+ if ::Ojo.configuration.location
6
+ data_sets = Dir[File.join(::Ojo.configuration.location, '*')].select{ |d| File.directory?(d) && File.basename(d) != 'diff' }.map{ |d| File.basename(d) }.sort
7
+ end
8
+ data_sets
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+ module Ojo
2
+ class FileSizer
3
+ def make_files_same_size(file_1, file_2)
4
+ dim_1 = get_file_dimensions(file_1)
5
+ dim_2 = get_file_dimensions(file_2)
6
+
7
+ unless dim_1 == dim_2
8
+ x, y = max_dimensions(dim_1, dim_2)
9
+ add_extra_to_file x, y, file_1
10
+ add_extra_to_file x, y, file_2
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def get_file_dimensions(file)
17
+ im = "identify -format '%[fx:w]x%[fx:h]' #{file}"
18
+
19
+ output = nil
20
+ status = Open4::popen4(im) do |pid, stdin, stdout, stderr|
21
+ output = stdout.read
22
+ end
23
+ raise "problem getting dimensions of #{file}" unless status.success?
24
+ output.chomp
25
+ end
26
+
27
+ def add_extra_to_file(x, y, filename)
28
+ basename = File.basename(filename, '.*')
29
+ temp_filename = File.join(File.dirname(filename), "#{basename}_tmp.png")
30
+ make_canvas x, y, temp_filename
31
+
32
+ im = "convert #{temp_filename} #{filename} -composite #{temp_filename}"
33
+ ::Ojo::ImageMagician.new.make_magic(im)
34
+
35
+ FileUtils.mv(temp_filename, filename)
36
+ end
37
+
38
+ def max_dimensions(dim_1, dim_2)
39
+ x1, y1 = dim_1.split('x')
40
+ x2, y2 = dim_2.split('x')
41
+
42
+ x = [x1, x2].max
43
+ y = [y1, y2].max
44
+ [x, y]
45
+ end
46
+
47
+ def make_canvas(x, y, filename)
48
+ im = "convert -size #{x}x#{y} canvas:yellow #{filename}"
49
+ ::Ojo::ImageMagician.new.make_magic(im)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ module Ojo
2
+ class ImageMagician
3
+ def make_magic(command_string)
4
+ output = nil
5
+ status = Open4::popen4(command_string) do |pid, stdin, stdout, stderr|
6
+ output = stderr.read
7
+ end
8
+ output
9
+ end
10
+
11
+ def unpack_comparison_result(packed)
12
+ return false if packed.include?('image widths or heights differ')
13
+
14
+ color_values = get_color_values(packed)
15
+
16
+ same = true
17
+ color_values.each_pair do |color, value|
18
+ same = same && value.to_f == 0
19
+ end
20
+
21
+ return same
22
+ end
23
+
24
+ private
25
+
26
+ def get_color_values(raw)
27
+ # raw looks like
28
+ # "/Users/geordie/src/gems/ojo/tmp/branch_1/test_one.png PNG 200x200 200x200+0+0 16-bit sRGB 1.04KB 0.000u 0:00.000\n/Users/geordie/src/gems/ojo/tmp/branch_2/test_one.png PNG 200x200 200x200+0+0 16-bit sRGB 1.05KB 0.000u 0:00.000\nImage: /Users/geordie/src/gems/ojo/tmp/branch_1/test_one.png\n Channel distortion: AE\n red: 944\n green: 944\n blue: 944\n all: 944\n/Users/geordie/src/gems/ojo/tmp/branch_1/test_one.png=>/Users/geordie/src/gems/ojo/tmp/diff/test_one.png PNG 200x200 200x200+0+0 16-bit sRGB 6c 1.18KB 0.010u 0:00.000\n"
29
+ outputs = raw.split(/\n/).select { |o| o.strip.start_with?('red', 'green', 'blue', 'alpha', 'all') }
30
+
31
+ out_hash = {}
32
+ outputs.each do |line|
33
+ k, v = line.strip.split(':')
34
+ out_hash[k.to_sym] = v.strip
35
+ end
36
+
37
+ out_hash
38
+ end
39
+ end
40
+ end
@@ -1,20 +1,11 @@
1
1
  module Ojo
2
- @location = nil
3
-
4
2
  def self.location=(location)
5
- @location = location
3
+ ::Ojo.configure unless ::Ojo.configuration
4
+ ::Ojo.configuration.location = location
6
5
  end
7
6
 
8
7
  def self.location
9
- @location
10
- end
11
-
12
- def self.get_data_sets_available
13
- data_sets = []
14
- if @location
15
- data_sets = Dir[File.join(location, '*')].select{ |d| File.directory?(d) && File.basename(d) != 'diff' }.map{ |d| File.basename(d) }
16
- end
17
- data_sets
8
+ ::Ojo.configuration.location
18
9
  end
19
10
 
20
11
  def self.display_data_sets(data_sets)
@@ -0,0 +1,49 @@
1
+ module Ojo
2
+ class Manager
3
+ def location
4
+ puts "Ojo file location: #{::Ojo.configuration.location}"
5
+ end
6
+
7
+ def data_sets
8
+ data_sets = ::Ojo::DataSets.new.sets_available
9
+ ::Ojo.display_data_sets(data_sets)
10
+ end
11
+
12
+ def clear_diff
13
+ FileUtils.rm_rf File.join(::Ojo.configuration.location, 'diff')
14
+ end
15
+
16
+ def clear_all
17
+ data_sets = ::Ojo::DataSets.new.sets_available
18
+ FileUtils.rm_rf File.join(::Ojo.configuration.location, 'diff')
19
+ data_sets.each { |d| FileUtils.rm_rf(File.join(::Ojo.configuration.location, d)) }
20
+ end
21
+
22
+ def compare(branch_1, branch_2)
23
+ unless branch_1 && branch_2
24
+ branches = ::Ojo::DataSets.new.sets_available
25
+ unless branch_1
26
+ branches.each do |branch|
27
+ if branch != branch_2
28
+ branch_1 = branch
29
+ break
30
+ end
31
+ end
32
+ end
33
+
34
+ unless branch_2
35
+ branches.each do |branch|
36
+ if branch != branch_1
37
+ branch_2 = branch
38
+ break
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ results = ::Ojo::Ojo.new.compare(branch_1, branch_2)
45
+ ::Ojo::Output.new.display_to_console results[1]
46
+ end
47
+
48
+ end
49
+ end
@@ -1,90 +1,94 @@
1
1
  module Ojo
2
- def self.display_to_console(data)
3
- format_table data
2
+ class Output
3
+ include Collimator::Table
4
4
 
5
- failure_count = 0
5
+ def display_to_console(data)
6
+ format_table data
6
7
 
7
- data[:results].each_key do |basename|
8
- file_1 = file_basename(data[:results][basename][:file_1])
9
- file_2 = file_basename(data[:results][basename][:file_2])
8
+ failure_count = 0
10
9
 
11
- color = :blue
12
- result_text = '--'
10
+ data[:results].each_key do |basename|
11
+ file_1 = file_basename(data[:results][basename][:file_1])
12
+ file_2 = file_basename(data[:results][basename][:file_2])
13
13
 
14
- if test_performed?(data[:results][basename])
15
- same = data[:results][basename][:same]
16
- color = same ? :green : :red
17
- result_text = same ? 'PASS' : 'FAIL'
18
- failure_count += 1 unless same
19
- end
20
-
21
- one_row file_1, file_2, result_text, color
22
- end
23
- format_table_footer failure_count, data
24
- end
25
-
26
- private
14
+ color = :blue
15
+ result_text = '--'
27
16
 
28
- def self.format_table_footer(failure_count, data)
29
- Table.footer(results_message(failure_count == 0, failure_count), :justification => :center)
30
- Table.footer("Difference Files at #{File.join(data[:location], 'diff')}", :justification => :center)
17
+ if test_performed?(data[:results][basename])
18
+ same = data[:results][basename][:same]
19
+ color = same ? :green : :red
20
+ result_text = same ? 'PASS' : 'FAIL'
21
+ failure_count += 1 unless same
22
+ end
31
23
 
32
- Table.tabulate
33
- end
24
+ one_row file_1, file_2, result_text, color
25
+ end
26
+ format_table_footer failure_count, data
27
+ end
34
28
 
35
- def self.file_basename(filename)
36
- out = filename
37
- out = File.basename(filename) unless out.nil?
38
- out
39
- end
29
+ private
40
30
 
41
- def self.test_performed?(data)
42
- !data[:same].nil?
43
- end
31
+ def format_table_footer(failure_count, data)
32
+ Collimator::Table.footer(results_message(failure_count == 0, failure_count), :justification => :center)
33
+ Collimator::Table.footer("Difference Files at #{File.join(data[:location], 'diff')}", :justification => :center)
44
34
 
45
- def self.format_table_header(data)
46
- Table.header("Ojo v.#{VERSION}")
47
- Table.header("file location: #{data[:location]}")
48
- Table.header(Date.today.strftime('%m/%d/%Y'))
49
- end
35
+ Collimator::Table.tabulate
36
+ end
50
37
 
51
- def self.format_table(data)
52
- format_table_header data
38
+ def file_basename(filename)
39
+ out = filename
40
+ out = File.basename(filename) unless out.nil?
41
+ out
42
+ end
53
43
 
54
- Table.column(data[:branch_1], :width => 60, :padding => 2, :justification => :left)
55
- Table.column(data[:branch_2], :width => 60, :padding => 2, :justification => :left)
56
- Table.column('Results', :width => 11, :justification => :center)
57
- end
44
+ def test_performed?(data)
45
+ !data[:same].nil?
46
+ end
58
47
 
59
- def self.one_row(file_1, file_2, result_text, color)
60
- max_printable_length = 50
48
+ def format_table_header(data)
49
+ Collimator::Table.header("Ojo v.#{VERSION}")
50
+ Collimator::Table.header("file location: #{data[:location]}")
51
+ Collimator::Table.header(Date.today.strftime('%m/%d/%Y'))
52
+ end
61
53
 
62
- formatted_file_1 = make_printable_name(file_1, max_printable_length)
63
- formatted_file_2 = make_printable_name(file_2, max_printable_length)
54
+ def format_table(data)
55
+ format_table_header data
64
56
 
65
- row_data = [formatted_file_1, formatted_file_2, result_text]
66
- Table.row(:data => row_data, :color => color)
67
- end
57
+ Collimator::Table.column(data[:branch_1], :width => 60, :padding => 2, :justification => :left)
58
+ Collimator::Table.column(data[:branch_2], :width => 60, :padding => 2, :justification => :left)
59
+ Collimator::Table.column('Results', :width => 11, :justification => :center)
60
+ end
68
61
 
69
- def self.results_message(same, failure_count)
70
- results_message = ['Results: ']
71
- results_message << 'All Same' if same
72
- results_message << "#{failure_count} file#{failure_count > 1 ? 's were' : ' was'} found to be different" unless same
73
- results_message.join('')
74
- end
62
+ def one_row(file_1, file_2, result_text, color)
63
+ max_printable_length = 50
75
64
 
76
- def self.make_printable_name(input, max_length)
77
- output = input || ''
65
+ formatted_file_1 = make_printable_name(file_1, max_printable_length)
66
+ formatted_file_2 = make_printable_name(file_2, max_printable_length)
78
67
 
79
- if output.length > max_length
80
- how_much_too_long = output.length - max_length
81
- center_of_string = output.length / 2
82
- front_of_new_string = output[0..(center_of_string - how_much_too_long/2 - 3)]
83
- back_of_new_string = output[(center_of_string + how_much_too_long/2 + 3)..output.length]
68
+ row_data = [formatted_file_1, formatted_file_2, result_text]
69
+ Collimator::Table.row(:data => row_data, :color => color)
70
+ end
84
71
 
85
- output = "#{front_of_new_string}....#{back_of_new_string}"
72
+ def results_message(same, failure_count)
73
+ results_message = ['Results: ']
74
+ results_message << 'All Same' if same
75
+ results_message << "#{failure_count} file#{failure_count > 1 ? 's were' : ' was'} found to be different" unless same
76
+ results_message.join('')
86
77
  end
87
78
 
88
- output
79
+ def make_printable_name(input, max_length)
80
+ output = input || ''
81
+
82
+ if output.length > max_length
83
+ how_much_too_long = output.length - max_length
84
+ center_of_string = output.length / 2
85
+ front_of_new_string = output[0..(center_of_string - how_much_too_long/2 - 3)]
86
+ back_of_new_string = output[(center_of_string + how_much_too_long/2 + 3)..output.length]
87
+
88
+ output = "#{front_of_new_string}....#{back_of_new_string}"
89
+ end
90
+
91
+ output
92
+ end
89
93
  end
90
94
  end