2010-11-14 00:41:18 -05:00
|
|
|
/**
|
|
|
|
* Tests abstract classes
|
|
|
|
*
|
2013-12-20 01:11:26 -05:00
|
|
|
* Copyright (C) 2010, 2011, 2012, 2013 Mike Gerwitz
|
2010-11-14 00:41:18 -05:00
|
|
|
*
|
|
|
|
* This file is part of ease.js.
|
|
|
|
*
|
|
|
|
* ease.js is free software: you can redistribute it and/or modify it under the
|
Relicensed under the GPLv3+
This project was originally LGPLv+-licensed to encourage its use in a community
that is largely copyleft-phobic. After further reflection, that was a mistake,
as adoption is not the important factor here---software freedom is.
When submitting ease.js to the GNU project, it was asked if I would be willing
to relicense it under the GPLv3+; I agreed happily, because there is no reason
why we should provide proprietary software any sort of edge. Indeed, proprietary
JavaScript is a huge problem since it is automatically downloaded on the user's
PC generally without them even knowing, and is a current focus for the FSF. As
such, to remain firm in our stance against proprietary JavaScript, relicensing
made the most sense for GNU.
This is likely to upset current users of ease.js. I am not sure of their
number---I have only seen download counts periodically on npmjs.org---but I know
there are at least a small number. These users are free to continue using the
previous LGPL'd releases, but with the understanding that there will be no
further maintenance (not even bug fixes). If possible, users should use the
GPL-licensed versions and release their software as free software.
Here comes GNU ease.js.
2013-12-20 01:00:35 -05:00
|
|
|
* 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.
|
2010-11-14 00:41:18 -05:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
Relicensed under the GPLv3+
This project was originally LGPLv+-licensed to encourage its use in a community
that is largely copyleft-phobic. After further reflection, that was a mistake,
as adoption is not the important factor here---software freedom is.
When submitting ease.js to the GNU project, it was asked if I would be willing
to relicense it under the GPLv3+; I agreed happily, because there is no reason
why we should provide proprietary software any sort of edge. Indeed, proprietary
JavaScript is a huge problem since it is automatically downloaded on the user's
PC generally without them even knowing, and is a current focus for the FSF. As
such, to remain firm in our stance against proprietary JavaScript, relicensing
made the most sense for GNU.
This is likely to upset current users of ease.js. I am not sure of their
number---I have only seen download counts periodically on npmjs.org---but I know
there are at least a small number. These users are free to continue using the
previous LGPL'd releases, but with the understanding that there will be no
further maintenance (not even bug fixes). If possible, users should use the
GPL-licensed versions and release their software as free software.
Here comes GNU ease.js.
2013-12-20 01:00:35 -05:00
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
2010-11-14 00:41:18 -05:00
|
|
|
*
|
Relicensed under the GPLv3+
This project was originally LGPLv+-licensed to encourage its use in a community
that is largely copyleft-phobic. After further reflection, that was a mistake,
as adoption is not the important factor here---software freedom is.
When submitting ease.js to the GNU project, it was asked if I would be willing
to relicense it under the GPLv3+; I agreed happily, because there is no reason
why we should provide proprietary software any sort of edge. Indeed, proprietary
JavaScript is a huge problem since it is automatically downloaded on the user's
PC generally without them even knowing, and is a current focus for the FSF. As
such, to remain firm in our stance against proprietary JavaScript, relicensing
made the most sense for GNU.
This is likely to upset current users of ease.js. I am not sure of their
number---I have only seen download counts periodically on npmjs.org---but I know
there are at least a small number. These users are free to continue using the
previous LGPL'd releases, but with the understanding that there will be no
further maintenance (not even bug fixes). If possible, users should use the
GPL-licensed versions and release their software as free software.
Here comes GNU ease.js.
2013-12-20 01:00:35 -05:00
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
2010-11-14 00:41:18 -05:00
|
|
|
*
|
|
|
|
* @author Mike Gerwitz
|
|
|
|
*/
|
|
|
|
|
2010-12-27 22:24:41 -05:00
|
|
|
var common = require( './common' ),
|
|
|
|
assert = require( 'assert' ),
|
2011-05-22 13:57:56 -04:00
|
|
|
util = common.require( 'util' ),
|
|
|
|
|
|
|
|
Class = common.require( 'class' ),
|
2011-12-20 20:06:38 -05:00
|
|
|
AbstractClass = common.require( 'class_abstract' ),
|
|
|
|
Interface = common.require( 'interface' )
|
2011-05-22 13:57:56 -04:00
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In order to ensure the code documents itself, we should require that all
|
|
|
|
* classes containing abstract members must themselves be declared as abstract.
|
|
|
|
* Otherwise, you are at the mercy of the developer's documentation/comments to
|
|
|
|
* know whether or not the class is indeed abstract without looking through its
|
|
|
|
* definition.
|
|
|
|
*/
|
|
|
|
( function testMustDeclareClassesWithAbstractMembersAsAbstract()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// should fail; class not declared as abstract
|
|
|
|
Class( 'Foo',
|
|
|
|
{
|
|
|
|
'abstract foo': [],
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
catch ( e )
|
|
|
|
{
|
|
|
|
assert.ok(
|
|
|
|
e.message.search( 'Foo' ) !== -1,
|
|
|
|
"Abstract class declaration error should contain class name"
|
|
|
|
);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.fail(
|
|
|
|
"Should not be able to declare abstract members unless class is also " +
|
|
|
|
"declared as abstract"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Abstract members should be permitted if the class itself is declared as
|
|
|
|
* abstract
|
|
|
|
*/
|
|
|
|
( function testCanDeclareClassAsAbstract()
|
|
|
|
{
|
|
|
|
AbstractClass(
|
|
|
|
{
|
|
|
|
'abstract foo': [],
|
|
|
|
} );
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If a class is declared as abstract, it should contain at least one abstract
|
|
|
|
* method. Otherwise, the abstract definition is pointless and unnecessarily
|
|
|
|
* confusing. The whole point of the declaration is self-documenting code.
|
|
|
|
*/
|
|
|
|
( function testAbstractClassesMustContainAbstractMethods()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// should fail; class not declared as abstract
|
|
|
|
AbstractClass( 'Foo', {} );
|
|
|
|
}
|
|
|
|
catch ( e )
|
|
|
|
{
|
|
|
|
assert.ok(
|
|
|
|
e.message.search( 'Foo' ) !== -1,
|
|
|
|
"Abstract class declaration error should contain class name"
|
|
|
|
);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.fail(
|
|
|
|
"Abstract classes should contain at least one abstract method"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
2011-06-08 01:11:53 -04:00
|
|
|
/**
|
|
|
|
* Abstract methods should remain virtual until they are overridden. That is, if
|
|
|
|
* a subtype doesn't provide a concrete implementation, it should still be
|
|
|
|
* considered virtual.
|
|
|
|
*/
|
|
|
|
( function testAbstractMethodsCanBeOverriddenBySubSubTypes()
|
|
|
|
{
|
|
|
|
var AbstractFoo = AbstractClass( 'Foo',
|
|
|
|
{
|
|
|
|
'abstract foo': [],
|
|
|
|
} ),
|
|
|
|
|
|
|
|
SubAbstractFoo = AbstractClass.extend( AbstractFoo, {} ),
|
|
|
|
|
|
|
|
ConcreteFoo = Class.extend( SubAbstractFoo,
|
|
|
|
{
|
2011-08-04 00:32:10 -04:00
|
|
|
// we should NOT need the override keyword for concrete
|
|
|
|
// implementations of abstract super methods
|
2011-06-08 01:11:53 -04:00
|
|
|
'foo': function() {},
|
|
|
|
} )
|
|
|
|
;
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
2011-05-22 21:05:46 -04:00
|
|
|
/**
|
|
|
|
* Just as Class contains an extend method, so should AbstractClass.
|
|
|
|
*/
|
|
|
|
( function testAbstractClassExtendMethodReturnsNewClass()
|
2011-05-22 13:57:56 -04:00
|
|
|
{
|
|
|
|
assert.ok( typeof AbstractClass.extend === 'function',
|
|
|
|
"AbstractClass contains extend method"
|
|
|
|
);
|
2011-05-22 21:05:46 -04:00
|
|
|
|
|
|
|
assert.ok(
|
|
|
|
Class.isClass(
|
|
|
|
AbstractClass.extend( { 'abstract foo': [] } )
|
|
|
|
),
|
|
|
|
"Abstract class extend method returns class"
|
|
|
|
);
|
2011-05-22 13:57:56 -04:00
|
|
|
} )();
|
|
|
|
|
|
|
|
|
2011-05-22 21:05:46 -04:00
|
|
|
/**
|
|
|
|
* Just as Class contains an implement method, so should AbstractClass.
|
|
|
|
*/
|
2011-05-22 13:57:56 -04:00
|
|
|
( function testAbstractClassContainsImplementMethod()
|
|
|
|
{
|
|
|
|
assert.ok( typeof AbstractClass.implement === 'function',
|
|
|
|
"AbstractClass contains implement method"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
2010-11-14 00:41:18 -05:00
|
|
|
|
|
|
|
// not abstract
|
|
|
|
var Foo = Class.extend( {} );
|
|
|
|
|
2011-03-02 07:53:58 -05:00
|
|
|
// abstract (ctor_called is not a class member to ensure that visibility bugs do
|
|
|
|
// not impact our test)
|
|
|
|
var ctor_called = false,
|
2011-05-22 13:57:56 -04:00
|
|
|
AbstractFoo = AbstractClass.extend(
|
2010-11-14 21:09:24 -05:00
|
|
|
{
|
2011-03-02 07:53:58 -05:00
|
|
|
__construct: function()
|
|
|
|
{
|
|
|
|
ctor_called = true;
|
|
|
|
},
|
2010-11-14 21:09:24 -05:00
|
|
|
|
2011-03-02 07:53:58 -05:00
|
|
|
'abstract method': [ 'one', 'two', 'three' ],
|
2010-11-14 00:41:18 -05:00
|
|
|
|
2011-03-02 07:53:58 -05:00
|
|
|
'abstract second': [],
|
|
|
|
})
|
|
|
|
;
|
2010-11-14 00:41:18 -05:00
|
|
|
|
|
|
|
// still abstract (didn't provide a concrete implementation of both abstract
|
|
|
|
// methods)
|
2011-05-22 13:57:56 -04:00
|
|
|
var SubAbstractFoo = AbstractClass.extend( AbstractFoo,
|
2010-11-14 00:41:18 -05:00
|
|
|
{
|
|
|
|
second: function()
|
|
|
|
{
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
// concrete
|
2011-05-22 13:57:56 -04:00
|
|
|
var ConcreteFoo = Class.extend( AbstractFoo,
|
2010-11-14 00:41:18 -05:00
|
|
|
{
|
|
|
|
method: function( one, two, three )
|
|
|
|
{
|
2011-12-06 18:28:16 -05:00
|
|
|
// prevent Closure Compiler from optimizing the arguments away, causing
|
|
|
|
// a definition failure
|
|
|
|
return [ one, two, three ];
|
2010-11-14 00:41:18 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
second: function()
|
|
|
|
{
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2010-12-01 21:00:15 -05:00
|
|
|
|
2011-05-22 11:33:11 -04:00
|
|
|
/**
|
|
|
|
* All classes should have a method to determine if they are abstract.
|
|
|
|
*/
|
|
|
|
( function testAllClassesHaveAMethodToDetmineIfAbstract()
|
2010-11-14 20:48:39 -05:00
|
|
|
{
|
2011-05-22 11:33:11 -04:00
|
|
|
assert.ok(
|
|
|
|
( Class( {} ).isAbstract instanceof Function ),
|
|
|
|
"All classes should have an isAbstract() method"
|
|
|
|
);
|
|
|
|
} )();
|
2010-11-14 20:48:39 -05:00
|
|
|
|
|
|
|
|
2011-05-22 11:33:11 -04:00
|
|
|
( function testClassesAreNotConsideredToBeAbstractIfTheyHaveNoAbstractMethods()
|
|
|
|
{
|
|
|
|
assert.equal(
|
|
|
|
Class( {} ).isAbstract(),
|
|
|
|
false,
|
|
|
|
"Classes are not abstract if they contain no abstract methods"
|
|
|
|
);
|
|
|
|
} )();
|
2010-11-14 21:09:24 -05:00
|
|
|
|
2010-11-14 21:33:13 -05:00
|
|
|
|
2011-05-22 11:33:11 -04:00
|
|
|
( function testClassesShouldBeConsideredAbstractIfTheyContainAbstractMethods()
|
2010-11-14 21:33:13 -05:00
|
|
|
{
|
2011-05-22 11:33:11 -04:00
|
|
|
assert.equal(
|
|
|
|
AbstractFoo.isAbstract(),
|
|
|
|
true,
|
|
|
|
"Classes should be considered abstract if they contain any abstract methods"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testSubtypesAreAbstractIfNoConcreteMethodIsProvided()
|
|
|
|
{
|
|
|
|
assert.equal(
|
|
|
|
SubAbstractFoo.isAbstract(),
|
|
|
|
true,
|
|
|
|
"Subtypes of abstract types are abstract if they don't provide a " +
|
|
|
|
"concrete implementation for all abstract methods"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testSubtypesAreNotConisderedAbstractIfConcreteImplIsProvided()
|
|
|
|
{
|
|
|
|
assert.equal(
|
|
|
|
ConcreteFoo.isAbstract(),
|
|
|
|
false,
|
|
|
|
"Subtypes of abstract types are not abstract if they provide concrete " +
|
|
|
|
"implementations of all abstract methods"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testAbstractClassesCannotBeInstantiated()
|
|
|
|
{
|
2011-12-04 19:26:53 -05:00
|
|
|
assert['throws']( function()
|
2010-11-14 21:33:13 -05:00
|
|
|
{
|
2011-05-22 11:33:11 -04:00
|
|
|
// both should fail
|
|
|
|
AbstractFoo();
|
|
|
|
SubAbstractFoo();
|
|
|
|
}, Error, "Abstract classes cannot be instantiated" );
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testConcreteSubclassesCanBeInstantiated()
|
|
|
|
{
|
|
|
|
assert.ok(
|
|
|
|
ConcreteFoo(),
|
|
|
|
"Concrete subclasses can be instantiated"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testCanCallConstructorsOfAbstractSupertypes()
|
|
|
|
{
|
|
|
|
ctor_called = false;
|
|
|
|
ConcreteFoo();
|
2010-11-14 21:33:13 -05:00
|
|
|
|
2011-05-22 11:33:11 -04:00
|
|
|
assert.equal(
|
|
|
|
ctor_called,
|
|
|
|
true,
|
|
|
|
"Can call constructors of abstract supertypes"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testConcreteMethodsMustImplementTheProperNumberOfArguments()
|
|
|
|
{
|
2011-12-04 19:26:53 -05:00
|
|
|
assert['throws']( function()
|
2010-12-01 21:34:57 -05:00
|
|
|
{
|
2010-12-10 00:00:47 -05:00
|
|
|
AbstractFoo.extend(
|
|
|
|
{
|
|
|
|
// incorrect number of arguments
|
2011-05-22 11:33:11 -04:00
|
|
|
method: function()
|
|
|
|
{
|
|
|
|
},
|
2010-12-10 00:00:47 -05:00
|
|
|
});
|
2011-05-22 11:33:11 -04:00
|
|
|
}, Error, "Concrete methods must implement the proper number of argments" );
|
|
|
|
} )();
|
2010-12-01 21:34:57 -05:00
|
|
|
|
2011-05-22 11:33:11 -04:00
|
|
|
|
|
|
|
( function testAbstractMethodsOfSubtypesMustImplementProperNumberOfArguments()
|
|
|
|
{
|
2011-12-04 19:26:53 -05:00
|
|
|
assert['throws'](
|
2011-05-22 11:33:11 -04:00
|
|
|
function()
|
2010-12-01 21:34:57 -05:00
|
|
|
{
|
2011-05-22 11:33:11 -04:00
|
|
|
AbstractFoo.extend(
|
|
|
|
{
|
|
|
|
// incorrect number of arguments
|
|
|
|
'abstract method': [],
|
|
|
|
});
|
|
|
|
},
|
|
|
|
TypeError,
|
|
|
|
"Abstract methods of subtypes must implement the proper number of " +
|
|
|
|
"argments"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testAbstractMembersMayImplementMoreArgumentsThanSupertype()
|
|
|
|
{
|
|
|
|
assert.doesNotThrow(
|
|
|
|
function()
|
2010-11-14 21:33:13 -05:00
|
|
|
{
|
2011-05-22 13:57:56 -04:00
|
|
|
AbstractClass.extend( AbstractFoo,
|
2010-11-14 21:33:13 -05:00
|
|
|
{
|
2011-05-22 11:33:11 -04:00
|
|
|
// incorrect number of arguments
|
|
|
|
'abstract method': [ 'one', 'two', 'three', 'four' ],
|
|
|
|
});
|
|
|
|
},
|
|
|
|
Error,
|
|
|
|
"Abstract methods of subtypes may implement additional arguments, " +
|
|
|
|
"so long as they implement at least the required number of " +
|
|
|
|
"arguments as defined by it supertype"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
( function testConcreteMethodsHaveNoArgumentRequirementsIfNoDefinitionGiven()
|
|
|
|
{
|
|
|
|
assert.doesNotThrow(
|
|
|
|
function()
|
|
|
|
{
|
2011-05-22 13:57:56 -04:00
|
|
|
AbstractClass.extend( AbstractFoo,
|
2011-05-22 11:33:11 -04:00
|
|
|
{
|
|
|
|
second: function( foo )
|
|
|
|
{
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
Error,
|
|
|
|
"Concrete methods needn't implement the proper number of arguments " +
|
|
|
|
"if no definition was provided"
|
|
|
|
);
|
|
|
|
} )();
|
2010-11-14 21:33:13 -05:00
|
|
|
|
2010-12-27 22:30:28 -05:00
|
|
|
|
2011-05-22 11:33:11 -04:00
|
|
|
( function testAbstractMethodsMustBeDeclaredAsArrays()
|
2010-12-27 22:30:28 -05:00
|
|
|
{
|
2011-12-04 19:26:53 -05:00
|
|
|
assert['throws']( function()
|
2010-12-27 22:30:28 -05:00
|
|
|
{
|
2011-05-22 11:33:11 -04:00
|
|
|
Class.extend(
|
|
|
|
{
|
|
|
|
// not an array (invalid)
|
|
|
|
'abstract foo': 'scalar',
|
|
|
|
} );
|
|
|
|
}, TypeError, "Abstract methods must be declared as arrays" );
|
|
|
|
} )();
|
2010-12-27 22:30:28 -05:00
|
|
|
|
2011-01-17 20:22:30 -05:00
|
|
|
|
2011-03-01 12:11:36 -05:00
|
|
|
/**
|
|
|
|
* There was an issue where the object holding the abstract methods list was not
|
|
|
|
* checking for methods by using hasOwnProperty(). Therefore, if a method such
|
|
|
|
* as toString() was defined, it would be matched in the abstract methods list.
|
|
|
|
* As such, the abstract methods count would be decreased, even though it was
|
|
|
|
* not an abstract method to begin with (nor was it removed from the list,
|
|
|
|
* because it was never defined in the first place outside of the prototype).
|
|
|
|
*
|
|
|
|
* This negative number !== 0, which causes a problem when checking to ensure
|
|
|
|
* that there are 0 abstract methods. We check explicitly for 0 for two reasons:
|
|
|
|
* (a) it's faster than <, and (b - most importantly) if it's non-zero, then
|
|
|
|
* it's either abstract or something is wrong. Negative is especially wrong. It
|
|
|
|
* should never be negative!
|
|
|
|
*/
|
|
|
|
( function testDoesNotRecognizeObjectPrototypeMembersAsAbstractWhenDefining()
|
|
|
|
{
|
|
|
|
assert.doesNotThrow( function()
|
|
|
|
{
|
2011-05-22 13:57:56 -04:00
|
|
|
Class.extend( SubAbstractFoo,
|
|
|
|
{
|
2011-12-06 18:28:16 -05:00
|
|
|
// concrete, so the result would otherwise not be abstract (return
|
|
|
|
// args so they're not optimized away during compile)
|
|
|
|
'method': function( _, __, ___ ) { return [ _, __, ___ ]; },
|
2011-03-01 12:11:36 -05:00
|
|
|
|
|
|
|
// the problem
|
|
|
|
'toString': function() {},
|
|
|
|
})();
|
|
|
|
}, Error, "Should not throw error if overriding a prototype method" );
|
|
|
|
} )();
|
|
|
|
|
2011-05-22 21:05:46 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensure we support named abstract class extending
|
|
|
|
*/
|
|
|
|
( function testCanCreateNamedAbstractSubtypes()
|
|
|
|
{
|
|
|
|
assert.doesNotThrow( function()
|
|
|
|
{
|
|
|
|
var cls = AbstractClass( 'NamedSubFoo' ).extend( AbstractFoo, {} );
|
|
|
|
}, Error, "Can create named abstract subtypes" );
|
|
|
|
} )();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Abstract classes, when extended, should yield a concrete class by default.
|
|
|
|
* Otherwise, the user should once again use AbstractClass to clearly state that
|
|
|
|
* the subtype is abstract.
|
|
|
|
*/
|
|
|
|
( function testExtendingAbstractClassIsNotAbstractByDefault()
|
|
|
|
{
|
|
|
|
var cls_named = AbstractClass( 'NamedSubFoo' ).extend( AbstractFoo, {} ),
|
|
|
|
anon_named = AbstractClass.extend( AbstractFoo, {} );
|
|
|
|
|
|
|
|
// named
|
2011-12-04 19:26:53 -05:00
|
|
|
assert['throws'](
|
2011-05-22 21:05:46 -04:00
|
|
|
function()
|
|
|
|
{
|
|
|
|
// should throw an error, since we're not declaring it as abstract
|
|
|
|
// and we're not providing a concrete impl
|
|
|
|
Class.isAbstract( cls_named.extend( {} ) );
|
|
|
|
},
|
|
|
|
TypeError,
|
|
|
|
"Extending named abstract classes should be concrete by default"
|
|
|
|
);
|
|
|
|
|
|
|
|
// anonymous
|
2011-12-04 19:26:53 -05:00
|
|
|
assert['throws'](
|
2011-05-22 21:05:46 -04:00
|
|
|
function()
|
|
|
|
{
|
|
|
|
// should throw an error, since we're not declaring it as abstract
|
|
|
|
// and we're not providing a concrete impl
|
|
|
|
Class.isAbstract( AbstractFoo.extend( {} ) );
|
|
|
|
},
|
|
|
|
TypeError,
|
|
|
|
"Extending anonymous abstract classes should be concrete by default"
|
|
|
|
);
|
|
|
|
} )();
|
|
|
|
|
2011-12-20 20:06:38 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Extending an abstract class after an implement() should still result in an
|
|
|
|
* abstract class. Essentially, we are testing to ensure that the extend()
|
|
|
|
* method is properly wrapped to flag the resulting class as abstract. This was
|
|
|
|
* a bug.
|
|
|
|
*/
|
|
|
|
( function testImplementingInterfacesWillPreserveAbstractClassDeclaration()
|
|
|
|
{
|
|
|
|
// if not considered abstract, extend() will fail, as it will contain
|
|
|
|
// abstract member foo
|
|
|
|
AbstractClass( 'TestImplExtend' )
|
|
|
|
.implement( Interface( { foo: [] } ) )
|
|
|
|
.extend( {} );
|
|
|
|
} )()
|
|
|
|
|