use std::sync::Arc; use oxide_compiler::compiler::Compiler; use oxide_types::value::JsValue; use oxide_vm::vm::Vm; fn eval(source: &str) -> Result<(Vm, JsValue), String> { let allocator = oxide_parser::Allocator::default(); let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?; let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?; let mut vm = Vm::new(); let result = vm.run(&Arc::new(module))?; Ok((vm, result)) } fn eval_str(source: &str) -> Result { let (vm, result) = eval(source)?; vm.lookup_str(result) .ok_or_else(|| "completion value is not a string".to_string()) } fn assert_nan(source: &str) { let (_vm, result) = eval(source).unwrap(); assert!(result.is_double() && result.as_double().is_nan(), "expected NaN from {source}"); } // -Infinity 结束位:ToIntegerOrInfinity 不截断,负无穷归 0,slice 得空 buffer。 #[test] fn array_buffer_slice_negative_infinity_end() { let (_vm, result) = eval("new ArrayBuffer(8).slice(2, -Infinity).byteLength").unwrap(); assert_eq!(result.as_int(), 0); } // -Infinity 结束位:copyWithin 相对结束位归 0,区间为空,元素不变。 #[test] fn typed_array_copy_within_negative_infinity_end() { let s = eval_str("new Uint8Array([1, 2, 3, 4, 5]).copyWithin(0, 1, -Infinity).join(',')").unwrap(); assert_eq!(s, "1,2,3,4,5"); } // 无穷年份入参:MakeDay 非有限分量得 NaN,日期置 Invalid。 #[test] fn set_full_year_infinity_is_nan() { assert_nan("new Date(2016, 6, 7).setFullYear(Infinity)"); } // 无穷月/日入参:Date.UTC 走 MakeDay,非有限分量得 NaN。 #[test] fn date_utc_infinite_fields_are_nan() { assert_nan("Date.UTC(0, Infinity)"); assert_nan("Date.UTC(0, 0, -Infinity)"); } // 毫秒分量 1e300:MakeTime 组合越界,整体得 NaN(不得溢出)。 #[test] fn set_hours_huge_millisecond_is_nan() { assert_nan("new Date(2016, 6, 7, 12, 30, 45, 99).setHours(0, 0, 0, 1e300)"); } // at(-1e300):负无穷索引越界,得 undefined 而非溢出。 #[test] fn typed_array_at_negative_infinity() { let (_vm, result) = eval("new Uint8Array([1, 2, 3]).at(-1e300)").unwrap(); assert!(result.is_undefined()); } // lastIndexOf(2, -Infinity):负无穷起点越界,得 -1 而非下溢。 #[test] fn typed_array_last_index_of_negative_infinity() { let (_vm, result) = eval("new Int8Array([7, 2, 9]).lastIndexOf(2, -Infinity)").unwrap(); assert_eq!(result.as_int(), -1); } // 日分量 0:rollover 到上一月月末(引擎内部自比,免时区依赖)。 #[test] fn set_full_year_day_zero_rolls_to_previous_month() { let s = eval_str("String((function() { var d = new Date(2016, 6, 7, 11, 36, 23, 2); return d.setFullYear(2016, 6, 0) === new Date(2016, 5, 30, 11, 36, 23, 2).getTime(); })())").unwrap(); assert_eq!(s, "true"); } // 日分量 0 经 setMonth 同样 rollover。 #[test] fn set_month_day_zero_rolls_to_previous_month() { let s = eval_str("String((function() { var d = new Date(2016, 6, 7, 11, 36, 23, 2); return d.setMonth(6, 0) === new Date(2016, 5, 30, 11, 36, 23, 2).getTime(); })())").unwrap(); assert_eq!(s, "true"); } // 无效日期 this 值:setFullYear 不早退,按 +0 基准得 2016-01-01。 #[test] fn set_full_year_on_invalid_date_uses_epoch() { let s = eval_str("String((function() { var d = new Date(NaN); return d.setFullYear(2016) === new Date(2016, 0, 1).getTime(); })())").unwrap(); assert_eq!(s, "true"); } // 有限巨负起点:截断饱和成 isize::MIN 后归一化到 0,debug 构建不得取负溢出。 #[test] fn typed_array_fill_finite_negative_huge_start() { let s = eval_str("new Uint8Array(4).fill(0, -1e300).join(',')").unwrap(); assert_eq!(s, "0,0,0,0"); } // 月份分量 ±Infinity/有限巨值:构造器与 setter 均直接 NaN(debug 构建不得整型溢出)。 #[test] fn date_constructor_huge_month_is_nan() { assert_nan("new Date(2020, Infinity, 1).getTime()"); assert_nan("new Date(2020, -Infinity, 1).getTime()"); assert_nan("new Date(2020, 1e300, 1).getTime()"); assert_nan("new Date(2020, 0, 1).setMonth(1e300)"); } // 年分量超 TimeClip 包络:构造器组合结果归 NaN;包络内邻近组合不损伤 // (valueOf 直接读槽位,不经 chrono 年份上限,可钉超 262142 年存储值)。 #[test] fn date_constructor_out_of_envelope_year_is_nan() { assert_nan("new Date(275760, 8, 13, 1).getTime()"); let (_vm, result) = eval("new Date(275759, 11, 31).valueOf()").unwrap(); assert!(result.is_double() && result.as_double().is_finite(), "包络内组合应得有限时间戳"); }