use crate::{run_test_actions, JsNativeErrorKind, JsValue, TestAction};
use indoc::indoc;
#[test]
fn object_create_length() {
run_test_actions([TestAction::assert_eq("Object.create.length", 2)]);
}
#[test]
fn object_create_with_regular_object() {
run_test_actions([TestAction::assert_eq("Object.create({ a: 5 }).a", 5)]);
}
#[test]
fn object_create_with_undefined() {
run_test_actions([TestAction::assert_native_error(
"Object.create()",
JsNativeErrorKind::Type,
"Object prototype may only be an Object or null: undefined",
)]);
}
#[test]
fn object_create_with_number() {
run_test_actions([TestAction::assert_native_error(
"Object.create(5)",
JsNativeErrorKind::Type,
"Object prototype may only be an Object or null: 5",
)]);
}
#[test]
fn object_create_with_function() {
run_test_actions([TestAction::assert(indoc! {r#"
const x = function (){};
const bar = Object.create(x);
bar.__proto__ === x
"#})]);
}
#[test]
fn object_is() {
run_test_actions([
TestAction::run(indoc! {r#"
var foo = { a: 1};
var bar = { a: 1};
"#}),
TestAction::assert("Object.is('foo', 'foo')"),
TestAction::assert("!Object.is('foo', 'bar')"),
TestAction::assert("!Object.is([], [])"),
TestAction::assert("Object.is(foo, foo)"),
TestAction::assert("!Object.is(foo, bar)"),
TestAction::assert("Object.is(null, null)"),
TestAction::assert("!Object.is(0, -0)"),
TestAction::assert("Object.is(-0, -0)"),
TestAction::assert("Object.is(NaN, 0/0)"),
TestAction::assert("Object.is()"),
TestAction::assert("Object.is(undefined)"),
]);
}
#[test]
fn object_has_own_property() {
run_test_actions([
TestAction::run(indoc! {r#"
let symA = Symbol('a');
let symB = Symbol('b');
let x = {
undefinedProp: undefined,
nullProp: null,
someProp: 1,
[symA]: 2,
100: 3,
};
"#}),
TestAction::assert("!x.hasOwnProperty('hasOwnProperty')"),
TestAction::assert("x.hasOwnProperty('undefinedProp')"),
TestAction::assert("x.hasOwnProperty('nullProp')"),
TestAction::assert("x.hasOwnProperty('someProp')"),
TestAction::assert("!x.hasOwnProperty(symB)"),
TestAction::assert("x.hasOwnProperty(symA)"),
TestAction::assert("!x.hasOwnProperty(1000)"),
TestAction::assert("x.hasOwnProperty(100)"),
]);
}
#[test]
fn object_has_own() {
run_test_actions([
TestAction::run(indoc! {r#"
let symA = Symbol('a');
let symB = Symbol('b');
let x = {
undefinedProp: undefined,
nullProp: null,
someProp: 1,
[symA]: 2,
100: 3,
};
"#}),
TestAction::assert("!Object.hasOwn(x, 'hasOwnProperty')"),
TestAction::assert("Object.hasOwn(x, 'undefinedProp')"),
TestAction::assert("Object.hasOwn(x, 'nullProp')"),
TestAction::assert("Object.hasOwn(x, 'someProp')"),
TestAction::assert("!Object.hasOwn(x, symB)"),
TestAction::assert("Object.hasOwn(x, symA)"),
TestAction::assert("!Object.hasOwn(x, 1000)"),
TestAction::assert("Object.hasOwn(x, 100)"),
]);
}
#[test]
fn object_property_is_enumerable() {
run_test_actions([
TestAction::run("let x = { enumerableProp: 'yes' };"),
TestAction::assert("x.propertyIsEnumerable('enumerableProp')"),
TestAction::assert("!x.propertyIsEnumerable('hasOwnProperty')"),
TestAction::assert("!x.propertyIsEnumerable('not_here')"),
TestAction::assert("!x.propertyIsEnumerable()"),
]);
}
#[test]
fn object_to_string() {
run_test_actions([
TestAction::run(indoc! {r#"
Array.prototype.toString = Object.prototype.toString;
Function.prototype.toString = Object.prototype.toString;
Error.prototype.toString = Object.prototype.toString;
Boolean.prototype.toString = Object.prototype.toString;
Number.prototype.toString = Object.prototype.toString;
String.prototype.toString = Object.prototype.toString;
Date.prototype.toString = Object.prototype.toString;
RegExp.prototype.toString = Object.prototype.toString;
"#}),
TestAction::assert_eq(
"Object.prototype.toString.call(undefined)",
"[object Undefined]",
),
TestAction::assert_eq("Object.prototype.toString.call(null)", "[object Null]"),
TestAction::assert_eq("[].toString()", "[object Array]"),
TestAction::assert_eq("(() => {}).toString()", "[object Function]"),
TestAction::assert_eq("(new Error('')).toString()", "[object Error]"),
TestAction::assert_eq("Boolean().toString()", "[object Boolean]"),
TestAction::assert_eq("Number(42).toString()", "[object Number]"),
TestAction::assert_eq("String('boa').toString()", "[object String]"),
TestAction::assert_eq("(new Date()).toString()", "[object Date]"),
TestAction::assert_eq("/boa/.toString()", "[object RegExp]"),
TestAction::assert_eq("({}).toString()", "[object Object]"),
]);
}
#[test]
fn define_symbol_property() {
run_test_actions([
TestAction::run(indoc! {r#"
let obj = {};
let sym = Symbol("key");
Object.defineProperty(obj, sym, { value: "val" });
"#}),
TestAction::assert_eq("obj[sym]", "val"),
]);
}
#[test]
fn get_own_property_descriptor_1_arg_returns_undefined() {
run_test_actions([TestAction::assert_eq(
"Object.getOwnPropertyDescriptor({a: 2})",
JsValue::undefined(),
)]);
}
#[test]
fn get_own_property_descriptor() {
run_test_actions([
TestAction::run(indoc! {r#"
let obj = {a: 2};
let prop = Object.getOwnPropertyDescriptor(obj, "a");
"#}),
TestAction::assert("prop.enumerable"),
TestAction::assert("prop.writable"),
TestAction::assert("prop.configurable"),
TestAction::assert_eq("prop.value", 2),
]);
}
#[test]
fn get_own_property_descriptors() {
run_test_actions([
TestAction::run(indoc! {r#"
let obj = {a: 1, b: 2};
let props = Object.getOwnPropertyDescriptors(obj);
"#}),
TestAction::assert("props.a.enumerable"),
TestAction::assert("props.a.writable"),
TestAction::assert("props.a.configurable"),
TestAction::assert_eq("props.a.value", 1),
TestAction::assert("props.b.enumerable"),
TestAction::assert("props.b.writable"),
TestAction::assert("props.b.configurable"),
TestAction::assert_eq("props.b.value", 2),
]);
}
#[test]
fn object_define_properties() {
run_test_actions([
TestAction::run(indoc! {r#"
const obj = {};
Object.defineProperties(obj, {
p: {
value: 42,
writable: true
}
});
const prop = Object.getOwnPropertyDescriptor(obj, 'p');
"#}),
TestAction::assert("!prop.enumerable"),
TestAction::assert("prop.writable"),
TestAction::assert("!prop.configurable"),
TestAction::assert_eq("prop.value", 42),
]);
}
#[test]
fn object_is_prototype_of() {
run_test_actions([TestAction::assert(
"Object.prototype.isPrototypeOf(String.prototype)",
)]);
}
#[test]
fn object_get_own_property_names_invalid_args() {
const ERROR: &str = "cannot convert 'null' or 'undefined' to object";
run_test_actions([
TestAction::assert_native_error(
"Object.getOwnPropertyNames()",
JsNativeErrorKind::Type,
ERROR,
),
TestAction::assert_native_error(
"Object.getOwnPropertyNames(null)",
JsNativeErrorKind::Type,
ERROR,
),
TestAction::assert_native_error(
"Object.getOwnPropertyNames(undefined)",
JsNativeErrorKind::Type,
ERROR,
),
]);
}
#[test]
fn object_get_own_property_names() {
run_test_actions([
TestAction::run_harness(),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertyNames(0),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertyNames(false),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertyNames(Symbol("a")),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertyNames({}),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertyNames(NaN),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertyNames([1, 2, 3]),
["0", "1", "2", "length"]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertyNames({
"a": 1,
"b": 2,
[ Symbol("c") ]: 3,
[ Symbol("d") ]: 4,
}),
["a", "b"]
)
"#}),
]);
}
#[test]
fn object_get_own_property_symbols_invalid_args() {
const ERROR: &str = "cannot convert 'null' or 'undefined' to object";
run_test_actions([
TestAction::assert_native_error(
"Object.getOwnPropertySymbols()",
JsNativeErrorKind::Type,
ERROR,
),
TestAction::assert_native_error(
"Object.getOwnPropertySymbols(null)",
JsNativeErrorKind::Type,
ERROR,
),
TestAction::assert_native_error(
"Object.getOwnPropertySymbols(undefined)",
JsNativeErrorKind::Type,
ERROR,
),
]);
}
#[test]
fn object_get_own_property_symbols() {
run_test_actions([
TestAction::run_harness(),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertySymbols(0),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertySymbols(false),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertySymbols(Symbol("a")),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertySymbols({}),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertySymbols(NaN),
[]
)
"#}),
TestAction::assert(indoc! {r#"
arrayEquals(
Object.getOwnPropertySymbols([1, 2, 3]),
[]
)
"#}),
TestAction::assert(indoc! {r#"
let c = Symbol("c");
let d = Symbol("d");
arrayEquals(
Object.getOwnPropertySymbols({
"a": 1,
"b": 2,
[ c ]: 3,
[ d ]: 4,
}),
[c, d]
)
"#}),
]);
}
#[test]
fn object_from_entries_invalid_args() {
const ERROR: &str = "cannot convert null or undefined to Object";
run_test_actions([
TestAction::assert_native_error("Object.fromEntries()", JsNativeErrorKind::Type, ERROR),
TestAction::assert_native_error("Object.fromEntries(null)", JsNativeErrorKind::Type, ERROR),
TestAction::assert_native_error(
"Object.fromEntries(undefined)",
JsNativeErrorKind::Type,
ERROR,
),
]);
}
#[test]
fn object_from_entries() {
run_test_actions([
TestAction::run(indoc! {r#"
let sym = Symbol("sym");
let map = Object.fromEntries([
["long key", 1],
["short", 2],
[sym, 3],
[5, 4],
]);
"#}),
TestAction::assert_eq("map['long key']", 1),
TestAction::assert_eq("map.short", 2),
TestAction::assert_eq("map[sym]", 3),
TestAction::assert_eq("map[5]", 4),
]);
}