Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit d71f16e

Browse files
shahatacaitp
authored andcommitted
fix(injector): allow multiple loading of function modules
Change HashMap to give $$hashKey also for functions so it will be possible to load multiple module function instances. In order to prevent problem in angular's test suite, added an option to HashMap to maintain its own id counter and added cleanup of $$hashKey from all module functions after each test. Before this CL, functions were added to the HashMap via toString(), which could potentially return the same value for different actual instances of a function. This corrects this behaviour by ensuring that functions are mapped with hashKeys, and ensuring that hashKeys are removed from functions and objects at the end of tests. In addition to these changes, the injector uses its own set of UIDs in order to prevent confusingly breaking tests which expect scopes or ng-repeated items to have specific hash keys. Closes #7255
1 parent ed59370 commit d71f16e

File tree

6 files changed

+90
-8
lines changed

6 files changed

+90
-8
lines changed

src/apis.js

+13-7
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
* @returns {string} hash string such that the same input will have the same hash string.
1414
* The resulting string key is in 'type:hashKey' format.
1515
*/
16-
function hashKey(obj) {
16+
function hashKey(obj, nextUidFn) {
1717
var objType = typeof obj,
1818
key;
1919

20-
if (objType == 'object' && obj !== null) {
20+
if (objType == 'function' || (objType == 'object' && obj !== null)) {
2121
if (typeof (key = obj.$$hashKey) == 'function') {
2222
// must invoke on object to keep the right this
2323
key = obj.$$hashKey();
2424
} else if (key === undefined) {
25-
key = obj.$$hashKey = nextUid();
25+
key = obj.$$hashKey = (nextUidFn || nextUid)();
2626
}
2727
} else {
2828
key = obj;
@@ -34,7 +34,13 @@ function hashKey(obj) {
3434
/**
3535
* HashMap which can use objects as keys
3636
*/
37-
function HashMap(array){
37+
function HashMap(array, isolatedUid) {
38+
if (isolatedUid) {
39+
var uid = 0;
40+
this.nextUid = function() {
41+
return ++uid;
42+
};
43+
}
3844
forEach(array, this.put, this);
3945
}
4046
HashMap.prototype = {
@@ -44,23 +50,23 @@ HashMap.prototype = {
4450
* @param value value to store can be any type
4551
*/
4652
put: function(key, value) {
47-
this[hashKey(key)] = value;
53+
this[hashKey(key, this.nextUid)] = value;
4854
},
4955

5056
/**
5157
* @param key
5258
* @returns {Object} the value for the key
5359
*/
5460
get: function(key) {
55-
return this[hashKey(key)];
61+
return this[hashKey(key, this.nextUid)];
5662
},
5763

5864
/**
5965
* Remove the key/value pair
6066
* @param key
6167
*/
6268
remove: function(key) {
63-
var value = this[key = hashKey(key)];
69+
var value = this[key = hashKey(key, this.nextUid)];
6470
delete this[key];
6571
return value;
6672
}

src/auto/injector.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ function createInjector(modulesToLoad) {
591591
var INSTANTIATING = {},
592592
providerSuffix = 'Provider',
593593
path = [],
594-
loadedModules = new HashMap(),
594+
loadedModules = new HashMap([], true),
595595
providerCache = {
596596
$provide: {
597597
provider: supportObject(provider),

src/ngMock/angular-mocks.js

+6
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,12 @@ if(window.jasmine || window.mocha) {
19581958
(window.afterEach || window.teardown)(function() {
19591959
var injector = currentSpec.$injector;
19601960

1961+
angular.forEach(currentSpec.$modules, function(module) {
1962+
if (module && module.$$hashKey) {
1963+
module.$$hashKey = undefined;
1964+
}
1965+
});
1966+
19611967
currentSpec.$injector = null;
19621968
currentSpec.$modules = null;
19631969
currentSpec = null;

test/ApiSpecs.js

+30
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,36 @@ describe('api', function() {
2222
expect(map.get('b')).toBe(1);
2323
expect(map.get('c')).toBe(undefined);
2424
});
25+
26+
it('should maintain hashKey for object keys', function() {
27+
var map = new HashMap();
28+
var key = {};
29+
map.get(key);
30+
expect(key.$$hashKey).toBeDefined();
31+
});
32+
33+
it('should maintain hashKey for function keys', function() {
34+
var map = new HashMap();
35+
var key = function() {};
36+
map.get(key);
37+
expect(key.$$hashKey).toBeDefined();
38+
});
39+
40+
it('should share hashKey between HashMap by default', function() {
41+
var map1 = new HashMap(), map2 = new HashMap();
42+
var key1 = {}, key2 = {};
43+
map1.get(key1);
44+
map2.get(key2);
45+
expect(key1.$$hashKey).not.toEqual(key2.$$hashKey);
46+
});
47+
48+
it('should maintain hashKey per HashMap if flag is passed', function() {
49+
var map1 = new HashMap([], true), map2 = new HashMap([], true);
50+
var key1 = {}, key2 = {};
51+
map1.get(key1);
52+
map2.get(key2);
53+
expect(key1.$$hashKey).toEqual(key2.$$hashKey);
54+
});
2555
});
2656
});
2757

test/auto/injectorSpec.js

+23
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,29 @@ describe('injector', function() {
293293
expect(log).toEqual('abc');
294294
});
295295

296+
it('should load different instances of dependent functions', function() {
297+
function generateValueModule(name, value) {
298+
return function ($provide) {
299+
$provide.value(name, value);
300+
};
301+
}
302+
var injector = createInjector([generateValueModule('name1', 'value1'),
303+
generateValueModule('name2', 'value2')]);
304+
expect(injector.get('name2')).toBe('value2');
305+
});
306+
307+
it('should load same instance of dependent function only once', function() {
308+
var count = 0;
309+
function valueModule($provide) {
310+
count++;
311+
$provide.value('name', 'value');
312+
}
313+
314+
var injector = createInjector([valueModule, valueModule]);
315+
expect(injector.get('name')).toBe('value');
316+
expect(count).toBe(1);
317+
});
318+
296319
it('should execute runBlocks after injector creation', function() {
297320
var log = '';
298321
angular.module('a', [], function(){ log += 'a'; }).run(function() { log += 'A'; });

test/ngMock/angular-mocksSpec.js

+17
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,23 @@ describe('ngMock', function() {
805805
expect(example).toEqual('win');
806806
});
807807
});
808+
809+
describe('module cleanup', function() {
810+
function testFn() {
811+
812+
}
813+
814+
it('should add hashKey to module function', function() {
815+
module(testFn);
816+
inject(function () {
817+
expect(testFn.$$hashKey).toBeDefined();
818+
});
819+
});
820+
821+
it('should cleanup hashKey after previous test', function() {
822+
expect(testFn.$$hashKey).toBeUndefined();
823+
});
824+
});
808825
});
809826

810827
describe('in DSL', function() {

0 commit comments

Comments
 (0)