From b9ba6388d20eba0615a90f918c525efe1666acea Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Wed, 6 Aug 2014 23:06:13 -0400 Subject: [PATCH] Interface.isInstanceOf will account for interop compatibility This is a bug fix. If the provided object's constructor is an ease.js type, then the conventional rules will apply (as mentioned in the test docblock and in the manual); however, if it's just a vanilla ECMAScript object, then the interop compatibility checks will be used instead. The manual already states that this is the case; unfortunately, it lies---this was apparently overlooked, and is a bug. --- lib/interface.js | 2 +- test/Interface/InteropTest.js | 42 ++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/interface.js b/lib/interface.js index a8225c0..f3e9b5a 100644 --- a/lib/interface.js +++ b/lib/interface.js @@ -500,7 +500,7 @@ function _isInstanceOf( type, instance ) var meta; if ( !instance.__cid || !( meta = ClassBuilder.getMeta( proto ) ) ) { - return false; + return isCompat( type, instance ); } var implemented = meta.implemented, diff --git a/test/Interface/InteropTest.js b/test/Interface/InteropTest.js index 6740d09..ccfda98 100644 --- a/test/Interface/InteropTest.js +++ b/test/Interface/InteropTest.js @@ -23,7 +23,8 @@ require( 'common' ).testCase( { caseSetUp: function() { - this.Sut = this.require( 'interface' ); + this.Sut = this.require( 'interface' ); + this.Class = this.require( 'class' ); this.I = this.Sut( { @@ -34,11 +35,13 @@ require( 'common' ).testCase( this.assertICompat = function( I, inst ) { this.assertOk( I.isCompatible( inst ) ); + this.assertOk( this.Sut.isInstanceOf( I, inst ) ); }; this.assertNotICompat = function( I, inst ) { this.assertOk( !I.isCompatible( inst ) ); + this.assertOk( !this.Sut.isInstanceOf( I, inst ) ); }; }, @@ -165,5 +168,42 @@ require( 'common' ).testCase( this.assertICompat( I, obj ); }, + + + /** + * When an object is instantiated from an ease.js class, it does not + * matter if the interface is compatible: in order to be considered an + * instance some interface I, the instance's type must implement I; in + * this sense, ease.js' interface typing is strict, allowing *intent* to + * be conveyed. + * + * An example of why this is important can be found in the + * interoperability section of the manual. + */ + 'Objects can be compatible but not instances of interface': function() + { + // same API, different interface objects + var Ia = this.Sut( { foo: [] } ), + Ib = this.Sut( { foo: [] } ); + + var dfn = { foo: function() {} }, + Ca = this.Class.implement( Ia ).extend( dfn ), + Cb = this.Class.implement( Ib ).extend( dfn ); + + var ia = Ca(), + ib = Cb(); + + // clearly the two are compatible, regardless of their type + this.assertOk( Ia.isCompatible( ia ) ); + this.assertOk( Ia.isCompatible( ib ) ); + this.assertOk( Ib.isCompatible( ia ) ); + this.assertOk( Ib.isCompatible( ib ) ); + + // but ia is *not* an instance of Ib, nor ib of Ia + this.assertOk( this.Sut.isInstanceOf( Ia, ia ) ); + this.assertOk( !this.Sut.isInstanceOf( Ia, ib ) ); + this.assertOk( this.Sut.isInstanceOf( Ib, ib ) ); + this.assertOk( !this.Sut.isInstanceOf( Ib, ia ) ); + }, } );