Skip to content
This repository was archived by the owner on Sep 19, 2018. It is now read-only.

Issue #177: Update assert_readonly implementation to use ES5 features #178

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions examples/apisample.htm
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,41 @@ <h1>Sample HTML5 API Tests</h1>
assert_throws("TEST_ERR", function() {throw e});
}, "Test assert_throws with non-DOM-exception expected to Fail");

test(function()
{
var o = Object.create(null, {
"readonly": {value: NaN, writable: false}
});

assert_readonly(Object.create(o), "readonly", "must succeed for inherited properties.");
}, "Test assert_readonly with non-writable property.");

test(function()
{
var o = Object.create(null, {
"readonly": { get: function() { throw new Error('Access is denied.'); }}
});

assert_readonly(o, "readonly", "must anticipate a get accessor that throws.");
}, "Test assert_readonly with non-settable property.");

test(function()
{
var o = { writable: NaN };
assert_readonly(o, "writable", "expected failure.");
}, "Test assert_readonly with writable property expected to fail.");

test(function()
{
var o = Object.create(null, {
"settable": {
get: function() { return NaN; },
set: function() {}
}});

assert_readonly(o, "settable", "expected failure.");
}, "Test assert_readonly with settable property expected to fail.");

var t = async_test("Test step_func")
setTimeout(
t.step_func(
Expand Down
63 changes: 49 additions & 14 deletions testharness.js
Original file line number Diff line number Diff line change
Expand Up @@ -1128,20 +1128,55 @@ policies and contribution forms [3].
expose(_assert_inherits("assert_inherits"), "assert_inherits");
expose(_assert_inherits("assert_idl_attribute"), "assert_idl_attribute");

function assert_readonly(object, property_name, description)
{
var initial_value = object[property_name];
try {
//Note that this can have side effects in the case where
//the property has PutForwards
object[property_name] = initial_value + "a"; //XXX use some other value here?
assert(same_value(object[property_name], initial_value),
"assert_readonly", description,
"changing property ${p} succeeded",
{p:property_name});
} finally {
object[property_name] = initial_value;
}
function getPropertyDescriptor(object, property_name) {
for (; object; object = Object.getPrototypeOf(object)) {
var descriptor = Object.getOwnPropertyDescriptor(object, property_name);
if (descriptor) {
return descriptor;
}
}
return undefined;
}

function assert_readonly(object, property_name, description) {
// Ensure that the property is non-writable and has no set accessor.
var descriptor = getPropertyDescriptor(object, property_name);
assert(!!descriptor, "assert_readonly", description, "property ${p} not defined on object.", {p:property_name});
assert(!descriptor.writable, "assert_readonly", description, "property ${p} must not be writable.", {p:property_name});
assert(!descriptor.set, "assert_readonly", description, "property ${p} must not define a set accessor.", {p:property_name});

// Attempt to retrieve the current proprety value to use as one of our test values below.
var maybe_initial_value = "initial value unknown";
try {
maybe_initial_value = object[property_name];
} catch (e) {
// Swallow any errors. It's valid for a property to throw (e.g., 'Access is denied').
}

// Ensure that setting the property in 'strict mode' fails with a TypeError. We attempt
// setting a few values that possibly involve special handling in host implementations.
[maybe_initial_value, undefined, null, NaN]
.forEach(function (value) {
'use strict';

var thrown = undefined;
try {
object[property_name] = value;
} catch (e) {
thrown = e;
}

// Ensure a TypeError was thrown.
assert(!!thrown, "assert_readonly", description,
"setting property ${p} to ${v} must throw an error when in strict mode, but did not.",
{p:property_name, v:value});
assert(thrown.name === "TypeError", "assert_readonly", description,
"setting property ${p} to ${v} must throw a TypeError when in strict mode, but threw ${e}.",
{p:property_name, v:value, e:thrown.name});

// Note: While it would be unusual, a readonly property can conceivably change value.
// Therefore, we do not assert that the current value matches the initial value.
});
}
expose(assert_readonly, "assert_readonly");

Expand Down