Adding mapbox-gl branch
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
goog.provide('goog.crypt.BlobHasherTest');
|
||||
goog.setTestOnly('goog.crypt.BlobHasherTest');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.BlobHasher');
|
||||
goog.require('goog.crypt.Md5');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.testing.PropertyReplacer');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
// A browser-independent mock of goog.fs.sliceBlob. The actual implementation
|
||||
// calls the underlying slice method differently based on browser version.
|
||||
// This mock does not support negative opt_end.
|
||||
var fsSliceBlobMock = function(blob, start, opt_end) {
|
||||
if (!goog.isNumber(opt_end)) {
|
||||
opt_end = blob.size;
|
||||
}
|
||||
return blob.slice(start, opt_end);
|
||||
};
|
||||
|
||||
// Mock out the Blob using a string.
|
||||
BlobMock = function(string) {
|
||||
this.data = string;
|
||||
this.size = this.data.length;
|
||||
};
|
||||
|
||||
BlobMock.prototype.slice = function(start, end) {
|
||||
return new BlobMock(this.data.substr(start, end - start));
|
||||
};
|
||||
|
||||
|
||||
// Mock out the FileReader to have control over the flow.
|
||||
FileReaderMock = function() {
|
||||
this.array_ = [];
|
||||
this.result = null;
|
||||
this.readyState = this.EMPTY;
|
||||
|
||||
this.onload = null;
|
||||
this.onabort = null;
|
||||
this.onerror = null;
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.EMPTY = 0;
|
||||
FileReaderMock.prototype.LOADING = 1;
|
||||
FileReaderMock.prototype.DONE = 2;
|
||||
|
||||
FileReaderMock.prototype.mockLoad = function() {
|
||||
this.readyState = this.DONE;
|
||||
this.result = this.array_;
|
||||
if (this.onload) {
|
||||
this.onload.call();
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.abort = function() {
|
||||
this.readyState = this.DONE;
|
||||
if (this.onabort) {
|
||||
this.onabort.call();
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.mockError = function() {
|
||||
this.readyState = this.DONE;
|
||||
if (this.onerror) {
|
||||
this.onerror.call();
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.readAsArrayBuffer = function(blobMock) {
|
||||
this.readyState = this.LOADING;
|
||||
this.array_ = [];
|
||||
for (var i = 0; i < blobMock.size; ++i) {
|
||||
this.array_[i] = blobMock.data.charCodeAt(i);
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.isLoading = function() {
|
||||
return this.readyState == this.LOADING;
|
||||
};
|
||||
|
||||
var stubs = new goog.testing.PropertyReplacer();
|
||||
function setUp() {
|
||||
stubs.set(goog.global, 'FileReader', FileReaderMock);
|
||||
stubs.set(goog.fs, 'sliceBlob', fsSliceBlobMock);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
stubs.reset();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes the blobHasher read chunks from the blob and hash it. The number of
|
||||
* reads shall not exceed a pre-determined number (typically blob size / chunk
|
||||
* size) for computing hash. This function fails fast (after maxReads is
|
||||
* reached), assuming that the hasher failed to generate hashes. This prevents
|
||||
* the test suite from going into infinite loop.
|
||||
* @param {!goog.crypt.BlobHasher} blobHasher Hasher in action.
|
||||
* @param {number} maxReads Max number of read attempts.
|
||||
*/
|
||||
function readFromBlob(blobHasher, maxReads) {
|
||||
var counter = 0;
|
||||
while (blobHasher.fileReader_ && blobHasher.fileReader_.isLoading() &&
|
||||
counter <= maxReads) {
|
||||
blobHasher.fileReader_.mockLoad();
|
||||
counter++;
|
||||
}
|
||||
assertTrue(counter <= maxReads);
|
||||
return counter;
|
||||
}
|
||||
|
||||
function testBasicOperations() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Test hashing with one chunk.
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
blobHasher.hash(blob);
|
||||
readFromBlob(blobHasher, 1);
|
||||
assertEquals('9e107d9d372bb6826bd81d3542a419d6',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
|
||||
// Test hashing with multiple chunks.
|
||||
blobHasher = new goog.crypt.BlobHasher(hashFn, 7);
|
||||
blobHasher.hash(blob);
|
||||
readFromBlob(blobHasher, Math.ceil(blob.size / 7));
|
||||
assertEquals('9e107d9d372bb6826bd81d3542a419d6',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
|
||||
// Test hashing with no chunks.
|
||||
blob = new BlobMock('');
|
||||
blobHasher.hash(blob);
|
||||
readFromBlob(blobHasher, 1);
|
||||
assertEquals('d41d8cd98f00b204e9800998ecf8427e',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
|
||||
}
|
||||
|
||||
function testNormalFlow() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Test the flow with one chunk.
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 13);
|
||||
var blob = new BlobMock('short');
|
||||
var startedEvents = 0;
|
||||
var progressEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.STARTED,
|
||||
function() { ++startedEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.PROGRESS,
|
||||
function() { ++progressEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(0, progressEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
readFromBlob(blobHasher, 1);
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(1, progressEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
|
||||
// Test the flow with multiple chunks.
|
||||
blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
startedEvents = 0;
|
||||
progressEvents = 0;
|
||||
completeEvents = 0;
|
||||
var progressLoops = 0;
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(0, progressEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
progressLoops = readFromBlob(blobHasher, Math.ceil(blob.size / 13));
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(progressLoops, progressEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
}
|
||||
|
||||
function testAbortsAndErrors() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 13);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
var abortEvents = 0;
|
||||
var errorEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ABORT,
|
||||
function() { ++abortEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ERROR,
|
||||
function() { ++errorEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Immediate abort.
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
blobHasher.abort();
|
||||
blobHasher.abort();
|
||||
assertEquals(1, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
abortEvents = 0;
|
||||
|
||||
// Delayed abort.
|
||||
blobHasher.hash(blob);
|
||||
blobHasher.fileReader_.mockLoad();
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
blobHasher.abort();
|
||||
blobHasher.abort();
|
||||
assertEquals(1, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
abortEvents = 0;
|
||||
|
||||
// Immediate error.
|
||||
blobHasher.hash(blob);
|
||||
blobHasher.fileReader_.mockError();
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(1, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
errorEvents = 0;
|
||||
|
||||
// Delayed error.
|
||||
blobHasher.hash(blob);
|
||||
blobHasher.fileReader_.mockLoad();
|
||||
blobHasher.fileReader_.mockError();
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(1, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
abortEvents = 0;
|
||||
|
||||
}
|
||||
|
||||
function testBasicThrottling() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 5);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
var throttledEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.THROTTLED,
|
||||
function() { ++throttledEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Start a throttled hash. No chunks should be processed yet.
|
||||
blobHasher.setHashingLimit(0);
|
||||
assertEquals(0, throttledEvents);
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(0, blobHasher.getBytesProcessed());
|
||||
assertNull(blobHasher.fileReader_);
|
||||
|
||||
// One chunk should be processed.
|
||||
blobHasher.setHashingLimit(4);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(1, readFromBlob(blobHasher, 1));
|
||||
assertEquals(2, throttledEvents);
|
||||
assertEquals(4, blobHasher.getBytesProcessed());
|
||||
|
||||
// One more chunk should be processed.
|
||||
blobHasher.setHashingLimit(5);
|
||||
assertEquals(2, throttledEvents);
|
||||
assertEquals(1, readFromBlob(blobHasher, 1));
|
||||
assertEquals(3, throttledEvents);
|
||||
assertEquals(5, blobHasher.getBytesProcessed());
|
||||
|
||||
// Two more chunks should be processed.
|
||||
blobHasher.setHashingLimit(15);
|
||||
assertEquals(3, throttledEvents);
|
||||
assertEquals(2, readFromBlob(blobHasher, 2));
|
||||
assertEquals(4, throttledEvents);
|
||||
assertEquals(15, blobHasher.getBytesProcessed());
|
||||
|
||||
// The entire blob should be processed.
|
||||
blobHasher.setHashingLimit(Infinity);
|
||||
var expectedChunks = Math.ceil(blob.size / 5) - 3;
|
||||
assertEquals(expectedChunks, readFromBlob(blobHasher, expectedChunks));
|
||||
assertEquals(4, throttledEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
assertEquals('9e107d9d372bb6826bd81d3542a419d6',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
}
|
||||
|
||||
function testLengthZeroThrottling() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn);
|
||||
var throttledEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.THROTTLED,
|
||||
function() { ++throttledEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Test throttling with length 0 blob.
|
||||
var blob = new BlobMock('');
|
||||
blobHasher.setHashingLimit(0);
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(0, throttledEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
assertEquals('d41d8cd98f00b204e9800998ecf8427e',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
}
|
||||
|
||||
function testAbortsAndErrorsWhileThrottling() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 5);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
var abortEvents = 0;
|
||||
var errorEvents = 0;
|
||||
var throttledEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ABORT,
|
||||
function() { ++abortEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ERROR,
|
||||
function() { ++errorEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.THROTTLED,
|
||||
function() { ++throttledEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Test that processing cannot be continued after abort.
|
||||
blobHasher.setHashingLimit(0);
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, throttledEvents);
|
||||
blobHasher.abort();
|
||||
assertEquals(1, abortEvents);
|
||||
blobHasher.setHashingLimit(10);
|
||||
assertNull(blobHasher.fileReader_);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
assertNull(blobHasher.getHash());
|
||||
|
||||
// Test that processing cannot be continued after error.
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, throttledEvents);
|
||||
blobHasher.fileReader_.mockError();
|
||||
assertEquals(1, errorEvents);
|
||||
blobHasher.setHashingLimit(100);
|
||||
assertNull(blobHasher.fileReader_);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
assertNull(blobHasher.getHash());
|
||||
}
|
||||
Reference in New Issue
Block a user