1#[cfg(test)]
2mod tests {
3 use std::panic;
4
5 use num_bigint::BigInt as BigIntValue;
6 use swc_atoms::Atom;
7
8 use super::super::*;
9
10 fn lex<F, Ret>(s: &'static str, f: F) -> Ret
11 where
12 F: FnOnce(&mut Lexer<'_>) -> Ret,
13 {
14 crate::with_test_sess(s, |_, input| {
15 let mut l = Lexer::new(
16 Syntax::Es(Default::default()),
17 Default::default(),
18 input,
19 None,
20 );
21 let ret = f(&mut l);
22 assert_eq!(l.input.cur(), None);
23 Ok(ret)
24 })
25 .unwrap()
26 }
27
28 fn num(s: &'static str) -> (f64, Atom) {
29 lex(s, |l| {
30 if s.starts_with('.') {
31 l.read_number::<true, false>().unwrap().left().unwrap()
32 } else if s.starts_with('0') {
33 l.read_number::<false, true>().unwrap().left().unwrap()
34 } else {
35 l.read_number::<false, false>().unwrap().left().unwrap()
36 }
37 })
38 }
39
40 fn int<const RADIX: u8>(s: &'static str) -> u32 {
41 lex(s, |l| {
42 l.read_int_u32::<RADIX>(0)
43 .unwrap()
44 .expect("read_int returned None")
45 })
46 }
47
48 const LONG: &str = "1e10000000000000000000000000000000000000000\
49 0000000000000000000000000000000000000000000000000000";
50 #[test]
51 fn num_inf() {
52 assert_eq!(num(LONG), (f64::INFINITY, LONG.into()));
53 }
54
55 #[test]
57 fn num_big_exp() {
58 assert_eq!((1e30, "1e30".into()), num("1e30"));
59 }
60
61 #[test]
62 fn num_very_big_exp() {
63 const LARGE_POSITIVE_EXP: &str =
64 "1e100000000000000000000000000000000000000000000000000000000000000\
65 00000000000000000000000000000000000000000000000000000000000000000\
66 00000000000000000000000000000000000000000000000000000000000000000\
67 00000000000000000000000000000000000000000000000000000000000000000\
68 00000000000000000000000000000000000000000000000000000";
69 const LARGE_NEGATIVE_EXP: &str =
70 "1e-10000000000000000000000000000000000000000000000000000000000000\
71 00000000000000000000000000000000000000000000000000000000000000000\
72 00000000000000000000000000000000000000000000000000000000000000000\
73 00000000000000000000000000000000000000000000000000000000000000000\
74 000000000000000000000000000000000000000000000000000000";
75 const ZERO_WITH_LARGE_POSITIVE_EXP: &str =
76 "0e100000000000000000000000000000000000000000000000000000000000000\
77 00000000000000000000000000000000000000000000000000000000000000000\
78 00000000000000000000000000000000000000000000000000000000000000000\
79 00000000000000000000000000000000000000000000000000000000000000000\
80 00000000000000000000000000000000000000000000000000000";
81 const ZERO_WITH_LARGE_NEGATIVE_EXP: &str =
82 "0e-10000000000000000000000000000000000000000000000000000000000000\
83 00000000000000000000000000000000000000000000000000000000000000000\
84 00000000000000000000000000000000000000000000000000000000000000000\
85 00000000000000000000000000000000000000000000000000000000000000000\
86 000000000000000000000000000000000000000000000000000000";
87 const LARGE_MANTISSA_WITH_LARGE_NEGATIVE_EXP: &str =
88 "10000000000000000000000000000000000000000000000000000000000000\
89 00000000000000000000000000000000000000000000000000000000000000000\
90 00000000000000000000000000000000000000000000000000000000000000000\
91 00000000000000000000000000000000000000000000000000000000000000000\
92 000000000000000000000000000000000000000000000000000000\
93 e-100000000000000000000000000000000000000000000000000000000000000\
94 00000000000000000000000000000000000000000000000000000000000000000\
95 00000000000000000000000000000000000000000000000000000000000000000\
96 00000000000000000000000000000000000000000000000000000000000000000\
97 000000000000000000000000000000000000000000000000000000";
98
99 assert_eq!(
100 num(LARGE_POSITIVE_EXP),
101 (f64::INFINITY, LARGE_POSITIVE_EXP.into())
102 );
103 assert_eq!(num(LARGE_NEGATIVE_EXP), (0.0, LARGE_NEGATIVE_EXP.into()));
104 assert_eq!(
105 num(ZERO_WITH_LARGE_POSITIVE_EXP),
106 (0.0, ZERO_WITH_LARGE_POSITIVE_EXP.into())
107 );
108 assert_eq!(
109 num(ZERO_WITH_LARGE_NEGATIVE_EXP),
110 (0.0, ZERO_WITH_LARGE_NEGATIVE_EXP.into())
111 );
112 assert_eq!(
113 num(LARGE_MANTISSA_WITH_LARGE_NEGATIVE_EXP),
114 (0.0, LARGE_MANTISSA_WITH_LARGE_NEGATIVE_EXP.into())
115 );
116 }
117
118 #[test]
119 fn num_big_many_zero() {
120 assert_eq!(
121 (
122 1_000_000_000_000_000_000_000_000_000_000f64,
123 "1000000000000000000000000000000".into()
124 ),
125 num("1000000000000000000000000000000")
126 );
127 assert_eq!(
128 (3.402_823_466_385_288_6e38, "34028234663852886e22".into()),
129 num("34028234663852886e22"),
130 );
131 }
132
133 #[test]
134 fn big_number_with_fract() {
135 assert_eq!(
136 (77777777777777777.1f64, "77777777777777777.1".into()),
137 num("77777777777777777.1")
138 )
139 }
140
141 #[test]
142 fn issue_480() {
143 assert_eq!((9.09, "9.09".into()), num("9.09"))
144 }
145
146 #[test]
147 fn num_legacy_octal() {
148 assert_eq!((0o12 as f64, "0012".into()), num("0012"));
149 assert_eq!((10f64, "012".into()), num("012"));
150 }
151
152 #[test]
153 fn read_int_1() {
154 assert_eq!(60, int::<10>("60"));
155 assert_eq!(0o73, int::<8>("73"));
156 }
157
158 #[test]
159 fn read_int_short() {
160 assert_eq!(7, int::<10>("7"));
161 assert_eq!(10, int::<10>("10"));
162 }
163
164 #[test]
165 fn read_radix_number() {
166 assert_eq!(
167 (0o73 as f64, "0o73".into()),
168 lex("0o73", |l| l
169 .read_radix_number::<8>()
170 .unwrap()
171 .left()
172 .unwrap())
173 );
174 }
175
176 #[test]
177 fn read_num_sep() {
178 assert_eq!(1_000, int::<10>("1_000"));
179 assert_eq!(0xaebece, int::<16>("AE_BE_CE"));
180 assert_eq!(0b1010000110000101, int::<2>("1010_0001_1000_0101"));
181 assert_eq!(0o0666, int::<8>("0_6_6_6"));
182 }
183
184 #[test]
185 fn read_bigint() {
186 assert_eq!(
187 lex(
188 "10000000000000000000000000000000000000000000000000000n",
189 |l| l.read_number::<false, false>().unwrap().right().unwrap()
190 ),
191 (
192 Box::new(
193 "10000000000000000000000000000000000000000000000000000"
194 .parse::<BigIntValue>()
195 .unwrap()
196 ),
197 Atom::from("10000000000000000000000000000000000000000000000000000n")
198 ),
199 );
200 }
201
202 #[test]
203 fn large_bin_number() {
204 const LONG: &str =
205 "0B11111111111111111111111111111111111111111111111101001010100000010111110001111111111";
206 const VERY_LARGE_BINARY_NUMBER: &str =
207 "0B1111111111111111111111111111111111111111111111111111111111111111\
208 111111111111111111111111111111111111111111111111111111111111111111\
209 111111111111111111111111111111111111111111111111111111111111111111\
210 111111111111111111111111111111111111111111111111111111111111111111\
211 111111111111111111111111111111111111111111111111111111111111111111\
212 111111111111111111111111111111111111111111111111111111111111111111\
213 111111111111111111111111111111111111111111111111111111111111111111\
214 111111111111111111111111111111111111111111111111111111111111111111\
215 111111111111111111111111111111111111111111111111111111111111111111\
216 111111111111111111111111111111111111111111111111111111111111111111\
217 111111111111111111111111111111111111111111111111111111111111111111\
218 111111111111111111111111111111111111111111111111111111111111111111\
219 111111111111111111111111111111111111111111111111111111111111111111\
220 111111111111111111111111111111111111111111111111111111111111111111\
221 111111111111111111111111111111111111111111111111111111111111111111\
222 0010111110001111111111";
223 assert_eq!(
224 lex(LONG, |l| l
225 .read_radix_number::<2>()
226 .unwrap()
227 .left()
228 .unwrap()),
229 (9.671_406_556_917_009e24, LONG.into())
230 );
231 assert_eq!(
232 lex(VERY_LARGE_BINARY_NUMBER, |l| l
233 .read_radix_number::<2>()
234 .unwrap()
235 .left()
236 .unwrap()),
237 (1.0972248137587377e304, VERY_LARGE_BINARY_NUMBER.into())
238 );
239 }
240
241 #[test]
242 fn large_float_number() {
243 const LONG: &str = "9.671406556917009e+24";
244
245 assert_eq!(num(LONG), (9.671_406_556_917_009e24, LONG.into()));
246 }
247
248 const VALID_CASES: &[&str] = &[".0", "0.e-1", "0e8", ".8e1", "0.8e1", "1.18e1"];
250 const INVALID_CASES_ON_STRICT: &[&str] = &["08e1", "08.1", "08.8e1", "08", "01"];
251 const INVALID_CASES: &[&str] = &["01.8e1", "012e1", "00e1", "00.0"];
252
253 fn test_floats(strict: bool, success: bool, cases: &'static [&'static str]) {
254 for case in cases {
255 println!("Testing {case} (when strict = {strict}); Expects success = {success}");
256 let expected: f64 = (i64::from_str_radix(case, 8).map(|v| v as f64))
258 .or_else(|_| case.parse::<i64>().map(|v| v as f64))
259 .or_else(|_| case.parse::<f64>())
260 .unwrap_or_else(|err| {
261 panic!("failed to parse '{case}' as float using str.parse(): {err}")
262 });
263
264 let vec = panic::catch_unwind(|| {
265 crate::with_test_sess(case, |_, input| {
266 let mut l = Lexer::new(Syntax::default(), Default::default(), input, None);
267 l.ctx.set(Context::Strict, strict);
268 Ok(l.map(|ts| ts.token).collect::<Vec<_>>())
269 })
270 .unwrap()
271 });
272
273 if success {
274 let vec = match vec {
275 Ok(vec) => vec,
276 Err(err) => panic::resume_unwind(err),
277 };
278
279 assert_eq!(vec.len(), 1);
280
281 let token = vec.into_iter().next().unwrap();
282 let value = match token {
283 Token::Num { value, .. } => value,
284 _ => {
285 panic!("expected num token in test")
286 }
287 };
288
289 assert_eq!(expected, value);
290 } else if let Ok(vec) = vec {
291 assert_ne!(
292 vec![Token::Num {
293 value: expected,
294 raw: expected.to_string().into()
295 }],
296 vec
297 )
298 }
299 }
300 }
301
302 #[test]
310 fn non_strict() {
311 test_floats(false, true, VALID_CASES);
312 test_floats(false, true, INVALID_CASES_ON_STRICT);
313 test_floats(false, false, INVALID_CASES);
314 }
315}