diff --git a/lib/util.js b/lib/util.js index db35e75..da063da 100644 --- a/lib/util.js +++ b/lib/util.js @@ -598,7 +598,7 @@ function getDefineSecureProp() // exceptions will do nothing but slow down the system exports.definePropertyFallback( true ); - // if there's an error (ehem, IE8), fall back + // there's an error (ehem, IE8); fall back fallback( obj, prop, value ); } }; diff --git a/test/Util/DefineSecurePropTest.js b/test/Util/DefineSecurePropTest.js new file mode 100644 index 0000000..d530f80 --- /dev/null +++ b/test/Util/DefineSecurePropTest.js @@ -0,0 +1,181 @@ +/** + * Tests util.defineSecureProp + * + * 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( +{ + caseSetUp: function() + { + this.Sut = this.require( 'util' ); + + this.expected = ( ( Object.defineProperty instanceof Function ) + ? false + : true + ); + + this.fallback = this.Sut.definePropertyFallback(); + + // IE 8 will fall back on first failure because of its partial + // implementation (DOM elements only...!) + if ( !( this.expected ) && this.fallback ) + { + try + { + this.Sut.definePropertyFallback( false ); + this.Sut.defineSecureProp( {}, 'foo', 1 ); + + // If the fallback was changed on us, then there was a + // problem (and this is likely IE8); change the value we're + // expecting so our tests don't fail. + if ( this.Sut.definePropertyFallback() === true ) + { + this.expected = true; + } + } + catch ( e ) {} + } + + this.descRestrictionCheck = function( type, expected ) + { + this.fallback && this.skip(); + + var obj = {}; + this.Sut.defineSecureProp( obj, 'foo', null ); + this.assertEqual( + Object.getOwnPropertyDescriptor( obj, 'foo' )[ type ], + expected + ); + }; + + // TODO: this is only necessary because we use global state; get rid + // of that state. + this.forceFallback = function( c ) + { + this.Sut.definePropertyFallback( true ); + c.call( this ); + this.Sut.definePropertyFallback( this.fallback ); + }; + }, + + + /** + * The definition of ``secure'' fields depends on ECMAScript 5. + */ + 'definePropertyFallback returns whether secure definition is supported': + function() + { + this.assertEqual( + this.expected, + this.Sut.definePropertyFallback() + ); + }, + + + /** + * Permits method chaining. + */ + 'definePropertyFallback returns util when used as a setter': function() + { + this.assertStrictEqual( + this.Sut.definePropertyFallback( this.fallback ), + this.Sut + ); + }, + + + /** + * The data created by the defineSecureProp function should exist + * regardless of whether or not the concept of a ``secure'' property is + * supported by the environment. + */ + 'Defining secure prop creates field with given value on given object': + function() + { + var obj = {}, + val = { bar: 'baz' }; + + this.Sut.defineSecureProp( obj, 'foo', val ); + this.assertStrictEqual( obj.foo, val ); + }, + + + /** + * Our assertions below are going to use the data from the following + * method. We're not going to test directly whether they're writable, + * etc, because different engines may have different interpretations at + * this stage. (Or it may not yet be implemented.) Therefore, we'll + * simply see if what we requested has been set, and leave the problems + * up to the engine developers. + * + * This is a case of ensuring we're testing our own functionality---we + * do not want to test engine functionality. + */ + 'Secure property is not writable': function() + { + this.descRestrictionCheck( 'writable', false ); + }, + 'Secure property is not configurable': function() + { + this.descRestrictionCheck( 'configurable', false ); + }, + 'Secure property is not enumerable': function() + { + this.descRestrictionCheck( 'enumerable', false ); + }, + + + /** + * These tests the same as the above set of tests, but forces a fallback + * to pre-ES5 functionality. + */ + 'Defining secure prop creates field and value when falling back': + function() + { + this.forceFallback( function() + { + var obj = {}, + val = { bar: 'baz' }; + + this.Sut.defineSecureProp( obj, 'foo', val ); + this.assertStrictEqual( obj.foo, val ); + } ); + }, + 'Secure property is writable when falling back': function() + { + this.forceFallback( function() + { + this.descRestrictionCheck( 'writable', true ); + } ); + }, + 'Secure property is configurable when falling back': function() + { + this.forceFallback( function() + { + this.descRestrictionCheck( 'configurable', true ); + } ); + }, + 'Secure property is enumerable when falling back': function() + { + this.forceFallback( function() + { + this.descRestrictionCheck( 'enumerable', true ); + } ); + }, +} ); diff --git a/test/test-util-define-secure-prop.js b/test/test-util-define-secure-prop.js deleted file mode 100644 index 588ddf8..0000000 --- a/test/test-util-define-secure-prop.js +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Tests util.defineSecureProp - * - * 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' ), - util = common.require( 'util' ); - -var obj = {}, - val = 'bar'; - -var expected = ( ( Object.defineProperty instanceof Function ) ? false : true ), - fallback = util.definePropertyFallback(); - -// IE 8 will fall back on first failure -if ( !expected && fallback ) -{ - try - { - util.definePropertyFallback( false ); - util.defineSecureProp( {}, 'foo', 1 ); - - // If the fallback was changed on us, then there was a problem (and this - // is likely IE8). Change the value we're expecting so our tests don't - // fail. - if ( util.definePropertyFallback() === true ) - { - expected = true; - } - } - catch ( e ) {} -} - -assert.equal( - expected, - fallback, - "util.definePropertyFallback() returns whether defining a secure property is " + - "unsupported" -); - -assert.equal( - util.definePropertyFallback( fallback ), - util, - "util.definePropertyFallback() returns self when used as a setter" -); - -// perform secure property tests only if our parser supports it -if ( fallback === false ) -{ - util.defineSecureProp( obj, 'foo', val ); - - assert.equal( - obj.foo, - val, - "Defining a secure prop creates a property with the correct value on " + - "the given object" - ); - - // Our assertions below are going to use the data from the following method. - // We're not going to test directly whether they're writable, etc, because - // different engines may have different interpretations at this stage. (Or - // it may not yet be implemented.) Therefore, we'll simply see if what we - // requested has been set, and leave the problems up to the engine - // developers. - // - // This is a case of ensuring we're testing our own functionality. We do not - // want to test engine functionality. - var desc = Object.getOwnPropertyDescriptor( obj, 'foo' ); - - assert.equal( - desc.writable, - false, - "Secure property is not writable" - ); - - assert.equal( - desc.configurable, - false, - "Secure property is not configurable" - ); - - assert.equal( - desc.enumerable, - false, - "Secure property is not enumerable" - ); -} - - -// be naughty so we can test the alternative implementation -util.definePropertyFallback( true ); - -var obj2 = {}, - val2 = 'baz'; - -// this should fall back on defining a normal property -util.defineSecureProp( obj2, 'foo', val2 ); - -assert.equal( - obj2.foo, - val2, - "Secure property fallback still creates a property with the correct " + - "value on the given object" -); - -// if we have the ES5 functions available, ensure that the property was not -// defined securely -if ( fallback === false ) -{ - var desc2 = Object.getOwnPropertyDescriptor( obj2, 'foo' ); - - assert.equal( - desc2.writable, - true, - "Secure property is writable when falling back" - ); - - assert.equal( - desc2.configurable, - true, - "Secure property is configurable when falling back" - ); - - assert.equal( - desc2.enumerable, - true, - "Secure property is enumerable when falling back" - ); -} - -// restore in case the tests are not being run in separate processes -util.definePropertyFallback( fallback ); -