use super::{format_bytes, SizeBase, SizeFormat, SizeShape};
#[test]
fn both_ladders_cover_the_whole_input_type() {
assert_eq!(format_bytes(u64::MAX, &SizeFormat::binary()), "16.00EiB");
assert_eq!(format_bytes(u64::MAX, &SizeFormat::decimal()), "18.45EB");
}
#[test]
fn a_petabyte_does_not_saturate_into_terabytes() {
assert_eq!(
format_bytes(1024_u64.pow(5), &SizeFormat::binary()),
"1.00PiB"
);
assert_eq!(
format_bytes(1000_u64.pow(5), &SizeFormat::decimal()),
"1.00PB"
);
}
#[test]
fn binary_units_step_at_their_own_boundaries() {
let fmt = SizeFormat::binary();
assert_eq!(format_bytes(1024, &fmt), "1.00KiB");
assert_eq!(format_bytes(1024_u64.pow(2), &fmt), "1.00MiB");
assert_eq!(format_bytes(1024_u64.pow(3), &fmt), "1.00GiB");
assert_eq!(format_bytes(1024_u64.pow(4), &fmt), "1.00TiB");
assert_eq!(format_bytes(1024_u64.pow(5), &fmt), "1.00PiB");
assert_eq!(format_bytes(1024_u64.pow(6), &fmt), "1.00EiB");
}
#[test]
fn decimal_units_step_at_their_own_boundaries() {
let fmt = SizeFormat::decimal();
assert_eq!(format_bytes(1000, &fmt), "1.00kB");
assert_eq!(format_bytes(1000_u64.pow(2), &fmt), "1.00MB");
assert_eq!(format_bytes(1000_u64.pow(3), &fmt), "1.00GB");
assert_eq!(format_bytes(1000_u64.pow(4), &fmt), "1.00TB");
assert_eq!(format_bytes(1000_u64.pow(5), &fmt), "1.00PB");
assert_eq!(format_bytes(1000_u64.pow(6), &fmt), "1.00EB");
}
#[test]
fn the_two_bases_render_the_same_input_differently() {
assert_eq!(format_bytes(8_710_000, &SizeFormat::decimal()), "8.71MB");
assert_eq!(format_bytes(8_710_000, &SizeFormat::binary()), "8.31MiB");
}
#[test]
fn whole_bytes_carry_no_decimals() {
assert_eq!(format_bytes(0, &SizeFormat::binary()), "0B");
assert_eq!(format_bytes(1, &SizeFormat::binary()), "1B");
assert_eq!(format_bytes(1023, &SizeFormat::binary()), "1023B");
assert_eq!(format_bytes(999, &SizeFormat::decimal()), "999B");
}
#[test]
fn a_value_that_rounds_onto_the_next_unit_is_promoted() {
assert_eq!(
format_bytes(1024_u64.pow(2) - 1, &SizeFormat::binary()),
"1.00MiB"
);
assert_eq!(
format_bytes(1000_u64.pow(2) - 1, &SizeFormat::decimal()),
"1.00MB"
);
assert_eq!(
format_bytes(1024_u64.pow(4) - 1, &SizeFormat::binary()),
"1.00TiB"
);
}
#[test]
fn a_value_that_does_not_round_up_stays_on_its_rung() {
assert_eq!(format_bytes(1_048_000, &SizeFormat::binary()), "1023.44KiB");
}
#[test]
fn the_decimal_count_is_configurable() {
let bytes = 1_610_612_736; assert_eq!(
format_bytes(bytes, &SizeFormat::binary().with_decimals(0)),
"2GiB"
);
assert_eq!(
format_bytes(bytes, &SizeFormat::binary().with_decimals(1)),
"1.5GiB"
);
assert_eq!(
format_bytes(bytes, &SizeFormat::binary().with_decimals(4)),
"1.5000GiB"
);
}
#[test]
fn significant_digits_match_what_podman_and_docker_print() {
let fmt = SizeFormat::decimal().with_significant(3);
assert_eq!(format_bytes(98_234_179, &fmt), "98.2MB");
assert_eq!(format_bytes(8_710_000, &fmt), "8.71MB");
assert_eq!(format_bytes(805_007, &fmt), "805kB");
assert_eq!(format_bytes(1_010_000_000, &fmt), "1.01GB");
}
#[test]
fn significant_digits_keep_a_constant_width() {
let fmt = SizeFormat::decimal().with_significant(3);
for (bytes, expected) in [
(1_000_u64, "1.00kB"),
(12_000, "12.0kB"),
(123_000, "123kB"),
(1_230_000, "1.23MB"),
(123_000_000_000_000_000, "123PB"),
] {
let rendered = format_bytes(bytes, &fmt);
assert_eq!(rendered, expected);
let digits = rendered.chars().filter(char::is_ascii_digit).count();
assert_eq!(digits, 3, "{rendered:?} is not three digits wide");
}
}
#[test]
fn significant_digits_are_recomputed_after_a_promotion() {
let fmt = SizeFormat::decimal().with_significant(3);
assert_eq!(format_bytes(999_999, &fmt), "1.00MB");
assert_eq!(format_bytes(999_999_999, &fmt), "1.00GB");
}
#[test]
fn significant_digits_do_not_reach_below_a_byte() {
let fmt = SizeFormat::decimal().with_significant(3);
assert_eq!(format_bytes(0, &fmt), "0B");
assert_eq!(format_bytes(7, &fmt), "7B");
assert_eq!(format_bytes(999, &fmt), "999B");
}
#[test]
fn a_zero_digit_request_still_renders_a_digit() {
let fmt = SizeFormat::decimal().with_significant(0);
assert_eq!(format_bytes(8_710_000, &fmt), "9MB");
}
#[test]
fn the_decimal_count_is_pinned_below_its_public_entry_point() {
use super::Precision;
assert_eq!(Precision::Significant(3).decimals_for(98.2), 1);
assert_eq!(Precision::Significant(3).decimals_for(8.71), 2);
assert_eq!(Precision::Significant(3).decimals_for(805.0), 0);
assert_eq!(Precision::Fixed(4).decimals_for(805.0), 4);
assert_eq!(Precision::Significant(3).decimals_for(0.5), 2);
assert_eq!(Precision::Significant(1).decimals_for(0.5), 0);
}
#[test]
fn composite_renders_the_examples_from_the_issue() {
let decimal = SizeFormat::decimal().with_parts(2);
assert_eq!(format_bytes(1_001_000_000_000, &decimal), "1TB 1GB");
assert_eq!(format_bytes(1_512_000_000, &decimal), "1GB 512MB");
}
#[test]
fn composite_skips_empty_components() {
let fmt = SizeFormat::binary().with_parts(2);
let bytes = 1024_u64.pow(4) + 5 * 1024_u64.pow(2);
assert_eq!(format_bytes(bytes, &fmt), "1TiB 5MiB");
}
#[test]
fn composite_stops_when_the_value_runs_out() {
let fmt = SizeFormat::binary().with_parts(7);
assert_eq!(format_bytes(1024, &fmt), "1KiB");
assert_eq!(format_bytes(1025, &fmt), "1KiB 1B");
}
#[test]
fn composite_components_are_exact() {
let fmt = SizeFormat::binary().with_parts(7);
let bytes = u64::MAX;
let rendered = format_bytes(bytes, &fmt);
let units: Vec<(&str, u64)> = vec![
("EiB", 1024_u64.pow(6)),
("PiB", 1024_u64.pow(5)),
("TiB", 1024_u64.pow(4)),
("GiB", 1024_u64.pow(3)),
("MiB", 1024_u64.pow(2)),
("KiB", 1024),
("B", 1),
];
let total: u64 = rendered
.split(' ')
.map(|part| {
let (unit, scale) = units
.iter()
.find(|(unit, _)| part.ends_with(unit))
.unwrap_or_else(|| panic!("unknown unit in {rendered:?}"));
let count: u64 = part[..part.len() - unit.len()].parse().unwrap();
count * scale
})
.sum();
assert_eq!(total, bytes, "{rendered:?} did not sum back to the input");
}
#[test]
fn zero_renders_under_either_shape() {
assert_eq!(format_bytes(0, &SizeFormat::binary().with_parts(3)), "0B");
assert_eq!(format_bytes(0, &SizeFormat::decimal().with_parts(3)), "0B");
assert_eq!(format_bytes(0, &SizeFormat::decimal()), "0B");
}
#[test]
fn a_zero_component_count_still_renders_one_component() {
assert_eq!(
format_bytes(1025, &SizeFormat::binary().with_parts(0)),
"1KiB"
);
}
#[test]
fn the_default_component_count_is_three_and_matches_durations() {
use super::super::DurationFormat;
let fmt = SizeFormat::decimal().default_parts();
assert_eq!(fmt.shape, SizeShape::Composite { parts: 3 });
assert_eq!(
format_bytes(1_512_200_000, &fmt),
"1GB 512MB 200kB",
"three components, largest first"
);
assert_eq!(DurationFormat::default_parts(), DurationFormat::Parts(3));
}
#[test]
fn the_default_count_never_pads_a_short_value() {
let fmt = SizeFormat::decimal().default_parts();
assert_eq!(format_bytes(1000, &fmt), "1kB");
assert_eq!(format_bytes(0, &fmt), "0B");
}
#[test]
fn the_builders_replace_the_shape() {
let fmt = SizeFormat::binary().with_decimals(3).with_parts(2);
assert_eq!(fmt.shape, SizeShape::Composite { parts: 2 });
assert_eq!(fmt.base, SizeBase::Binary);
let fmt = SizeFormat::decimal().with_parts(2).with_decimals(3);
assert_eq!(fmt.shape, SizeShape::Single { decimals: 3 });
assert_eq!(fmt.base, SizeBase::Decimal);
}