diff options
author | garykac <garykac@chromium.org> | 2015-03-31 11:31:39 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-31 18:32:26 +0000 |
commit | 2683fe7e0cdc04c01afb870817116b8d62a355ca (patch) | |
tree | 9d00e4bab3a936803b7604b7bdafb4037c767ad7 /remoting | |
parent | 3074045136e6a83a08de513e847c68ccfb71e4dd (diff) | |
download | chromium_src-2683fe7e0cdc04c01afb870817116b8d62a355ca.zip chromium_src-2683fe7e0cdc04c01afb870817116b8d62a355ca.tar.gz chromium_src-2683fe7e0cdc04c01afb870817116b8d62a355ca.tar.bz2 |
[Chromoting] Fix base.inherits so parent methods can be used in parent ctor.
The current code calls the parent constructor before merging in the parent
prototypes. This means that when a child is created, the parent methods
aren't available in the parent ctor the first time that object is created.
Also, the base.inherits tests set up the Parent, Child and GrandChild
classes once before any tests are run. This means that the objects are
global and that the prototype chain for the parent is "fixed" the first time
a child object of that type is created. To fix this, the Class setup is now
done in a setupTestClasses function.
BUG=465878
Review URL: https://codereview.chromium.org/1035363002
Cr-Commit-Position: refs/heads/master@{#323076}
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/webapp/base/js/base.js | 12 | ||||
-rw-r--r-- | remoting/webapp/base/js/base_inherits_unittest.js | 81 | ||||
-rw-r--r-- | remoting/webapp/js_proto/qunit_proto.js | 2 |
3 files changed, 58 insertions, 37 deletions
diff --git a/remoting/webapp/base/js/base.js b/remoting/webapp/base/js/base.js index 417979b..9257a86 100644 --- a/remoting/webapp/base/js/base.js +++ b/remoting/webapp/base/js/base.js @@ -165,13 +165,17 @@ base.extend = function(dest, src) { * * @param {*} childObject * @param {*} parentCtor - * @param {...} parentCtorAargs + * @param {...} parentCtorArgs * @suppress {checkTypes|reportUnknownTypes} */ -base.inherits = function(childObject, parentCtor, parentCtorAargs) { +base.inherits = function(childObject, parentCtor, parentCtorArgs) { base.debug.assert(parentCtor && parentCtor.prototype, 'Invalid parent constructor.'); var parentArgs = Array.prototype.slice.call(arguments, 2); + + // Mix in the parent's prototypes so that they're available during the parent + // ctor. + base.mix(childObject, parentCtor.prototype); parentCtor.apply(childObject, parentArgs); // Note that __proto__ is deprecated. @@ -179,10 +183,6 @@ base.inherits = function(childObject, parentCtor, parentCtorAargs) { // Global_Objects/Object/proto. // It is used so that childObject instanceof parentCtor will // return true. - // - // Alternatively, this could be implemented using mixins, e.g. - // base.mix(childObject, parentCtor.prototype); - // if we don't care about the correctness of instanceof in the future. childObject.__proto__.__proto__ = parentCtor.prototype; base.debug.assert(childObject instanceof parentCtor); }; diff --git a/remoting/webapp/base/js/base_inherits_unittest.js b/remoting/webapp/base/js/base_inherits_unittest.js index baa5b6f..32df103 100644 --- a/remoting/webapp/base/js/base_inherits_unittest.js +++ b/remoting/webapp/base/js/base_inherits_unittest.js @@ -2,18 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -(function() { - 'use strict'; -QUnit.module('base.inherits'); +QUnit.module('base.inherits', { + beforeEach: function() { + base_inherits.setupTestClasses(); + } +}); + +var base_inherits = {}; + +base_inherits.setupTestClasses = function() { /** * @constructor - * @extends {ChildClass} + * @extends {base_inherits.ChildClass} */ -var GrandChildClass = function() { - base.inherits(this, ChildClass); +base_inherits.GrandChildClass = function() { + base.inherits(this, base_inherits.ChildClass); this.name = 'grandChild'; } @@ -21,16 +27,16 @@ var GrandChildClass = function() { * @param {string} arg * @return {string} */ -GrandChildClass.prototype.overrideMethod = function(arg) { +base_inherits.GrandChildClass.prototype.overrideMethod = function(arg) { return 'overrideMethod - grandChild - ' + arg; } /** * @constructor - * @extends {ParentClass} + * @extends {base_inherits.ParentClass} */ -var ChildClass = function() { - base.inherits(this, ParentClass, 'parentArg'); +base_inherits.ChildClass = function() { + base.inherits(this, base_inherits.ParentClass, 'parentArg'); this.name = 'child'; this.childOnly = 'childOnly'; } @@ -39,12 +45,12 @@ var ChildClass = function() { * @param {string} arg * @return {string} */ -ChildClass.prototype.overrideMethod = function(arg) { +base_inherits.ChildClass.prototype.overrideMethod = function(arg) { return 'overrideMethod - child - ' + arg; } /** @return {string} */ -ChildClass.prototype.childMethod = function() { +base_inherits.ChildClass.prototype.childMethod = function() { return 'childMethod'; } @@ -52,17 +58,21 @@ ChildClass.prototype.childMethod = function() { * @param {string} arg * @constructor */ -var ParentClass = function(arg) { +base_inherits.ParentClass = function(arg) { /** @type {string} */ this.name = 'parent'; /** @type {string} */ this.parentOnly = 'parentOnly'; /** @type {string} */ this.parentConstructorArg = arg; + + // Record the parent method so that we can ensure that it is available in + // the parent constructor regardless of what type of object |this| points to. + this.parentMethodDuringCtor = this.parentMethod; } /** @return {string} */ -ParentClass.prototype.parentMethod = function() { +base_inherits.ParentClass.prototype.parentMethod = function() { return 'parentMethod'; } @@ -70,34 +80,36 @@ ParentClass.prototype.parentMethod = function() { * @param {string} arg * @return {string} */ -ParentClass.prototype.overrideMethod = function(arg) { +base_inherits.ParentClass.prototype.overrideMethod = function(arg) { return 'overrideMethod - parent - ' + arg; } +}; + QUnit.test('should invoke parent constructor with the correct arguments', function(assert) { - var child = new ChildClass(); + var child = new base_inherits.ChildClass(); assert.equal(child.parentConstructorArg, 'parentArg'); }); QUnit.test('should preserve parent property and method', function(assert) { - var child = new ChildClass(); + var child = new base_inherits.ChildClass(); assert.equal(child.parentOnly, 'parentOnly'); assert.equal(child.parentMethod(), 'parentMethod'); }); QUnit.test('should preserve instanceof', function(assert) { - var child = new ChildClass(); - var grandChild = new GrandChildClass(); - assert.ok(child instanceof ParentClass); - assert.ok(child instanceof ChildClass); - assert.ok(grandChild instanceof ParentClass); - assert.ok(grandChild instanceof ChildClass); - assert.ok(grandChild instanceof GrandChildClass); + var child = new base_inherits.ChildClass(); + var grandChild = new base_inherits.GrandChildClass(); + assert.ok(child instanceof base_inherits.ParentClass); + assert.ok(child instanceof base_inherits.ChildClass); + assert.ok(grandChild instanceof base_inherits.ParentClass); + assert.ok(grandChild instanceof base_inherits.ChildClass); + assert.ok(grandChild instanceof base_inherits.GrandChildClass); }); QUnit.test('should override parent property and method', function(assert) { - var child = new ChildClass(); + var child = new base_inherits.ChildClass(); assert.equal(child.name, 'child'); assert.equal(child.overrideMethod('123'), 'overrideMethod - child - 123'); assert.equal(child.childOnly, 'childOnly'); @@ -105,7 +117,7 @@ QUnit.test('should override parent property and method', function(assert) { }); QUnit.test('should work on an inheritance chain', function(assert) { - var grandChild = new GrandChildClass(); + var grandChild = new base_inherits.GrandChildClass(); assert.equal(grandChild.name, 'grandChild'); assert.equal(grandChild.overrideMethod('246'), 'overrideMethod - grandChild - 246'); @@ -116,16 +128,25 @@ QUnit.test('should work on an inheritance chain', function(assert) { }); QUnit.test('should be able to access parent class methods', function(assert) { - var grandChild = new GrandChildClass(); + var grandChild = new base_inherits.GrandChildClass(); assert.equal(grandChild.overrideMethod('789'), 'overrideMethod - grandChild - 789'); - var childMethod = ChildClass.prototype.overrideMethod.call(grandChild, '81'); + var childMethod = base_inherits.ChildClass.prototype.overrideMethod. + call(grandChild, '81'); assert.equal(childMethod, 'overrideMethod - child - 81'); - var parentMethod = ParentClass.prototype.overrideMethod.call(grandChild, '4'); + var parentMethod = base_inherits.ParentClass.prototype.overrideMethod. + call(grandChild, '4'); assert.equal(parentMethod, 'overrideMethod - parent - 4'); }); -})(); +QUnit.test('parent ctor should have access to parent methods', + function(assert) { + var child = new base_inherits.ChildClass(); + assert.ok(child.parentMethodDuringCtor); + + var parent = new base_inherits.ParentClass('blah'); + assert.ok(parent.parentMethodDuringCtor); +}); diff --git a/remoting/webapp/js_proto/qunit_proto.js b/remoting/webapp/js_proto/qunit_proto.js index 33b30f7..274282b 100644 --- a/remoting/webapp/js_proto/qunit_proto.js +++ b/remoting/webapp/js_proto/qunit_proto.js @@ -43,7 +43,7 @@ QUnit.Assert.prototype.async = function() {}; QUnit.Assert.prototype.notEqual = function(a, b, opt_desc) {}; /** - * @param {boolean} cond + * @param {*} cond Passes if cond is truthy. * @param {string=} desc * @return {boolean} */ |