parent
72e5d481e6
commit
81fa2ae424
3
Makefile
3
Makefile
|
@ -10,6 +10,9 @@ path_perf_test=${path_test}/perf
|
||||||
|
|
||||||
perf_tests := $(shell find "$(path_perf_test)" -name 'perf-*.js')
|
perf_tests := $(shell find "$(path_perf_test)" -name 'perf-*.js')
|
||||||
|
|
||||||
|
src_js := index.js $(wildcard $(path_lib)/*.js)
|
||||||
|
src_tests := index.js $(wildcard $(path_test)/test-*)
|
||||||
|
|
||||||
path_doc := ./doc
|
path_doc := ./doc
|
||||||
|
|
||||||
combine=${path_tools}/combine
|
combine=${path_tools}/combine
|
||||||
|
|
|
@ -15,8 +15,6 @@ path_manual_texi=${path_doc}/manual.texi
|
||||||
|
|
||||||
path_info_install := /usr/local/share/info
|
path_info_install := /usr/local/share/info
|
||||||
|
|
||||||
src_js := index.js $(wildcard $(path_lib)/*.js)
|
|
||||||
src_tests := index.js $(wildcard $(path_test)/test-*)
|
|
||||||
doc_src := $(wildcard $(path_doc)/*.texi)
|
doc_src := $(wildcard $(path_doc)/*.texi)
|
||||||
doc_imgs := $(patsubst %.dia, %.png, $(wildcard $(path_doc_img)/*.dia))
|
doc_imgs := $(patsubst %.dia, %.png, $(wildcard $(path_doc_img)/*.dia))
|
||||||
doc_imgs_txt := $(patsubst %.dia, %.png, $(wildcard $(path_doc_img)/*.txt))
|
doc_imgs_txt := $(patsubst %.dia, %.png, $(wildcard $(path_doc_img)/*.txt))
|
||||||
|
|
|
@ -541,7 +541,7 @@ function buildMembers(
|
||||||
var dest = ( keywordStatic( keywords ) ) ? smethods : members;
|
var dest = ( keywordStatic( keywords ) ) ? smethods : members;
|
||||||
|
|
||||||
member_builder.buildGetter(
|
member_builder.buildGetter(
|
||||||
dest, null, name, value, keywords
|
dest, null, name, value, keywords, base
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -550,7 +550,7 @@ function buildMembers(
|
||||||
var dest = ( keywordStatic( keywords ) ) ? smethods : members;
|
var dest = ( keywordStatic( keywords ) ) ? smethods : members;
|
||||||
|
|
||||||
member_builder.buildSetter(
|
member_builder.buildSetter(
|
||||||
dest, null, name, value, keywords
|
dest, null, name, value, keywords, base
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,14 @@ function validateMethod( keywords, prev_data, value, name )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do not allow overriding getters/setters
|
||||||
|
if ( prev_data && ( prev_data.get || prev_data.set ) )
|
||||||
|
{
|
||||||
|
throw TypeError(
|
||||||
|
"Cannot override getter/setter '" + name + "' with method"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// search for any previous instances of this member
|
// search for any previous instances of this member
|
||||||
if ( prev )
|
if ( prev )
|
||||||
{
|
{
|
||||||
|
@ -236,6 +244,14 @@ exports.buildProp = function( members, meta, name, value, keywords, base )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do not allow overriding getters/setters
|
||||||
|
if ( prev_data && ( prev_data.get || prev_data.set ) )
|
||||||
|
{
|
||||||
|
throw TypeError(
|
||||||
|
"Cannot override getter/setter '" + name + "' with property"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// do not permit visibility de-escalation
|
// do not permit visibility de-escalation
|
||||||
if ( prev && ( prev_data.visibility < getVisibilityValue( keywords ) ) )
|
if ( prev && ( prev_data.visibility < getVisibilityValue( keywords ) ) )
|
||||||
{
|
{
|
||||||
|
@ -282,10 +298,14 @@ exports.buildProp = function( members, meta, name, value, keywords, base )
|
||||||
*
|
*
|
||||||
* @param {Object.<string,boolean>} keywords parsed keywords
|
* @param {Object.<string,boolean>} keywords parsed keywords
|
||||||
*
|
*
|
||||||
|
* @param {Object=} base optional base object to scan
|
||||||
|
*
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
exports.buildGetter = function( members, meta, name, value, keywords )
|
exports.buildGetter = function( members, meta, name, value, keywords, base )
|
||||||
{
|
{
|
||||||
|
validateGetterSetter( members, keywords, name, base );
|
||||||
|
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
getMemberVisibility( members, keywords ),
|
getMemberVisibility( members, keywords ),
|
||||||
name,
|
name,
|
||||||
|
@ -312,10 +332,14 @@ exports.buildGetter = function( members, meta, name, value, keywords )
|
||||||
*
|
*
|
||||||
* @param {Object.<string,boolean>} keywords parsed keywords
|
* @param {Object.<string,boolean>} keywords parsed keywords
|
||||||
*
|
*
|
||||||
|
* @param {Object=} base optional base object to scan
|
||||||
|
*
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
exports.buildSetter = function( members, meta, name, value, keywords )
|
exports.buildSetter = function( members, meta, name, value, keywords, base )
|
||||||
{
|
{
|
||||||
|
validateGetterSetter( members, keywords, name, base );
|
||||||
|
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
getMemberVisibility( members, keywords ),
|
getMemberVisibility( members, keywords ),
|
||||||
name,
|
name,
|
||||||
|
@ -330,6 +354,43 @@ exports.buildSetter = function( members, meta, name, value, keywords )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs common validations on getters/setters
|
||||||
|
*
|
||||||
|
* If a problem is found, an exception will be thrown.
|
||||||
|
*
|
||||||
|
* @param {{public: Object, protected: Object, private: Object}} members
|
||||||
|
*
|
||||||
|
* @param {Object.<string,boolean>} keywords parsed keywords
|
||||||
|
* @param {string} name getter/setter name
|
||||||
|
* @param {Object} base optional base to parse
|
||||||
|
*/
|
||||||
|
function validateGetterSetter( members, keywords, name, base )
|
||||||
|
{
|
||||||
|
var prev_data = scanMembers( members, name, base ),
|
||||||
|
prev = ( prev_data ) ? prev_data.member : null,
|
||||||
|
|
||||||
|
prev_keywords = ( prev && prev.___$$keywords$$ )
|
||||||
|
? prev.___$$keywords$$
|
||||||
|
: {}
|
||||||
|
;
|
||||||
|
|
||||||
|
if ( prev )
|
||||||
|
{
|
||||||
|
// To speed up the system we'll simply check for a getter/setter, rather
|
||||||
|
// than checking separately for methods/properties. This is at the
|
||||||
|
// expense of more detailed error messages. They'll live.
|
||||||
|
if ( !( prev_data.get || prev_data.set ) )
|
||||||
|
{
|
||||||
|
throw TypeError(
|
||||||
|
"Cannot override method or property '" + name +
|
||||||
|
"' with getter/setter"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns member prototype to use for the requested visibility
|
* Returns member prototype to use for the requested visibility
|
||||||
*
|
*
|
||||||
|
@ -389,20 +450,22 @@ function scanMembers( members, name, base )
|
||||||
// locate requested member by scanning each level of visibility
|
// locate requested member by scanning each level of visibility
|
||||||
while ( i-- )
|
while ( i-- )
|
||||||
{
|
{
|
||||||
if ( member = members[ visibility[ i ] ][ name ] )
|
var visobj = members[ visibility[ i ] ];
|
||||||
{
|
|
||||||
// We need to filter out base properties (such as
|
// In order to support getters/setters, we must go off of the
|
||||||
// Object.prototype.toString()), but we still need to traverse the
|
// descriptor. We must also ignore base properties (last argument), such
|
||||||
// prototype chain. As such, we cannot use hasOwnProperty().
|
// as Object.prototype.toString(). However, we must still traverse the
|
||||||
if ( member !== Object.prototype[ name ] )
|
// prototype chain.
|
||||||
|
if ( member = util.getPropertyDescriptor( visobj, name, true ) )
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
member: member,
|
get: member.get,
|
||||||
|
set: member.set,
|
||||||
|
member: member.value,
|
||||||
visibility: ( ( fallback ) ? 0 : i ),
|
visibility: ( ( fallback ) ? 0 : i ),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if a second comparison object was given, try again using it instead of
|
// if a second comparison object was given, try again using it instead of
|
||||||
// the original members object
|
// the original members object
|
||||||
|
|
89
lib/util.js
89
lib/util.js
|
@ -419,6 +419,95 @@ exports.arrayShrink = function( items )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses Object.getOwnPropertyDescriptor if available, otherwise provides our own
|
||||||
|
* implementation to fall back on
|
||||||
|
*
|
||||||
|
* If the environment does not support retrieving property descriptors (ES5),
|
||||||
|
* then the following will be true:
|
||||||
|
* - get/set will always be undefined
|
||||||
|
* - writable, enumerable and configurable will always be true
|
||||||
|
* - value will be the value of the requested property on the given object
|
||||||
|
*
|
||||||
|
* @param {Object} obj object to check property on
|
||||||
|
* @param {string} prop property to retrieve descriptor for
|
||||||
|
*
|
||||||
|
* @return {Object} descriptor for requested property or undefined if not found
|
||||||
|
*/
|
||||||
|
exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor
|
||||||
|
|| function( obj, prop )
|
||||||
|
{
|
||||||
|
if ( !Object.prototype.hasOwnProperty.call( obj, prop ) )
|
||||||
|
{
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback response
|
||||||
|
return {
|
||||||
|
get: undefined,
|
||||||
|
set: undefined,
|
||||||
|
|
||||||
|
writable: true,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
|
||||||
|
value: obj[ prop ],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Travels down the prototype chain of the given object in search of the
|
||||||
|
* requested property and returns its descriptor
|
||||||
|
*
|
||||||
|
* This operates as Object.getOwnPropertyDescriptor(), except that it traverses
|
||||||
|
* the prototype chain. For environments that do not support __proto__, it will
|
||||||
|
* not traverse the prototype chain and essentially serve as an alias for
|
||||||
|
* getOwnPropertyDescriptor().
|
||||||
|
*
|
||||||
|
* This method has the option to ignore the base prototype. This is useful to,
|
||||||
|
* for example, not catch properties like Object.prototype.toString() when
|
||||||
|
* searching for 'toString' on an object.
|
||||||
|
*
|
||||||
|
* @param {Object} obj object to check property on
|
||||||
|
* @param {string} prop property to retrieve descriptor for
|
||||||
|
* @param {bool} nobase whether to ignore the base prototype
|
||||||
|
*
|
||||||
|
* @return {Object} descriptor for requested property or undefined if not found
|
||||||
|
*/
|
||||||
|
exports.getPropertyDescriptor = function( obj, prop, nobase )
|
||||||
|
{
|
||||||
|
// false by default
|
||||||
|
nobase = !!nobase;
|
||||||
|
|
||||||
|
// note that this uses util's function, not Object's
|
||||||
|
var desc = exports.getOwnPropertyDescriptor( obj, prop ),
|
||||||
|
next = obj.__proto__;
|
||||||
|
|
||||||
|
// if we didn't find a descriptor and a prototype is available, recurse down
|
||||||
|
// the prototype chain, ensuring that the next prototype has a prototype if
|
||||||
|
// the base is to be excluded
|
||||||
|
if ( !desc && next && ( !nobase || next.__proto__ ) )
|
||||||
|
{
|
||||||
|
return exports.getPropertyDescriptor( obj.__proto__, prop, nobase );
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the descriptor or undefined if no prototype is available
|
||||||
|
return desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not the getPropertyDescriptor method is capable of
|
||||||
|
* traversing the prototype chain
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
exports.defineSecureProp( exports.getPropertyDescriptor, 'canTraverse',
|
||||||
|
( {}.__proto__ ) ? true : false
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appropriately returns defineSecureProp implementation to avoid check on each
|
* Appropriately returns defineSecureProp implementation to avoid check on each
|
||||||
* invocation
|
* invocation
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
/**
|
||||||
|
* ease.js warning system
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Mike Gerwitz
|
||||||
|
* @package core
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active warning handler
|
||||||
|
* @type {function()}
|
||||||
|
*/
|
||||||
|
var _handler = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permits wrapping an exception as a warning
|
||||||
|
*
|
||||||
|
* Warnings are handled differently by the system, depending on the warning
|
||||||
|
* level that has been set.
|
||||||
|
*
|
||||||
|
* @param {Error} e exception (error) to wrap
|
||||||
|
*
|
||||||
|
* @return {Warning} new warning instance
|
||||||
|
*/
|
||||||
|
var Warning = exports.Warning = function( e )
|
||||||
|
{
|
||||||
|
// allow instantiation without use of 'new' keyword
|
||||||
|
if ( !( this instanceof Warning ) )
|
||||||
|
{
|
||||||
|
return new Warning( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure we're wrapping an exception
|
||||||
|
if ( !( e instanceof Error ) )
|
||||||
|
{
|
||||||
|
throw TypeError( "Must provide exception to wrap" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy over the message for convenience
|
||||||
|
this.message = e.message;
|
||||||
|
this._error = e;
|
||||||
|
};
|
||||||
|
|
||||||
|
Warning.prototype = Error();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the error wrapped by the warning
|
||||||
|
*
|
||||||
|
* @return {Error} wrapped error
|
||||||
|
*/
|
||||||
|
Warning.prototype.getError = function()
|
||||||
|
{
|
||||||
|
return this._error;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core warning handlers
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
exports.handlers = {
|
||||||
|
/**
|
||||||
|
* Logs message to console
|
||||||
|
*
|
||||||
|
* Will attempt to log using console.warn(), falling back to console.log()
|
||||||
|
* if necessary and aborting entirely if neither is available.
|
||||||
|
*
|
||||||
|
* This is useful as a default option to bring problems to the developer's
|
||||||
|
* attention without affecting the control flow of the software.
|
||||||
|
*
|
||||||
|
* @param {Warning} warning to log
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
log: function( warning )
|
||||||
|
{
|
||||||
|
var dest;
|
||||||
|
|
||||||
|
console && ( dest = console.warn || console.log ) &&
|
||||||
|
dest( warning.message );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws the error associated with the warning
|
||||||
|
*
|
||||||
|
* This handler is useful for development and will ensure that problems are
|
||||||
|
* brought to the attention of the developer.
|
||||||
|
*
|
||||||
|
* @param {Warning} warning to log
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
throwError: function( warning )
|
||||||
|
{
|
||||||
|
throw warning.getError();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignores warnings
|
||||||
|
*
|
||||||
|
* This is useful in a production environment where (a) warnings will affect
|
||||||
|
* the reputation of the software or (b) warnings may provide too much
|
||||||
|
* insight into the software. If using this option, you should always
|
||||||
|
* develop in a separate environment so that the system may bring warnings
|
||||||
|
* to your attention.
|
||||||
|
*
|
||||||
|
* @param {Warning} warning to log
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
dismiss: function( warning )
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the active warning handler
|
||||||
|
*
|
||||||
|
* You may use any of the predefined warning handlers or pass your own function.
|
||||||
|
*
|
||||||
|
* @param {function( Warning )} handler warning handler
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
exports.setHandler = function( handler )
|
||||||
|
{
|
||||||
|
_handler = handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a warning using the active warning handler
|
||||||
|
*
|
||||||
|
* @param {Warning} warning warning to handle
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
exports.handle = function( warning )
|
||||||
|
{
|
||||||
|
_handler( warning );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set the default handler
|
||||||
|
_handler = exports.handlers.log;
|
||||||
|
|
|
@ -56,16 +56,42 @@ function setUp()
|
||||||
/**
|
/**
|
||||||
* Partially applied function to quickly build getter from common test data
|
* Partially applied function to quickly build getter from common test data
|
||||||
*/
|
*/
|
||||||
function buildGetterSetterQuick( keywords, val )
|
function buildGetterSetterQuick( keywords, val, preserve_prior, use )
|
||||||
{
|
{
|
||||||
|
preserve_prior = !!preserve_prior;
|
||||||
|
use = ( use === undefined ) ? 0 : +use;
|
||||||
|
|
||||||
keywords = keywords || {};
|
keywords = keywords || {};
|
||||||
val = val || value;
|
val = val || value;
|
||||||
|
|
||||||
|
if ( !preserve_prior )
|
||||||
|
{
|
||||||
setUp();
|
setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( use == 0 || use == 1 )
|
||||||
|
{
|
||||||
buildGetter( members, meta, name, val, keywords );
|
buildGetter( members, meta, name, val, keywords );
|
||||||
|
}
|
||||||
|
if ( use == 0 || use == 2 )
|
||||||
|
{
|
||||||
buildSetter( members, meta, name, val, keywords );
|
buildSetter( members, meta, name, val, keywords );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testEach( test )
|
||||||
|
{
|
||||||
|
test( 'getter', function( keywords, val, preserve )
|
||||||
|
{
|
||||||
|
buildGetterSetterQuick.call( this, keywords, val, preserve, 1 );
|
||||||
|
} );
|
||||||
|
|
||||||
|
test( 'setter', function( keywords, val, preserve )
|
||||||
|
{
|
||||||
|
buildGetterSetterQuick.call( this, keywords, val, preserve, 2 );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -176,3 +202,62 @@ function assertOnlyVisibility( vis, name, value, message )
|
||||||
|
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getters/setters should not be able to override methods, for the obvious
|
||||||
|
* reason that they are two different types and operate entirely differently. Go
|
||||||
|
* figure.
|
||||||
|
*/
|
||||||
|
testEach( function testCannotOverrideMethodWithGetterOrSetter( type, build )
|
||||||
|
{
|
||||||
|
setUp();
|
||||||
|
|
||||||
|
// method
|
||||||
|
members[ 'public' ][ name ] = function() {};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// attempt to override method with getter/setter (should fail)
|
||||||
|
build( { 'public': true }, null, true );
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
assert.ok( e.message.search( name ) !== -1,
|
||||||
|
"Method override error message should contain getter/setter name"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail( type + " should not be able to override methods");
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getters/setters should not be able to override properties. While, at first,
|
||||||
|
* this concept may seem odd, keep in mind that the parent would likely not
|
||||||
|
* expect a subtype to be able to override property assignments. This could open
|
||||||
|
* up holes to exploit the parent class.
|
||||||
|
*/
|
||||||
|
testEach( function testCannotOverridePropertiesWithGetterOrSetter( type, build )
|
||||||
|
{
|
||||||
|
setUp();
|
||||||
|
|
||||||
|
// declare a property
|
||||||
|
members[ 'public' ][ name ] = 'foo';
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// attempt to override property with getter/setter (should fail)
|
||||||
|
build( { 'public': true }, null, true );
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
assert.ok( e.message.search( name ) !== -1,
|
||||||
|
"Property override error message should contain getter/setter name"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail( type + " should not be able to override properties" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
var common = require( './common' ),
|
var common = require( './common' ),
|
||||||
assert = require( 'assert' ),
|
assert = require( 'assert' ),
|
||||||
mb_common = require( __dirname + '/inc-member_builder-common' ),
|
mb_common = require( __dirname + '/inc-member_builder-common' ),
|
||||||
builder = common.require( 'member_builder' )
|
builder = common.require( 'member_builder' ),
|
||||||
|
util = common.require( 'util' )
|
||||||
;
|
;
|
||||||
|
|
||||||
mb_common.funcVal = 'foobar';
|
mb_common.funcVal = 'foobar';
|
||||||
|
@ -440,3 +441,85 @@ mb_common.assertCommon();
|
||||||
}, TypeError, "Cannot declare private abstract method" );
|
}, TypeError, "Cannot declare private abstract method" );
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While getters are technically methods, it doesn't make sense to override
|
||||||
|
* getters/setters with methods because they are fundamentally different.
|
||||||
|
*/
|
||||||
|
( function testCannotOverrideGetters()
|
||||||
|
{
|
||||||
|
if ( util.definePropertyFallback() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mb_common.members[ 'public' ] = {};
|
||||||
|
Object.defineProperty( mb_common.members[ 'public' ], mb_common.name, {
|
||||||
|
get: function() {},
|
||||||
|
} );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mb_common.value = function() {};
|
||||||
|
mb_common.buildMemberQuick( {}, true );
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
assert.ok( e.message.search( mb_common.name ) !== -1,
|
||||||
|
"Method override getter failure should contain method name"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ensure we have the correct error
|
||||||
|
assert.ok( e.message.search( 'getter' ) !== -1,
|
||||||
|
"Proper error is thrown for getter override failure"
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail(
|
||||||
|
"Should not be permitted to override getters with methods"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While setters are technically methods, it doesn't make sense to override
|
||||||
|
* getters/setters with methods because they are fundamentally different.
|
||||||
|
*/
|
||||||
|
( function testCannotOverrideSetters()
|
||||||
|
{
|
||||||
|
if ( util.definePropertyFallback() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mb_common.members[ 'public' ] = {};
|
||||||
|
Object.defineProperty( mb_common.members[ 'public' ], mb_common.name, {
|
||||||
|
set: function() {},
|
||||||
|
} );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mb_common.value = function() {};
|
||||||
|
mb_common.buildMemberQuick( {}, true );
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
assert.ok( e.message.search( mb_common.name ) !== -1,
|
||||||
|
"Method override setter failure should contain method name"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ensure we have the correct error
|
||||||
|
assert.ok( e.message.search( 'setter' ) !== -1,
|
||||||
|
"Proper error is thrown for setter override failure"
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail(
|
||||||
|
"Should not be permitted to override setters with methods"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
var common = require( './common' ),
|
var common = require( './common' ),
|
||||||
assert = require( 'assert' ),
|
assert = require( 'assert' ),
|
||||||
mb_common = require( __dirname + '/inc-member_builder-common' ),
|
mb_common = require( __dirname + '/inc-member_builder-common' ),
|
||||||
builder = common.require( 'member_builder' )
|
builder = common.require( 'member_builder' ),
|
||||||
|
util = common.require( 'util' )
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,3 +93,85 @@ mb_common.assertCommon();
|
||||||
assert.fail( "Should not be permitted to declare virtual properties" );
|
assert.fail( "Should not be permitted to declare virtual properties" );
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While getters act as properties, it doesn't make sense to override
|
||||||
|
* getters/setters with properties because they are fundamentally different.
|
||||||
|
*/
|
||||||
|
( function testCannotOverrideGetters()
|
||||||
|
{
|
||||||
|
if ( util.definePropertyFallback() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mb_common.members[ 'public' ] = {};
|
||||||
|
Object.defineProperty( mb_common.members[ 'public' ], mb_common.name, {
|
||||||
|
get: function() {},
|
||||||
|
} );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mb_common.value = 'foo';
|
||||||
|
mb_common.buildMemberQuick( {}, true );
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
assert.ok( e.message.search( mb_common.name ) !== -1,
|
||||||
|
"Property override getter failure should contain property name"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ensure we have the correct error
|
||||||
|
assert.ok( e.message.search( 'getter' ) !== -1,
|
||||||
|
"Proper error is thrown for getter override failure"
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail(
|
||||||
|
"Should not be permitted to override getters with properties"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While setters act as properties, it doesn't make sense to override
|
||||||
|
* getters/setters with properties because they are fundamentally different.
|
||||||
|
*/
|
||||||
|
( function testCannotOverrideSetters()
|
||||||
|
{
|
||||||
|
if ( util.definePropertyFallback() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mb_common.members[ 'public' ] = {};
|
||||||
|
Object.defineProperty( mb_common.members[ 'public' ], mb_common.name, {
|
||||||
|
set: function() {},
|
||||||
|
} );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mb_common.value = 'foo';
|
||||||
|
mb_common.buildMemberQuick( {}, true );
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
assert.ok( e.message.search( mb_common.name ) !== -1,
|
||||||
|
"Property override setter failure should contain method name"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ensure we have the correct error
|
||||||
|
assert.ok( e.message.search( 'setter' ) !== -1,
|
||||||
|
"Proper error is thrown for setter override failure"
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail(
|
||||||
|
"Should not be permitted to override setters with properties"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
/**
|
||||||
|
* Tests util.getPropertyDescriptor
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Mike Gerwitz
|
||||||
|
* @package test
|
||||||
|
*/
|
||||||
|
|
||||||
|
var common = require( './common' ),
|
||||||
|
assert = require( 'assert' ),
|
||||||
|
util = common.require( 'util' ),
|
||||||
|
|
||||||
|
get_set = !( util.definePropertyFallback() )
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If Object.getOwnPropertyDescriptor is provided by our environment, it should
|
||||||
|
* be used by util
|
||||||
|
*/
|
||||||
|
( function testUtilGetOwnPropertyDescriptorIsObjectsIfAvailable()
|
||||||
|
{
|
||||||
|
if ( Object.getOwnPropertyDescriptor )
|
||||||
|
{
|
||||||
|
assert.strictEqual(
|
||||||
|
util.getOwnPropertyDescriptor,
|
||||||
|
Object.getOwnPropertyDescriptor,
|
||||||
|
"Util should use Object.getOwnPropertyDescriptor if available"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should provide a boolean value indicating whether it can
|
||||||
|
* traverse the prototype chain
|
||||||
|
*/
|
||||||
|
( function testIndicatesWhetherTraversalIsPossible()
|
||||||
|
{
|
||||||
|
var traversable = ( {}.__proto__ ) ? true : false;
|
||||||
|
|
||||||
|
assert.equal( util.getPropertyDescriptor.canTraverse, traversable,
|
||||||
|
"Indicates whether traversal is possible"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We don't want tricksters to get funky with our system
|
||||||
|
*/
|
||||||
|
( function testTraversablePropertyIsNonWritable()
|
||||||
|
{
|
||||||
|
var getDesc;
|
||||||
|
|
||||||
|
if ( get_set )
|
||||||
|
{
|
||||||
|
assert.equal(
|
||||||
|
Object.getOwnPropertyDescriptor(
|
||||||
|
util.getPropertyDescriptor, 'canTraverse'
|
||||||
|
).writable,
|
||||||
|
false,
|
||||||
|
"Should not be able to alter canTravese value"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The return value should mimic Object.getOwnPropertyDescriptor() if we're not
|
||||||
|
* having to traverse the prototype chain
|
||||||
|
*/
|
||||||
|
( function testActsExactlyAsGetOwnPropertyDescriptorInEs5SystemsOnSameObject()
|
||||||
|
{
|
||||||
|
var obj = { foo: 'bar' },
|
||||||
|
desc1 = util.getOwnPropertyDescriptor( obj, 'foo' ),
|
||||||
|
desc2 = util.getPropertyDescriptor( obj, 'foo' )
|
||||||
|
;
|
||||||
|
|
||||||
|
assert.deepEqual( desc1, desc2,
|
||||||
|
"When operating one level deep, should return same as " +
|
||||||
|
"Object.getOwnPropertyDescriptor"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we *do* have to start traversing the prototype chain (which
|
||||||
|
* Object.getOwnPropertyDescriptor() cannot do), then it should be as if we
|
||||||
|
* called Object.getOwnPropertyDescriptor() on the object in the prototype chain
|
||||||
|
* containing the requested property.
|
||||||
|
*/
|
||||||
|
( function testTraversesThePrototypeChain()
|
||||||
|
{
|
||||||
|
// if we cannot traverse the prototype chain, this test is pointless
|
||||||
|
if ( !util.getPropertyDescriptor.canTraverse )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var proto = { foo: 'bar' },
|
||||||
|
obj = function() {}
|
||||||
|
;
|
||||||
|
|
||||||
|
obj.prototype = proto;
|
||||||
|
|
||||||
|
// to give ourselves the prototype chain (we don't want to set __proto__
|
||||||
|
// because this test will also be run on pre-ES5 engines)
|
||||||
|
var inst = new obj(),
|
||||||
|
|
||||||
|
// get the actual descriptor
|
||||||
|
expected = util.getOwnPropertyDescriptor( proto, 'foo' ),
|
||||||
|
|
||||||
|
// attempt to gather the descriptor from the prototype chain
|
||||||
|
given = util.getPropertyDescriptor( inst, 'foo' )
|
||||||
|
;
|
||||||
|
|
||||||
|
assert.deepEqual( given, expected,
|
||||||
|
"Properly traverses the prototype chain to retrieve the descriptor"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* Tests the Warning prototype
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Mike Gerwitz
|
||||||
|
* @package test
|
||||||
|
*/
|
||||||
|
|
||||||
|
var common = require( './common' ),
|
||||||
|
assert = require( 'assert' ),
|
||||||
|
Warning = common.require( 'warn' ).Warning
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning's prototype should be Error to ensure instanceof() checks work
|
||||||
|
* properly
|
||||||
|
*/
|
||||||
|
( function testWarningIsAvailableAndHasErrorAsPrototype()
|
||||||
|
{
|
||||||
|
assert.ok( ( Warning.prototype instanceof Error ),
|
||||||
|
"Warning should be an instance of Error"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just as with the other Error classes, as well as all ease.js classes, the
|
||||||
|
* 'new' keyword should be optional when instantiating the class
|
||||||
|
*/
|
||||||
|
( function testNewKeywordIsNotRequiredForInstantiation()
|
||||||
|
{
|
||||||
|
assert.ok( Warning( Error( '' ) ) instanceof Warning,
|
||||||
|
"'new' keyword should not be necessary to instantiate Warning"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning message should be taken from the exception passed to it
|
||||||
|
*/
|
||||||
|
( function testCanWarningMessageIsSetFromWrappedException()
|
||||||
|
{
|
||||||
|
var err = Error( 'oshit' ),
|
||||||
|
warning = Warning( err );
|
||||||
|
|
||||||
|
assert.equal( warning.message, err.message,
|
||||||
|
"Warning message should be taken from wrapped exception"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The whole point of Warning is to wrap an exception. So, ensure that one is
|
||||||
|
* wrapped.
|
||||||
|
*/
|
||||||
|
( function testThrowsExceptionIfNoExceptionIsWrapped()
|
||||||
|
{
|
||||||
|
assert.throws( function()
|
||||||
|
{
|
||||||
|
Warning( /* nothing provided to wrap */ );
|
||||||
|
}, TypeError, "Exception should be thrown if no exception is provided" );
|
||||||
|
|
||||||
|
assert.throws( function()
|
||||||
|
{
|
||||||
|
Warning( 'not an exception' );
|
||||||
|
}, TypeError, "Exception should be thrown if given value is not an Error" );
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We must provide access to the wrapped exception so that it can be properly
|
||||||
|
* handled. Warning is only intended to provide additional information so that
|
||||||
|
* ease.js may handle it differently than other Error instances.
|
||||||
|
*/
|
||||||
|
( function testCanRetrieveWrappedException()
|
||||||
|
{
|
||||||
|
var err = Error( 'foo' ),
|
||||||
|
warning = Warning( err );
|
||||||
|
|
||||||
|
assert.deepEqual( err, warning.getError(),
|
||||||
|
"Can retrieve wrapped exception"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/**
|
||||||
|
* Tests core warning handlers
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Mike Gerwitz
|
||||||
|
* @package test
|
||||||
|
*/
|
||||||
|
|
||||||
|
var common = require( './common' ),
|
||||||
|
assert = require( 'assert' ),
|
||||||
|
warn = common.require( 'warn' ),
|
||||||
|
Warning = warn.Warning,
|
||||||
|
|
||||||
|
warning = Warning( Error( 'gninraw' ) )
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the console object, without throwing errors if it does not exist
|
||||||
|
*
|
||||||
|
* @return {Object} console
|
||||||
|
*/
|
||||||
|
function backupConsole()
|
||||||
|
{
|
||||||
|
// ensure that we don't throw errors if console is not defined
|
||||||
|
if ( typeof console !== 'undefined' )
|
||||||
|
{
|
||||||
|
return console;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The log warning handler should log warnings to the console
|
||||||
|
*/
|
||||||
|
( function testLogWarningHandlerLogsMessageToConsole()
|
||||||
|
{
|
||||||
|
var logged = false,
|
||||||
|
|
||||||
|
// back up console ref
|
||||||
|
console_ = backupConsole()
|
||||||
|
;
|
||||||
|
|
||||||
|
// mock console
|
||||||
|
console = {
|
||||||
|
warn: function( message )
|
||||||
|
{
|
||||||
|
assert.equal( message, warning.message,
|
||||||
|
"Should log proper message to console"
|
||||||
|
);
|
||||||
|
|
||||||
|
logged = true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// call handler with the warning
|
||||||
|
warn.handlers.log( warning );
|
||||||
|
|
||||||
|
assert.equal( logged, true,
|
||||||
|
"Message should be logged to console"
|
||||||
|
);
|
||||||
|
|
||||||
|
// restore console
|
||||||
|
console = console_;
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some environments may not have a console reference, or they may not have
|
||||||
|
* console.warn. In this case, we just want to make sure we don't throw an error
|
||||||
|
* when attempting to invoke undefined, or access a property of undefined.
|
||||||
|
*/
|
||||||
|
( function testLogWarningHandlerHandlesMissingConsole()
|
||||||
|
{
|
||||||
|
// back up console
|
||||||
|
var console_ = backupConsole();
|
||||||
|
|
||||||
|
// destroy it
|
||||||
|
console = undefined;
|
||||||
|
|
||||||
|
// attempt to log
|
||||||
|
warn.handlers.log( warning );
|
||||||
|
|
||||||
|
// restore console
|
||||||
|
console = console_;
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Furthermore, an environment may implement console.log(), but not
|
||||||
|
* console.warn(). By default, we use warn(), so let's ensure we can fall back
|
||||||
|
* to log() if warn() is unavailable.
|
||||||
|
*/
|
||||||
|
( function testLogWarningHandlerWillFallBackToLogMethodIfWarnIsMissing()
|
||||||
|
{
|
||||||
|
// back up and overwrite console to contain only log()
|
||||||
|
var console_ = backupConsole(),
|
||||||
|
given = '';
|
||||||
|
|
||||||
|
console = {
|
||||||
|
log: function( message )
|
||||||
|
{
|
||||||
|
given = message;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// attempt to log
|
||||||
|
warn.handlers.log( warning );
|
||||||
|
|
||||||
|
assert.equal( given, warning.message,
|
||||||
|
"Should fall back to log() and log proper message"
|
||||||
|
);
|
||||||
|
|
||||||
|
// restore console
|
||||||
|
console = console_;
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The throwError warning handler should throw the wrapped error as an exception
|
||||||
|
*/
|
||||||
|
( function testThrowErrorWarningHandlerThrowsWrappedError()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
warn.handlers.throwError( warning );
|
||||||
|
}
|
||||||
|
catch ( e )
|
||||||
|
{
|
||||||
|
assert.deepEqual( e, warning.getError(),
|
||||||
|
"Wrapped exception should be thrown"
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.fail( "Wrapped exception should be thrown" );
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 'dismiss' error handler is a pretty basic concept. Simply do nothing. We
|
||||||
|
* don't want to log, we don't want to throw anything, we just want to pretend
|
||||||
|
* nothing ever happened and move on our merry way. This is intended for use in
|
||||||
|
* production environments where providing warnings may provide too much insight
|
||||||
|
* into the software.
|
||||||
|
*/
|
||||||
|
( function testDismissWarningHandlerShouldDoNothing()
|
||||||
|
{
|
||||||
|
// destroy the console to ensure nothing is logged
|
||||||
|
var console_ = backupConsole();
|
||||||
|
console = undefined;
|
||||||
|
|
||||||
|
// don't catch anything, to ensure no errors occur and that no exceptions
|
||||||
|
// are thrown
|
||||||
|
warn.handlers.dismiss( warning );
|
||||||
|
|
||||||
|
// restore console
|
||||||
|
console = console_;
|
||||||
|
} )();
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/**
|
||||||
|
* Tests warning system implementation
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @author Mike Gerwitz
|
||||||
|
* @package test
|
||||||
|
*/
|
||||||
|
|
||||||
|
var common = require( './common' ),
|
||||||
|
assert = require( 'assert' ),
|
||||||
|
warn = common.require( 'warn' )
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default warning handler should be the 'log' handler. This is a friendly
|
||||||
|
* compromise that will allow the developer to be warned of potential issues
|
||||||
|
* without affecting program execution.
|
||||||
|
*/
|
||||||
|
( function testDefaultHandlerIsLogger()
|
||||||
|
{
|
||||||
|
// back up console object
|
||||||
|
var console_ = ( typeof console !== 'undefined' ) ? console : undefined,
|
||||||
|
called = false;
|
||||||
|
|
||||||
|
// stub it
|
||||||
|
console = {
|
||||||
|
warn: function()
|
||||||
|
{
|
||||||
|
called = true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
warn.handle( warn.Warning( Error( 'foo' ) ) );
|
||||||
|
|
||||||
|
assert.ok( called,
|
||||||
|
"Default handler will log to console"
|
||||||
|
);
|
||||||
|
|
||||||
|
// restore console
|
||||||
|
console = console_;
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The warning handler can be altered at runtime. Ensure we can set it and call
|
||||||
|
* it appropriately. We do not need to use one of the pre-defined handlers.
|
||||||
|
*/
|
||||||
|
( function testCanSetAndCallWarningHandler()
|
||||||
|
{
|
||||||
|
var given,
|
||||||
|
warning = warn.Warning( Error( 'foo' ) );
|
||||||
|
|
||||||
|
// set a stub warning handler
|
||||||
|
warn.setHandler( function( warn )
|
||||||
|
{
|
||||||
|
given = warn;
|
||||||
|
} );
|
||||||
|
|
||||||
|
// trigger the handler
|
||||||
|
warn.handle( warning );
|
||||||
|
|
||||||
|
assert.deepEqual( given, warning,
|
||||||
|
"Set warning handler should be called with given Warning"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
|
@ -29,7 +29,7 @@ TPL_VAR='/**{CONTENT}**/'
|
||||||
RMTRAIL="$PATH_TOOLS/rmtrail"
|
RMTRAIL="$PATH_TOOLS/rmtrail"
|
||||||
|
|
||||||
# order matters
|
# order matters
|
||||||
CAT_MODULES="prop_parser util propobj member_builder class_builder"
|
CAT_MODULES="warn prop_parser util propobj member_builder class_builder"
|
||||||
CAT_MODULES="$CAT_MODULES class class_final class_abstract interface"
|
CAT_MODULES="$CAT_MODULES class class_final class_abstract interface"
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -73,7 +73,7 @@ module.assert = { exports: {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cmp instanceof Array )
|
if ( ( cmp instanceof Array ) && ( val instanceof Array ) )
|
||||||
{
|
{
|
||||||
var i = 0,
|
var i = 0,
|
||||||
len = cmp.length;
|
len = cmp.length;
|
||||||
|
@ -86,7 +86,7 @@ module.assert = { exports: {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if ( cmp instanceof Object )
|
else if ( ( typeof cmp === 'object' ) && ( typeof val === 'object' ) )
|
||||||
{
|
{
|
||||||
for ( var i in cmp )
|
for ( var i in cmp )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue