diff --git a/test/Class/ExtendTest.js b/test/Class/ExtendTest.js
new file mode 100644
index 0000000..53a4951
--- /dev/null
+++ b/test/Class/ExtendTest.js
@@ -0,0 +1,431 @@
+/**
+ * Tests class module extend() method
+ *
+ * Copyright (C) 2010, 2011, 2013 Mike Gerwitz
+ *
+ * This file is part of GNU ease.js.
+ *
+ * ease.js is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Note that these tests all use the `new' keyword for instantiating
+ * classes, even though it is not required with ease.js; this is both for
+ * historical reasons (when `new' was required during early development) and
+ * because we are not testing (and do want to depend upon) that feature.
+ */
+
+require( 'common' ).testCase(
+{
+ caseSetUp: function()
+ {
+ this.test_props = {
+ one: 1,
+ two: 2,
+ };
+
+ this.Sut = this.require( 'class' );
+
+ // there are two different means of extending; we want to test them
+ // both (this will be denoted Foo)
+ this.classes = [
+ this.Sut.extend( this.test_props ),
+ this.Sut( this.test_props ),
+ ];
+ },
+
+
+ /**
+ * All classes can be easily extended via an extend method, although it
+ * is not necessarily recommended to be used directly, as you must
+ * ensure that the object is an ease.js class and the resulting class
+ * will be anonymous.
+ */
+ '@each(classes) Created class contains extend method': function( C )
+ {
+ this.assertOk( typeof C.extend === 'function' );
+ },
+
+
+ /**
+ * It would make sense that a subtype returned is an object, since it
+ * cannot be a class if it isn't.
+ */
+ '@each(classes) Subtype is returned as an object': function( C )
+ {
+ this.assertOk( C.extend() instanceof Object );
+ },
+
+
+ /**
+ * Subtypes should inherit all properties of the supertype into their
+ * prototype chain.
+ */
+ '@each(classes) Subtype inherits parent properties': function( C )
+ {
+ var SubFoo = C.extend();
+
+ for ( var prop in this.test_props )
+ {
+ this.assertEqual(
+ this.test_props[ prop ],
+ SubFoo.prototype[ prop ],
+ "Missing property: " + prop
+ );
+ }
+ },
+
+
+ /**
+ * A subtype should obvious contain the properties that were a part of
+ * its definition.
+ */
+ '@each(classes) Subtype contains its own properties': function( C )
+ {
+ var sub_props = {
+ three: 3,
+ four: 4,
+ };
+
+ var sub_foo = new C.extend( sub_props )();
+
+ // and ensure that the subtype's properties were included
+ for ( var prop in sub_props )
+ {
+ this.assertEqual(
+ sub_props[ prop ],
+ sub_foo[ prop ],
+ "Missing property: " + prop
+ );
+ }
+ },
+
+
+ /**
+ * In addition to the core functions provided by ease.js for checking
+ * instances, we try to ease into the protype model the best we can in
+ * order to work with other prototypes; therefore, instances should be
+ * recognized as instances of their parent classes even by the
+ * ECMAScript `instanceof' operator.
+ */
+ '@each(classes) Subtypes are ECMAScript instances of their supertypes':
+ function( C )
+ {
+ this.assertOk( C.extend()() instanceof C );
+ },
+
+
+ /**
+ * Even though this can be checked using the instanceof operator,
+ * ease.js has a more complex type system (e.g. supporting of
+ * interfaces) and so we want to provide a consistent alternative.
+ */
+ '@each(classes) Subtypes are easejs instances of their supertypes':
+ function( C )
+ {
+ var SubFoo = C.extend(),
+ sub_instance = new SubFoo();
+
+ this.assertOk( sub_instance.isInstanceOf( SubFoo ) );
+ },
+
+
+ /*
+ * Foo
+ * |
+ * SubFoo
+ * / \
+ * SubSubFoo SubSubFoo2
+ *
+ /
+
+ /**
+ * Objects should be considered instances of any classes that their
+ * instantiating class inherits from, since they inherit their API and
+ * are interchangable, provided that only the common subset of the API
+ * is used.
+ */
+ '@each(classes) Objects are instances of their super-supertypes':
+ function( C )
+ {
+ var sub_sub_instance = new ( C.extend().extend() )();
+
+ this.assertOk(
+ ( ( sub_sub_instance instanceof C )
+ && sub_sub_instance.isInstanceOf( C )
+ )
+ );
+ },
+
+
+ /**
+ * It would not make sense that an object is considered to be an
+ * instance of any possible subtypes---that is, if C inherits B, then an
+ * instance of B is not of type C; C could introduce an incompatible
+ * interface.
+ */
+ '@each(classes) Objects are not instances of subtypes': function( C )
+ {
+ var SubFoo = C.extend(),
+ SubSubFoo = SubFoo.extend(),
+ sub_inst = new SubFoo();
+
+ this.assertOk(
+ ( !( sub_inst instanceof SubSubFoo )
+ && !( sub_inst.isInstanceOf( SubSubFoo ) )
+ )
+ );
+ },
+
+
+ /**
+ * Two classes that inherit from a common parent are not compatible, as
+ * they can introduce their own distinct interfaces.
+ */
+ '@each(classes) Objects are not instances of sibling types':
+ function( C )
+ {
+ var SubFoo = C.extend(),
+ SubSubFoo = SubFoo.extend(),
+ SubSubFoo2 = SubFoo.extend(),
+
+ sub_sub2_inst = new SubSubFoo2();
+
+ this.assertOk(
+ ( !( sub_sub2_inst instanceof SubSubFoo )
+ && !( sub_sub2_inst.isInstanceOf( SubSubFoo ) )
+ )
+ );
+ },
+
+
+ /**
+ * We support extending existing prototypes (that is, inherit from
+ * constructors that were not created using ease.js).
+ */
+ 'Constructor prototype is copied to subclass': function()
+ {
+ var Ctor = function() {};
+ Ctor.prototype = { foo: {} };
+
+ this.assertStrictEqual(
+ this.Sut.extend( Ctor, {} ).prototype.foo,
+ Ctor.prototype.foo
+ );
+ },
+
+
+ /**
+ * This should go without saying---we're aiming for consistency here and
+ * subclassing doesn't make much sense if it doesn't work.
+ */
+ 'Subtype of constructor should contain extended members': function()
+ {
+ var Ctor = function() {};
+
+ this.assertNotEqual(
+ ( new this.Sut.extend( Ctor, { foo: {} } )() ).foo,
+ undefined
+ );
+ },
+
+
+ /**
+ * If a subtype provides a property of the same name as its parent, then
+ * it should act as a reassignment.
+ */
+ 'Subtypes can override parent property values': function()
+ {
+ var expect = 'ok',
+ C = this.Sut.extend( { p: null } ).extend( { p: expect } );
+
+ this.assertEqual( C().p, expect );
+ },
+
+
+ /**
+ * Prevent overriding the internal method that initializes property
+ * values upon instantiation.
+ */
+ '__initProps() cannot be declared (internal method)': function()
+ {
+ var _self = this;
+
+ this.assertThrows( function()
+ {
+ _self.Sut.extend(
+ {
+ __initProps: function() {},
+ } );
+ }, Error );
+ },
+
+
+ // TODO: move me into a more appropriate test case (this may actually be
+ // tested elsewhere)
+ /**
+ * If using the short-hand extend, an object is required to represent
+ * the class defintiion.
+ */
+ 'Invoking class module requires object as argument if extending':
+ function()
+ {
+ var _self = this;
+
+ // these tests can be run in the browser in pre-ES5 environments, so
+ // no forEach()
+ var chk = [ 5, false, undefined ],
+ i = chk.length;
+
+ while ( i-- )
+ {
+ this.assertThrows( function()
+ {
+ _self.Sut( chk[ i ] );
+ },
+ TypeError
+ );
+ }
+ },
+
+
+ /**
+ * We provide a useful default toString() method, but one may wish to
+ * override it
+ */
+ 'Can override toString() method': function()
+ {
+ var str = 'foomookittypoo',
+ result = ''
+ ;
+
+ result = this.Sut( 'FooToStr',
+ {
+ toString: function()
+ {
+ return str;
+ },
+ } )().toString();
+
+ this.assertEqual( result, str );
+ },
+
+
+ /**
+ * In ease.js's initial design, keywords were not included. This meant
+ * that duplicate member definitions were not possible---it'd throw a
+ * parse error (maybe). However, with keywords, it is now possible to
+ * redeclare a member with the same name in the same class definition.
+ * Since this doesn't make much sense, we must disallow it.
+ */
+ 'Cannot provide duplicate member definitions using unique keys':
+ function()
+ {
+ var _self = this;
+
+ this.assertThrows( function()
+ {
+ _self.Sut(
+ {
+ // declare as protected first so that we won't get a visibility
+ // de-escalation error with the below re-definition
+ 'protected foo': '',
+
+ // should fail; redefinition
+ 'public foo': '',
+ } );
+ }, Error );
+
+ this.assertThrows( function()
+ {
+ _self.Sut(
+ {
+ // declare as protected first so that we won't get a visibility
+ // de-escalation error with the below re-definition
+ 'protected foo': function() {},
+
+ // should fail; redefinition
+ 'public foo': function() {},
+ } );
+ }, Error );
+ },
+
+
+ /**
+ * To understand this test, one must understand how "inheritance" works
+ * with prototypes. We must create a new instance of the ctor (class)
+ * and add that instance to the prototype chain (if we added an
+ * un-instantiated constructor, then the members in the prototype would
+ * be accessible only though ctor.prototype). Therefore, when we
+ * instantiate this class for use in the prototype, we must ensure the
+ * constructor is not invoked, since our intent is not to create a new
+ * instance of the class.
+ */
+ '__construct should not be called when extending class': function()
+ {
+ var called = false,
+ Foo = this.Sut( {
+ 'public __construct': function()
+ {
+ called = true;
+ }
+ } ).extend( {} );
+
+ this.assertEqual( called, false );
+ },
+
+
+ /**
+ * Previously, when attempting to extend from an invalid supertype,
+ * you'd get a CALL_NON_FUNCTION_AS_CONSTRUCTOR error, which is not very
+ * helpful to someone who is not familiar with the ease.js internals.
+ * Let's provide a more useful error that clearly states what's going
+ * on.
+ */
+ 'Extending from non-ctor or non-class provides useful error': function()
+ {
+ try
+ {
+ // invalid supertype
+ this.Sut.extend( 'oops', {} );
+ }
+ catch ( e )
+ {
+ this.assertOk( e.message.search( 'extend from' ),
+ "Error message for extending from non-ctor or class " +
+ "makes sense"
+ );
+
+ return;
+ }
+
+ this.assertFail(
+ "Attempting to extend from non-ctor or class should " +
+ "throw exception"
+ );
+ },
+
+
+ /**
+ * If we attempt to extend an object (rather than a constructor), we
+ * should simply use that as the prototype directly rather than
+ * attempting to instantiate it.
+ */
+ 'Extending object will not attempt instantiation': function()
+ {
+ var obj = { foo: 'bar' };
+
+ this.assertEqual( obj.foo, this.Sut.extend( obj, {} )().foo,
+ "Should be able to use object as prototype"
+ );
+ },
+} );
diff --git a/test/Class/InstanceSafetyTest.js b/test/Class/InstanceSafetyTest.js
new file mode 100644
index 0000000..46952dc
--- /dev/null
+++ b/test/Class/InstanceSafetyTest.js
@@ -0,0 +1,87 @@
+/**
+ * Tests safety of class instances
+ *
+ * Copyright (C) 2010, 2011, 2013, 2014 Mike Gerwitz
+ *
+ * This file is part of GNU ease.js.
+ *
+ * ease.js is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+require( 'common' ).testCase(
+{
+ caseSetUp: function()
+ {
+ this.Sut = this.require( 'class' );
+ },
+
+
+ /**
+ * Ensure that we're not getting/setting values of the prototype, which
+ * would have disasterous implications (=== can also be used to test for
+ * references, but this test demonstrates the functionality that we're
+ * looking to ensure)
+ */
+ 'Multiple instances of same class do not share array references':
+ function()
+ {
+ var C = this.Sut.extend( { arr: [] } ),
+ obj1 = new C(),
+ obj2 = new C();
+
+ obj1.arr.push( 'one' );
+ obj2.arr.push( 'two' );
+
+ // if the arrays are distinct, then each will have only one element
+ this.assertEqual( obj1.arr[ 0 ], 'one' );
+ this.assertEqual( obj2.arr[ 0 ], 'two' );
+ this.assertEqual( obj1.arr.length, 1 );
+ this.assertEqual( obj2.arr.length, 1 );
+ },
+
+
+ /**
+ * Same concept as above, but with objects instead of arrays.
+ */
+ 'Multiple instances of same class do not share object references':
+ function()
+ {
+ var C = this.Sut.extend( { obj: {} } ),
+ obj1 = new C(),
+ obj2 = new C();
+
+ obj1.obj.a = true;
+ obj2.obj.b = true;
+
+ this.assertEqual( obj1.obj.a, true );
+ this.assertEqual( obj1.obj.b, undefined );
+
+ this.assertEqual( obj2.obj.a, undefined );
+ this.assertEqual( obj2.obj.b, true );
+ },
+
+
+ /**
+ * Ensure that the above checks extend to subtypes.
+ */
+ 'Instances of subtypes do not share property references': function()
+ {
+ var C2 = this.Sut.extend( { arr: [], obj: {} } ).extend( {} ),
+ obj1 = new C2(),
+ obj2 = new C2();
+
+ this.assertNotEqual( obj1.arr !== obj2.arr );
+ this.assertNotEqual( obj1.obj !== obj2.obj );
+ },
+} );
diff --git a/test/inc-testcase.js b/test/inc-testcase.js
index 50e3477..b3c3892 100644
--- a/test/inc-testcase.js
+++ b/test/inc-testcase.js
@@ -116,6 +116,11 @@ module.exports = function( test_case )
if ( method === 'each' )
{
+ if ( !( context[ prop ] ) )
+ {
+ throw Error( "Unknown @each context: " + prop );
+ }
+
count = context[ prop ].length;
args = [];
diff --git a/test/test-class-extend.js b/test/test-class-extend.js
deleted file mode 100644
index 6e01192..0000000
--- a/test/test-class-extend.js
+++ /dev/null
@@ -1,463 +0,0 @@
-/**
- * Tests class module extend() method
- *
- * Copyright (C) 2010, 2011, 2013 Mike Gerwitz
- *
- * This file is part of GNU ease.js.
- *
- * ease.js is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-var common = require( './common' ),
- assert = require( 'assert' ),
- Class = common.require( 'class' );
-
-var foo_props = {
- one: 1,
- two: 2,
- },
-
- // there are two different means of extending; we want to test them both
- classes = [
- Class.extend( foo_props ),
- Class( foo_props ),
- ],
-
- class_count = classes.length,
-
- // will hold the class being tested
- Foo = null
-;
-
-
-// Run all tests for both. This will ensure that, regardless of how the class is
-// created, it operates as it should. Fortunately, these tests are fairly quick.
-for ( var i = 0; i < class_count; i++ )
-{
- Foo = classes[ i ];
-
- assert.ok(
- ( Foo.extend instanceof Function ),
- "Created class contains extend method"
- );
-
- var sub_props = {
- three: 3,
- four: 4,
- },
-
- SubFoo = Foo.extend( sub_props ),
- sub_foo = SubFoo()
- ;
-
- assert.ok(
- ( SubFoo instanceof Object ),
- "Subtype is returned as an object"
- );
-
- // ensure properties were inherited from supertype
- for ( var prop in foo_props )
- {
- assert.equal(
- foo_props[ prop ],
- SubFoo.prototype[ prop ],
- "Subtype inherits parent properties: " + prop
- );
- }
-
- // and ensure that the subtype's properties were included
- for ( var prop in sub_props )
- {
- assert.equal(
- sub_props[ prop ],
- sub_foo[ prop ],
- "Subtype contains its own properties: " + prop
- );
- }
-
-
- var sub_instance = new SubFoo();
-
- assert.ok(
- ( sub_instance instanceof Foo ),
- "Subtypes are considered to be instances of their supertypes " +
- "(via instanceof operator)"
- );
-
- assert.ok(
- sub_instance.isInstanceOf( SubFoo ),
- "Subtypes are considered to be instances of their supertypes (via " +
- "isInstanceOf method)"
- );
-
-
- // Foo
- // |
- // SubFoo
- // / \
- // SubSubFoo SubSubFoo2
- //
- var SubSubFoo = SubFoo.extend(),
- SubSubFoo2 = SubFoo.extend(),
-
- sub_sub_instance = new SubSubFoo(),
- sub_sub2_instance = new SubSubFoo2();
-
- assert.ok(
- ( ( sub_sub_instance instanceof Foo )
- && sub_sub_instance.isInstanceOf( Foo )
- ),
- "Sub-subtypes should be instances of their super-supertype"
- );
-
- assert.ok(
- ( !( sub_instance instanceof SubSubFoo )
- && !( sub_instance.isInstanceOf( SubSubFoo ) )
- ),
- "Supertypes should not be considered instances of their subtypes"
- );
-
- assert.ok(
- ( !( sub_sub2_instance instanceof SubSubFoo )
- && !( sub_sub2_instance.isInstanceOf( SubSubFoo ) )
- ),
- "Subtypes should not be considered instances of their siblings"
- );
-
-
- // to test inheritance of classes that were not previously created via the
- // Class.extend() method
- var OtherClass = function() {};
- OtherClass.prototype =
- {
- foo: 'bla',
- };
-
- var SubOther = Class.extend( OtherClass,
- {
- newFoo: 2,
- });
-
-
- assert.equal(
- SubOther.prototype.foo,
- OtherClass.prototype.foo,
- "Prototype of existing class should be copied to subclass"
- );
-
- assert.notEqual(
- SubOther().newFoo,
- undefined,
- "Subtype should contain extended members"
- );
-
-
- assert['throws']( function()
- {
- Class.extend( OtherClass,
- {
- foo: function() {},
- });
- }, TypeError, "Cannot override property with a method" );
-
-
- var AnotherFoo = Class.extend(
- {
- arr: [],
- obj: {},
- });
-
- var Obj1 = new AnotherFoo(),
- Obj2 = new AnotherFoo();
-
- Obj1.arr.push( 'one' );
- Obj2.arr.push( 'two' );
-
- Obj1.obj.a = true;
- Obj2.obj.b = true;
-
- // to ensure we're not getting/setting values of the prototype (=== can also be
- // used to test for references, but this test demonstrates the functionality
- // that we're looking to ensure)
- assert.ok(
- ( ( Obj1.arr[ 0 ] === 'one' ) && ( Obj2.arr[ 0 ] === 'two' ) ),
- "Multiple instances of the same class do not share array references"
- );
-
- assert.ok(
- ( ( ( Obj1.obj.a === true ) && ( Obj1.obj.b === undefined ) )
- && ( ( Obj2.obj.a === undefined ) && ( Obj2.obj.b === true ) )
- ),
- "Multiple instances of the same class do not share object references"
- );
-
- var arr_val = 1;
- var SubAnotherFoo = AnotherFoo.extend(
- {
- arr: [ arr_val ],
- });
-
- var SubObj1 = new SubAnotherFoo(),
- SubObj2 = new SubAnotherFoo();
-
- assert.ok(
- ( ( SubObj1.arr !== SubObj2.arr ) && ( SubObj1.obj !== SubObj2.obj ) ),
- "Instances of subtypes do not share property references"
- );
-
- assert.ok(
- ( ( SubObj1.arr[ 0 ] === arr_val ) && ( SubObj2.arr[ 0 ] === arr_val ) ),
- "Subtypes can override parent property values"
- );
-
- assert['throws']( function()
- {
- Class.extend(
- {
- __initProps: function() {},
- });
- }, Error, "__initProps() cannot be declared (internal method)" );
-
-
- var SubSubAnotherFoo = AnotherFoo.extend(),
- SubSubObj1 = new SubSubAnotherFoo(),
- SubSubObj2 = new SubSubAnotherFoo();
-
- // to ensure the effect is recursive
- assert.ok(
- ( ( SubSubObj1.arr !== SubSubObj2.arr )
- && ( SubSubObj1.obj !== SubSubObj2.obj )
- ),
- "Instances of subtypes do not share property references"
- );
-}
-
-
-( function testInvokingClassModuleRequiresObjectAsArgumentIfCreating()
-{
- assert['throws']( function()
- {
- Class( 'moo' );
- Class( 5 );
- Class( false );
- Class();
- },
- TypeError,
- "Invoking class module requires object as argument if extending " +
- "from base class"
- );
-
- var args = [ {}, 'one', 'two', 'three' ];
-
- // we must only provide one argument if the first argument is an object (the
- // class definition)
- try
- {
- Class.apply( null, args );
-
- // if all goes well, we don't get to this line
- assert.fail(
- "Only one argument for class definitions is permitted"
- );
- }
- catch ( e )
- {
- assert.notEqual(
- e.message.match( args.length + ' given' ),
- null,
- "Class invocation should give argument count on error"
- );
- }
-} )();
-
-
-/**
- * We provide a useful default toString() method, but one may wish to override
- * it
- */
-( function testCanOverrideToStringMethod()
-{
- var str = 'foomookittypoo',
- result = ''
- ;
-
- result = Class( 'FooToStr',
- {
- toString: function()
- {
- return str;
- },
- bla: function() {},
- })().toString();
-
- assert.equal(
- result,
- str,
- "Can override default toString() method of class"
- );
-} )();
-
-
-/**
- * In ease.js's initial design, keywords were not included. This meant that
- * duplicate member definitions were not possible - it'd throw a parse error.
- * However, with keywords, it is now possible to redeclare a member with the
- * same name in the same class definition. Since this doesn't make much sense,
- * we must disallow it.
- */
-( function testCannotProvideDuplicateMemberDefintions()
-{
- assert['throws']( function()
- {
- Class(
- {
- // declare as protected first so that we won't get a visibility
- // de-escalation error with the below re-definition
- 'protected foo': '',
-
- // should fail; redefinition
- 'public foo': '',
- } );
- }, Error, "Cannot redeclare property in same class definition" );
-
- assert['throws']( function()
- {
- Class(
- {
- // declare as protected first so that we won't get a visibility
- // de-escalation error with the below re-definition
- 'protected foo': function() {},
-
- // should fail; redefinition
- 'public foo': function() {},
- } );
- }, Error, "Cannot redeclare method in same class definition" );
-} )();
-
-
-/**
- * To understand this test, one must understand how "inheritance" works
- * with prototypes. We must create a new instance of the ctor (class) and add
- * that instance to the prototype chain (if we added an un-instantiated
- * constructor, then the members in the prototype would be accessible only
- * though ctor.prototype). Therefore, when we instantiate this class for use in
- * the prototype, we must ensure the constructor is not invoked, since our
- * intent is not to create a new instance of the class.
- */
-( function testConstructorShouldNotBeCalledWhenExtendingClass()
-{
- var called = false,
- Foo = Class( {
- 'public __construct': function()
- {
- called = true;
- }
- } ).extend( {} );
-
- assert.equal( called, false,
- "Constructor should not be called when extending a class"
- );
-} )();
-
-
-/**
- * Previously, when attempting to extend from an invalid supertype, you'd get a
- * CALL_NON_FUNCTION_AS_CONSTRUCTOR error, which is not very helpful to someone
- * who is not familiar with the ease.js internals. Let's provide a more useful
- * error that clearly states what's going on.
- */
-( function testExtendingFromNonCtorOrClassProvidesUsefulError()
-{
- try
- {
- // invalid supertype
- Class.extend( 'oops', {} );
- }
- catch ( e )
- {
- assert.ok( e.message.search( 'extend from' ),
- "Error message for extending from non-ctor or class makes sense"
- );
-
- return;
- }
-
- assert.fail(
- "Attempting to extend from non-ctor or class should throw exception"
- );
-} )();
-
-
-/**
- * Only virtual methods may be overridden.
- */
-( function testCannotOverrideNonVirtualMethod()
-{
- try
- {
- var Foo = Class(
- {
- // non-virtual
- 'public foo': function() {},
- } ),
-
- SubFoo = Foo.extend(
- {
- // should fail (cannot override non-virtual method)
- 'override public foo': function() {},
- } );
- }
- catch ( e )
- {
- assert.ok( e.message.search( 'foo' ),
- "Non-virtual override error message should contain name of method"
- );
-
- return;
- }
-
- assert.fail( "Should not be permitted to override non-virtual method" );
-} )();
-
-
-/**
- * If we attempt to extend an object (rather than a constructor), we should
- * simply use that as the prototype directly rather than attempting to
- * instantiate it.
- */
-( function testExtendingObjectWillNotAttemptInstantiation()
-{
- var obj = { foo: 'bar' };
-
- assert.equal( obj.foo, Class.extend( obj, {} )().foo,
- 'Should be able to use object as prototype'
- );
-} )();
-
-
-/**
- * It only makes sense to extend from an object or function (constructor, more
- * specifically)
- *
- * We could also test to ensure that the return value of the constructor is an
- * object, but that is unnecessary for the time being.
- */
-( function testWillThrowExceptionIfNonObjectOrCtorIsProvided()
-{
- assert['throws']( function()
- {
- Class.extend( 'foo', {} );
- }, TypeError, 'Should not be able to extend from non-object or non-ctor' );
-} )();
-