Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!-- Any copyright is dedicated to the Public Domain.
<!DOCTYPE HTML>
<html>
<head>
<title>Test Observable Array Type</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script>
/* global TestInterfaceObservableArray */
add_task(async function init() {
await SpecialPowers.pushPrefEnv({set: [["dom.expose_test_interfaces", true]]});
});
add_task(function testObservableArrayExoticObjects_defineProperty() {
let setCallbackCount = 0;
let deleteCallbackCount = 0;
let setCallbackTests = null;
let deleteCallbackTests = null;
let m = new TestInterfaceObservableArray({
setBooleanCallback(value, index) {
setCallbackCount++;
if (typeof setCallbackTests === 'function') {
setCallbackTests(value, index);
}
},
deleteBooleanCallback(value, index) {
deleteCallbackCount++;
if (typeof deleteCallbackTests === 'function') {
deleteCallbackTests(value, index);
}
},
});
m.observableArrayBoolean = [true, true, true];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 3, "length of observable array should be 0");
// Test length
[
// [descriptor, shouldThrow, expectedResult]
// Invalid descriptor
[{configurable: true, value: 0}, false, false],
[{enumerable: true, value: 0}, false, false],
[{writable: false, value: 0}, false, false],
[{get: ()=>{}}, false, false],
[{set: ()=>{}}, false, false],
[{get: ()=>{}, set: ()=>{}}, false, false],
[{get: ()=>{}, value: 0}, true],
// Invalid length value
[{value: 1.9}, true],
[{value: "invalid"}, true],
[{value: {}}, true],
// length value should not greater than current length
[{value: b.length + 1}, false, false],
// descriptor without value
[{configurable: false, enumerable: false, writable: true}, false, true],
// Success
[{value: b.length}, false, true],
[{value: b.length - 1}, false, true],
[{value: 0}, false, true],
].forEach(function([descriptor, shouldThrow, expectedResult]) {
// Initialize
let oldLen = b.length;
let oldValues = b.slice();
let deleteCallbackIndex = oldLen - 1;
let success = expectedResult && "value" in descriptor;
setCallbackCount = 0;
deleteCallbackCount = 0;
setCallbackTests = null;
deleteCallbackTests = function(_value, _index) {
is(_value, oldValues[deleteCallbackIndex], "deleteCallbackTests: test value argument");
is(_index, deleteCallbackIndex, "deleteCallbackTests: test index argument");
deleteCallbackIndex--;
};
// Test
info(`defining "length" property with ${JSON.stringify(descriptor)}`);
try {
is(Reflect.defineProperty(b, "length", descriptor), expectedResult,
`Reflect.defineProperty should return ${expectedResult}`);
ok(!shouldThrow, "Reflect.defineProperty should not throw");
} catch(e) {
ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
}
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, success ? oldLen - descriptor.value : 0, "deleteCallback count");
isDeeply(b, success ? oldValues.slice(0, descriptor.value) : oldValues, "property values");
is(b.length, success ? descriptor.value : oldLen, "length of observable array");
});
// Test indexed value
[
// [index, descriptor, shouldThrow, expectedResult]
// Invalid descriptor
[0, {configurable: false, value: true}, false, false],
[0, {enumerable: false, value: true}, false, false],
[0, {writable: false, value: true}, false, false],
[0, {get: ()=>{}}, false, false],
[0, {set: ()=>{}}, false, false],
[0, {get: ()=>{}, set: ()=>{}}, false, false],
[0, {get: ()=>{}, value: true}, true],
// Index could not greater than last index + 1.
[b.length + 1, {configurable: true, enumerable: true, value: true}, false, false],
// descriptor without value
[b.length, {configurable: true, enumerable: true}, false, true],
// Success
[b.length, {configurable: true, enumerable: true, value: true}, false, true],
[b.length + 1, {configurable: true, enumerable: true, value: true}, false, true],
].forEach(function([index, descriptor, shouldThrow, expectedResult]) {
// Initialize
let oldLen = b.length;
let oldValue = b[index];
let success = expectedResult && "value" in descriptor;
setCallbackCount = 0;
deleteCallbackCount = 0;
setCallbackTests = function(_value, _index) {
is(_value, descriptor.value, "setCallbackTests: test value argument");
is(_index, index, "setCallbackTests: test index argument");
};
deleteCallbackTests = function(_value, _index) {
is(_value, oldValue, "deleteCallbackTests: test value argument");
is(_index, index, "deleteCallbackTests: test index argument");
};
// Test
info(`defining ${index} property with ${JSON.stringify(descriptor)}`);
try {
is(Reflect.defineProperty(b, index, descriptor), expectedResult,
`Reflect.defineProperty should return ${expectedResult}`);
ok(!shouldThrow, "Reflect.defineProperty should not throw");
} catch(e) {
ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
}
is(setCallbackCount, success ? 1 : 0, "setCallback count");
is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
is(b[index], success ? descriptor.value : oldValue, "property value");
is(b.length, success ? Math.max(index + 1, oldLen) : oldLen, "length of observable array");
});
// Test other property
[
// [property, descriptor, shouldThrow, expectedResult]
["prop1", {configurable: false, value: "value1"}, false, true],
["prop1", {configurable: true, value: "value2"}, false, false],
["prop2", {enumerable: false, value: 5}, false, true],
["prop3", {enumerable: false, value: []}, false, true],
["prop4", {enumerable: false, value: {}}, false, true],
["prop5", {get: ()=>{}, value: true}, true, false],
["prop6", {get: ()=>{}, set: ()=>{}}, false, true],
].forEach(function([property, descriptor, shouldThrow, expectedResult]) {
// Initialize
let oldValue = b[property];
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
setCallbackTests = null;
deleteCallbackTests = null;
// Test
info(`defining ${property} property with ${JSON.stringify(descriptor)}`);
try {
is(Reflect.defineProperty(b, property, descriptor), expectedResult,
`Reflect.defineProperty should return ${expectedResult}`);
ok(!shouldThrow, "Reflect.defineProperty should not throw");
} catch(e) {
ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
}
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, 0, "deleteCallback count");
is(b[property], expectedResult ? descriptor.value : oldValue, "property value");
is(b.length, oldLen, "length of observable array");
});
});
add_task(function testObservableArrayExoticObjects_defineProperty_callback_throw() {
let setCallbackCount = 0;
let deleteCallbackCount = 0;
const minLen = 3;
let m = new TestInterfaceObservableArray({
setBooleanCallback(value) {
setCallbackCount++;
if (value) {
throw new Error("setBooleanCallback");
}
},
deleteBooleanCallback(value, index) {
deleteCallbackCount++;
if (index < minLen) {
throw new Error("deleteBooleanCallback");
}
},
});
m.observableArrayBoolean = [false, false, false, false, false];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 5, "length of observable array should be 3");
// Test length
[
// [length, shouldThrow]
[b.length, false],
[b.length - 1, false],
[0, true],
].forEach(function([length, shouldThrow]) {
// Initialize
let oldValues = b.slice();
let oldLen = b.length;
let descriptor = {value: length};
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`defining "length" property with ${JSON.stringify(descriptor)}`);
try {
ok(Reflect.defineProperty(b, "length", descriptor),
"Reflect.defineProperty should return true");
ok(!shouldThrow, "Reflect.defineProperty should not throw");
} catch(e) {
ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
}
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, oldLen - (shouldThrow ? minLen - 1 : length), "deleteCallback count");
isDeeply(b, oldValues.slice(0, shouldThrow ? minLen : length), "property values");
is(b.length, shouldThrow ? minLen : length, "length of observable array");
});
// Test indexed value
[
// [index, value, shouldThrow]
[b.length, true, true],
[b.length, false, false],
[b.length + 1, false, false],
[b.length + 1, true, true],
[0, true, true],
[0, false, true],
].forEach(function([index, value, shouldThrow]) {
// Initialize
let oldValue = b[index];
let oldLen = b.length;
let descriptor = {configurable: true, enumerable: true, value};
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`defining ${index} property with ${JSON.stringify(descriptor)}`);
try {
ok(Reflect.defineProperty(b, index, descriptor), "Reflect.defineProperty should return true");
ok(!shouldThrow, "Reflect.defineProperty should not throw");
} catch(e) {
ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
}
is(setCallbackCount, (index < minLen) ? 0 : 1, "setCallback count");
is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
is(b[index], shouldThrow ? oldValue : value, "property value");
is(b.length, shouldThrow ? oldLen : Math.max(oldLen, index + 1), "length of observable array");
});
// Test other property
[
// [property, descriptor, expectedResult]
["prop1", {configurable: false, value: "value1"}, true],
["prop1", {configurable: true, value: "value2"}, false],
["prop2", {enumerable: false, value: 5}, true],
["prop3", {enumerable: false, value: []}, true],
["prop4", {enumerable: false, value: {}}, true],
].forEach(function([property, descriptor, expectedResult]) {
// Initialize
let oldValue = b[property];
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`defining ${property} property with ${JSON.stringify(descriptor)}`);
try {
is(Reflect.defineProperty(b, property, descriptor), expectedResult,
`Reflect.defineProperty should return ${expectedResult}`);
ok(true, "Reflect.defineProperty should not throw");
} catch(e) {
ok(false, `Reflect.defineProperty throws ${e}`);
}
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, 0, "deleteCallback count");
is(b[property], expectedResult ? descriptor.value : oldValue, "property value");
is(b.length, oldLen, "length of observable array");
});
});
add_task(function testObservableArrayExoticObjects_deleteProperty() {
let setCallbackCount = 0;
let deleteCallbackCount = 0;
let deleteCallbackTests = null;
let m = new TestInterfaceObservableArray({
setBooleanCallback() {
setCallbackCount++;
},
deleteBooleanCallback(value, index) {
deleteCallbackCount++;
if (typeof deleteCallbackTests === 'function') {
deleteCallbackTests(value, index);
}
},
});
m.observableArrayBoolean = [true, true];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 2, "length of observable array should be 2");
// Test length
setCallbackCount = 0;
deleteCallbackCount = 0;
info("deleting length property");
ok(!Reflect.deleteProperty(b, "length"), "test result of deleting length property");
is(setCallbackCount, 0, "setCallback should not be called");
is(deleteCallbackCount, 0, "deleteCallback should not be called");
is(b.length, 2, "length should still be 2");
// Test indexed value
[
// [index, expectedResult]
[2, false],
[0, false],
[1, true],
].forEach(function([index, expectedResult]) {
// Initialize
let oldLen = b.length;
let oldValue = b[index];
setCallbackCount = 0;
deleteCallbackCount = 0;
deleteCallbackTests = function(_value, _index) {
is(_value, oldValue, "deleteCallbackTests: test value argument");
is(_index, index, "deleteCallbackTests: test index argument");
};
// Test
info(`deleting ${index} property`);
is(Reflect.deleteProperty(b, index), expectedResult,
`Reflect.deleteProperty should return ${expectedResult}`);
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, expectedResult ? 1 : 0, "deleteCallback count");
is(b[index], expectedResult ? undefined : oldValue, "property value");
is(b.length, expectedResult ? oldLen - 1 : oldLen,
"length of observable array");
});
// Test other property
[
// [property, value]
["prop1", "value1"],
["prop2", 5],
["prop3", []],
["prop4", {}],
].forEach(function([property, value]) {
// Initialize
b[property] = value;
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
deleteCallbackTests = null;
// Test
info(`deleting ${property} property`);
is(b[property], value, `property value should be ${value} before deleting`);
ok(Reflect.deleteProperty(b, property), "Reflect.deleteProperty should return true");
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, 0, "deleteCallback count");
is(b[property], undefined, "property value should be undefined after deleting");
is(b.length, oldLen, "length of observable array");
});
});
add_task(function testObservableArrayExoticObjects_deleteProperty_callback_throw() {
let setCallbackCount = 0;
let deleteCallbackCount = 0;
let m = new TestInterfaceObservableArray({
setBooleanCallback() {
setCallbackCount++;
},
deleteBooleanCallback(value) {
deleteCallbackCount++;
if (value) {
throw new Error("deleteBooleanCallback");
}
},
});
m.observableArrayBoolean = [true, false];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 2, "length of observable array should be 2");
// Test indexed value
let index = b.length;
while (index--) {
// Initialize
let oldValue = b[index];
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`deleting index ${index}`);
try {
ok(Reflect.deleteProperty(b, index), "Reflect.deleteProperty should return true");
ok(!oldValue, "Reflect.deleteProperty should not throw");
} catch(e) {
ok(oldValue, `Reflect.deleteProperty throws ${e}`);
}
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, 1, "deleteCallback count");
is(b[index], oldValue ? oldValue : undefined, "property value");
is(b.length, oldValue ? oldLen : oldLen - 1, "length of observable array");
}
// Test other property
[
// [property, value]
["prop1", "value1"],
["prop2", 5],
["prop3", []],
["prop4", {}],
["prop5", false],
].forEach(function([property, value]) {
// Initialize
b[property] = value;
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`deleting ${property} property`);
is(b[property], value, `property value should be ${JSON.stringify(value)} before deleting`);
try {
ok(Reflect.deleteProperty(b, property), `Reflect.deleteProperty should return true`);
ok(true, "Reflect.deleteProperty should not throw");
} catch(e) {
ok(false, `Reflect.deleteProperty throws ${e}`);
}
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, 0, "deleteCallback count");
is(b[property], undefined, `property value should be undefined after deleting`);
is(b.length, oldLen, "length of observable array");
});
});
add_task(function testObservableArrayExoticObjects_get() {
let m = new TestInterfaceObservableArray();
m.observableArrayBoolean = [true, false];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 2, "length of observable array should be 2");
// Test length
is(Reflect.get(b, "length"), 2, "test result of getting length property");
// Test indexed value
is(Reflect.get(b, 0), true, "test result of getting index 0");
is(Reflect.get(b, 1), false, "test result of getting index 1");
is(Reflect.get(b, 2), undefined, "test result of getting index 2");
// Test other property
[
// [property, value]
["prop1", "value1"],
["prop2", 5],
["prop3", []],
["prop4", {}],
].forEach(function([property, value]) {
is(Reflect.get(b, property), undefined, `test ${property} property before setting property value`);
b[property] = value;
is(Reflect.get(b, property), value, `test ${property} property after setting property value`);
});
});
add_task(function testObservableArrayExoticObjects_getOwnPropertyDescriptor() {
function TestDescriptor(object, property, exist, configurable, enumerable,
writable, value) {
let descriptor = Reflect.getOwnPropertyDescriptor(object, property);
if (!exist) {
is(descriptor, undefined, `descriptor of ${property} property should be undefined`);
return;
}
is(descriptor.configurable, configurable, `test descriptor of ${property} property (configurable)`);
is(descriptor.enumerable, enumerable, `test descriptor of ${property} property (enumerable)`);
is(descriptor.writable, writable, `test descriptor of ${property} property (writable)`);
is(descriptor.value, value, `test descriptor of ${property} property (value)`);
}
let m = new TestInterfaceObservableArray();
m.observableArrayBoolean = [true, false];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 2, "length of observable array should be 2");
// Test length
TestDescriptor(b, "length", true, false /* configurable */,
false /* enumerable */, true /* writable */ , 2 /* value */);
// Test indexed value
TestDescriptor(b, 0, true, true /* configurable */, true /* enumerable */,
true /* writable */ , true /* value */);
TestDescriptor(b, 1, true, true /* configurable */, true /* enumerable */,
true /* writable */ , false /* value */);
TestDescriptor(b, 2, false);
// Test other property
[
// [property, value, configurable, enumerable, writable]
["prop1", "value1", true, true, true],
["prop2", 5, true, true, false],
["prop3", [], true, false, false],
["prop4", {}, false, false, false],
].forEach(function([property, value, configurable, enumerable, writable]) {
Object.defineProperty(b, property, {
value,
configurable,
enumerable,
writable,
});
TestDescriptor(b, property, true, configurable, enumerable, writable , value);
});
});
add_task(function testObservableArrayExoticObjects_has() {
let m = new TestInterfaceObservableArray();
m.observableArrayBoolean = [true, false];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 2, "length of observable array should be 2");
// Test length
ok(Reflect.has(b, "length"), `test length property`);
// Test indexed value
ok(Reflect.has(b, 0), `test 0 property`);
ok(Reflect.has(b, 1), `test 1 property`);
ok(!Reflect.has(b, 2), `test 2 property`);
// Test other property
[
// [property, value]
["prop1", "value1"],
["prop2", 5],
["prop3", []],
["prop4", {}],
].forEach(function([property, value]) {
ok(!Reflect.has(b, property), `test ${property} property before setting property value`);
b[property] = value;
ok(Reflect.has(b, property), `test ${property} property after setting property value`);
});
});
add_task(function testObservableArrayExoticObjects_ownKeys() {
let m = new TestInterfaceObservableArray();
m.observableArrayBoolean = [true, false];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 2, "length of observable array should be 2");
// Add other properties
b.prop1 = "value1";
b.prop2 = 5;
b.prop3 = [];
b.prop4 = {};
let keys = Reflect.ownKeys(b);
SimpleTest.isDeeply(keys, ["0", "1", "length", "prop1", "prop2", "prop3", "prop4"], `test property keys`);
});
add_task(function testObservableArrayExoticObjects_preventExtensions() {
let m = new TestInterfaceObservableArray();
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 0, "length of observable array should be 0");
// Test preventExtensions
ok(Reflect.isExtensible(b), "test isExtensible before preventExtensions");
ok(!Reflect.preventExtensions(b), "test preventExtensions");
ok(Reflect.isExtensible(b), "test isExtensible after preventExtensions");
});
add_task(function testObservableArrayExoticObjects_set() {
let setCallbackCount = 0;
let deleteCallbackCount = 0;
let setCallbackTests = null;
let deleteCallbackTests = null;
let m = new TestInterfaceObservableArray({
setBooleanCallback(value, index) {
setCallbackCount++;
if (typeof setCallbackTests === 'function') {
setCallbackTests(value, index);
}
},
deleteBooleanCallback(value, index) {
deleteCallbackCount++;
if (typeof deleteCallbackTests === 'function') {
deleteCallbackTests(value, index);
}
},
});
m.observableArrayBoolean = [true, true, true];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 3, "length of observable array should be 3");
// Test length
[
// [length, shouldThrow, expectedResult]
// Invalid length value
[1.9, true],
['invalid', true],
[{}, true],
// length value should not greater than current length
[b.length + 1, false, false],
// Success
[b.length, false, true],
[b.length - 1, false, true],
[0, false, true],
].forEach(function([length, shouldThrow, expectedResult]) {
// Initialize
let oldLen = b.length;
let oldValues = b.slice();
setCallbackCount = 0;
deleteCallbackCount = 0;
setCallbackTests = null;
let deleteCallbackIndex = oldLen - 1;
deleteCallbackTests = function(_value, _index) {
is(_value, oldValues[deleteCallbackIndex], "deleteCallbackTests: test value argument");
is(_index, deleteCallbackIndex, "deleteCallbackTests: test index argument");
deleteCallbackIndex--;
};
// Test
info(`setting "length" property value to ${length}`);
try {
is(Reflect.set(b, "length", length), expectedResult, `Reflect.set should return ${expectedResult}`);
ok(!shouldThrow, "Reflect.set should not throw");
} catch(e) {
ok(shouldThrow, `Reflect.set throws ${e}`);
}
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, expectedResult ? oldLen - length : 0, "deleteCallback count");
isDeeply(b, expectedResult ? oldValues.slice(0, length) : oldValues, "property values");
is(b.length, expectedResult ? length : oldLen, "length of observable array");
});
// Test indexed value
[
// [index, value, shouldThrow, expectedResult]
// Index could not greater than last index.
[b.length + 1, true, false, false],
// Success
[b.length, true, false, true],
[b.length + 1, true, false, true],
].forEach(function([index, value, shouldThrow, expectedResult]) {
// Initialize
let oldLen = b.length;
let oldValue = b[index];
setCallbackCount = 0;
deleteCallbackCount = 0;
setCallbackTests = function(_value, _index) {
is(_value, value, "setCallbackTests: test value argument");
is(_index, index, "setCallbackTests: test index argument");
};
deleteCallbackTests = function(_value, _index) {
is(_value, oldValue, "deleteCallbackTests: test value argument");
is(_index, index, "deleteCallbackTests: test index argument");
};
// Test
info(`setting ${index} property to ${value}`);
try {
is(Reflect.set(b, index, value), expectedResult, `Reflect.set should return ${expectedResult}`);
ok(!shouldThrow, "Reflect.set should not throw");
} catch(e) {
ok(shouldThrow, `Reflect.set throws ${e}`);
}
is(setCallbackCount, expectedResult ? 1 : 0, "setCallback count");
is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
is(b[index], expectedResult ? value : oldValue, "property value");
is(b.length, expectedResult ? Math.max(index + 1, oldLen) : oldLen, "length of observable array");
});
// Test other property
[
// [property, value]
["prop1", "value1"],
["prop1", "value2"],
["prop2", 5],
["prop3", []],
["prop4", {}],
].forEach(function([property, value]) {
// Initialize
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
setCallbackTests = null;
deleteCallbackTests = null;
// Test
info(`setting ${property} property to ${value}`);
ok(Reflect.set(b, property, value), "Reflect.defineProperty should return true");
is(setCallbackCount, 0, "setCallback count");
is(deleteCallbackCount, 0, "deleteCallback count");
is(b[property], value, "property value");
is(b.length, oldLen, "length of observable array");
});
});
add_task(function testObservableArrayExoticObjects_set_callback_throw() {
let setCallbackCount = 0;
let deleteCallbackCount = 0;
const minLen = 3;
let m = new TestInterfaceObservableArray({
setBooleanCallback(value) {
setCallbackCount++;
if (value) {
throw new Error("setBooleanCallback");
}
},
deleteBooleanCallback(value, index) {
deleteCallbackCount++;
if (index < minLen) {
throw new Error("deleteBooleanCallback");
}
},
});
m.observableArrayBoolean = [false, false, false, false, false];
let b = m.observableArrayBoolean;
ok(Array.isArray(b), "observable array should be an array type");
is(b.length, 5, "length of observable array should be 3");
// Test length
[
// [value, shouldThrow]
[b.length, false],
[b.length - 1, false],
[0, true],
].forEach(function([length, shouldThrow]) {
// Initialize
let oldValues = b.slice();
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`setting "length" property to ${length}`);
try {
ok(Reflect.set(b, "length", length), "Reflect.set should return true");
ok(!shouldThrow, `Reflect.set should not throw`);
} catch(e) {
ok(shouldThrow, `Reflect.set throws ${e}`);
}
is(setCallbackCount, 0, "setCallback should not be called");
is(deleteCallbackCount, oldLen - (shouldThrow ? minLen - 1 : length), "deleteCallback count");
isDeeply(b, oldValues.slice(0, shouldThrow ? minLen : length), "property values");
is(b.length, shouldThrow ? minLen : length, "length of observable array");
});
// Test indexed value
[
// [index, value, shouldThrow]
[b.length, true, true],
[b.length, false, false],
[b.length + 1, false, false],
[b.length + 1, true, true],
[0, false, true],
[0, true, true],
].forEach(function([index, value, shouldThrow]) {
// Initialize
let oldValue = b[index];
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`setting ${index} property to ${value}`);
try {
ok(Reflect.set(b, index, value), "Reflect.set should return true");
ok(!shouldThrow, `Reflect.set should not throw`);
} catch(e) {
ok(shouldThrow, `Reflect.set throws ${e}`);
}
is(setCallbackCount, (index < minLen) ? 0 : 1, "setCallback count");
is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
is(b[index], shouldThrow ? oldValue : value, "property value");
is(b.length, shouldThrow ? oldLen : Math.max(oldLen, index + 1), "length of observable array");
});
// Test other property
[
["prop1", "value1"],
["prop1", "value2"],
["prop2", 5],
["prop3", []],
["prop4", {}],
].forEach(function([property, value]) {
// Initialize
let oldLen = b.length;
setCallbackCount = 0;
deleteCallbackCount = 0;
// Test
info(`setting ${property} property to ${JSON.stringify(value)}`);
try {
ok(Reflect.set(b, property, value), "Reflect.set should return true");
ok(true, `Reflect.set should not throw`);
} catch(e) {
ok(false, `Reflect.set throws ${e}`);
}
is(setCallbackCount, 0, "setCallback should not be called");
is(deleteCallbackCount, 0, "deleteCallback should be called");
is(b[property], value, "property value");
is(b.length, oldLen, "length of observable array");
});
});
add_task(function testObservableArrayExoticObjects_invalidtype() {
let m = new TestInterfaceObservableArray();
let i = m.observableArrayInterface;
ok(Array.isArray(i), "Observable array should be an array type");
is(i.length, 0, "length should be 0");
[true, "invalid"].forEach(function(value) {
SimpleTest.doesThrow(() => {
let descriptor = {configurable: true, enumerable: true, writable: true, value};
Reflect.defineProperty(i, i.length, descriptor);
}, `defining ${i.length} property with ${JSON.stringify(value)} should throw`);
SimpleTest.doesThrow(() => {
Reflect.set(i, i.length, value);
}, `setting ${i.length} property to ${JSON.stringify(value)} should throw`);
});
is(i.length, 0, "length should still be 0");
});
</script>
</body>
</html>