compaa 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,15 @@
1
1
  !!!
2
2
  %head
3
- %script{src: '/assets/underscore.js'}
4
- %script{src: '/assets/jquery-2.0.0.js'}
3
+ %script{src: '/assets/context_blender.js'}
4
+ %script{src: '/assets/blender.js'}
5
5
  %script{src: '/assets/compaa.js'}
6
6
  %link{rel: 'stylesheet', href: '/assets/bootstrap.css'}
7
7
  :javascript
8
8
  var compaa;
9
- $(function() {
9
+ document.addEventListener('DOMContentLoaded', function() {
10
10
  compaa = Object.create(Compaa);
11
11
  compaa.init();
12
- });
12
+ }, false);
13
13
 
14
14
  %body
15
15
  %canvas#difference
@@ -37,9 +37,12 @@ module Compaa
37
37
 
38
38
  def get
39
39
  case @request.path
40
- when '/' then index
41
- when '/artifacts.json' then artifacts_json
42
- else four_oh_four
40
+ when '/' then index
41
+ when '/artifacts.json' then artifacts_json
42
+ when '/compaa.js' then compaa_js
43
+ when '/blender.js' then blender_js
44
+ when '/context_blender.js' then context_blender_js
45
+ else four_oh_four
43
46
  end
44
47
  end
45
48
 
@@ -1,3 +1,3 @@
1
1
  module Compaa
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -1,22 +1,31 @@
1
- require 'sinatra'
1
+ require 'sinatra/base'
2
2
  require 'json'
3
3
  require 'rack/cors'
4
4
 
5
- use Rack::Cors do
6
- allow do
7
- origins '*'
8
- resource '/*', :headers => :any, :methods => [:get, :post]
5
+ class MockCompaa < Sinatra::Base
6
+ set :port, 4567
7
+ disable :logging
8
+
9
+ use Rack::Cors do
10
+ allow do
11
+ origins '*'
12
+ resource '/*', :headers => :any, :methods => [:get, :post]
13
+ end
14
+ end
15
+
16
+ get '/artifacts.json' do
17
+ content_type 'application/json'
18
+ {
19
+ artifacts: %w(
20
+ artifacts/reference_screenshots/one.png
21
+ artifacts/reference_screenshots/two.png
22
+ artifacts/reference_screenshots/three.png
23
+ artifacts/reference_screenshots/four.png
24
+ )
25
+ }.to_json
9
26
  end
10
27
  end
11
28
 
12
- get '/artifacts.json' do
13
- content_type 'application/json'
14
- {
15
- artifacts: %w(
16
- artifacts/reference_screenshots/one.png
17
- artifacts/reference_screenshots/two.png
18
- artifacts/reference_screenshots/three.png
19
- artifacts/reference_screenshots/four.png
20
- )
21
- }.to_json
29
+ Thread.new do
30
+ MockCompaa.run!
22
31
  end
@@ -71,7 +71,7 @@ describe Compaa::GeneratedImage do
71
71
  difference_path =
72
72
  File.join %w[artifacts differences_in_screenshots_this_run dir file.png_difference.gif]
73
73
 
74
- mock_file_manager.expect :rm, true, [difference_path]
74
+ mock_file_manager.expect :rm, true, [difference_path, { force: true }]
75
75
 
76
76
  subject.delete_difference_image
77
77
 
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
- require 'capybara/poltergeist'
2
+ require 'capybara'
3
3
 
4
4
  Dir.chdir 'tmp/homemove' do
5
5
  Capybara.app = Compaa::RackApp.new
@@ -0,0 +1,26 @@
1
+ describe("blender", function() {
2
+ describe("makeItBlend()", function() {
3
+ it("produces a difference image", function() {
4
+ var imageOne = new Image(),
5
+ imageTwo = new Image(),
6
+ expectedImage = new Image(),
7
+ actual;
8
+
9
+ this.addMatchers(imagediff.jasmine);
10
+
11
+ expectedImage.src = '/spec/javascripts/support/expected.png';
12
+ imageOne.src = '/spec/javascripts/support/generated.png';
13
+ imageTwo.src = '/spec/javascripts/support/reference.png';
14
+
15
+ waitsFor(function() {
16
+ return imageOne.complete && imageTwo.complete && expectedImage.complete;
17
+ });
18
+
19
+ runs(function() {
20
+ window.blender.makeItBlend(imageOne, imageTwo, function(blended) {
21
+ expect(blended).toImageDiffEqual(expectedImage);
22
+ });
23
+ });
24
+ });
25
+ });
26
+ });
@@ -0,0 +1,382 @@
1
+ // js-imagediff 1.0.3
2
+ // (c) 2011-2012 Carl Sutherland, Humble Software
3
+ // Distributed under the MIT License
4
+ // For original source and documentation visit:
5
+ // http://www.github.com/HumbleSoftware/js-imagediff
6
+
7
+ (function (name, definition) {
8
+ var root = this;
9
+ if (typeof module !== 'undefined') {
10
+ var Canvas = require('canvas');
11
+ module.exports = definition(root, name, Canvas);
12
+ } else if (typeof define === 'function' && typeof define.amd === 'object') {
13
+ define(definition);
14
+ } else {
15
+ root[name] = definition(root, name);
16
+ }
17
+ })('imagediff', function (root, name, Canvas) {
18
+
19
+ var
20
+ TYPE_ARRAY = /\[object Array\]/i,
21
+ TYPE_CANVAS = /\[object (Canvas|HTMLCanvasElement)\]/i,
22
+ TYPE_CONTEXT = /\[object CanvasRenderingContext2D\]/i,
23
+ TYPE_IMAGE = /\[object (Image|HTMLImageElement)\]/i,
24
+ TYPE_IMAGE_DATA = /\[object ImageData\]/i,
25
+
26
+ UNDEFINED = 'undefined',
27
+
28
+ canvas = getCanvas(),
29
+ context = canvas.getContext('2d'),
30
+ previous = root[name],
31
+ imagediff, jasmine;
32
+
33
+ // Creation
34
+ function getCanvas (width, height) {
35
+ var
36
+ canvas = Canvas ?
37
+ new Canvas() :
38
+ document.createElement('canvas');
39
+ if (width) canvas.width = width;
40
+ if (height) canvas.height = height;
41
+ return canvas;
42
+ }
43
+ function getImageData (width, height) {
44
+ canvas.width = width;
45
+ canvas.height = height;
46
+ context.clearRect(0, 0, width, height);
47
+ return context.createImageData(width, height);
48
+ }
49
+
50
+
51
+ // Type Checking
52
+ function isImage (object) {
53
+ return isType(object, TYPE_IMAGE);
54
+ }
55
+ function isCanvas (object) {
56
+ return isType(object, TYPE_CANVAS);
57
+ }
58
+ function isContext (object) {
59
+ return isType(object, TYPE_CONTEXT);
60
+ }
61
+ function isImageData (object) {
62
+ return !!(object &&
63
+ isType(object, TYPE_IMAGE_DATA) &&
64
+ typeof(object.width) !== UNDEFINED &&
65
+ typeof(object.height) !== UNDEFINED &&
66
+ typeof(object.data) !== UNDEFINED);
67
+ }
68
+ function isImageType (object) {
69
+ return (
70
+ isImage(object) ||
71
+ isCanvas(object) ||
72
+ isContext(object) ||
73
+ isImageData(object)
74
+ );
75
+ }
76
+ function isType (object, type) {
77
+ return typeof (object) === 'object' && !!Object.prototype.toString.apply(object).match(type);
78
+ }
79
+
80
+
81
+ // Type Conversion
82
+ function copyImageData (imageData) {
83
+ var
84
+ height = imageData.height,
85
+ width = imageData.width,
86
+ data = imageData.data,
87
+ newImageData, newData, i;
88
+
89
+ canvas.width = width;
90
+ canvas.height = height;
91
+ newImageData = context.getImageData(0, 0, width, height);
92
+ newData = newImageData.data;
93
+
94
+ for (i = imageData.data.length; i--;) {
95
+ newData[i] = data[i];
96
+ }
97
+
98
+ return newImageData;
99
+ }
100
+ function toImageData (object) {
101
+ if (isImage(object)) { return toImageDataFromImage(object); }
102
+ if (isCanvas(object)) { return toImageDataFromCanvas(object); }
103
+ if (isContext(object)) { return toImageDataFromContext(object); }
104
+ if (isImageData(object)) { return object; }
105
+ }
106
+ function toImageDataFromImage (image) {
107
+ var
108
+ height = image.height,
109
+ width = image.width;
110
+ canvas.width = width;
111
+ canvas.height = height;
112
+ context.clearRect(0, 0, width, height);
113
+ context.drawImage(image, 0, 0);
114
+ return context.getImageData(0, 0, width, height);
115
+ }
116
+ function toImageDataFromCanvas (canvas) {
117
+ var
118
+ height = canvas.height,
119
+ width = canvas.width,
120
+ context = canvas.getContext('2d');
121
+ return context.getImageData(0, 0, width, height);
122
+ }
123
+ function toImageDataFromContext (context) {
124
+ var
125
+ canvas = context.canvas,
126
+ height = canvas.height,
127
+ width = canvas.width;
128
+ return context.getImageData(0, 0, width, height);
129
+ }
130
+ function toCanvas (object) {
131
+ var
132
+ data = toImageData(object),
133
+ canvas = getCanvas(data.width, data.height),
134
+ context = canvas.getContext('2d');
135
+
136
+ context.putImageData(data, 0, 0);
137
+ return canvas;
138
+ }
139
+
140
+
141
+ // ImageData Equality Operators
142
+ function equalWidth (a, b) {
143
+ return a.width === b.width;
144
+ }
145
+ function equalHeight (a, b) {
146
+ return a.height === b.height;
147
+ }
148
+ function equalDimensions (a, b) {
149
+ return equalHeight(a, b) && equalWidth(a, b);
150
+ }
151
+ function equal (a, b, tolerance) {
152
+
153
+ var
154
+ aData = a.data,
155
+ bData = b.data,
156
+ length = aData.length,
157
+ i;
158
+
159
+ tolerance = tolerance || 0;
160
+
161
+ if (!equalDimensions(a, b)) return false;
162
+ for (i = length; i--;) if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > tolerance) return false;
163
+
164
+ return true;
165
+ }
166
+
167
+
168
+ // Diff
169
+ function diff (a, b) {
170
+ return (equalDimensions(a, b) ? diffEqual : diffUnequal)(a, b);
171
+ }
172
+ function diffEqual (a, b) {
173
+
174
+ var
175
+ height = a.height,
176
+ width = a.width,
177
+ c = getImageData(width, height), // c = a - b
178
+ aData = a.data,
179
+ bData = b.data,
180
+ cData = c.data,
181
+ length = cData.length,
182
+ row, column,
183
+ i, j, k, v;
184
+
185
+ for (i = 0; i < length; i += 4) {
186
+ cData[i] = Math.abs(aData[i] - bData[i]);
187
+ cData[i+1] = Math.abs(aData[i+1] - bData[i+1]);
188
+ cData[i+2] = Math.abs(aData[i+2] - bData[i+2]);
189
+ cData[i+3] = Math.abs(255 - aData[i+3] - bData[i+3]);
190
+ }
191
+
192
+ return c;
193
+ }
194
+ function diffUnequal (a, b) {
195
+
196
+ var
197
+ height = Math.max(a.height, b.height),
198
+ width = Math.max(a.width, b.width),
199
+ c = getImageData(width, height), // c = a - b
200
+ aData = a.data,
201
+ bData = b.data,
202
+ cData = c.data,
203
+ rowOffset,
204
+ columnOffset,
205
+ row, column,
206
+ i, j, k, v;
207
+
208
+
209
+ for (i = cData.length - 1; i > 0; i = i - 4) {
210
+ cData[i] = 255;
211
+ }
212
+
213
+ // Add First Image
214
+ offsets(a);
215
+ for (row = a.height; row--;){
216
+ for (column = a.width; column--;) {
217
+ i = 4 * ((row + rowOffset) * width + (column + columnOffset));
218
+ j = 4 * (row * a.width + column);
219
+ cData[i+0] = aData[j+0]; // r
220
+ cData[i+1] = aData[j+1]; // g
221
+ cData[i+2] = aData[j+2]; // b
222
+ // cData[i+3] = aData[j+3]; // a
223
+ }
224
+ }
225
+
226
+ // Subtract Second Image
227
+ offsets(b);
228
+ for (row = b.height; row--;){
229
+ for (column = b.width; column--;) {
230
+ i = 4 * ((row + rowOffset) * width + (column + columnOffset));
231
+ j = 4 * (row * b.width + column);
232
+ cData[i+0] = Math.abs(cData[i+0] - bData[j+0]); // r
233
+ cData[i+1] = Math.abs(cData[i+1] - bData[j+1]); // g
234
+ cData[i+2] = Math.abs(cData[i+2] - bData[j+2]); // b
235
+ }
236
+ }
237
+
238
+ // Helpers
239
+ function offsets (imageData) {
240
+ rowOffset = Math.floor((height - imageData.height) / 2);
241
+ columnOffset = Math.floor((width - imageData.width) / 2);
242
+ }
243
+
244
+ return c;
245
+ }
246
+
247
+
248
+ // Validation
249
+ function checkType () {
250
+ var i;
251
+ for (i = 0; i < arguments.length; i++) {
252
+ if (!isImageType(arguments[i])) {
253
+ throw {
254
+ name : 'ImageTypeError',
255
+ message : 'Submitted object was not an image.'
256
+ };
257
+ }
258
+ }
259
+ }
260
+
261
+
262
+ // Jasmine Matchers
263
+ function get (element, content) {
264
+ element = document.createElement(element);
265
+ if (element && content) {
266
+ element.innerHTML = content;
267
+ }
268
+ return element;
269
+ }
270
+
271
+ jasmine = {
272
+
273
+ toBeImageData : function () {
274
+ return imagediff.isImageData(this.actual);
275
+ },
276
+
277
+ toImageDiffEqual : function (expected, tolerance) {
278
+
279
+ if (typeof (document) !== UNDEFINED) {
280
+ this.message = function () {
281
+ var
282
+ div = get('div'),
283
+ a = get('div', '<div>Actual:</div>'),
284
+ b = get('div', '<div>Expected:</div>'),
285
+ c = get('div', '<div>Diff:</div>'),
286
+ diff = imagediff.diff(this.actual, expected),
287
+ canvas = getCanvas(),
288
+ context;
289
+
290
+ canvas.height = diff.height;
291
+ canvas.width = diff.width;
292
+
293
+ div.style.overflow = 'hidden';
294
+ a.style.float = 'left';
295
+ b.style.float = 'left';
296
+ c.style.float = 'left';
297
+
298
+ context = canvas.getContext('2d');
299
+ context.putImageData(diff, 0, 0);
300
+
301
+ a.appendChild(toCanvas(this.actual));
302
+ b.appendChild(toCanvas(expected));
303
+ c.appendChild(canvas);
304
+
305
+ div.appendChild(a);
306
+ div.appendChild(b);
307
+ div.appendChild(c);
308
+
309
+ return [
310
+ div,
311
+ "Expected not to be equal."
312
+ ];
313
+ };
314
+ }
315
+
316
+ return imagediff.equal(this.actual, expected, tolerance);
317
+ }
318
+ };
319
+
320
+
321
+ // Image Output
322
+ function imageDataToPNG (imageData, outputFile, callback) {
323
+
324
+ var
325
+ canvas = toCanvas(imageData),
326
+ base64Data,
327
+ decodedImage;
328
+
329
+ callback = callback || Function;
330
+
331
+ base64Data = canvas.toDataURL().replace(/^data:image\/\w+;base64,/,"");
332
+ decodedImage = new Buffer(base64Data, 'base64');
333
+ require('fs').writeFile(outputFile, decodedImage, callback);
334
+ }
335
+
336
+
337
+ // Definition
338
+ imagediff = {
339
+
340
+ createCanvas : getCanvas,
341
+ createImageData : getImageData,
342
+
343
+ isImage : isImage,
344
+ isCanvas : isCanvas,
345
+ isContext : isContext,
346
+ isImageData : isImageData,
347
+ isImageType : isImageType,
348
+
349
+ toImageData : function (object) {
350
+ checkType(object);
351
+ if (isImageData(object)) { return copyImageData(object); }
352
+ return toImageData(object);
353
+ },
354
+
355
+ equal : function (a, b, tolerance) {
356
+ checkType(a, b);
357
+ a = toImageData(a);
358
+ b = toImageData(b);
359
+ return equal(a, b, tolerance);
360
+ },
361
+ diff : function (a, b) {
362
+ checkType(a, b);
363
+ a = toImageData(a);
364
+ b = toImageData(b);
365
+ return diff(a, b);
366
+ },
367
+
368
+ jasmine : jasmine,
369
+
370
+ // Compatibility
371
+ noConflict : function () {
372
+ root[name] = previous;
373
+ return imagediff;
374
+ }
375
+ };
376
+
377
+ if (typeof module !== 'undefined') {
378
+ imagediff.imageDataToPNG = imageDataToPNG;
379
+ }
380
+
381
+ return imagediff;
382
+ });