Skip to content

Commit

Permalink
Fix 2377: Throw error when trying to stub non-configurable or non-wri…
Browse files Browse the repository at this point in the history
…table properties (#2417)

Fixes issue #2377 by throwing an error when trying to stub non-configurable or non-writable properties
  • Loading branch information
sdotson committed Dec 24, 2021
1 parent 27df9cb commit 12a4593
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
22 changes: 22 additions & 0 deletions lib/sinon/stub.js
Expand Up @@ -81,6 +81,9 @@ function stub(object, property) {
}

var actualDescriptor = getPropertyDescriptor(object, property);

assertValidPropertyDescriptor(actualDescriptor, property);

var isObjectOrFunction =
typeof object === "object" || typeof object === "function";
var isStubbingEntireObject =
Expand Down Expand Up @@ -147,6 +150,25 @@ stub.createStubInstance = function (constructor, overrides) {
return stubbedObject;
};

function assertValidPropertyDescriptor(descriptor, property) {
if (!descriptor || !property) {
return;
}
if (!descriptor.configurable && !descriptor.writable) {
throw new TypeError(`Descriptor for property ${property} is non-configurable and non-writable`);
}
if ((descriptor.get || descriptor.set) && !descriptor.configurable) {
throw new TypeError(`Descriptor for accessor property ${property} is non-configurable`);
}
if (isDataDescriptor(descriptor) && !descriptor.writable) {
throw new TypeError(`Descriptor for data property ${property} is non-writable`);
}
}

function isDataDescriptor(descriptor) {
return !descriptor.value && !descriptor.writable && !descriptor.set && !descriptor.get;
}

/*eslint-disable no-use-before-define*/
function getParentBehaviour(stubInstance) {
return stubInstance.parent && getCurrentBehavior(stubInstance.parent);
Expand Down
47 changes: 47 additions & 0 deletions test/shared-spy-stub-everything-tests.js
Expand Up @@ -151,4 +151,51 @@ module.exports = function shared(createSpyOrStub) {

assert.isUndefined(myObj.ouch);
});

it("throws on data property descriptors that are not writable or configurable", function () {
var myObj = {};
Object.defineProperty(myObj, 'ignoreme', {
writable: false,
configurable: false
});

assert.exception(function () {
createSpyOrStub(myObj, "ignoreme");
},
new TypeError('Descriptor for property ignoreme is non-configurable and non-writable')
);
});

it("throws on accessor property descriptors that are not configurable", function () {
var myObj = {};
Object.defineProperty(myObj, 'ignoreme', {
get: function(key) {
return this[key];
},
set: function(key, val) {
this[key] = val;
},
configurable: false
});

assert.exception(function () {
createSpyOrStub(myObj, "ignoreme");
},
new TypeError('Descriptor for accessor property ignoreme is non-configurable')
);
});

it("throws on data descriptors that are not stubbable", function () {
var myObj = {};
Object.defineProperty(myObj, 'ignoreme', {
writable: false,
configurable: false
});

assert.exception(function () {
createSpyOrStub(myObj, "ignoreme");
},
new TypeError('Descriptor for data property ignoreme is non-writable')
);
});
};

0 comments on commit 12a4593

Please sign in to comment.