Browse Source

Fix `Number.prototype.toFixed()` (#2898)

* Fix `Number.prototype.toFixed()`

* Add more tests

* Update ryu-js version
pull/3361/head
Haled Odat 1 year ago committed by GitHub
parent
commit
8ae39afb53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 154
      Cargo.lock
  2. 2
      boa_engine/Cargo.toml
  3. 18
      boa_engine/src/builtins/number/mod.rs
  4. 116
      boa_engine/src/builtins/number/tests.rs

154
Cargo.lock generated

@ -60,9 +60,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
version = "0.6.1"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6cd65a4b849ace0b7f6daeebcc1a1d111282227ca745458c61dbf670e52a597"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
dependencies = [
"anstyle",
"anstyle-parse",
@ -74,15 +74,15 @@ dependencies = [
[[package]]
name = "anstyle"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
dependencies = [
"utf8parse",
]
@ -98,9 +98,9 @@ dependencies = [
[[package]]
name = "anstyle-wincon"
version = "3.0.0"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0238ca56c96dfa37bdf7c373c8886dd591322500aceeeccdb2216fe06dc2f796"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
@ -122,15 +122,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
dependencies = [
"concurrent-queue",
"event-listener 2.5.3",
"event-listener",
"futures-core",
]
[[package]]
name = "async-executor"
version = "1.5.3"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78f2db9467baa66a700abce2a18c5ad793f6f83310aca1284796fc3921d113fd"
checksum = "2c1da3ae8dabd9c00f453a329dfe1fb28da3c0a72e2478cdcd93171740c20499"
dependencies = [
"async-lock",
"async-task",
@ -166,7 +166,7 @@ dependencies = [
"log",
"parking",
"polling",
"rustix 0.37.23",
"rustix 0.37.24",
"slab",
"socket2",
"waker-fn",
@ -178,7 +178,7 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
dependencies = [
"event-listener 2.5.3",
"event-listener",
]
[[package]]
@ -194,37 +194,19 @@ dependencies = [
[[package]]
name = "async-process"
version = "1.8.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf012553ce51eb7aa6dc2143804cc8252bd1cb681a1c5cb7fa94ca88682dee1d"
checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
dependencies = [
"async-io",
"async-lock",
"async-signal",
"autocfg",
"blocking",
"cfg-if",
"event-listener 3.0.0",
"event-listener",
"futures-lite",
"rustix 0.38.14",
"windows-sys 0.48.0",
]
[[package]]
name = "async-signal"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4af361a844928cb7d36590d406709473a1b574f443094422ef166daa3b493208"
dependencies = [
"async-io",
"async-lock",
"atomic-waker",
"cfg-if",
"concurrent-queue",
"futures-core",
"futures-io",
"libc",
"signal-hook-registry",
"slab",
"rustix 0.37.24",
"signal-hook",
"windows-sys 0.48.0",
]
@ -998,6 +980,12 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "endian-type"
version = "0.1.2"
@ -1021,9 +1009,9 @@ dependencies = [
[[package]]
name = "errno"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480"
dependencies = [
"errno-dragonfly",
"libc",
@ -1056,17 +1044,6 @@ version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "event-listener"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29e56284f00d94c1bc7fd3c77027b4623c88c1f53d8d2394c6199f2921dea325"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "eyre"
version = "0.6.8"
@ -1105,7 +1082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5"
dependencies = [
"cfg-if",
"rustix 0.38.14",
"rustix 0.38.17",
"windows-sys 0.48.0",
]
@ -1336,12 +1313,11 @@ dependencies = [
[[package]]
name = "icu_codepointtrie_builder"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f848e681eee3907b3a5ecda6f1e6ce47e50cbafad37c5e85d2135e52bc481e80"
checksum = "872a3fcc14248bb28572e1340fc23c14c0bcc083d1660743a76c4121e7fcb859"
dependencies = [
"icu_collections",
"lazy_static",
"toml 0.5.11",
]
@ -1381,9 +1357,9 @@ dependencies = [
[[package]]
name = "icu_datagen"
version = "1.3.0"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ec4916c5bc6843fa7789888dee44fc72cf5565352a8ba9851fe531848adb7ef"
checksum = "1cdad9848f19a7b00f64cd28bb8f16113f54212323c5be9f9da5238cbb6611b6"
dependencies = [
"displaydoc",
"elsa",
@ -1601,9 +1577,9 @@ dependencies = [
[[package]]
name = "icu_provider_adapters"
version = "1.3.0"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb43949fa871c2c79828575058971af57b0ac5e58c9e4fdb69f1f4a2f3f4e17"
checksum = "36b380ef2d3d93b015cd0563d7e0d005cc07f82a5503716dbc191798d0079e1d"
dependencies = [
"icu_locid",
"icu_locid_transform",
@ -1731,7 +1707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix 0.38.14",
"rustix 0.38.17",
"windows-sys 0.48.0",
]
@ -1814,9 +1790,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "linux-raw-sys"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
[[package]]
name = "litemap"
@ -1869,9 +1845,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.6.3"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memmap2"
@ -2249,11 +2225,12 @@ checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
[[package]]
name = "postcard"
version = "1.0.7"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d534c6e61df1c7166e636ca612d9820d486fe96ddad37f7abc671517b297488e"
checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8"
dependencies = [
"cobs",
"embedded-io",
"serde",
]
@ -2459,9 +2436,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.37.23"
version = "0.37.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
checksum = "4279d76516df406a8bd37e7dff53fd37d1a093f997a3c34a5c21658c126db06d"
dependencies = [
"bitflags 1.3.2",
"errno",
@ -2473,14 +2450,14 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.14"
version = "0.38.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys 0.4.7",
"linux-raw-sys 0.4.8",
"windows-sys 0.48.0",
]
@ -2492,20 +2469,10 @@ checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8"
dependencies = [
"log",
"ring",
"rustls-webpki 0.101.6",
"rustls-webpki",
"sct",
]
[[package]]
name = "rustls-webpki"
version = "0.100.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "rustls-webpki"
version = "0.101.6"
@ -2565,9 +2532,9 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "ryu-js"
version = "0.2.2"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f"
checksum = "4950d85bc52415f8432144c97c4791bd0c4f7954de32a7270ee9cccd3c22b12b"
[[package]]
name = "same-file"
@ -2670,9 +2637,9 @@ dependencies = [
[[package]]
name = "sharded-slab"
version = "0.1.4"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
@ -2984,9 +2951,9 @@ dependencies = [
[[package]]
name = "tinystr"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07bb54ef1f8ff27564b08b861144d3b8d40263efe07684f64987f4c0d044e3e"
checksum = "d5d0e245e80bdc9b4e5356fc45a72184abbc3861992603f515270e9340f5a219"
dependencies = [
"databake",
"displaydoc",
@ -3199,16 +3166,16 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "ureq"
version = "2.7.1"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9"
checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3"
dependencies = [
"base64",
"flate2",
"log",
"once_cell",
"rustls",
"rustls-webpki 0.100.3",
"rustls-webpki",
"url",
"webpki-roots",
]
@ -3342,12 +3309,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "0.23.1"
version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338"
dependencies = [
"rustls-webpki 0.100.3",
]
checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
[[package]]
name = "winapi"

2
boa_engine/Cargo.toml

@ -66,7 +66,7 @@ num-bigint = { workspace = true, features = ["serde"] }
num-integer = "0.1.45"
bitflags.workspace = true
indexmap = { workspace = true, features = ["std"] }
ryu-js = "0.2.2"
ryu-js = "1.0.0"
chrono = { workspace = true, default-features = false, features = ["clock", "std"] }
fast-float.workspace = true
once_cell = { workspace = true, features = ["std"] }

18
boa_engine/src/builtins/number/mod.rs

@ -277,20 +277,12 @@ impl Number {
.ok_or_else(|| {
JsNativeError::range()
.with_message("toFixed() digits argument must be between 0 and 100")
})? as usize;
})? as u8;
// 6. If x is not finite, return ! Number::toString(x).
if !this_num.is_finite() {
Ok(JsValue::new(Self::to_js_string(this_num)))
// 10. If x ≥ 10^21, then let m be ! ToString(𝔽(x)).
} else if this_num >= 1.0e21 {
Ok(JsValue::new(f64_to_exponential(this_num)))
} else {
// Get rid of the '-' sign for -0.0 because of 9. If x < 0, then set s to "-".
let this_num = if this_num == 0_f64 { 0_f64 } else { this_num };
let this_fixed_num = format!("{this_num:.precision$}");
Ok(JsValue::new(js_string!(this_fixed_num)))
}
let mut buffer = ryu_js::Buffer::new();
let string = buffer.format_to_fixed(this_num, precision);
Ok(js_string!(string).into())
}
/// `Number.prototype.toLocaleString( [locales [, options]] )`

116
boa_engine/src/builtins/number/tests.rs

@ -48,6 +48,122 @@ fn to_fixed() {
"Number('I am also not a number').toFixed()",
js_string!("NaN"),
),
TestAction::assert_eq("(1.35).toFixed(1)", js_string!("1.4")),
// Test cases from https://source.chromium.org/chromium/chromium/src/+/main:v8/test/mjsunit/number-tostring-func.js;l=157-240;drc=aa3518a0f37245ebe8f062dce97ee492e2a41652
TestAction::assert_eq("(NaN).toFixed(2)", js_string!("NaN")),
TestAction::assert_eq("(1/0).toFixed(2)", js_string!("Infinity")),
TestAction::assert_eq("(-1/0).toFixed(2)", js_string!("-Infinity")),
TestAction::assert_eq(
"(1111111111111111111111).toFixed(8)",
js_string!("1.1111111111111111e+21"),
),
TestAction::assert_eq("(0.1).toFixed(1)", js_string!("0.1")),
TestAction::assert_eq("(0.1).toFixed(2)", js_string!("0.10")),
TestAction::assert_eq("(0.1).toFixed(3)", js_string!("0.100")),
TestAction::assert_eq("(0.01).toFixed(2)", js_string!("0.01")),
TestAction::assert_eq("(0.01).toFixed(3)", js_string!("0.010")),
TestAction::assert_eq("(0.01).toFixed(4)", js_string!("0.0100")),
TestAction::assert_eq("(0.001).toFixed(2)", js_string!("0.00")),
TestAction::assert_eq("(0.001).toFixed(3)", js_string!("0.001")),
TestAction::assert_eq("(0.001).toFixed(4)", js_string!("0.0010")),
TestAction::assert_eq("(1).toFixed(4)", js_string!("1.0000")),
TestAction::assert_eq("(1).toFixed(1)", js_string!("1.0")),
TestAction::assert_eq("(1).toFixed(0)", js_string!("1")),
TestAction::assert_eq("(12).toFixed(0)", js_string!("12")),
TestAction::assert_eq("(1.1).toFixed(0)", js_string!("1")),
TestAction::assert_eq("(12.1).toFixed(0)", js_string!("12")),
TestAction::assert_eq("(1.12).toFixed(0)", js_string!("1")),
TestAction::assert_eq("(12.12).toFixed(0)", js_string!("12")),
TestAction::assert_eq("(0.0000006).toFixed(7)", js_string!("0.0000006")),
TestAction::assert_eq("(0.00000006).toFixed(8)", js_string!("0.00000006")),
TestAction::assert_eq("(0.00000006).toFixed(9)", js_string!("0.000000060")),
TestAction::assert_eq("(0.00000006).toFixed(10)", js_string!("0.0000000600")),
TestAction::assert_eq("(0).toFixed(0)", js_string!("0")),
TestAction::assert_eq("(0).toFixed(1)", js_string!("0.0")),
TestAction::assert_eq("(0).toFixed(2)", js_string!("0.00")),
TestAction::assert_eq(
"(-1111111111111111111111).toFixed(8)",
js_string!("-1.1111111111111111e+21"),
),
TestAction::assert_eq("(-0.1).toFixed(1)", js_string!("-0.1")),
TestAction::assert_eq("(-0.1).toFixed(2)", js_string!("-0.10")),
TestAction::assert_eq("(-0.1).toFixed(3)", js_string!("-0.100")),
TestAction::assert_eq("(-0.01).toFixed(2)", js_string!("-0.01")),
TestAction::assert_eq("(-0.01).toFixed(3)", js_string!("-0.010")),
TestAction::assert_eq("(-0.01).toFixed(4)", js_string!("-0.0100")),
TestAction::assert_eq("(-0.001).toFixed(2)", js_string!("-0.00")),
TestAction::assert_eq("(-0.001).toFixed(3)", js_string!("-0.001")),
TestAction::assert_eq("(-0.001).toFixed(4)", js_string!("-0.0010")),
TestAction::assert_eq("(-1).toFixed(4)", js_string!("-1.0000")),
TestAction::assert_eq("(-1).toFixed(1)", js_string!("-1.0")),
TestAction::assert_eq("(-1).toFixed(0)", js_string!("-1")),
TestAction::assert_eq("(-1.1).toFixed(0)", js_string!("-1")),
TestAction::assert_eq("(-12.1).toFixed(0)", js_string!("-12")),
TestAction::assert_eq("(-1.12).toFixed(0)", js_string!("-1")),
TestAction::assert_eq("(-12.12).toFixed(0)", js_string!("-12")),
TestAction::assert_eq("(-0.0000006).toFixed(7)", js_string!("-0.0000006")),
TestAction::assert_eq("(-0.00000006).toFixed(8)", js_string!("-0.00000006")),
TestAction::assert_eq("(-0.00000006).toFixed(9)", js_string!("-0.000000060")),
TestAction::assert_eq("(-0.00000006).toFixed(10)", js_string!("-0.0000000600")),
TestAction::assert_eq("(-0).toFixed(0)", js_string!("0")),
TestAction::assert_eq("(-0).toFixed(1)", js_string!("0.0")),
TestAction::assert_eq("(-0).toFixed(2)", js_string!("0.00")),
TestAction::assert_eq("(0.00001).toFixed(5)", js_string!("0.00001")),
TestAction::assert_eq(
"(0.0000000000000000001).toFixed(20)",
js_string!("0.00000000000000000010"),
),
TestAction::assert_eq("(0.00001).toFixed(17)", js_string!("0.00001000000000000")),
TestAction::assert_eq("(1).toFixed(17)", js_string!("1.00000000000000000")),
TestAction::assert_eq(
"(100000000000000128).toFixed(1)",
js_string!("100000000000000128.0"),
),
TestAction::assert_eq(
"(10000000000000128).toFixed(2)",
js_string!("10000000000000128.00"),
),
TestAction::assert_eq(
"(10000000000000128).toFixed(20)",
js_string!("10000000000000128.00000000000000000000"),
),
TestAction::assert_eq("(-42).toFixed(3)", js_string!("-42.000")),
TestAction::assert_eq(
"(-0.0000000000000000001).toFixed(20)",
js_string!("-0.00000000000000000010"),
),
TestAction::assert_eq(
"(0.123123123123123).toFixed(20)",
js_string!("0.12312312312312299889"),
),
TestAction::assert_eq(
"(-1000000000000000128).toFixed()",
js_string!("-1000000000000000128"),
),
TestAction::assert_eq("(0).toFixed()", js_string!("0")),
TestAction::assert_eq(
"(1000000000000000128).toFixed()",
js_string!("1000000000000000128"),
),
TestAction::assert_eq("(1000).toFixed()", js_string!("1000")),
TestAction::assert_eq("(0.00001).toFixed()", js_string!("0")),
// Test that we round up even when the last digit generated is even.
// dtoa does not do this in its original form.
TestAction::assert_eq("(0.5).toFixed(0)", js_string!("1")),
TestAction::assert_eq("(-0.5).toFixed(0)", js_string!("-1")),
TestAction::assert_eq("(1.25).toFixed(1)", js_string!("1.3")),
// This is bizare, but Spidermonkey and KJS behave the same.
TestAction::assert_eq("(234.2040).toFixed(4)", js_string!("234.2040")),
TestAction::assert_eq("(234.2040506).toFixed(4)", js_string!("234.2041")),
]);
}
// https://github.com/boa-dev/boa/issues/2609
#[test]
fn issue_2609() {
run_test_actions([
TestAction::assert_eq("(1.25).toFixed(1)", js_string!("1.3")),
TestAction::assert_eq("(1.35).toFixed(1)", js_string!("1.4")),
]);
}

Loading…
Cancel
Save