sku-pg
Version:
Skulpt is a Javascript implementation of Python 2.x. Python that runs in your browser!
1,171 lines (1,035 loc) • 37.5 kB
HTML
<html>
<!--
Copyright 2008 The Closure Library Authors. All Rights Reserved.
Use of this source code is governed by an Apache 2.0 License.
See the COPYING file for details.
-->
<!--
Author: pupius@google.com (Daniel Pupius)
Author: jananir@google.com (Janani Ravi) (Modified for Closure)
-->
<head>
<title>Closure Unit Tests - goog.module.ModuleManager</title>
<script src="../base.js"></script>
<script src="../../../third_party/closure/goog/deps.js"></script>
<script>
goog.require('goog.functions');
goog.require('goog.module.BaseModule');
goog.require('goog.module.ModuleManager');
goog.require('goog.testing.MockClock');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.recordFunction');
</script>
</head>
<body>
<script>
var clock;
function setUpPage() {
clock = new goog.testing.MockClock(true);
}
function tearDownPage() {
clock.dispose();
}
function getModuleManager(infoMap) {
var mm = new goog.module.ModuleManager();
mm.setAllModuleInfo(infoMap);
mm.isModuleLoaded = function(id) {
return this.getModuleInfo(id).isLoaded();
}
return mm;
}
function createSuccessfulBatchLoader(moduleMgr) {
return {
loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn,
opt_timeoutFn) {
setTimeout(goog.bind(this.onLoad, this, ids.concat(), 0), 5);
},
onLoad: function(ids, idxLoaded) {
moduleMgr.beforeLoadModuleCode(ids[0]);
moduleMgr.setLoaded(ids[idxLoaded]);
moduleMgr.afterLoadModuleCode(ids[idxLoaded]);
var idx = idxLoaded + 1;
if (idx < ids.length) {
moduleMgr.beforeLoadModuleCode(ids[idx]);
setTimeout(goog.bind(this.onLoad, this, ids, idx), 2);
}
}};
}
function createSuccessfulNonBatchLoader(moduleMgr) {
return {
loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn,
opt_timeoutFn) {
setTimeout(function() {
moduleMgr.beforeLoadModuleCode(ids[0]);
moduleMgr.setLoaded(ids[0]);
moduleMgr.afterLoadModuleCode(ids[0]);
if (opt_successFn) {
opt_successFn();
}
}, 5);
}};
}
function createUnsuccessfulLoader(moduleMgr, status) {
return {
loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn,
opt_timeoutFn) {
moduleMgr.beforeLoadModuleCode(ids[0]);
setTimeout(function() { opt_errFn(status); }, 5);
}};
}
function createTimeoutLoader(moduleMgr, status) {
return {
loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn,
opt_timeoutFn) {
setTimeout(function() { opt_timeoutFn(status); }, 5);
}};
}
/**
* Tests loading a module under different conditions i.e. unloaded
* module, already loaded module, module loaded through user initiated
* actions, synchronous callback for a module that has been already
* loaded. Test both batch and non-batch loaders.
*/
function testExecOnLoad() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
execOnLoad_(mm);
mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulBatchLoader(mm));
mm.setBatchModeEnabled(true);
execOnLoad_(mm);
}
/**
* Tests execOnLoad with the specified module manager.
* @param {goog.module.ModuleManager} mm The module manager.
*/
function execOnLoad_(mm) {
// When module is unloaded, execOnLoad is async.
var execCalled1 = false;
mm.execOnLoad('a', function() { execCalled1 = true; });
assertFalse('module "a" should not be loaded', mm.isModuleLoaded('a'));
assertTrue('module "a" should be loading', mm.isModuleLoading('a'));
assertFalse('execCalled1 should not be set yet', execCalled1);
assertTrue('ModuleManager should be active', mm.isActive());
assertFalse(
'ModuleManager should not be user active', mm.isUserActive());
clock.tick(5);
assertTrue('module "a" should be loaded', mm.isModuleLoaded('a'));
assertFalse(
'module "a" should not be loading', mm.isModuleLoading('a'));
assertTrue('execCalled1 should be set', execCalled1);
assertFalse('ModuleManager should not be active', mm.isActive());
assertFalse(
'ModuleManager should not be user active', mm.isUserActive());
// When module is already loaded, execOnLoad is still async unless
// specified otherwise.
var execCalled2 = false;
mm.execOnLoad('a', function() { execCalled2 = true; });
assertTrue('module "a" should be loaded', mm.isModuleLoaded('a'));
assertFalse(
'module "a" should not be loading', mm.isModuleLoading('a'));
assertFalse('execCalled2 should not be set yet', execCalled2);
clock.tick(5);
assertTrue('execCalled2 should be set', execCalled2);
// When module is unloaded, execOnLoad is async (user active).
var execCalled5 = false;
mm.execOnLoad('c',
function() { execCalled5 = true; }, null, null, true);
assertFalse('module "c" should not be loaded', mm.isModuleLoaded('c'));
assertTrue('module "c" should be loading', mm.isModuleLoading('c'));
assertFalse('execCalled1 should not be set yet', execCalled5);
assertTrue('ModuleManager should be active', mm.isActive());
assertTrue('ModuleManager should be user active', mm.isUserActive());
clock.tick(5);
assertTrue('module "c" should be loaded', mm.isModuleLoaded('c'));
assertFalse(
'module "c" should not be loading', mm.isModuleLoading('c'));
assertTrue('execCalled1 should be set', execCalled5);
assertFalse('ModuleManager should not be active', mm.isActive());
assertFalse(
'ModuleManager should not be user active', mm.isUserActive());
// When module is already loaded, execOnLoad is still synchronous when
// so specified
var execCalled6 = false;
mm.execOnLoad('c', function() { execCalled6 = true; },
undefined, undefined, undefined, true);
assertTrue('module "c" should be loaded', mm.isModuleLoaded('c'));
assertFalse(
'module "c" should not be loading', mm.isModuleLoading('c'));
assertTrue('execCalled6 should be set', execCalled6);
clock.tick(5);
assertTrue('execCalled6 should still be set', execCalled6);
}
/**
* Test aborting the callback called on module load.
*/
function testExecOnLoadAbort() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
// When module is unloaded and abort is called, module still gets
// loaded, but callback is cancelled.
var execCalled1 = false;
var callback1 = mm.execOnLoad('b', function() { execCalled1 = true; });
callback1.abort();
clock.tick(5);
assertTrue('module "b" should be loaded', mm.isModuleLoaded('b'));
assertFalse('execCalled3 should not be set', execCalled1);
// When module is already loaded, execOnLoad is still async, so calling
// abort should still cancel the callback.
var execCalled2 = false;
var callback2 = mm.execOnLoad('a', function() { execCalled2 = true; });
callback2.abort();
clock.tick(5);
assertFalse('execCalled2 should not be set', execCalled2);
}
/**
* Test preloading modules and ensure that the before load, after load
* and set load called are called only once per module.
*/
function testExecOnLoadWhilePreloadingAndViceVersa() {
var mm = getModuleManager({'c': [], 'd': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
execOnLoadWhilePreloadingAndViceVersa_(mm);
mm = getModuleManager({'c': [], 'd': []});
mm.setLoader(createSuccessfulBatchLoader(mm));
mm.setBatchModeEnabled(true);
execOnLoadWhilePreloadingAndViceVersa_(mm);
}
/**
* Perform tests with the specified module manager.
* @param {goog.module.ModuleManager} mm The module manager.
*/
function execOnLoadWhilePreloadingAndViceVersa_(mm) {
var mm = getModuleManager({'c': [], 'd': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var origSetLoaded = mm.setLoaded;
var calls = [0, 0, 0];
mm.beforeLoadModuleCode = function(id) {
calls[0]++;
};
mm.setLoaded = function(id) {
calls[1]++;
origSetLoaded.call(mm, id);
};
mm.afterLoadModuleCode = function(id) {
calls[2]++;
};
mm.preloadModule('c', 2);
assertFalse(
'module "c" should not be loading yet', mm.isModuleLoading('c'));
clock.tick(2);
assertTrue(
'module "c" should now be loading', mm.isModuleLoading('c'));
mm.execOnLoad('c', function() {});
assertTrue(
'module "c" should still be loading', mm.isModuleLoading('c'));
clock.tick(5);
assertFalse(
'module "c" should be done loading', mm.isModuleLoading('c'));
assertEquals(
'beforeLoad should only be called once for "c"', 1, calls[0]);
assertEquals(
'setLoaded should only be called once for "c"', 1, calls[1]);
assertEquals(
'afterLoad should only be called once for "c"', 1, calls[2]);
mm.execOnLoad('d', function() {});
assertTrue(
'module "d" should now be loading', mm.isModuleLoading('d'));
mm.preloadModule('d', 2);
clock.tick(5);
assertFalse(
'module "d" should be done loading', mm.isModuleLoading('d'));
assertTrue(
'module "d" should now be loaded', mm.isModuleLoaded('d'));
assertEquals(
'beforeLoad should only be called once for "d"', 2, calls[0]);
assertEquals(
'setLoaded should only be called once for "d"', 2, calls[1]);
assertEquals(
'afterLoad should only be called once for "d"', 2, calls[2]);
}
/**
* Tests loading a module by requesting a Deferred object.
*/
function testLoad() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var calledBack = false;
var error = null;
var d = mm.load('a');
d.addCallback(function(ctx) {
calledBack = true;
});
d.addErrback(function(err) {
error = err;
});
assertFalse(calledBack);
assertNull(error);
assertFalse(mm.isUserActive());
clock.tick(5);
assertTrue(calledBack);
assertNull(error);
}
/**
* Tests loading a module by user action by requesting a Deferred object.
*/
function testLoadForUser() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var calledBack = false;
var error = null;
var d = mm.load('a', true);
d.addCallback(function(ctx) {
calledBack = true;
});
d.addErrback(function(err) {
error = err;
});
assertFalse(calledBack);
assertNull(error);
assertTrue(mm.isUserActive());
clock.tick(5);
assertTrue(calledBack);
assertNull(error);
}
/**
* Tests that preloading a module calls back the deferred object.
*/
function testPreloadDeferredWhenNotLoaded() {
var mm = getModuleManager({'a': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var calledBack = false;
var d = mm.preloadModule('a');;
d.addCallback(function(ctx) {
calledBack = true;
});
// First load should take five ticks.
assertFalse('module "a" should not be loaded yet', calledBack);
clock.tick(5);
assertTrue('module "a" should be loaded', calledBack);
}
/**
* Tests preloading an already loaded module.
*/
function testPreloadDeferredWhenLoaded() {
var mm = getModuleManager({'a': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var calledBack = false;
mm.preloadModule('a');
clock.tick(5);
var d = mm.preloadModule('a');;
d.addCallback(function(ctx) {
calledBack = true;
});
// Module is already loaded, should be called back after the setTimeout
// in preloadModule.
assertFalse('deferred for module "a" should not be called yet', calledBack);
clock.tick(1);
assertTrue('module "a" should be loaded', calledBack);
}
/**
* Tests preloading a module that is currently loading.
*/
function testPreloadDeferredWhenLoading() {
var mm = getModuleManager({'a': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
mm.preloadModule('a');
clock.tick(1);
// 'b' is in the middle of loading, should get called back when it's done.
var calledBack = false;
var d = mm.preloadModule('a');;
d.addCallback(function(ctx) {
calledBack = true;
});
assertFalse('module "a" should not be loaded yet', calledBack);
clock.tick(4);
assertTrue('module "a" should be loaded', calledBack);
}
/**
* Tests that load doesn't trigger another load if a module is already
* preloading.
*/
function testLoadWhenPreloading() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var origSetLoaded = mm.setLoaded;
var calls = [0, 0, 0];
mm.beforeLoadModuleCode = function(id) {
calls[0]++;
};
mm.setLoaded = function(id) {
calls[1]++;
origSetLoaded.call(mm, id);
};
mm.afterLoadModuleCode = function(id) {
calls[2]++;
};
var calledBack = false;
var error = null;
mm.preloadModule('c', 2);
assertFalse(
'module "c" should not be loading yet', mm.isModuleLoading('c'));
clock.tick(2);
assertTrue(
'module "c" should now be loading', mm.isModuleLoading('c'));
var d = mm.load('c');
d.addCallback(function(ctx) {
calledBack = true;
});
d.addErrback(function(err) {
error = err;
});
assertTrue(
'module "c" should still be loading', mm.isModuleLoading('c'));
clock.tick(5);
assertFalse(
'module "c" should be done loading', mm.isModuleLoading('c'));
assertEquals(
'beforeLoad should only be called once for "c"', 1, calls[0]);
assertEquals(
'setLoaded should only be called once for "c"', 1, calls[1]);
assertEquals(
'afterLoad should only be called once for "c"', 1, calls[2]);
assertTrue(calledBack);
assertNull(error);
}
/**
* Tests loading a module via load when the module is already
* loaded. The deferred's callback should be called immediately.
*/
function testLoadWhenLoaded() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var calledBack = false;
var error = null;
mm.preloadModule('b', 2);
clock.tick(10);
assertFalse(
'module "b" should be done loading', mm.isModuleLoading('b'));
var d = mm.load('b');
d.addCallback(function(ctx) {
calledBack = true;
});
d.addErrback(function(err) {
error = err;
});
assertTrue(calledBack);
assertNull(error);
}
/**
* Tests that the deferred's errbacks are called if the module fails to load.
*/
function testLoadWithFailingModule() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createUnsuccessfulLoader(mm, 401));
mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR,
function(callbackType, id, cause) {
assertEquals('Failure cause was not as expected',
goog.module.ModuleManager.FailureType.UNAUTHORIZED,
cause);
firedLoadFailed = true;
});
var calledBack = false;
var error = null;
var d = mm.load('a');
d.addCallback(function(ctx) {
calledBack = true;
});
d.addErrback(function(err) {
error = err;
});
assertFalse(calledBack);
assertNull(error);
clock.tick(500);
assertFalse(calledBack);
// NOTE: Deferred always calls errbacks with an Error object. For now the
// module manager just passes the FailureType which gets set as the Error
// object's message.
assertEquals('Failure cause was not as expected',
goog.module.ModuleManager.FailureType.UNAUTHORIZED,
Number(error.message));
}
/**
* Test loading dependencies transitively.
*/
function testLoadingDepsInNonBatchMode1() {
var mm = getModuleManager({
'i': [],
'j': [],
'k': ['j'],
'l': ['i','j','k']});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
mm.preloadModule('j');
clock.tick(5);
assertTrue('module "j" should be loaded', mm.isModuleLoaded('j'));
assertFalse(
'module "i" should not be loaded (1)', mm.isModuleLoaded('i'));
assertFalse(
'module "k" should not be loaded (1)', mm.isModuleLoaded('k'));
assertFalse(
'module "l" should not be loaded (1)', mm.isModuleLoaded('l'));
// When loading a module in non-batch mode, its dependencies should be
// requested independently, and in dependency order.
mm.preloadModule('l');
clock.tick(5);
assertTrue('module "i" should be loaded', mm.isModuleLoaded('i'));
assertFalse(
'module "k" should not be loaded (2)', mm.isModuleLoaded('k'));
assertFalse(
'module "l" should not be loaded (2)', mm.isModuleLoaded('l'));
clock.tick(5);
assertTrue('module "k" should be loaded', mm.isModuleLoaded('k'));
assertFalse(
'module "l" should not be loaded (3)', mm.isModuleLoaded('l'));
clock.tick(5);
assertTrue(
'module "l" should be loaded', mm.isModuleLoaded('l'));
}
/**
* Test loading dependencies transitively and in dependency order.
*/
function testLoadingDepsInNonBatchMode2() {
var mm = getModuleManager({
'h': [],
'i': ['h'],
'j': ['i'],
'k': ['j'],
'l': ['i','j','k'],
'm': ['l']});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
// When loading a module in non-batch mode, its dependencies should be
// requested independently, and in dependency order. The order in this
// case should be h,i,j,k,l,m.
mm.preloadModule('m');
clock.tick(5);
assertTrue('module "h" should be loaded', mm.isModuleLoaded('h'));
assertFalse(
'module "i" should not be loaded (1)', mm.isModuleLoaded('i'));
assertFalse(
'module "j" should not be loaded (1)', mm.isModuleLoaded('j'));
assertFalse(
'module "k" should not be loaded (1)', mm.isModuleLoaded('k'));
assertFalse(
'module "l" should not be loaded (1)', mm.isModuleLoaded('l'));
assertFalse(
'module "m" should not be loaded (1)', mm.isModuleLoaded('m'));
clock.tick(5);
assertTrue('module "i" should be loaded', mm.isModuleLoaded('i'));
assertFalse(
'module "j" should not be loaded (2)', mm.isModuleLoaded('j'));
assertFalse(
'module "k" should not be loaded (2)', mm.isModuleLoaded('k'));
assertFalse(
'module "l" should not be loaded (2)', mm.isModuleLoaded('l'));
assertFalse(
'module "m" should not be loaded (2)', mm.isModuleLoaded('m'));
clock.tick(5);
assertTrue('module "j" should be loaded', mm.isModuleLoaded('j'));
assertFalse(
'module "k" should not be loaded (3)', mm.isModuleLoaded('k'));
assertFalse(
'module "l" should not be loaded (3)', mm.isModuleLoaded('l'));
assertFalse(
'module "m" should not be loaded (3)', mm.isModuleLoaded('m'));
clock.tick(5);
assertTrue('module "k" should be loaded', mm.isModuleLoaded('k'));
assertFalse(
'module "l" should not be loaded (4)', mm.isModuleLoaded('l'));
assertFalse(
'module "m" should not be loaded (4)', mm.isModuleLoaded('m'));
clock.tick(5);
assertTrue('module "l" should be loaded', mm.isModuleLoaded('l'));
assertFalse(
'module "m" should not be loaded (5)', mm.isModuleLoaded('m'));
clock.tick(5);
assertTrue('module "m" should be loaded', mm.isModuleLoaded('m'));
}
function testLoadingDepsInBatchMode() {
var mm = getModuleManager({
'e': [],
'f': [],
'g': ['f'],
'h': ['e','f','g']});
mm.setLoader(createSuccessfulBatchLoader(mm));
mm.setBatchModeEnabled(true);
mm.preloadModule('f');
clock.tick(5);
assertTrue('module "f" should be loaded', mm.isModuleLoaded('f'));
assertFalse(
'module "e" should not be loaded (1)', mm.isModuleLoaded('e'));
assertFalse(
'module "g" should not be loaded (1)', mm.isModuleLoaded('g'));
assertFalse(
'module "h" should not be loaded (1)', mm.isModuleLoaded('h'));
// When loading a module in batch mode, its not-yet-loaded dependencies
// should be requested at the same time, and in dependency order.
mm.preloadModule('h');
clock.tick(5);
assertTrue('module "e" should be loaded', mm.isModuleLoaded('e'));
assertFalse(
'module "g" should not be loaded (2)', mm.isModuleLoaded('g'));
assertFalse(
'module "h" should not be loaded (2)', mm.isModuleLoaded('h'));
clock.tick(2);
assertTrue(
'module "g" should be loaded', mm.isModuleLoaded('g'));
assertFalse(
'module "h" should not be loaded (3)', mm.isModuleLoaded('h'));
clock.tick(2);
assertTrue(
'module "h" should be loaded', mm.isModuleLoaded('h'));
}
/**
* Test unauthorized errors while loading modules.
*/
function testUnauthorizedLoading() {
var mm = getModuleManager({
'm': [],
'n': [],
'o': ['n']});
mm.setLoader(createUnsuccessfulLoader(mm, 401));
// Callback checks for an unauthorized error
var firedLoadFailed = false;
mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR,
function(callbackType, id, cause) {
assertEquals('Failure cause was not as expected',
goog.module.ModuleManager.FailureType.UNAUTHORIZED,
cause);
firedLoadFailed = true;
});
mm.execOnLoad('o', function() {});
assertTrue('module "o" should be loading', mm.isModuleLoading('o'));
assertTrue('module "n" should be loading', mm.isModuleLoading('n'));
clock.tick(5);
assertTrue(
'should have called unauthorized module callback', firedLoadFailed);
assertFalse(
'module "o" should not be loaded', mm.isModuleLoaded('o'));
assertFalse(
'module "o" should not be loading', mm.isModuleLoading('o'));
assertFalse(
'module "n" should not be loaded', mm.isModuleLoaded('n'));
assertFalse(
'module "n" should not be loading', mm.isModuleLoading('n'));
}
/**
* Test error loading modules which are retried.
*/
function testErrorLoadingModule() {
var mm = getModuleManager({
'p': ['q'],
'q': [],
'r': ['q','p']});
mm.setLoader(createUnsuccessfulLoader(mm, 500));
mm.preloadModule('r');
clock.tick(4);
// A module request is now underway using the unsuccessful loader.
// We substitute a successful loader for future module load requests.
mm.setLoader(createSuccessfulNonBatchLoader(mm));
clock.tick(1);
assertFalse(
'module "q" should not be loaded (1)', mm.isModuleLoaded('q'));
assertFalse(
'module "p" should not be loaded (1)', mm.isModuleLoaded('p'));
assertFalse(
'module "r" should not be loaded (1)', mm.isModuleLoaded('r'));
// Failed loads are automatically retried.
clock.tick(5);
assertTrue('module "q" should be loaded', mm.isModuleLoaded('q'));
assertFalse(
'module "p" should not be loaded (2)', mm.isModuleLoaded('p'));
assertFalse(
'module "r" should not be loaded (2)', mm.isModuleLoaded('r'));
clock.tick(5);
assertTrue('module "p" should be loaded', mm.isModuleLoaded('p'));
assertFalse(
'module "r" should not be loaded (3)', mm.isModuleLoaded('r'));
clock.tick(5);
assertTrue(
'module "r" should be loaded', mm.isModuleLoaded('r'));
}
/**
* Test consecutive errors in loading modules.
*/
function testConsecutiveErrors() {
var mm = getModuleManager({'s': []});
mm.setLoader(createUnsuccessfulLoader(mm, 500));
// Register an error callback for consecutive failures.
var firedLoadFailed = false;
mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR,
function(callbackType, id, cause) {
assertEquals('Failure cause was not as expected',
goog.module.ModuleManager.FailureType.CONSECUTIVE_FAILURES,
cause);
firedLoadFailed = true;
});
mm.preloadModule('s');
assertFalse(
'module "s" should not be loaded (0)', mm.isModuleLoaded('s'));
// Fail twice.
for (var i = 0; i < 2; i++) {
clock.tick(5);
assertFalse(
'module "s" should not be loaded (1)', mm.isModuleLoaded('s'));
assertFalse(
'should not fire failed callback (1)', firedLoadFailed);
}
// Fail a third time and check that the callback is fired.
clock.tick(5);
assertFalse(
'module "s" should not be loaded (2)', mm.isModuleLoaded('s'));
assertTrue(
'should have fired failed callback', firedLoadFailed);
// Check that it doesn't attempt to load the module anymore after it has
// failed.
var triedLoad = false;
mm.setLoader({
loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn) {
triedLoad = true;
}});
// Also reset the failed callback flag and make sure it isn't called
// again.
firedLoadFailed = false;
clock.tick(10);
assertFalse(
'module "s" should not be loaded (3)', mm.isModuleLoaded('s'));
assertFalse('No more loads should have been tried', triedLoad);
assertFalse('The load failed callback should be fired only once',
firedLoadFailed);
}
/**
* Test loading errors due to old code.
*/
function testOldCodeGoneError() {
var mm = getModuleManager({'s': []});
mm.setLoader(createUnsuccessfulLoader(mm, 410));
// Callback checks for an old code failure
var firedLoadFailed = false;
mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR,
function(callbackType, id, cause) {
assertEquals('Failure cause was not as expected',
goog.module.ModuleManager.FailureType.OLD_CODE_GONE,
cause);
firedLoadFailed = true;
});
mm.preloadModule('s', 0);
assertFalse(
'module "s" should not be loaded (0)', mm.isModuleLoaded('s'));
clock.tick(5);
assertFalse(
'module "s" should not be loaded (1)', mm.isModuleLoaded('s'));
assertTrue(
'should have called old code gone callback', firedLoadFailed);
}
/**
* Test timeout.
*/
function testTimeout() {
var mm = getModuleManager({'s': []});
mm.setLoader(createTimeoutLoader(mm));
// Callback checks for timeout
var firedTimeout = false;
mm.registerCallback(goog.module.ModuleManager.CallbackType.ERROR,
function(callbackType, id, cause) {
assertEquals('Failure cause was not as expected',
goog.module.ModuleManager.FailureType.TIMEOUT,
cause);
firedTimeout = true;
});
mm.preloadModule('s', 0);
assertFalse(
'module "s" should not be loaded (0)', mm.isModuleLoaded('s'));
clock.tick(5);
assertFalse(
'module "s" should not be loaded (1)', mm.isModuleLoaded('s'));
assertTrue(
'should have called timeout callback', firedTimeout);
}
/**
* Make sure ModuleInfo objects in moduleInfoMap_ get disposed.
*/
function testDispose() {
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
var moduleInfoA = mm.getModuleInfo('a');
assertNotNull(moduleInfoA);
var moduleInfoB = mm.getModuleInfo('b');
assertNotNull(moduleInfoB);
var moduleInfoC = mm.getModuleInfo('c');
assertNotNull(moduleInfoC);
mm.dispose();
assertTrue(moduleInfoA.isDisposed());
assertTrue(moduleInfoB.isDisposed());
assertTrue(moduleInfoC.isDisposed());
}
function testDependencyOrderingWithSimpleDeps() {
var mm = getModuleManager({
'a': ['b', 'c'],
'b': ['d'],
'c': ['e', 'f'],
'd': [],
'e': [],
'f': []
});
var ids = mm.getNotYetLoadedTransitiveDepIds_('a');
assertDependencyOrder(ids, mm);
assertArrayEquals(['d', 'e', 'f', 'b', 'c', 'a'], ids);
}
function testDependencyOrderingWithCommonDepsInDeps() {
// Tests to make sure that if dependencies of the root are loaded before
// their common dependencies.
var mm = getModuleManager({
'a': ['b', 'c'],
'b': ['d'],
'c': ['d'],
'd': []
});
var ids = mm.getNotYetLoadedTransitiveDepIds_('a');
assertDependencyOrder(ids, mm);
assertArrayEquals(['d', 'b', 'c', 'a'], ids);
}
function testDependencyOrderingWithCommonDepsInRoot1() {
// Tests the case where a dependency of the root depends on another
// dependency of the root. Irregardless of ordering in the root's
// deps.
var mm = getModuleManager({
'a': ['b', 'c'],
'b': ['c'],
'c': []
});
var ids = mm.getNotYetLoadedTransitiveDepIds_('a');
assertDependencyOrder(ids, mm);
assertArrayEquals(['c', 'b', 'a'], ids);
}
function testDependencyOrderingWithCommonDepsInRoot2() {
// Tests the case where a dependency of the root depends on another
// dependency of the root. Irregardless of ordering in the root's
// deps.
var mm = getModuleManager({
'a': ['b', 'c'],
'b': [],
'c': ['b']
});
var ids = mm.getNotYetLoadedTransitiveDepIds_('a');
assertDependencyOrder(ids, mm);
assertArrayEquals(['b', 'c', 'a'], ids);
}
function testDependencyOrderingWithGmailExample() {
// Real dependency graph taken from gmail.
var mm = getModuleManager({
's': ['dp', 'ml', 'md'],
'dp': ['a'],
'ml': ['ld', 'm'],
'ld': ['a'],
'm': ['ad', 'mh', 'n'],
'md': ['mh', 'ld'],
'a': [],
'mh': [],
'ad': [],
'n': []
});
mm.setLoaded('a');
mm.setLoaded('m');
mm.setLoaded('n');
mm.setLoaded('ad');
mm.setLoaded('mh');
var ids = mm.getNotYetLoadedTransitiveDepIds_('s');
assertDependencyOrder(ids, mm);
assertArrayEquals(['ld', 'dp', 'ml', 'md', 's'], ids);
}
function assertDependencyOrder(list, mm) {
var seen = {};
for (var i = 0; i < list.length; i++) {
var id = list[i];
seen[id] = true;
var deps = mm.getModuleInfo(id).getDependencies();
for (var j = 0; j < deps.length; j++) {
var dep = deps[j];
assertTrue('Unresolved dependency [' + dep + '] for [' + id + '].',
seen[dep] || mm.getModuleInfo(dep).isLoaded());
}
}
}
function testRegisterInitializationCallback() {
var initCalled = 0;
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
mm.setLoader(createSuccessfulNonBatchLoaderWithRegisterInitCallback(mm,
function() {
++initCalled;
}));
execOnLoad_(mm);
// execOnLoad_ loads modules a and c
assertTrue(initCalled == 2);
}
function createSuccessfulNonBatchLoaderWithRegisterInitCallback(
moduleMgr, fn) {
return {
loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn,
opt_timeoutFn) {
moduleMgr.beforeLoadModuleCode(ids[0]);
moduleMgr.registerInitializationCallback(fn);
setTimeout(function() {
moduleMgr.setLoaded(ids[0]);
moduleMgr.afterLoadModuleCode(ids[0]);
if (opt_successFn) {
opt_successFn();
}
}, 5);
}};
}
function testSetModuleConstructor() {
var initCalled = 0;
var mm = getModuleManager({'a': [], 'b': [], 'c': []});
var info = {
'a': { ctor: AModule, count: 0 },
'b': { ctor: BModule, count: 0 },
'c': { ctor: CModule, count: 0 }
};
function AModule() {
++info['a'].count;
goog.module.BaseModule.call(this);
}
goog.inherits(AModule, goog.module.BaseModule);
function BModule() {
++info['b'].count;
goog.module.BaseModule.call(this);
}
goog.inherits(BModule, goog.module.BaseModule);
function CModule() {
++info['c'].count;
goog.module.BaseModule.call(this);
}
goog.inherits(CModule, goog.module.BaseModule);
mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor(mm, info));
execOnLoad_(mm);
assertTrue(info['a'].count == 1);
assertTrue(info['b'].count == 0);
assertTrue(info['c'].count == 1);
assertTrue(mm.getModuleInfo('a').getModule() instanceof AModule);
assertTrue(mm.getModuleInfo('c').getModule() instanceof CModule);
}
/**
* Tests that a call to load the loading module during module initialization
* doesn't trigger a second load.
*/
function testLoadWhenInitializing() {
var mm = getModuleManager({'a': []});
mm.setLoader(createSuccessfulNonBatchLoader(mm));
var info = {
'a': { ctor: AModule, count: 0 }
};
function AModule() {
++info['a'].count;
goog.module.BaseModule.call(this);
}
goog.inherits(AModule, goog.module.BaseModule);
AModule.prototype.initialize = function() {
mm.load('a');
};
mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor(mm, info));
mm.preloadModule('a');
clock.tick(5);
assertEquals(info['a'].count, 1);
}
function testErrorInEarlyCallback() {
var errback = goog.testing.recordFunction();
var callback = goog.testing.recordFunction();
var mm = getModuleManager({'a': [], 'b': ['a']});
mm.getModuleInfo('a').registerEarlyCallback(goog.functions.error('error'));
mm.getModuleInfo('a').registerCallback(callback);
mm.getModuleInfo('a').registerErrback(errback);
mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor(
mm, createModulesFor('a', 'b')));
mm.preloadModule('b');
clock.tick(5);
assertEquals(1, callback.getCallCount());
assertEquals(1, errback.getCallCount());
assertEquals(goog.module.ModuleManager.FailureType.INIT_ERROR,
errback.getLastCall().getArguments()[0]);
assertTrue(mm.getModuleInfo('a').isLoaded());
assertFalse(mm.getModuleInfo('b').isLoaded());
clock.tick(5);
assertTrue(mm.getModuleInfo('b').isLoaded());
}
function testErrorInNormalCallback() {
var earlyCallback = goog.testing.recordFunction();
var errback = goog.testing.recordFunction();
var mm = getModuleManager({'a': [], 'b': ['a']});
mm.getModuleInfo('a').registerEarlyCallback(earlyCallback);
mm.getModuleInfo('a').registerEarlyCallback(goog.functions.error('error'));
mm.getModuleInfo('a').registerErrback(errback);
mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor(
mm, createModulesFor('a', 'b')));
mm.preloadModule('b');
clock.tick(10);
assertEquals(1, errback.getCallCount());
assertEquals(goog.module.ModuleManager.FailureType.INIT_ERROR,
errback.getLastCall().getArguments()[0]);
assertTrue(mm.getModuleInfo('a').isLoaded());
assertTrue(mm.getModuleInfo('b').isLoaded());
}
function testErrorInErrback() {
var mm = getModuleManager({'a': [], 'b': ['a']});
mm.getModuleInfo('a').registerCallback(goog.functions.error('error1'));
mm.getModuleInfo('a').registerErrback(goog.functions.error('error2'));
mm.setLoader(createSuccessfulNonBatchLoaderWithConstructor(
mm, createModulesFor('a', 'b')));
mm.preloadModule('a');
try {
clock.tick(10);
} catch (e) {
assertContains('Module errback failure', e.message);
if (!goog.userAgent.IE) {
assertContains('error2', e.message);
}
}
assertTrue(mm.getModuleInfo('a').isLoaded());
}
function createModulesFor(var_args) {
var result = {};
for (var i = 0; i < arguments.length; i++) {
var key = arguments[i];
result[key] = {ctor: goog.module.BaseModule};
}
return result;
}
function createSuccessfulNonBatchLoaderWithConstructor(moduleMgr, info) {
return {
loadModules: function(ids, moduleInfoMap, opt_successFn, opt_errFn,
opt_timeoutFn) {
setTimeout(function() {
moduleMgr.beforeLoadModuleCode(ids[0]);
moduleMgr.setModuleConstructor(info[ids[0]].ctor);
moduleMgr.setLoaded(ids[0]);
moduleMgr.afterLoadModuleCode(ids[0]);
if (opt_successFn) {
opt_successFn();
}
}, 5);
}};
}
function testInitCallbackInBaseModule() {
var mm = new goog.module.ModuleManager();
var called = false;
var context;
mm.registerInitializationCallback(function(mcontext) {
called = true;
context = mcontext;
});
mm.setAllModuleInfo({'a': [], 'b': ['a']});
assertTrue('Base initialization not called', called);
assertNull('Context should still be null', context);
var mm = new goog.module.ModuleManager();
called = false;
mm.registerInitializationCallback(function(mcontext) {
called = true;
context = mcontext;
});
var appContext = {};
mm.setModuleContext(appContext);
assertTrue('Base initialization not called after setModuleContext', called);
assertEquals('Did not receive module context', appContext, context);
}
</script>
</body>
</html>