mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
feat: setYear 完整强转加 TimeClip 收尾,escape/unescape 码元口径
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1384,7 +1384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1402,7 +1402,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1415,7 +1415,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.101"
|
||||
version = "0.8.102"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -1018,37 +1018,40 @@ pub fn date_get_year<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
|
||||
/// Annex B `Date.prototype.setYear(y)`:设置年份,0..99 自动加 1900;
|
||||
/// 缺参/NaN 置为 Invalid Date。
|
||||
///
|
||||
/// 年份参数按完整 ToNumber 强转(对象走 valueOf/toString,Symbol 抛
|
||||
/// TypeError);this 值无效时取 +0 基准分量(1970-01-01 全零)继续,
|
||||
/// 结果经 TimeClip 包络收尾。
|
||||
pub fn date_set_year<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let obj = unsafe { &mut *native_try!(date_this_mut(vm, args)) };
|
||||
// this 值先于 ToNumber(year) 读取(规范步序)。
|
||||
let ms = get_timestamp(obj);
|
||||
// 缺省年份参数强制转为 NaN;按 Annex B 语义,NaN 年份把日期值置为
|
||||
// NaN 并返回 NaN。
|
||||
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let y_num = oxide_runtime_api::to_number(arg);
|
||||
if y_num.is_nan() {
|
||||
set_timestamp(obj, f64::NAN);
|
||||
return NativeResult::Ok(JsValue::float(f64::NAN));
|
||||
}
|
||||
if !ms.is_finite() {
|
||||
return NativeResult::Ok(JsValue::float(f64::NAN));
|
||||
}
|
||||
let dt = match dt_from_ms_local(ms) {
|
||||
Some(d) => d,
|
||||
None => return NativeResult::Ok(JsValue::float(f64::NAN)),
|
||||
};
|
||||
let y_trunc = y_num.trunc();
|
||||
// f64 截断后可能超出 i32 范围,先做有界转换。
|
||||
let y = if y_trunc >= i32::MIN as f64 && y_trunc <= i32::MAX as f64 {
|
||||
y_trunc as i32
|
||||
let y = native_try!(date_arg_number(vm, if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }));
|
||||
// 无效 this 值取 +0 基准分量(1970-01-01 时刻全零,与 setFullYear 同口径)。
|
||||
let (_dy, dm, dd, dh, dmin, dsec, dms) = if ms.is_finite() {
|
||||
local_components(ms).unwrap_or((1970, 0, 1, 0, 0, 0, 0))
|
||||
} else {
|
||||
(1970, 0, 1, 0, 0, 0, 0)
|
||||
};
|
||||
if y.is_nan() {
|
||||
set_timestamp(obj, f64::NAN);
|
||||
return NativeResult::Ok(JsValue::float(f64::NAN));
|
||||
};
|
||||
let full_year = if (0..=99).contains(&y) { y + 1900 } else { y };
|
||||
let nd = dt.with_year(full_year).unwrap_or(dt);
|
||||
let ts = nd.timestamp_millis() as f64;
|
||||
set_timestamp(obj, ts);
|
||||
NativeResult::Ok(JsValue::float(ts))
|
||||
}
|
||||
// MakeFullYear:ToIntegerOrInfinity 截断,0..99 映射到 1900..1999。
|
||||
let y_int = y.trunc() as i64;
|
||||
let full_year = if (0..=99).contains(&y_int) { y_int + 1900 } else { y_int };
|
||||
finish_local_setter(
|
||||
obj,
|
||||
make_local_timestamp(
|
||||
full_year as f64,
|
||||
dm as f64,
|
||||
dd as f64,
|
||||
dh as f64,
|
||||
dmin as f64,
|
||||
dsec as f64,
|
||||
dms as f64,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// `Date.prototype.toGMTString()`:别名 `toUTCString`(GMT 格式)。
|
||||
|
||||
@@ -51,14 +51,15 @@ pub fn global_is_finite<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
NativeResult::Ok(JsValue::bool(n.is_finite()))
|
||||
}
|
||||
|
||||
/// `escape`/`unescape` 的字符串参数:按规范 `? ToString` 完整转换。
|
||||
/// `escape`/`unescape` 的字符串参数:按规范 `? ToString` 完整转换,
|
||||
/// 取 UTF-16 单元序列(不 lossy,孤立 surrogate 保真)。
|
||||
///
|
||||
/// 对象经 ToPrimitive(string hint) 强制转换,Symbol 抛 TypeError,对象方法
|
||||
/// 抛出的原生异常原样传播;缺省参数按 "undefined" 处理。
|
||||
fn string_arg_full<H: VmHost>(vm: &mut H, args: &[u8]) -> Result<String, JsValue> {
|
||||
fn units_arg_full<H: VmHost>(vm: &mut H, args: &[u8]) -> Result<Vec<u16>, JsValue> {
|
||||
if args.len() > 1 {
|
||||
match oxide_runtime_api::to_string_full(vm.reg(args[1]), vm) {
|
||||
Ok(s) => Ok(s),
|
||||
match oxide_runtime_api::to_units_full(vm.reg(args[1]), vm) {
|
||||
Ok(u) => Ok(u),
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return Err(exc);
|
||||
@@ -67,7 +68,7 @@ fn string_arg_full<H: VmHost>(vm: &mut H, args: &[u8]) -> Result<String, JsValue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok("undefined".to_string())
|
||||
Ok("undefined".encode_utf16().collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,133 +2,124 @@ use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
const ESCAPE_SAFE: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./";
|
||||
|
||||
fn parse_hex_u16(slice: &[u8]) -> Option<u16> {
|
||||
std::str::from_utf8(slice).ok().and_then(|s| u16::from_str_radix(s, 16).ok())
|
||||
/// 单个码元的十六进制值(逐位严格匹配,不带符号位);非十六进制数字返回 None。
|
||||
fn hex_val(c: u16) -> Option<u16> {
|
||||
match c {
|
||||
48..=57 => Some(c - 48),
|
||||
97..=102 => Some(c - 97 + 10),
|
||||
65..=70 => Some(c - 65 + 10),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn escape_string(input: &str) -> String {
|
||||
let mut out = String::with_capacity(input.len());
|
||||
for ch in input.chars() {
|
||||
if ESCAPE_SAFE.contains(ch) {
|
||||
out.push(ch);
|
||||
/// escape 核(规范 B.2.1.1 逐码元迭代):安全集 `A-Za-z0-9@*_+-./` 直留,
|
||||
/// <=0xFF 码元产 `%XX`,其余产 `%uXXXX`;孤立 surrogate 码元按码元保真
|
||||
/// 输出(不替 U+FFFD)。
|
||||
fn escape_units(input: &[u16]) -> Vec<u16> {
|
||||
let mut out = Vec::with_capacity(input.len() * 6);
|
||||
for &u in input {
|
||||
if u < 0x80 && ESCAPE_SAFE.contains(char::from(u as u8)) {
|
||||
out.push(u);
|
||||
continue;
|
||||
}
|
||||
|
||||
let code = ch as u32;
|
||||
if code <= 0xFF {
|
||||
out.push('%');
|
||||
out.push_str(&format!("{code:02X}"));
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut buf = [0u16; 2];
|
||||
for unit in ch.encode_utf16(&mut buf).iter() {
|
||||
out.push_str(&format!("%u{:04X}", *unit));
|
||||
}
|
||||
// 转义序列恒为全 ASCII,按码元推入。
|
||||
let text = if u <= 0xFF {
|
||||
format!("%{u:02X}")
|
||||
} else {
|
||||
format!("%u{u:04X}")
|
||||
};
|
||||
out.extend(text.encode_utf16());
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn unescape_string(input: &str) -> String {
|
||||
let bytes = input.as_bytes();
|
||||
let mut out = String::with_capacity(input.len());
|
||||
/// unescape 核(规范 B.2.1.2 逐码元扫描):`%uXXXX` 优先于 `%XX` 解码,
|
||||
/// 解码值直接推码元(孤立 surrogate 码元按规范合法输出);无法解析的
|
||||
/// 序列原样保留。
|
||||
fn unescape_units(input: &[u16]) -> Vec<u16> {
|
||||
let mut out = Vec::with_capacity(input.len());
|
||||
let mut i = 0;
|
||||
|
||||
while i < bytes.len() {
|
||||
if bytes[i] == b'%' {
|
||||
if i + 6 <= bytes.len() && bytes[i + 1] == b'u' {
|
||||
if let Some(unit) = parse_hex_u16(&bytes[i + 2..i + 6]) {
|
||||
if (0xD800..=0xDBFF).contains(&unit)
|
||||
&& i + 12 <= bytes.len()
|
||||
&& bytes[i + 6] == b'%'
|
||||
&& bytes[i + 7] == b'u'
|
||||
{
|
||||
if let Some(low) = parse_hex_u16(&bytes[i + 8..i + 12]) {
|
||||
if (0xDC00..=0xDFFF).contains(&low) {
|
||||
let pair = [unit, low];
|
||||
let decoded = char::decode_utf16(pair).next();
|
||||
match decoded {
|
||||
Some(Ok(ch)) => out.push(ch),
|
||||
_ => {
|
||||
out.push_str(&input[i..i + 12]);
|
||||
}
|
||||
}
|
||||
i += 12;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ch) = char::from_u32(unit as u32) {
|
||||
out.push(ch);
|
||||
} else {
|
||||
out.push_str(&input[i..i + 6]);
|
||||
}
|
||||
i += 6;
|
||||
continue;
|
||||
}
|
||||
} else if i + 3 <= bytes.len() {
|
||||
if let Some(value) = super::parse_hex_u8(&bytes[i + 1..i + 3]) {
|
||||
out.push(value as char);
|
||||
i += 3;
|
||||
continue;
|
||||
}
|
||||
while i < input.len() {
|
||||
if input[i] == b'%' as u16 {
|
||||
// %uXXXX:后跟 4 位十六进制。
|
||||
if i + 6 <= input.len()
|
||||
&& input[i + 1] == b'u' as u16
|
||||
&& (2..6).all(|k| hex_val(input[i + k]).is_some())
|
||||
{
|
||||
let v = (0..4).fold(0u16, |acc, k| acc * 16 + hex_val(input[i + 2 + k]).unwrap());
|
||||
out.push(v);
|
||||
i += 6;
|
||||
continue;
|
||||
}
|
||||
// %XX:后跟 2 位十六进制。
|
||||
if i + 3 <= input.len() && (1..3).all(|k| hex_val(input[i + k]).is_some()) {
|
||||
out.push(hex_val(input[i + 1]).unwrap() * 16 + hex_val(input[i + 2]).unwrap());
|
||||
i += 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let ch = match input[i..].chars().next() {
|
||||
Some(c) => c,
|
||||
None => break,
|
||||
};
|
||||
out.push(ch);
|
||||
i += ch.len_utf8();
|
||||
out.push(input[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
/// Annex B 的全局 `escape(string)`:除 ASCII 字母数字与 `@*_+-./` 外全部编码。
|
||||
/// <=0xFF 字符用 `%XX`,其它按 UTF-16 code unit 用 `%uXXXX` 转义。
|
||||
/// <=0xFF 码元用 `%XX`,其它按 UTF-16 码元用 `%uXXXX` 转义。
|
||||
/// 参数按 `? ToString` 完整转换:Symbol 抛 TypeError,对象方法抛出的原生
|
||||
/// 异常原样传播。
|
||||
pub fn js_escape<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let input = match super::string_arg_full(vm, args) {
|
||||
Ok(s) => s,
|
||||
let input = match super::units_arg_full(vm, args) {
|
||||
Ok(u) => u,
|
||||
Err(exc) => return NativeResult::Err(exc),
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&escape_string(&input)))
|
||||
NativeResult::Ok(vm.new_string_units_owned(escape_units(&input)))
|
||||
}
|
||||
|
||||
/// Annex B 的全局 `unescape(string)`:解码 `escape` 生成的 `%XX`/`%uXXXX` 序列,
|
||||
/// 支持 surrogate pair 合并;无法解析的序列原样保留。
|
||||
/// Annex B 的全局 `unescape(string)`:解码 `escape` 生成的 `%XX`/`%uXXXX`
|
||||
/// 序列;无法解析的序列原样保留。
|
||||
/// 参数按 `? ToString` 完整转换:Symbol 抛 TypeError,对象方法抛出的原生
|
||||
/// 异常原样传播。
|
||||
pub fn js_unescape<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let input = match super::string_arg_full(vm, args) {
|
||||
Ok(s) => s,
|
||||
let input = match super::units_arg_full(vm, args) {
|
||||
Ok(u) => u,
|
||||
Err(exc) => return NativeResult::Err(exc),
|
||||
};
|
||||
NativeResult::Ok(vm.new_string(&unescape_string(&input)))
|
||||
NativeResult::Ok(vm.new_string_units_owned(unescape_units(&input)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{escape_string, unescape_string};
|
||||
use super::{escape_units, unescape_units};
|
||||
|
||||
fn units(s: &str) -> Vec<u16> {
|
||||
s.encode_utf16().collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn escape_encodes_spaces_and_unicode() {
|
||||
assert_eq!(escape_string("hello world"), "hello%20world");
|
||||
assert_eq!(escape_string("AΩ你"), "A%u03A9%u4F60");
|
||||
assert_eq!(escape_units(&units("hello world")), units("hello%20world"));
|
||||
assert_eq!(escape_units(&units("AΩ你")), units("A%u03A9%u4F60"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unescape_decodes_percent_sequences() {
|
||||
assert_eq!(unescape_string("hello%20world"), "hello world");
|
||||
assert_eq!(unescape_string("%u03A9%u4F60"), "Ω你");
|
||||
assert_eq!(unescape_units(&units("hello%20world")), units("hello world"));
|
||||
assert_eq!(unescape_units(&units("%u03A9%u4F60")), units("Ω你"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unescape_keeps_invalid_sequences() {
|
||||
assert_eq!(unescape_string("%uXYZ1%2G"), "%uXYZ1%2G");
|
||||
assert_eq!(unescape_units(&units("%uXYZ1%2G")), units("%uXYZ1%2G"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn escape_preserves_lone_surrogates() {
|
||||
assert_eq!(escape_units(&[0xD834, 0xDF06]), units("%uD834%uDF06"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unescape_outputs_lone_surrogate_unit() {
|
||||
assert_eq!(unescape_units(&units("%uD834")), vec![0xD834]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,6 +540,53 @@ fn date_set_year_four_digit_kept() {
|
||||
assert_eq!(r.as_double() as i64, 2020);
|
||||
}
|
||||
|
||||
// setYear 语义钉:this 值无效取 +0 基准(1970-01-01 全零)不早退、
|
||||
// 结果经 TimeClip 包络、年份参数走完整 ToNumber(valueOf 通道、
|
||||
// Symbol 抛 TypeError)。
|
||||
#[test]
|
||||
fn date_set_year_invalid_this_uses_plus_zero_base() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var d = new Date(NaN); d.setYear(71); d.getTime() == new Date(1971, 0).valueOf() ? 1 : 0",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(r.as_int(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn date_set_year_time_clip_returns_nan() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var d = new Date(1970, 8, 14); var ts = d.setYear(275760); Number.isNaN(ts) && Number.isNaN(d.valueOf()) ? 1 : 0",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(r.as_int(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn date_set_year_valueof_channel() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var d = new Date(0); d.setYear({valueOf: function() { return 20; }}); d.getFullYear()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(r.as_double() as i64, 1920);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn date_set_year_symbol_throws_type_error() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var d = new Date(0); try { d.setYear(Symbol()); 'no' } catch (e) { e instanceof TypeError ? 'yes' : 'no' }",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(str_val(&vm, r), "yes");
|
||||
}
|
||||
|
||||
// UTC setter 无参数调用此前会索引缺失的参数寄存器(panic / 进程中止)。
|
||||
// 缺失的主参数现在产出 NaN 并把日期置为 NaN。
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user