From c605113412b6bc47cd95d3818fff946e41876e5c Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Sat, 19 Nov 2011 14:09:59 -0500 Subject: [PATCH] [#29] Refactored test-interface-extend into new test case format - Preparing for minor changes --- test/Interface/ExtendTest.js | 328 ++++++++++++++++++++++++++++++++++ test/test-interface-extend.js | 233 ------------------------ 2 files changed, 328 insertions(+), 233 deletions(-) create mode 100644 test/Interface/ExtendTest.js delete mode 100644 test/test-interface-extend.js diff --git a/test/Interface/ExtendTest.js b/test/Interface/ExtendTest.js new file mode 100644 index 0000000..8932fd2 --- /dev/null +++ b/test/Interface/ExtendTest.js @@ -0,0 +1,328 @@ +/** + * Tests extending of interfaces + * + * Copyright (C) 2010 Mike Gerwitz + * + * This file is part of ease.js. + * + * ease.js is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * @author Mike Gerwitz + * @package test + */ + +var common = require( 'common' ), + Interface = common.require( 'interface' ); + + // get/set test support + gst = !( common.require( 'util' ).definePropertyFallback() ) +; + + +common.testCase( +{ + caseSetUp: function() + { + // There's a couple ways to create interfaces. Test 'em both. + this.baseTypes = [ + Interface.extend( + { + 'abstract method': [], + } ), + + Interface( { + 'abstract method': [], + } ) + ]; + + // non-object values to assert failures upon + this.invalidExtend = [ 'moo', 5, false, undefined ]; + + // bad access modifiers (cannot be used in interfaces) + this.badAm = [ 'protected', 'private' ]; + }, + + + 'Properties are not permitted within interfaces': function() + { + this.assertThrows( + function() + { + Interface.extend( + { + // properties are not permitted + prop: 'not permitted', + }); + }, + TypeError, + "Properties are not permitted within Interface definitions" + ); + }, + + + 'Getters are setters are not permitted within intefaces': function() + { + // don't perform get/set test if unsupported by environment + if ( !gst ) + { + return; + } + + // so we don't break browsers that do not support getters/setters in object + // notation + var data = {}; + Object.defineProperty( data, 'foo', { + get: function() {}, + set: function() {}, + + enumerable: true, + } ); + + this.assertThrows( function() + { + Interface.extend( data ); + }, TypeError, "Getters/setters not permitted within Interfaces" ); + }, + + + 'Concrete methods are not permitted': function() + { + this.assertThrows( + function() + { + Interface.extend( + { + // concrete method + method: function() {} + } ); + }, + TypeError, + "Concrete methods are not permitted within Interface definitions" + ); + }, + + + 'Abstract method declarations are permitted': function() + { + this.assertDoesNotThrow( + function() + { + Interface.extend( + { + 'abstract method': [], + } ); + }, + TypeError, + "Abstract method declarations are allowed within Interface " + + "definitions" + ); + }, + + + /** + * The defined abstract methods should be included in the resulting + * interface + */ + '@each(baseTypes) Interface contains defined abstract methods': + function( T ) + { + this.assertOk( + ( typeof T.prototype.method === 'function' ), + "Interface should contain defined abstract methods" + ); + }, + + + /** + * The resulting interface should be considered, by the system's + * isInterface() call, to be an interface. Otherwise that would be a pretty + * useless call, now wouldn't it? + */ + '@each(baseTypes) Result is considered to be an interface': function( T ) + { + this.assertEqual( + Interface.isInterface( T ), + true + ); + }, + + + /** + * Interfaces can be extended much like classes. In this case, however, we + * are only extending the API. + */ + '@each(baseTypes) Can extend interface using Interface.extend()': + function( T ) + { + var SubType = Interface.extend( T, {} ); + + this.assertOk( + ( SubType.prototype instanceof T ), + "Generic interface extend method should be able to extend from " + + "other interfaces" + ); + }, + + + /** + * As the term 'extending' would apply, sub-interfaces should 'inherit' + * their parents' API. + */ + '@each(baseTypes) Interface subtypes inherit abstract methods': + function( T ) + { + var SubType = Interface.extend( T, {} ); + + this.assertOk( + ( SubType.prototype.method === T.prototype.method ), + "Interface subtypes inherit abstract methods" + ); + }, + + + /** + * One should be able to add additional methods to the API of a + * sub-interface. + */ + '@each(baseTypes) Interfaces can extend the API with abstract methods': + function( T ) + { + var SubType = Interface.extend( T, + { + 'abstract second': [], + } ); + + this.assertOk( + ( typeof SubType.prototype.second === 'function' ), + "Should be able to extend interfaces with additional abstract " + + "methods" + ); + }, + + + /** + * Interfaces should contain a built-in extend() method as a short-hand for + * subtyping. + */ + '@each(baseTypes) Interfaces contain an extend() method': function( T ) + { + this.assertOk( + ( typeof T.extend === 'function' ), + "Interface should contain extend() method" + ); + }, + + + /** + * Similar to above, but using the interface itself's extend() method + */ + '@each(baseTypes) extend() method on interface itself can extend': + function( T ) + { + var SubType = T.extend( {} ); + + this.assertOk( + ( SubType.prototype instanceof T ), + "Interface extend method can extend interfaces" + ); + }, + + + /** + * Similar to above, but using the interface itself's extend() method + */ + '@each(baseTypes) Interface\'s extend() method can add to the API': + function( T ) + { + var SubType = T.extend( + { + 'abstract second': [], + } ); + + this.assertOk( + ( typeof SubType.prototype.second === 'function' ), + "Interfaces should be able to be extended with additional " + + "abstract methods using shorthand extend method" + ); + }, + + + /** + * The interface invocation action depends on what arguments are passed in. + * One use is to pass in an object as the first and only argument, creating + * a new interface with no supertype. + */ + '@each(invalidExtend) Invoking module to extend requires object': + function( val ) + { + this.assertThrows( function() + { + Interface( val ); + }, + TypeError, + "Invoking interface module should require object as argument if " + + "extending from base interface" + ); + }, + + + /** + * If defining a new interface (object as the first argument on invocation), + * then only one argument is permitted. + */ + 'Only one argment for interface definitions is permitted': function() + { + var args = [ {}, 'one', 'two', 'three' ]; + + // we must only provide one argument if the first argument is an object + // (the interface definition) + try + { + Interface.apply( null, args ); + + // if all goes well, we don't get to this line + this.fail( + "Only one argument for interface definitions should be " + + "permitted" + ); + } + catch ( e ) + { + this.assertOk( + ( e.message.search( args.length + " given" ) > -1 ), + "Interface invocation should give argument count on error" + ); + } + }, + + + /** + * Interfaces represent a public API that must be implemented. It does not + * make sense to have members be anything but public. If protected members + * are required, that is appropriate only for an abstract class. + */ + '@each(badAm) Interface members must be public': function( am ) + { + // protected + this.assertThrows( function() + { + // am = access modifier + var dfn = {}; + dfn[ 'abstract ' + am + ' foo' ] = []; + + Interface( dfn ); + }, Error, "Interface members should not be able to be " + am ); + }, +} ); + diff --git a/test/test-interface-extend.js b/test/test-interface-extend.js deleted file mode 100644 index 318e709..0000000 --- a/test/test-interface-extend.js +++ /dev/null @@ -1,233 +0,0 @@ -/** - * Tests extending of interfaces - * - * Copyright (C) 2010 Mike Gerwitz - * - * This file is part of ease.js. - * - * ease.js is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - * @author Mike Gerwitz - * @package test - */ - -var common = require( './common' ), - assert = require( 'assert' ), - Interface = common.require( 'interface' ), - util = common.require( 'util' ) -; - - -( function testPropertiesNotPermittedWithinInterfaces() -{ - assert.throws( function() - { - Interface.extend( - { - // properties (non-methods) are not permitted - prop: 'not permitted', - }); - }, TypeError, "Properties are not permitted within Interface definitions" ); -} )(); - - -( function testGettersAndSettersNotPermittedWithinInterfaces() -{ - // don't perform this test if unsupported by environment - if ( util.definePropertyFallback() ) - { - return; - } - - // so we don't break browsers that do not support getters/setters in object - // notation - var data = {}; - Object.defineProperty( data, 'foo', { - get: function() {}, - set: function() {}, - - enumerable: true, - } ); - - assert.throws( function() - { - Interface.extend( data ); - }, TypeError, "Getters/setters not permitted within Interfaces" ); -} )(); - - -assert.throws( function() -{ - Interface.extend( - { - // concrete method - method: function() {} - }); -}, TypeError, "Concrete methods are not permitted within Interface definitions" ); - -assert.doesNotThrow( - function() - { - Interface.extend( - { - 'abstract method': [], - }); - }, - TypeError, - "Abstract method declarations are allowed within Interface definitions" -); - - -// There's a couple ways to create interfaces. Test 'em both. -var base_types = [ - Interface.extend( - { - 'abstract method': [], - } ), - - Interface( { - 'abstract method': [], - } ) -]; - -var BaseType; -for ( var i = 0; i < base_types.length; i++ ) -{ - BaseType = base_types[ i ]; - - assert.ok( - ( BaseType.prototype.method instanceof Function ), - "Interface contains defined abstract methods" - ); - - assert.equal( - Interface.isInterface( BaseType ), - true, - "Interface is considered to be an interface" - ); - - - var SubType = Interface.extend( BaseType, - { - 'abstract second': [], - }); - - assert.ok( - ( SubType.prototype instanceof BaseType ), - "Generic interface extend method can extend from other interfaces" - ); - - assert.ok( - ( SubType.prototype.method === BaseType.prototype.method ), - "Interface subtypes inherit abstract methods" - ); - - assert.ok( - ( SubType.prototype.second instanceof Function ), - "Interfaces can be extended with additional abstract methods" - ); - - - assert.ok( - ( BaseType.extend instanceof Function ), - "Interface contains extend method" - ); - - - var SubType2 = BaseType.extend( - { - 'abstract second': [], - }); - - assert.ok( - ( SubType2.prototype instanceof BaseType ), - "Interface extend method can extend interfaces" - ); - - assert.ok( - ( SubType2.prototype.second instanceof Function ), - "Interfaces can be extended with additional abstract methods using " + - "shorthand extend method" - ); -} - - -/** - * The interface invocation action depends on what arguments are passed in. One - * use is to pass in an object as the first and only argument, creating a new - * interface with no supertype. - */ -( function testInvokingInterfaceModuleRequiresObjectAsArgumentIfExtending() -{ - assert.throws( function() - { - Interface( 'moo' ); - Interface( 5 ); - Interface( false ); - Interface(); - }, - TypeError, - "Invoking interface module requires object as argument if extending " + - "from base interface" - ); - - var args = [ {}, 'one', 'two', 'three' ]; - - // we must only provide one argument if the first argument is an object (the - // interface definition) - try - { - Interface.apply( null, args ); - - // if all goes well, we don't get to this line - assert.fail( - "Only one argument for interface definitions is permitted" - ); - } - catch ( e ) - { - assert.notEqual( - e.message.match( args.length + ' given' ), - null, - "Interface invocation should give argument count on error" - ); - } -} )(); - - -/** - * Interfaces represent a public API that must be implemented. It does not make - * sense to have members be anything but public. - */ -( function testInterfaceMembersMustBePublic() -{ - // protected - assert.throws( function() - { - Interface( - { - 'abstract protected foo': [], - } ); - }, Error, "Interface members must be public (1)" ); - - // private - assert.throws( function() - { - Interface( - { - 'abstract private foo': [], - } ); - }, Error, "Interface members must be public (2)" ); -} )(); -