blob: 92446695a7d1b5c43e89c28c6199d123b44b3f93 [file] [log] [blame] [edit]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate dtoa;
extern crate dtoa_short;
extern crate float_cmp;
use dtoa_short::{Floating, Notation};
use float_cmp::ApproxEqUlps;
use std::ops::Range;
struct SimpleNumberGenerator {
whole_part: Range<i32>,
digit1: Range<u8>,
digit2: Range<u8>,
}
impl SimpleNumberGenerator {
fn new(start: i32, end: i32) -> Self {
SimpleNumberGenerator {
whole_part: Range { start, end },
digit1: Range { start: 0, end: 0 },
digit2: Range { start: 0, end: 0 },
}
}
}
impl Iterator for SimpleNumberGenerator {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
if self.digit2.next().is_some() {
Some(format!("{}.{}{}", self.whole_part.start - 1,
self.digit1.start, self.digit2.start))
} else {
self.digit2 = Range { start: 0, end: 9 };
if self.digit1.next().is_some() {
Some(format!("{}.{}", self.whole_part.start - 1,
self.digit1.start))
} else {
self.digit1 = Range { start: 0, end: 9 };
if self.whole_part.next().is_some() {
Some(format!("{}", self.whole_part.start - 1))
} else {
None
}
}
}
}
}
#[test]
fn generator_correctness() {
let mut last = 0;
let end = 101;
for (i, s) in SimpleNumberGenerator::new(0, end).enumerate() {
let expected = i as f32 * 0.01;
let result = s.parse::<f32>().unwrap();
assert!(result.approx_eq_ulps(&expected, 1),
"str = {}, result = {}, expected = {}", s, result, expected);
last = i as i32;
}
assert_eq!(last, end * 100 - 1);
}
fn assert_expected_serialization<T: Floating>(value: T, expected: &str) {
let mut result = String::new();
let notation = dtoa_short::write(&mut result, value).unwrap();
assert_eq!(result, expected);
let exp_pos = expected.find('e');
let has_dot = exp_pos.map(|exp_pos| &expected[..exp_pos])
.unwrap_or(expected)
.contains('.');
let expected_notation = Notation {
decimal_point: has_dot,
scientific: exp_pos.is_some(),
};
assert_eq!(notation, expected_notation);
}
#[test]
fn roundtrip_simple_numbers_f32() {
for s in SimpleNumberGenerator::new(0, 101) {
let value = s.parse::<f32>().unwrap();
assert_expected_serialization(value, &s);
}
}
fn test_simple_number_percentage_f32<F: FnMut(f32, &str)>(mut test: F) {
for s in SimpleNumberGenerator::new(0, 101) {
let value = s.parse::<f32>().unwrap();
let value = value / 100.;
let value = value * 100.;
test(value, &s);
}
}
// This test is for checking that test_simple_number_percentage_f32
// actually works as expected, that it can generate numbers which dtoa
// fails to roundtrip.
#[test]
fn roundtrip_simple_numbers_percentage_dtoa_f32() {
let mut count = 0;
test_simple_number_percentage_f32(|value, expected| {
let mut result = Vec::new();
dtoa::write(&mut result, value).unwrap();
let result = String::from_utf8(result).unwrap();
if result != expected {
count += 1;
}
});
// This number may change if dtoa changes the algorithm.
assert_eq!(count, 1135);
}
#[test]
fn roundtrip_simple_numbers_percentage_f32() {
test_simple_number_percentage_f32(assert_expected_serialization);
}
#[test]
fn exponent_part_handling() {
assert_expected_serialization(3.999999e30_f32, "4e30");
assert_expected_serialization(-3.999999e30_f32, "-4e30");
assert_expected_serialization(3.999999e-30_f32, "4e-30");
assert_expected_serialization(-3.999999e-30_f32, "-4e-30");
// 10e30 should really be 1e31, and 10e-30 should be 1e-29.
// We can probably improve it later.
assert_expected_serialization(9.999999e30_f32, "10e30");
assert_expected_serialization(-9.999999e30_f32, "-10e30");
assert_expected_serialization(9.999999e-30_f32, "10e-30");
assert_expected_serialization(-9.999999e-30_f32, "-10e-30");
// Regression test for assertion failure (https://bugzilla.mozilla.org/show_bug.cgi?id=1402419)
assert_expected_serialization(-8192e17_f32, "-819200000000000000000");
}