Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,18 @@
{
"extends": "../../../../.jshintrc",
"predef": [
"assert",
"suite",
"test",
"setup",
"teardown",
"suiteSetup",
"suiteTeardown",
"require",
"requireApp",
"sinon",
"mocha",
"loadBodyHTML",
"MocksHelper"
]
}

View file

@ -0,0 +1,311 @@
'use strict';
requireApp('/gallery/js/image_processor.js');
requireApp('/gallery/js/image_processor_thread.js');
function defineTestSuite(implementationName) {
suite(implementationName, function() {
var processor;
suiteSetup(function() {
if (implementationName === 'ImageProcessorThread') {
// The path to the worker code is different in this test case
// so tweak the URL just for this test.
window.ImageProcessorThread.WORKER_URL =
'../../' + window.ImageProcessorThread.WORKER_URL;
}
processor = new window[implementationName](1024*1024);
});
var imageProcessingTests = [
{
name: 'implicit noop test',
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
},
{
name: 'explicit noop test',
gamma: 1.0,
levels: {
red: {min: 0, max:255},
green: {min: 0, max:255},
blue: {min: 0, max:255}
},
matrix: [1,0,0,0,0,1,0,0,0,0,1,0],
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
},
{
name: 'gamma=1.0',
gamma: 1.0,
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
},
{
name: 'gamma=0.5',
gamma: 0.5,
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0,
Math.round(255*Math.pow(50/255, 0.5)),
Math.round(255*Math.pow(100/255, 0.5)),
Math.round(255*Math.pow(150/255, 0.5)),
0]
},
{
name: 'gamma=2.0',
gamma: 2.0,
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0,
Math.round(255*Math.pow(50/255, 2.0)),
Math.round(255*Math.pow(100/255, 2.0)),
Math.round(255*Math.pow(150/255, 2.0)),
0],
},
{ // should not modify the image because range too small
name: 'narrow levels',
levels: {
red: {min: 100, max:105},
green: {min: 60, max:65},
blue: {min: 200, max:205}
},
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
},
{
name: 'no-op levels',
levels: {
red: {min: 0, max:255},
green: {min: 0, max:255},
blue: {min: 0, max:255}
},
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
},
{
name: 'levels',
levels: {
red: {min: 0, max: 255},
green: { min: 50, max: 200},
blue: {min: 100, max: 150 }
},
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0,
50, Math.round(255 * (100-50)/150), 255, 0]
},
{
name: 'levels plus gamma',
levels: {
red: {min: 0, max: 255},
green: { min: 50, max: 200},
blue: {min: 100, max: 150 }
},
gamma: 1.25,
input: [0,0,0,0, 255,255,255,0, 50, 100, 150, 0],
expected: [0,0,0,0, 255,255,255,0,
Math.round(255*Math.pow(50/255, 1.25)),
Math.round(255*Math.pow(Math.round(255*(100-50)/150)/255,
1.25)),
255, 0]
},
{
name: 'identity matrix',
matrix: [1,0,0,0,0,1,0,0,0,0,1,0],
input: [1,2,3,0],
expected: [1,2,3,0]
},
{
name: 'matrix m0',
matrix: [2,0,0,0, 0,0,0,0, 0,0,0,0],
input: [1,2,3,0],
expected: [2,0,0,0]
},
{
name: 'matrix m1',
matrix: [0,2,0,0, 0,0,0,0, 0,0,0,0],
input: [1,2,3,0],
expected: [4,0,0,0]
},
{
name: 'matrix m2',
matrix: [0,0,2,0, 0,0,0,0, 0,0,0,0],
input: [1,2,3,0],
expected: [6,0,0,0]
},
{
name: 'matrix m3',
matrix: [0,0,0,0.5, 0,0,0,0, 0,0,0,0],
input: [1,2,3,0],
expected: [128,0,0,0]
},
{
name: 'matrix m4',
matrix: [0,0,0,0, 2,0,0,0, 0,0,0,0],
input: [1,2,3,0],
expected: [0,2,0,0]
},
{
name: 'matrix m5',
matrix: [0,0,0,0, 0,2,0,0, 0,0,0,0],
input: [1,2,3,0],
expected: [0,4,0,0]
},
{
name: 'matrix m6',
matrix: [0,0,0,0, 0,0,2,0, 0,0,0,0],
input: [1,2,3,0],
expected: [0,6,0,0]
},
{
name: 'matrix m7',
matrix: [0,0,0,0, 0,0,0,0.5, 0,0,0,0],
input: [1,2,3,0],
expected: [0,128,0,0]
},
{
name: 'matrix m8',
matrix: [0,0,0,0, 0,0,0,0, 2,0,0,0],
input: [1,2,3,0],
expected: [0,0,2,0]
},
{
name: 'matrix m9',
matrix: [0,0,0,0, 0,0,0,0, 0,2,0,0],
input: [1,2,3,0],
expected: [0,0,4,0]
},
{
name: 'matrix m10',
matrix: [0,0,0,0, 0,0,0,0, 0,0,2,0],
input: [1,2,3,0],
expected: [0,0,6,0]
},
{
name: 'matrix m11',
matrix: [0,0,0,0, 0,0,0,0, 0,0,0,0.5],
input: [1,2,3,0],
expected: [0,0,128,0]
},
{
name: 'full matrix',
matrix: [1,2,3,0.1, 4,5,6,0.2, 7,8,9,0.4],
input: [1,2,3,0],
expected: [40,83,152,0]
},
{
name: 'matrix overflow',
matrix: [1,2,3,1, 4,5,6,1, 7,8,9,1],
input: [1,2,3,0],
expected: [255,255,255,0]
},
{
name: 'everything',
gamma: 0.75,
levels: {
red: {min: 20, max: 225},
green: { min: 50, max: 200},
blue: {min: 10, max: 180 }
},
matrix: [0.1,0.2,0.3,0, 0.4,0.5,0.6,0, 0.7,0.8,0.9,0],
input: [50,100,150,0],
expected: [94,212,255,0]
}
];
// Register all the tests defined in the array above
imageProcessingTests.forEach(function(t) {
test(t.name, function(done) {
if (t.gamma) {
processor.setGamma(t.gamma);
}
else {
processor.setGamma(1.0);
}
if (t.levels) {
processor.setLevels(t.levels);
}
else {
processor.setLevels(null);
}
if (t.matrix) {
processor.setMatrix(t.matrix);
}
else {
processor.setMatrix(null);
}
processor.processImage(new Uint8Array(t.input).buffer).then(
function(result) {
done(function() {
assert.deepEqual(new Uint8Array(result),
new Uint8Array(t.expected));
});
},
function(error) {
done(error);
});
});
});
test('compute histogram', function(done) {
// Generate some random input and keep track of the histogram
// we expect from that input;
var N = 16*1024;
var input = new Uint8Array(N*4);
var red = new Uint32Array(256);
var green = new Uint32Array(256);
var blue = new Uint32Array(256);
for(var i = 0; i < N; i++) {
var r = Math.floor(Math.random()*256);
var g = Math.floor(Math.random()*256);
var b = Math.floor(Math.random()*256);
input[i*4] = r;
input[i*4+1] = g;
input[i*4+2] = b;
red[r]++;
green[g]++;
blue[b]++;
}
// Now compute a histogram on that input and compare to expected
processor.computeHistogram(input.buffer).then(
function(result) {
done(function() {
assert.deepEqual(new Uint32Array(result, 0, 256), red);
assert.deepEqual(new Uint32Array(result, 256*4, 256), green);
assert.deepEqual(new Uint32Array(result, 256*8, 256), blue);
});
},
function(error) {
done(error);
});
});
});
}
defineTestSuite('ImageProcessor');
defineTestSuite('ImageProcessorThread');

View file

@ -0,0 +1,51 @@
'use strict';
/* exported MockImageEditor */
var MockImageEditor = (function() {
var MockImageEditor = function(imageBlob, container, edits, ready, croponly) {
this.imageBlob = imageBlob;
this.container = container;
this.edits = edits;
this.ready = ready;
this.croponly = croponly;
this.dest = {};
this.cropOverlayRegion = {};
setTimeout(ready);
};
MockImageEditor.prototype.showCropOverlay = sinon.spy();
MockImageEditor.prototype.setCropAspectRatio = sinon.spy();
MockImageEditor.prototype.destroy = sinon.spy();
MockImageEditor.prototype.hasBeenCropped = function() {
return (this.cropOverlayRegion.left !== 0 ||
this.cropOverlayRegion.top !== 0 ||
this.cropOverlayRegion.right !== this.dest.width ||
this.cropOverlayRegion.bottom !== this.dest.height);
};
MockImageEditor.prototype.getCropRegion = function() {
var region = this.cropOverlayRegion;
var previewRect = this.dest;
// Convert the preview crop region to fractions
var left = region.left / previewRect.width;
var right = region.right / previewRect.width;
var top = region.top / previewRect.height;
var bottom = region.bottom / previewRect.height;
return {
left: left,
top: top,
width: right - left,
height: bottom - top
};
};
sinon.spy(MockImageEditor.prototype, 'hasBeenCropped');
sinon.spy(MockImageEditor.prototype, 'getCropRegion');
return MockImageEditor;
})();

View file

@ -0,0 +1,7 @@
'use strict';
/* exported MockSpinner */
var MockSpinner = {
show: sinon.spy(),
hide: sinon.spy()
};

View file

@ -0,0 +1,53 @@
'use strict';
/* exported MockThumbnailGroup */
function MockThumbnailGroup(item) {
var counter = 0;
var dummyNode = document.createElement('div');
dummyNode.textContent = MockThumbnailGroup._GroupID;
var thumbnails = [];
function addItem(item) {
var obj = {data: item.name};
counter++;
thumbnails.push(obj);
return obj;
}
function removeItem(item) {
counter--;
thumbnails.pop({data: item.name});
}
function localize() {}
MockThumbnailGroup._GroupMap[MockThumbnailGroup._GroupID] = {
// api
addItem: addItem,
getCount: function() {return counter;},
removeItem: removeItem,
localize: localize,
// properties.
groupID: MockThumbnailGroup._GroupID,
htmlNode: dummyNode,
thumbnails: thumbnails
};
return MockThumbnailGroup._GroupMap[MockThumbnailGroup._GroupID];
}
MockThumbnailGroup.getGroupID = function(video) {
return MockThumbnailGroup._GroupID;
};
MockThumbnailGroup.compareGroupID = function(id1, id2) {
return id1 > id2 ? 1 : (id1 < id2 ? -1 : 0);
};
MockThumbnailGroup._GroupMap = {};
MockThumbnailGroup.reset = function() {
MockThumbnailGroup._GroupMap = {};
delete MockThumbnailGroup._GroupID;
};

View file

@ -0,0 +1,130 @@
/*jshint maxlen:false, sub:true*/
/*global NFC, MockShrinkingUI */
'use strict';
requireApp('/gallery/js/nfc.js');
requireApp('system/shared/test/unit/mocks/mock_shrinking_ui.js');
suite('nfc', function() {
var realMozNfc;
var target;
setup(function() {
realMozNfc = navigator.mozNfc;
navigator.mozNfc = {};
window.ShrinkingUI = MockShrinkingUI;
target = Object.create(NFC);
});
teardown(function() {
navigator.mozNfc = realMozNfc;
window.ShrinkingUI = null;
target = null;
});
suite('share', function() {
test('Should attach `onpeerready` event handler', function() {
target.share();
assert.equal(typeof navigator.mozNfc.onpeerready, 'function');
});
test('Should pass Blob to `peer.sendFile()`', function() {
var event = {
peer: {
sendFile: sinon.spy()
}
};
var blob = new Blob();
target.share(blob);
navigator.mozNfc.onpeerready(event);
assert.ok(event.peer.sendFile.calledWith(blob));
});
test('Should resolve Promise to pass Blob to `peer.sendFile()`', function(done) {
var event = {
peer: {
sendFile: sinon.spy()
}
};
target.share(function() {
return {
then: function(callback) {
var blob = new Blob();
callback(blob);
assert.ok(event.peer.sendFile.calledWith(blob));
done();
}
};
});
navigator.mozNfc.onpeerready(event);
});
});
suite('share, and shrinkingUI is handled by gallery itself', function() {
var targetWithShrink;
var testFile;
setup(function() {
targetWithShrink = target;
testFile = 'testFile';
targetWithShrink.share(testFile, {
foregroundElement: null,
backgroundElement: null
});
});
test('Should attach `onpeerfound, onpeerlost` event handler', function() {
assert.equal(typeof navigator.mozNfc.onpeerfound, 'function');
assert.equal(typeof navigator.mozNfc.onpeerlost, 'function');
});
test('should send file when receiving shrinking-sent', function() {
var event = {
peer: {
sendFile: sinon.spy()
},
preventDefault: function() {}
};
navigator.mozNfc.onpeerfound(event);
window.dispatchEvent(new CustomEvent('shrinking-sent'));
assert.ok(event.peer.sendFile.calledWith(testFile));
});
test('should start shrinking when onpeerfound', function() {
this.sinon.stub(targetWithShrink.shrinkingUI, 'start');
var event = {
peer: {},
preventDefault: function() {}
};
navigator.mozNfc.onpeerfound(event);
assert.isTrue(targetWithShrink.shrinkingUI.start.calledOnce);
});
test('should stop shrinking when onpeerlost', function() {
this.sinon.stub(targetWithShrink.shrinkingUI, 'stop');
var event = {
peer: {}
};
navigator.mozNfc.onpeerlost(event);
assert.isTrue(targetWithShrink.shrinkingUI.stop.calledOnce);
});
test('should stop shrinking when unshare', function() {
this.sinon.stub(targetWithShrink.shrinkingUI, 'stop');
targetWithShrink.unshare();
assert.equal(targetWithShrink.shrinkingUI, null);
});
});
suite('unshare', function() {
test('Should remove `onpeerready` event handler', function() {
target.unshare();
assert.equal(navigator.mozNfc.onpeerready, null);
});
});
});

View file

@ -0,0 +1,131 @@
/*jshint maxlen:false, sub:true*/
/*global MocksHelper, Overlay*/
'use strict';
require('/shared/test/unit/mocks/mock_lazy_loader.js');
requireApp('/gallery/js/overlay.js');
var mocksHelper = new MocksHelper([
'LazyLoader'
]).init();
suite('overlay', function() {
mocksHelper.attachTestHelpers();
var real$;
var selectors;
setup(function() {
selectors = {};
});
suiteSetup(function() {
real$ = window.$;
window.$ = function(selector) {
return (selectors[selector] = selectors[selector] || {
addEventListener: sinon.spy(),
removeEventListener: sinon.spy(),
classList: {
add: sinon.spy(),
remove: sinon.spy()
},
setAttribute: sinon.spy()
});
};
window.picking = false;
});
suiteTeardown(function() {
window.$ = real$;
});
suite('hide', function() {
test('Should set `Overlay.current` to `null`', function() {
Overlay.current = 'not `null`';
Overlay.hide();
assert.equal(Overlay.current, null);
});
test('Should add "hidden" to #overlay classList', function() {
Overlay.hide();
assert.ok(selectors['overlay'].classList.add.calledWith('hidden'));
});
});
suite('show', function() {
test('Should set `Overlay.current` to `foo`', function() {
Overlay.show('foo');
assert.equal(Overlay.current, 'foo');
});
test('Should add "hidden" to #overlay-camera-button', function() {
Overlay.show('foo');
assert.ok(selectors['overlay-camera-button'].classList.add.calledWith('hidden'));
});
test('Should add "hidden" to #overlay-cancel-button', function() {
Overlay.show('foo');
assert.ok(selectors['overlay-cancel-button'].classList.add.calledWith('hidden'));
});
test('Should add "hidden" to #overlay-menu', function() {
Overlay.show('foo');
assert.ok(selectors['overlay-menu'].classList.add.calledWith('hidden'));
});
test('Should call `Overlay.hide` if `id` is `null`', function() {
var realHide = Overlay.hide;
Overlay.hide = sinon.spy();
Overlay.show(null);
assert.ok(Overlay.hide.called);
Overlay.hide = realHide;
});
test('Should set "data-l10n-id" attribute on #overlay-title for a valid overlay `id`',
function() {
Overlay.show('nocard');
assert.ok(selectors['overlay-title'].setAttribute.calledWith('data-l10n-id'));
}
);
test('Should set "data-l10n-id" attribute on #overlay-text for a valid overlay `id`',
function() {
Overlay.show('nocard');
assert.ok(selectors['overlay-text'].setAttribute.calledWith('data-l10n-id'));
}
);
test('Should *NOT* set "data-l10n-id" attribute on #overlay-title for an invalid overlay `id`',
function() {
Overlay.show('foo');
assert.ok(!selectors['overlay-title']);
}
);
test('Should *NOT* set "data-l10n-id" attribute on #overlay-text for an invalid overlay `id`',
function() {
Overlay.show('foo');
assert.ok(!selectors['overlay-text']);
}
);
});
suite('addEventListener', function() {
test('Should add event listener to #overlay', function() {
Overlay.addEventListener('foo', 'bar');
assert.ok(selectors['overlay'].addEventListener.calledWith('foo', 'bar'));
});
});
suite('removeEventListener', function() {
test('Should remove event listener from #overlay', function() {
Overlay.removeEventListener('foo', 'bar');
assert.ok(selectors['overlay'].removeEventListener.calledWith('foo', 'bar'));
});
});
});

View file

@ -0,0 +1,269 @@
/*jshint maxlen:false, sub:true*/
/*global MockGetDeviceStorage, MockCropResizeRotate*/
/*global MocksHelper, LAYOUT_MODE, MediaDB, ImageEditor, Pick*/
'use strict';
require('/shared/test/unit/mocks/mock_lazy_loader.js');
require('/shared/test/unit/mocks/mock_mediadb.js');
require('/shared/test/unit/mocks/mock_crop_resize_rotate.js');
require('/shared/test/unit/mocks/mock_navigator_getdevicestorage.js');
require('/shared/js/media/jpeg-exif.js');
requireApp('/gallery/test/unit/mock_image_editor.js');
requireApp('/gallery/test/unit/mock_spinner.js');
requireApp('/gallery/js/pick.js');
var mocksHelper = new MocksHelper([
'LazyLoader',
'MediaDB',
'ImageEditor',
'Spinner'
]).init();
suite('pick', function() {
mocksHelper.attachTestHelpers();
var real$;
var selectors;
setup(function() {
selectors = {};
});
suiteSetup(function() {
window.cropResizeRotate = sinon.spy(MockCropResizeRotate);
navigator.getDeviceStorage = sinon.spy(MockGetDeviceStorage);
real$ = window.$;
window.$ = function(selector) {
return (selectors[selector] = selectors[selector] || {
addEventListener: sinon.spy()
});
};
window.LAYOUT_MODE = {
pick: 'pick',
crop: 'crop'
};
window.CONFIG_MAX_PICK_PIXEL_SIZE = 800 * 600;
window.setView = sinon.spy();
window.photodb = new MediaDB('pictures');
});
suiteTeardown(function() {
window.$ = real$;
});
suite('start', function() {
var activity = {
source: {
data: {
type: 'image/jpeg'
}
}
};
test('Should call `setView` with `LAYOUT_MODE.pick`', function() {
window.setView.reset();
Pick.start(activity);
assert.ok(window.setView.calledWith(LAYOUT_MODE.pick));
});
test('Should add "action" event listener to #pick-header', function() {
Pick.start(activity);
assert.ok(selectors['pick-header'].addEventListener.calledWith('action'));
});
test('Should add "action" event listener to #crop-top', function() {
Pick.start(activity);
assert.ok(selectors['crop-top'].addEventListener.calledWith('action'));
});
test('Should add "click" event listener to #crop-done-button', function() {
Pick.start(activity);
assert.ok(selectors['crop-done-button'].addEventListener.calledWith('click'));
});
});
suite('select', function() {
var activity = {
source: {
data: {
type: 'image/jpeg'
}
}
};
var fileinfo = {
name: '/foo/bar/baz.jpg',
metadata: {}
};
test('Should show file name in the title bar if `nocrop` flag is set', function() {
activity.source.data.nocrop = true;
Pick.start(activity);
Pick.select(fileinfo);
assert.equal(selectors['crop-header'].textContent, 'baz');
delete activity.source.data.nocrop;
});
test('Should call `setView` with `LAYOUT_MODE.crop`', function() {
window.setView.reset();
Pick.start(activity);
Pick.select(fileinfo);
assert.ok(window.setView.calledWith(LAYOUT_MODE.crop));
});
test('Should disable #crop-done-button', function() {
Pick.start(activity);
Pick.select(fileinfo);
assert.isTrue(selectors['crop-done-button'].disabled);
});
test('Should get file from MediaDB', function() {
window.photodb.getFile.reset();
Pick.start(activity);
Pick.select(fileinfo);
assert.ok(window.photodb.getFile.calledWith(fileinfo.name));
});
test('Should crop/resize/rotate file', function() {
window.cropResizeRotate.reset();
Pick.start(activity);
Pick.select(fileinfo);
assert.ok(window.cropResizeRotate.called);
});
test('Should use external preview file if specified', function() {
navigator.getDeviceStorage.reset();
fileinfo.metadata.preview = {
filename: '/foo/bar/baz_preview.jpg'
};
Pick.start(activity);
Pick.select(fileinfo);
assert.ok(navigator.getDeviceStorage.calledWith('pictures'));
});
});
suite('cancel', function() {
var activity = {
source: {
data: {
type: 'image/jpeg'
}
},
postError: sinon.spy()
};
var fileinfo = {
name: '/foo/bar/baz.jpg',
metadata: {}
};
test('Should post "pick cancelled" error', function() {
activity.postError.reset();
Pick.start(activity);
Pick.select(fileinfo);
Pick.cancel();
assert.ok(activity.postError.calledWith('pick cancelled'));
});
});
suite('restart', function() {
var activity = {
source: {
data: {
type: 'image/jpeg'
}
}
};
var fileinfo = {
name: '/foo/bar/baz.jpg',
metadata: {}
};
test('Should destroy `ImageEditor`', function(done) {
ImageEditor.prototype.destroy.reset();
Pick.start(activity);
Pick.select(fileinfo);
setTimeout(function() {
Pick.restart();
assert.ok(ImageEditor.prototype.destroy.called);
done();
});
});
test('Should call `setView` with `LAYOUT_MODE.pick`', function(done) {
window.setView.reset();
Pick.start(activity);
Pick.select(fileinfo);
setTimeout(function() {
Pick.restart();
assert.ok(window.setView.calledWith(LAYOUT_MODE.pick));
done();
});
});
});
suite('end', function() {
var activity = {
source: {
data: {
type: 'image/jpeg'
}
},
postResult: sinon.spy()
};
var fileinfo = {
name: '/foo/bar/baz.jpg',
metadata: {}
};
test('Should call `getCropRegion` on `ImageEditor`', function() {
ImageEditor.prototype.getCropRegion.reset();
Pick.start(activity);
Pick.select(fileinfo);
Pick.end();
assert.ok(ImageEditor.prototype.getCropRegion.called);
});
test('Should *NOT* call `getCropRegion` on `ImageEditor` if `nocrop` specified',
function() {
ImageEditor.prototype.getCropRegion.reset();
activity.source.data.nocrop = true;
Pick.start(activity);
Pick.select(fileinfo);
Pick.end();
assert.ok(ImageEditor.prototype.getCropRegion.notCalled);
delete activity.source.data.nocrop;
});
test('Should call `postResult`', function() {
activity.postResult.reset();
Pick.start(activity);
Pick.select(fileinfo);
Pick.end();
assert.ok(activity.postResult.called);
});
});
});

View file

@ -0,0 +1,7 @@
'use strict';
require('/shared/test/unit/mocks/mocks_helper.js');
require('/shared/test/unit/load_body_html_helper.js');
// Gaia Grid/ Element requires
require('/shared/js/component_utils.js');

View file

@ -0,0 +1,48 @@
/*jshint maxlen:false, sub:true*/
/*global Spinner*/
'use strict';
requireApp('/gallery/js/spinner.js');
suite('spinner', function() {
var real$;
var selectors;
setup(function() {
selectors = {};
});
suiteSetup(function() {
real$ = window.$;
window.$ = function(selector) {
return (selectors[selector] = selectors[selector] || {
classList: {
add: sinon.spy(),
remove: sinon.spy()
}
});
};
});
suiteTeardown(function() {
window.$ = real$;
});
suite('show', function() {
test('Should remove "hidden" from #spinner', function() {
Spinner.show();
assert.ok(selectors['spinner'].classList.remove.calledWith('hidden'));
});
});
suite('hide', function() {
test('Should add "hidden" to #spinner', function() {
Spinner.hide();
assert.ok(selectors['spinner'].classList.add.calledWith('hidden'));
});
});
});

View file

@ -0,0 +1,56 @@
/*
* Thumbnail Item tests
*/
'use strict';
/* global ThumbnailItem */
require('/shared/js/intl/l20n.js');
requireApp('/gallery/js/thumbnail_item.js');
suite('Thumbnail Item Unit Tests', function() {
suite('#test object creation', function() {
test('#empty gallery object', function() {
try {
/* jshint nonew: false */
new ThumbnailItem();
assert.fail('undefined or null galleryitem should not be ok.');
} catch (ex) {
assert.ok('correct behavior caught');
}
});
});
suite('#rendering', function() {
var filedata;
var thumbnail;
var domNode;
var imgNode;
suiteSetup(function() {
filedata = {
metadata: {
thumbnail: new Blob(['empty-image'], {'type': 'image/jpeg'})
},
date: 1375873140000,
name: 'dummy-file-name'
};
thumbnail = new ThumbnailItem(filedata);
domNode = thumbnail.htmlNode;
imgNode = thumbnail.imgNode;
});
test('#htmlNode', function() {
assert.equal(thumbnail.htmlNode, domNode);
});
test('#imgNode dataset name', function() {
assert.equal(thumbnail.imgNode.dataset.filename, filedata.name);
});
test('#imgNode src', function() {
assert.notEqual(thumbnail.imgNode.src, '');
});
});
});

View file

@ -0,0 +1,165 @@
/*
* Thumbnail List and getFileIndex method in gallery Unit tests
*/
'use strict';
/* global
getFileIndex,
MockThumbnailGroup,
ThumbnailList
*/
require('/shared/js/intl/l20n.js');
requireApp('/gallery/js/gallery.js');
requireApp('/gallery/test/unit/mock_thumbnail_group.js');
requireApp('/gallery/js/thumbnail_list.js');
suite('Thumbnail List Unit Tests', function() {
var nativeThumbnailList;
suiteSetup(function() {
nativeThumbnailList = window.thumbnailList;
});
suiteTeardown(function() {
window.thumbnailList = nativeThumbnailList;
});
suite('#constructor tests', function() {
var dummyContainer;
suiteSetup(function() {
MockThumbnailGroup.reset();
dummyContainer = document.createElement('div');
});
test('normal', function() {
/* jshint nonew: false */
new ThumbnailList(MockThumbnailGroup, dummyContainer);
assert.ok('everything should be ok');
});
test('missing arguments', function() {
try {
/* jshint nonew: false */
new ThumbnailList(MockThumbnailGroup);
assert.fail('it should throws an error.');
} catch (ex) {
assert.ok('everything should be ok');
}
try {
/* jshint nonew: false */
new ThumbnailList();
assert.fail('it should throws an error.');
} catch (ex) {
assert.ok('everything should be ok');
}
});
});
suite('#api tests', function() {
var dummyContainer;
var thumbnailList;
suiteSetup(function() {
dummyContainer = document.createElement('div');
thumbnailList = new ThumbnailList(MockThumbnailGroup, dummyContainer);
// Used in getFileIndex
window.thumbnailList = thumbnailList;
});
test('#addItem, Add multiple items', function() {
// first
MockThumbnailGroup._GroupID = '2013-09';
thumbnailList.addItem({'name': 'dummy-file-name-09.jpg'});
// Group Header
assert.equal(dummyContainer.firstChild.textContent, '2013-09');
// Index of File Added in Group 2013-09
assert.equal(getFileIndex('dummy-file-name-09.jpg'), 0);
//Total files
assert.equal(thumbnailList.count, 1);
// second
MockThumbnailGroup._GroupID = '2013-08';
thumbnailList.addItem({'name': 'dummy-file-name-08.jpg'});
assert.equal(dummyContainer.children[1].textContent, '2013-08');
// Index of File Added in Group 2013-08
assert.equal(getFileIndex('dummy-file-name-08.jpg'), 1);
assert.equal(thumbnailList.count, 2);
//third
MockThumbnailGroup._GroupID = '2013-07';
thumbnailList.addItem({'name': 'dummy-file-name-07.jpg'});
assert.equal(dummyContainer.children[2].textContent, '2013-07');
// Index of File Added in Group 2013-07
assert.equal(getFileIndex('dummy-file-name-07.jpg'), 2);
assert.equal(thumbnailList.count, 3);
// last
MockThumbnailGroup._GroupID = '2013-06';
thumbnailList.addItem({'name': 'dummy-file-name-06.jpg'});
assert.equal(dummyContainer.children[3].textContent, '2013-06');
// Index of File Added in Group 2013-06
assert.equal(getFileIndex('dummy-file-name-06.jpg'), 3);
assert.equal(thumbnailList.count, 4);
});
test('#addItem, to existing group', function() {
// first
MockThumbnailGroup._GroupID = '2013-07';
thumbnailList.addItem({'name': 'dummy-file-name-07-2.jpg'});
// Index of File Added in Group 2013-07
assert.equal(getFileIndex('dummy-file-name-07-2.jpg'), 3);
// Total files in group 2013-07
assert.equal(MockThumbnailGroup._GroupMap['2013-07'].getCount(), 2);
// Total groups
assert.equal(dummyContainer.children.length, 4);
//Total files in all groups
assert.equal(thumbnailList.count, 5);
});
test('#addItem, empty item', function() {
// first
MockThumbnailGroup._GroupID = '2013-07';
thumbnailList.addItem(null);
assert.equal(MockThumbnailGroup._GroupMap['2013-07'].getCount(), 2);
assert.equal(dummyContainer.children.length, 4);
assert.equal(thumbnailList.count, 5);
});
test('#addItem, duplicate item', function() {
// first
MockThumbnailGroup._GroupID = '2013-07';
thumbnailList.addItem({'name': 'dummy-file-name-07-2.jpg'});
assert.equal(thumbnailList.count, 5);
assert.equal(MockThumbnailGroup._GroupMap['2013-07'].getCount(), 2);
assert.equal(dummyContainer.children.length, 4);
});
test('#removeItem', function() {
MockThumbnailGroup._GroupID = '2013-07';
thumbnailList.removeItem('dummy-file-name-07-2.jpg');
assert.equal(thumbnailList.count, 4);
assert.equal(MockThumbnailGroup._GroupMap['2013-07'].getCount(), 1);
thumbnailList.removeItem('dummy-file-name-07.jpg');
assert.equal(thumbnailList.count, 3);
assert.equal(MockThumbnailGroup._GroupMap['2013-07'].getCount(), 0);
assert.equal(dummyContainer.children.length, 3);
// Index of last file in Group 2013-06
assert.equal(getFileIndex('dummy-file-name-06.jpg'), 2);
});
test('#thumbnailMap', function() {
assert.isDefined(thumbnailList.thumbnailMap['dummy-file-name-06.jpg']);
});
test('#reset', function() {
thumbnailList.reset();
assert.equal(thumbnailList.count, 0);
assert.isUndefined(thumbnailList.thumbnailMap['dummy-file-name-06.jpg']);
});
});
});