diff --git a/test/Class/GeneralTest.js b/test/Class/GeneralTest.js new file mode 100644 index 0000000..6def34f --- /dev/null +++ b/test/Class/GeneralTest.js @@ -0,0 +1,271 @@ +/** + * Tests class module object creation + * + * 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 . + */ + + +require( 'common' ).testCase( +{ + setUp: function() + { + this.Sut = this.require( 'class' ); + + this.Foo = this.Sut.extend( + { + value: 'foo', + } ); + }, + + + /** + * The most primitve means of creating a class is by calling the extend + * method on the module itself, which will extend the base class. (Any + * shorthand forms still do this.) + */ + 'Class module should provide an extend method': function() + { + this.assertOk( + typeof this.Sut.extend === 'function' + ); + }, + + + /** + * The extend method should create a new constructor, which itself is a + * function. + */ + 'Extend method creates a new function': function() + { + this.assertOk( typeof this.Foo === 'function' ); + }, + + + /** + * Sanity check. + */ + 'Classes are considered by the system to be classes': function() + { + this.assertOk( this.Sut.isClass( this.Foo ) ); + }, + + + /** + * Even though we have no problem working with conventional prototypes, + * there may be certian features that ease.js provides in which it is + * important to know whether or not the given object is a class created + * with ease.js. + */ + 'Only actual classes are considered to be classes': function() + { + this.assertOk( !( this.Sut.isClass( {} ) ) ); + }, + + + /** + * Class instances are objects, not classes. + */ + 'Class instances are not considered to be classes': function() + { + var inst = new this.Foo(); + this.assertOk( !( this.Sut.isClass( inst ) ) ); + }, + + + /** + * ease.js may expose features that are useful only to instances of + * classes created through ease.js, so it is useful to know when an + * object is such. + */ + 'Class instances are considered to be instances': function() + { + var inst = new this.Foo(); + this.assertOk( this.Sut.isClassInstance( inst ) ); + }, + + + /** + * An instance is, well, an instance of a class; it is not a class. + */ + 'Classes are not considered to be class instances': function() + { + this.assertOk( + ( !( this.Sut.isClassInstance( this.Foo ) ) ) + ); + }, + + + /** + * While an object may be an instance of something in the traditional + * ECMAScript sense, the distinction is important for the framework; you + * don't need ease.js to determine if an object is an instance of + * something that is non-ease.js-y. + */ + 'Non-class objects are not considered to be instances': function() + { + // plain 'ol object + this.assertOk( !( this.Sut.isClassInstance( {} ) ) ); + + // ctor instance + var proto = function() {}; + this.assertOk( !( this.Sut.isClassInstance( new proto() ) ) ); + }, + + + /** + * A class shoudl be an immutable blueprint for creating objects. Unlike + * prototypes, they should not be able to be modified at runtime to + * affect every instance. If you want that, then use prototypes, not + * classes. + */ + 'Generated classes should be frozen': function() + { + // only perform check if supported by the engine + if ( Object.isFrozen === undefined ) + { + return; + } + + this.assertOk( Object.isFrozen( this.Foo ) ); + }, + + + /** + * We provide a reflection mechanism that may be used to determine + * whether an instance was created from a given class; this can be used + * for typing. + */ + 'Class instance is recognized as instance of class': function() + { + this.assertOk( + this.Sut.isInstanceOf( this.Foo, new this.Foo() ) + ); + }, + + + /** + * We're talking about JS here; people do unpredictable things, and this + * is likely to be a common one if type checking arguments to a + * function/method. + */ + 'Checking instance of undefined will not throw an error': function() + { + this.assertOk( + this.Sut.isInstanceOf( this.Foo, undefined ) === false + ); + }, + + + /** + * Similar to the above, but instead of providing undefined to be + * checked against a class, the class to check against is undefined. + */ + 'Checking for instance of undefined will not throw an error': function() + { + this.assertOk( + this.Sut.isInstanceOf( undefined, {} ) === false + ); + }, + + + /** + * Since a class is not an instance, it should never be recognized as an + * instance of itself. + */ + 'Class is not an instance of itself': function() + { + this.assertOk( !( this.Sut.isInstanceOf( this.Foo, this.Foo ) ) ); + }, + + + /** + * Sanity check...prevent confoundentry, which is particularily + * important in the case of accidental argument order switching. + */ + 'Class is not an instance of its instance': function() + { + this.assertOk( + !( this.Sut.isInstanceOf( new this.Foo(), this.Foo ) ) + ); + }, + + + /** + * Sometimes it's easier to think in terms of types, not instances. This + * is also shorter. + */ + 'isA is an alias for isInstanceOf': function() + { + this.assertEqual( + this.Sut.isInstanceOf, + this.Sut.isA + ); + }, + + + /** + * While more concise if used responsibly, it can also be dangerous in + * the event that the instance may not be an ease.js class instance. + */ + 'Class instance has partially applied isInstanceOf method': function() + { + var inst = new this.Foo(); + + this.assertOk( + ( ( typeof inst.isInstanceOf === 'function' ) + && ( inst.isInstanceOf( this.Foo ) === true ) + && ( inst.isInstanceOf( inst ) === false ) + ) + ); + }, + + + /** + * Same as above. + */ + 'Class instance has partially applied isA alias method': function() + { + var inst = new this.Foo(); + + this.assertEqual( + inst.isInstanceOf, + inst.isA + ); + }, + + + /** + * This really should be encapsulated, probably, but it does exist for + * reference. + */ + 'Class id is available via class': function() + { + this.assertOk( this.Foo.__cid !== undefined ); + }, + + + /** + * This ensures that the class id is accessible through all instances. + */ + 'Class id is available via class prototype': function() + { + this.assertOk( + ( this.Foo.prototype.__cid !== undefined ) + ); + }, +} ); diff --git a/test/test-class.js b/test/test-class.js deleted file mode 100644 index 5eed9fa..0000000 --- a/test/test-class.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Tests class module object creation - * - * 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' ); - - -assert.ok( - ( Class.extend instanceof Function ), - "Class module should provide an 'extend' method" -); - - -var Foo = Class.extend( -{ - value: 'foo', -}); - - -assert.ok( - ( Foo instanceof Object ), - "Extend method creates a new object" -); - -assert.ok( - ( Class.isClass( Class.extend() ) ), - "Classes are considered by the system to be classes" -); - - -var inst = new Foo(); - - -// -// isClass -assert.ok( - ( !( Class.isClass( {} ) ) ), - "Only actual classes are considered to be classes" -); - -assert.ok( - !( Class.isClass( inst ) ), - "Class instances are not considered to be classes (they are objects)" -); - - -// -// isClassInstance -assert.ok( - ( Class.isClassInstance( inst ) ), - "Class instances are considered to be classes instances" -); - -assert.ok( - ( !( Class.isClassInstance( Foo ) ) ), - "Classes are not considered to be class instances" -); - -assert.ok( - ( !( Class.isClassInstance( {} ) ) ), - "Other objects are not considered to be class instances" -); - - -// only perform check if supported by the engine -if ( Object.isFrozen ) -{ - assert.equal( - Object.isFrozen( Foo ), - true, - "Generated class should be frozen" - ); -} - - -// -// isInstanceOf -assert.ok( - Class.isInstanceOf( Foo, inst ), - "Class instance is recognized by Class.isInstanceOf()" -); - -assert.ok( - Class.isInstanceOf( Foo, undefined ) === false, - "Checking instance of undefined will not throw an error" -); - -assert.ok( - Class.isInstanceOf( undefined, {} ) === false, - "Checking for instance of undefined will not throw an error" -); - -assert.ok( - !( Class.isInstanceOf( Foo, Foo ) ), - "Class is not an instance of itself when uninstantiated" -); - -assert.ok( - !( Class.isInstanceOf( inst, Foo ) ), - "Class is not an instance of its instance" -); - -assert.equal( - Class.isInstanceOf, - Class.isA, - "isA() is an alias for isInstanceOf()" -); - -assert.ok( - ( ( inst.isInstanceOf instanceof Function ) - && ( inst.isInstanceOf( Foo ) === true ) - && ( inst.isInstanceOf( inst ) === false ) - ), - "Class instance contains partially applied isInstanceOf method" -); - -assert.equal( - inst.isInstanceOf, - inst.isA, - "Class instance contains isA() alias for isInstanceOf() partially applied function" -); - - - -assert.ok( - ( Foo.__cid !== undefined ), - "Class id available via class" -); - -assert.ok( - ( Foo.prototype.__cid !== undefined ), - "Class id available via class prototype" -); -