Files
cs249r_book/mlsysim/tests/test_fmt.py
Vijay Janapa Reddi 8789d68780 Add typed FPS formatter
2026-06-11 23:49:47 -04:00

1383 lines
54 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tests for mlsysim.fmt formatting guards."""
import pytest
from mlsysim.core.units import ureg
from mlsysim.core.units import GB, J, K, MB, TB, USD, hour, kg, kWh, second
import math
from mlsysim.fmt import (
MarkdownStr,
fmt,
fmt_arithmetic_intensity,
fmt_area,
fmt_count,
fmt_count_range,
fmt_compute_efficiency,
fmt_carbon_intensity,
fmt_decibel,
fmt_display_math,
fmt_emissions,
fmt_eur,
fmt_int,
fmt_energy_per_bit,
fmt_energy_per_byte,
fmt_energy_per_flop,
fmt_energy_per_op,
fmt_heat_flux,
fmt_illuminance,
fmt_multiple,
fmt_multiple_range,
fmt_memory_capacity,
fmt_percent,
fmt_percent_range,
fmt_pp,
fmt_params,
fmt_power,
fmt_qty,
fmt_qty_int,
fmt_qty_range,
fmt_magnitude,
fmt_bandwidth,
fmt_flop_rate,
fmt_flops,
fmt_length,
fmt_ops_rate,
fmt_water,
fmt_water_rate,
fmt_water_intensity,
fmt_range,
fmt_rate,
fmt_fps,
fmt_ratio,
fmt_sci,
fmt_sci_flops,
fmt_sci_qty,
fmt_specific_heat,
fmt_temperature,
fmt_temperature_rate,
fmt_text,
fmt_time,
fmt_time_range,
fmt_tokens,
fmt_unit,
fmt_usd,
fmt_usd_range,
fmt_val,
)
class TestFmtComposition:
def test_fmt_text_preserves_markdown_rendering(self):
out = fmt_text(
fmt_usd(400_000),
" $\\times$ ",
fmt(0.4, precision=2),
" = ",
fmt_usd(160_000),
)
assert out == "\\$400,000 $\\times$ 0.40 = \\$160,000"
assert isinstance(out, MarkdownStr)
assert out._repr_markdown_() == str(out)
def test_fmt_display_math_wraps_block_math(self):
out = fmt_display_math(r"x = 1")
assert out == r"$$x = 1$$"
assert isinstance(out, MarkdownStr)
class TestFmtPrecisionGuards:
def test_precision_zero_accepts_whole_numbers(self):
assert fmt(989, precision=0, commas=False) == "989"
assert fmt(10.0, precision=0, commas=False) == "10"
assert fmt(175.0, precision=0, commas=False) == "175"
def test_precision_zero_rejects_small_fractions_that_display_as_zero(self):
with pytest.raises(ValueError, match="formatted as '0'"):
fmt(0.1, precision=0, commas=False)
with pytest.raises(ValueError, match="formatted as '0'"):
fmt(0.4, precision=0, commas=False)
def test_precision_zero_rejects_non_integer_values(self):
with pytest.raises(ValueError, match="not integer-like"):
fmt(10.7, precision=0, commas=False)
with pytest.raises(ValueError, match="not integer-like"):
fmt(84.7, precision=0, commas=False)
with pytest.raises(ValueError, match="not integer-like"):
fmt(4.1, precision=0, commas=False)
def test_precision_zero_accepts_explicit_round(self):
assert fmt(round(10.7), precision=0, commas=False) == "11"
assert fmt(round(362507.545), precision=0, commas=True) == "362,508"
def test_precision_one_preserves_fractions(self):
assert fmt(10.7, precision=1, commas=False) == "10.7"
assert fmt(8.5, precision=1, commas=False) == "8.5"
def test_fmt_precision_none_auto_trims_integer_like_values(self):
assert fmt(153.0, precision=None, commas=False) == "153"
assert fmt(153.016, precision=None, commas=False) == "153"
assert fmt(2.04, precision=None, commas=False) == "2.04"
assert fmt(0.2, precision=None, commas=False) == "0.2"
def test_auto_precision_preserves_large_fractions(self):
assert (
fmt_arithmetic_intensity(
153.016 * ureg.flop / ureg.byte,
commas=False,
)
== "153 FLOP/byte"
)
def test_auto_precision_keeps_meaningful_small_decimals(self):
assert fmt_bandwidth(0.2 * MB / second, unit=MB / second, commas=False) == "0.2 MB/s"
assert fmt_bandwidth(2.04 * TB / second, unit=TB / second, commas=False) == "2.04 TB/s"
def test_auto_precision_trim_preserves_commas(self):
assert (
fmt_bandwidth(1000.01 * MB / second, unit=MB / second, commas=True)
== "1,000 MB/s"
)
def test_explicit_precision_preserves_requested_decimal(self):
assert (
fmt_arithmetic_intensity(
153.016 * ureg.flop / ureg.byte,
precision=1,
commas=False,
)
== "153.0 FLOP/byte"
)
def test_precision_one_rejects_spurious_trailing_zeros_on_integers(self):
with pytest.raises(ValueError, match="spurious trailing zeros"):
fmt(512.0, precision=1, commas=False)
with pytest.raises(ValueError, match="spurious trailing zeros"):
fmt(989, precision=1, commas=False)
def test_returns_markdown_str(self):
out = fmt(42, precision=0, commas=False)
assert isinstance(out, MarkdownStr)
assert out._repr_markdown_() == "42"
def test_named_display_markers_replace_raw_prefixes(self):
assert fmt(100, precision=0, commas=False, approx=True, suffix=" MB/s") == "~100 MB/s"
assert fmt(1000, precision=0, lower_bound=True, suffix=" MB/s") == "> 1,000 MB/s"
def test_rejects_conflicting_display_markers(self):
with pytest.raises(ValueError, match="only one display marker"):
fmt(100, precision=0, approx=True, lower_bound=True)
with pytest.raises(ValueError, match="Use either prefix="):
fmt(100, precision=0, prefix="~", approx=True)
class TestFmtInt:
def test_rounds_computed_values_explicitly(self):
assert fmt_int(120.28, commas=False) == "120"
assert fmt_int(10.7, commas=False) == "11"
assert fmt_int(362507.545, commas=True) == "362,508"
def test_accepts_prefix_and_suffix(self):
assert fmt_int(175, commas=False, suffix=" billion") == "175 billion"
def test_accepts_named_approx_marker(self):
assert fmt_int(80, commas=False, approx=True, suffix=" GB") == "~80 GB"
class TestFmtQty:
def test_mj_over_ms_to_mw(self):
energy = 66 * ureg.millijoule
time = 1000 * ureg.millisecond
power = energy / time
out = fmt_qty(power, ureg.mW, precision=0, commas=False)
assert out == "66 mW"
def test_gb_display(self):
mem = 140 * ureg.GB
out = fmt_qty(mem, ureg.GB, precision=0, commas=False)
assert out == "140 GB"
def test_accepts_unit_keyword(self):
mem = 140 * ureg.GB
assert fmt_qty(mem, unit=ureg.GB, precision=0, commas=False) == "140 GB"
with pytest.raises(TypeError, match="either a positional unit or unit="):
fmt_qty(mem, ureg.GB, unit=ureg.GB, precision=0)
def test_fmt_magnitude_keeps_unit_conversion_checked(self):
q = 2048 * ureg.MB
assert fmt_magnitude(q, unit=ureg.GB, precision=3, commas=False) == "2.048"
def test_fmt_magnitude_requires_quantity(self):
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_magnitude(2048, unit=ureg.GB, precision=0)
def test_accepts_named_marker(self):
mem = 140 * ureg.GB
out = fmt_qty(mem, ureg.GB, precision=0, commas=False, approx=True)
assert out == "~140 GB"
def test_currency_is_refused(self):
# Currency must go through fmt_usd, not fmt_qty: fmt_qty cannot emit the
# Pandoc-safe escaped "\\$" and would leak a literal " USD" suffix.
price = 2.5 * USD
with pytest.raises(ValueError, match="fmt_usd"):
fmt_qty(price, USD, precision=2, commas=False)
def test_plain_number_is_refused(self):
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_qty(5, ureg.GB, precision=0, commas=False)
def test_returns_markdown_str(self):
out = fmt_qty(5 * ureg.millisecond, ureg.millisecond, precision=0, commas=False)
assert isinstance(out, MarkdownStr)
assert out == "5 ms"
def test_structured_denominator(self):
energy = 0.1 * ureg.millijoule
out = fmt_qty(
energy,
ureg.millijoule,
precision=1,
commas=False,
per="inference",
)
assert out == "0.1 mJ/inference"
def test_unit_label_preserves_dimension_check(self):
q = 5 * ureg.flop / ureg.byte
assert (
fmt_qty(q, ureg.flop / ureg.byte, precision=0, unit_label="FLOP/byte") == "5 FLOP/byte"
)
with pytest.raises(Exception):
fmt_qty(5 * ureg.second, ureg.flop / ureg.byte, unit_label="FLOP/byte")
def test_unit_label_rejects_value_kind_glyphs(self):
with pytest.raises(ValueError, match="currency, percent, or multiplier"):
fmt_qty(5 * ureg.GB, ureg.GB, unit_label="GB%")
def test_rejects_legacy_and_structured_denominator_mix(self):
with pytest.raises(ValueError, match="extra_suffix="):
fmt_qty(
1 * ureg.millijoule,
ureg.millijoule,
precision=0,
extra_suffix="/token",
per="inference",
)
class TestFmtQtyInt:
def test_rounds_quantity_after_unit_conversion(self):
assert fmt_qty_int(100 * ureg.GiB, ureg.GB, commas=False) == "107 GB"
def test_supports_structured_quantity_suffixes(self):
out = fmt_qty_int(
1250 * ureg.MB / ureg.second,
ureg.GB / ureg.second,
commas=False,
)
assert out == "1 GB/s"
def test_accepts_unit_keyword(self):
assert fmt_qty_int(100 * ureg.GB, unit=ureg.GB, commas=False) == "100 GB"
def test_plain_number_is_refused(self):
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_qty_int(5, ureg.GB, commas=False)
def test_returns_markdown_str(self):
assert isinstance(fmt_qty_int(5 * ureg.GB, ureg.GB), MarkdownStr)
class TestFmtUsd:
def test_basic_dollar_is_escaped(self):
# The escaped "\\$" is mandatory so prose never enters math mode.
assert fmt_usd(15000) == "\\$15,000"
assert fmt_usd(10, commas=False) == "\\$10"
def test_rounds_to_whole_dollars_at_precision_zero(self):
assert fmt_usd(12345.6) == "\\$12,346"
assert fmt_usd(999.4) == "\\$999"
def test_precision_preserves_cents(self):
assert fmt_usd(0.09, precision=2, commas=False, suffix="/GB") == "\\$0.09/GB"
assert fmt_usd(4.6, precision=1, suffix="M") == "\\$4.6M"
def test_structured_scale_and_denominator(self):
assert fmt_usd(4_600_000, precision=1, commas=False, scale="M") == "\\$4.6M"
assert fmt_usd(4_750_000, precision=2, commas=False, scale="million") == "\\$4.75 million"
assert fmt_usd(4_750_000, precision=2, commas=False, scale="Million") == "\\$4.75 Million"
assert fmt_usd(0.09, precision=2, commas=False, per="GB") == "\\$0.09/GB"
assert fmt_usd(0.50, precision=2, commas=False, per="click") == "\\$0.50/click"
assert fmt_usd(10_000, per="run") == "\\$10,000/run"
assert fmt_usd(10, commas=False, per="million queries") == "\\$10/million queries"
assert (
fmt_usd(0.06, precision=2, commas=False, per="1K inferences") == "\\$0.06/1K inferences"
)
assert fmt_usd(12_000, commas=False, scale="K", per="year") == "\\$12K/year"
assert fmt_usd(8000, approx=True, marker="*") == "~\\$8,000*"
def test_rejects_legacy_suffix_with_structured_parts(self):
with pytest.raises(ValueError, match="suffix="):
fmt_usd(1000, scale="K", suffix="K")
with pytest.raises(ValueError, match="suffix="):
fmt_usd(1000, marker="*", suffix="*")
def test_rejects_bad_denominator(self):
with pytest.raises(ValueError, match="omit the leading"):
fmt_usd(0.09, precision=2, per="/GB")
with pytest.raises(ValueError, match="fmt_usd per must be"):
fmt_usd(0.09, precision=2, per="widgets")
def test_rejects_bad_marker(self):
with pytest.raises(ValueError, match="fmt_usd marker"):
fmt_usd(1000, marker="note")
def test_approx_prepends_tilde(self):
assert fmt_usd(1234.7, approx=True, suffix="/year") == "~\\$1,235/year"
def test_accepts_pure_dollar_quantity(self):
assert fmt_usd(2500 * USD) == "\\$2,500"
def test_accepts_dollar_rate_quantity_with_physical_denominator(self):
assert fmt_usd(0.09 * USD / GB, precision=2, commas=False, per="GB") == "\\$0.09/GB"
assert fmt_usd(5 * USD / hour, commas=False, per="hr") == "\\$5/hr"
assert (
fmt_usd(23 * USD / (TB * ureg.month), commas=False, per="TB/month") == "\\$23/TB/month"
)
assert fmt_usd(0.12 * USD / kWh, precision=2, commas=False, per="kWh") == "\\$0.12/kWh"
def test_rejects_non_currency_quantities(self):
with pytest.raises(ValueError, match="dollar Quantity"):
fmt_usd(3 * GB)
def test_rejects_rate_quantity_without_denominator(self):
with pytest.raises(ValueError, match="no per="):
fmt_usd(0.09 * USD / GB, precision=2)
def test_never_emits_literal_usd(self):
for out in (fmt_usd(5), fmt_usd(5 * USD, suffix="/hr"), fmt_usd(5, approx=True)):
assert "USD" not in out
def test_returns_markdown_str(self):
assert isinstance(fmt_usd(100), MarkdownStr)
class TestFmtEur:
def test_basic_eur_code_style(self):
assert fmt_eur(210_000_000, scale="M", precision=0, commas=False) == "EUR 210M"
class TestFmtCountLegacy:
def test_accepts_named_marker(self):
assert fmt_count(1024, suffix=" GPUs", approx=True) == "~1,024 GPUs"
class TestFmtRate:
def test_formats_allowlisted_service_rates(self):
assert fmt_rate(2500, "QPS") == "2,500 QPS"
assert fmt_rate(1200, "tokens/s") == "1,200 tokens/s"
assert fmt_rate(500_000, "tokens/s", scale="K", commas=False) == "500K tokens/s"
assert (
fmt_rate(
45_200_000,
"tokens/hour",
scale="million",
precision=1,
commas=False,
)
== "45.2 million tokens/hour"
)
assert fmt_rate(2500, "QPS", commas=False) == "2500 QPS"
assert fmt_rate(60, "FPS") == "60 FPS"
assert fmt_rate(5000, "requests/s") == "5,000 requests/s"
assert fmt_rate(1000, "samples/hour", commas=False) == "1000 samples/hour"
def test_rejects_unknown_rate_unit(self):
with pytest.raises(ValueError, match="fmt_rate unit must be"):
fmt_rate(10, "GB/s")
def test_rejects_negative_by_default(self):
with pytest.raises(ValueError, match="non-negative rate"):
fmt_rate(-1, "QPS")
assert fmt_rate(-1, "QPS", allow_negative=True) == "-1 QPS"
def test_returns_markdown_str(self):
assert isinstance(fmt_rate(1, "QPS"), MarkdownStr)
class TestFmtFps:
def test_formats_frame_rate(self):
assert fmt_fps(30) == "30 FPS"
assert fmt_fps(30.3) == "30 FPS"
assert fmt_fps(29.5, precision=1) == "29.5 FPS"
assert fmt_fps(120, commas=True) == "120 FPS"
def test_rejects_negative_by_default(self):
with pytest.raises(ValueError, match="non-negative rate"):
fmt_fps(-1)
assert fmt_fps(-1, allow_negative=True) == "-1 FPS"
def test_returns_markdown_str(self):
assert isinstance(fmt_fps(30), MarkdownStr)
class TestFmtTime:
def test_symbol_style_accepts_quantities_and_plain_numbers(self):
assert fmt_time(1500 * ureg.millisecond, ureg.second) == "1.5 s"
assert fmt_time(1500 * ureg.millisecond, unit=ureg.second) == "1.5 s"
assert fmt_time(35, ureg.second, precision=0) == "35 s"
assert fmt_time(35, "second", precision=0) == "35 s"
assert fmt_time(35, "s", precision=0) == "35 s"
assert fmt_time(12, "millisecond", precision=0) == "12 ms"
assert fmt_time(12, "ms", precision=0) == "12 ms"
assert fmt_time(5, "microsecond", precision=0) == "5 μs"
assert fmt_time(5, "µs", precision=0) == "5 μs"
assert fmt_time(5, "μs", precision=0) == "5 μs"
def test_word_style_pluralizes(self):
assert fmt_time(1, ureg.second, precision=0, style="word") == "1 second"
assert fmt_time(2, ureg.second, precision=0, style="word") == "2 seconds"
assert fmt_time(2, "year", precision=0, style="word") == "2 years"
def test_attributive_word_style_is_hyphenated_singular(self):
assert fmt_time(1, "hour", precision=0, style="word", attributive=True) == "1-hour"
assert fmt_time(24, "hour", precision=0, style="word", attributive=True) == "24-hour"
assert fmt_time(15, "minute", precision=0, style="word", attributive=True) == "15-minute"
def test_attributive_rejects_symbol_style_and_per(self):
with pytest.raises(ValueError, match="attributive"):
fmt_time(5, "hour", precision=0, attributive=True)
with pytest.raises(ValueError, match="per="):
fmt_time(
5,
"hour",
precision=0,
style="word",
attributive=True,
per="day",
)
def test_checked_symbol_marker(self):
assert fmt_time(100, "millisecond", precision=0, marker="+") == "100 ms+"
with pytest.raises(ValueError, match="marker"):
fmt_time(100, "millisecond", precision=0, marker="ish")
with pytest.raises(ValueError, match="symbol"):
fmt_time(100, "millisecond", precision=0, style="word", marker="+")
with pytest.raises(ValueError, match="cannot be combined"):
fmt_time(100, "millisecond", precision=0, per="step", marker="+")
def test_rejects_non_time_unit(self):
with pytest.raises(ValueError, match="time unit"):
fmt_time(5, ureg.GB)
def test_rejects_negative_by_default(self):
with pytest.raises(ValueError, match="non-negative duration"):
fmt_time(-1, ureg.second, precision=0)
assert fmt_time(-1, ureg.second, precision=0, allow_negative=True) == "-1 s"
def test_returns_markdown_str(self):
assert isinstance(fmt_time(1, ureg.second, precision=0), MarkdownStr)
class TestFmtPercentGuards:
def test_precision_zero_accepts_whole_percentages(self):
assert fmt_percent(0.45, precision=0, commas=False) == "45"
def test_precision_zero_rejects_fractional_percentages(self):
with pytest.raises(ValueError, match="not integer-like"):
fmt_percent(0.456, precision=0, commas=False)
def test_default_style_is_bare_number_backward_compatible(self):
# Default precision=None auto-resolves integer-like percentages.
assert fmt_percent(0.85) == "85"
assert fmt_percent(0.123, precision=1) == "12.3"
def test_default_precision_auto_resolves_integer_like_percentages(self):
assert fmt_percent(0.85, style="prose") == "85 percent"
assert fmt_percent(0.90, style="symbol") == "90%"
assert fmt_percent_range(0.85, 0.90, style="prose") == "85\u201390 percent"
assert fmt_pp(7.0) == "7 percentage points"
def test_prose_style_owns_the_word_percent(self):
assert fmt_percent(0.85, precision=0, style="prose") == "85 percent"
def test_symbol_style_owns_the_glyph(self):
assert fmt_percent(0.85, precision=0, style="symbol") == "85%"
def test_rejects_already_scaled_value_the_10000_percent_bug(self):
with pytest.raises(ValueError, match="0-1 ratio"):
fmt_percent(85)
with pytest.raises(ValueError, match="0-1 ratio"):
fmt_percent(45, precision=0)
def test_allows_over_100_percent_only_with_explicit_max_ratio(self):
with pytest.raises(ValueError, match="0-1 ratio"):
fmt_percent(2.0, precision=0)
assert fmt_percent(2.0, precision=0, max_ratio=3) == "200"
def test_rejects_negative_ratio_by_default(self):
# a bounded proportion (accuracy, utilization) is never negative
with pytest.raises(ValueError, match="0-1 ratio"):
fmt_percent(-0.05, precision=0)
def test_allow_negative_widens_domain_for_signed_change(self):
# ROI / cost-delta: signed, may exceed 100% -> opt in explicitly
assert fmt_percent(-0.818, precision=1, style="symbol", allow_negative=True) == "-81.8%"
assert (
fmt_percent(8.089, precision=1, style="symbol", allow_negative=True, max_ratio=9)
== "808.9%"
)
def test_allow_negative_still_bounds_magnitude(self):
# the guard still catches a true 100x blunder even when signed
with pytest.raises(ValueError, match="0-1 ratio"):
fmt_percent(-85, allow_negative=True)
def test_rejects_unknown_style(self):
with pytest.raises(ValueError, match="style must be"):
fmt_percent(0.5, style="pct")
def test_returns_markdown_str(self):
assert isinstance(fmt_percent(0.5, precision=0, style="prose"), MarkdownStr)
class TestFmtPp:
def test_prose_default(self):
assert fmt_pp(7.0, precision=0) == "7 percentage points"
def test_symbol_style(self):
assert fmt_pp(7.0, precision=0, style="symbol") == "7 pp"
def test_not_multiplied_by_100(self):
# pp is already on the 0-100 point scale; 7 stays 7, not 700.
assert fmt_pp(7.0, precision=0).startswith("7 ")
def test_returns_markdown_str(self):
assert isinstance(fmt_pp(3.0, precision=0), MarkdownStr)
def test_singular_when_value_is_one(self):
assert fmt_pp(1.0, precision=0) == "1 percentage point"
def test_plural_for_fractional_near_one(self):
assert fmt_pp(0.9, precision=1) == "0.9 percentage points"
assert fmt_pp(1.5, precision=1) == "1.5 percentage points"
def test_pluralization_follows_rendered_number(self):
# any integer != 1 is plural
assert fmt_pp(2.0, precision=0) == "2 percentage points"
# a fractional value is always plural, even just below 1
assert fmt_pp(0.5, precision=1) == "0.5 percentage points"
def test_attributive_is_hyphenated_singular_word(self):
assert fmt_pp(5.0, precision=0, attributive=True) == "5 percentage-point"
# attributive stays singular/hyphenated regardless of magnitude
assert fmt_pp(12.0, precision=0, attributive=True) == "12 percentage-point"
def test_attributive_rejected_for_symbol_style(self):
with pytest.raises(ValueError, match="attributive"):
fmt_pp(5.0, style="symbol", attributive=True)
class TestFmtMultiple:
def test_owns_times_glyph(self):
assert fmt_multiple(3.2) == "3.2×"
assert fmt_multiple(10, precision=0) == "10×"
def test_owns_display_markers(self):
assert fmt_multiple(7.8, precision=1, approx=True) == "~7.8×"
assert fmt_multiple(10, precision=0, lower_bound=True) == "> 10×"
assert fmt_multiple(2, precision=0, upper_bound=True) == "< 2×"
with pytest.raises(ValueError, match="only one display marker"):
fmt_multiple(2, approx=True, upper_bound=True)
def test_inherits_fmt_precision_guard(self):
# An integer-like factor at precision=1 would render "2.0" — the
# shared fmt() guard rejects that; explicit precision=1 still errors.
with pytest.raises(ValueError, match="spurious trailing zeros"):
fmt_multiple(2.0, precision=1)
assert fmt_multiple(2.0, precision=0) == "2×"
assert fmt_multiple(2) == "2×"
assert fmt_multiple(2.0) == "2×"
def test_rejects_negative_factor(self):
with pytest.raises(ValueError, match="non-negative factor"):
fmt_multiple(-3)
def test_rejects_dimensioned_quantity(self):
with pytest.raises(ValueError, match="dimensionless scalar"):
fmt_multiple(3 * GB)
def test_returns_markdown_str(self):
assert isinstance(fmt_multiple(2.5), MarkdownStr)
class TestFmtSpecificHeat:
def test_uses_textbook_unit_label(self):
assert fmt_specific_heat(1005 * J / (kg * K), precision=0, commas=True) == "1,005 J/kg/K"
def test_rejects_wrong_dimension(self):
with pytest.raises(ValueError, match="energy/mass/temperature"):
fmt_specific_heat(1 * J, precision=0)
class TestFmtTimeAutoPrecision:
def test_auto_precision_trims_integer_like_display(self):
assert fmt_time(1.0 * second, second, precision=None, commas=False) == "1 s"
assert fmt_time(37.0 * second, second, precision=None, commas=False) == "37 s"
def test_auto_precision_preserves_sub_unit_fraction(self):
assert fmt_time(0.98 * second, second, precision=None, commas=False) == "0.98 s"
class TestFiniteGuard:
"""The divide-by-zero / non-finite last line of defense, on every helper."""
INF = float("inf")
NAN = float("nan")
def test_fmt_rejects_inf_and_nan(self):
with pytest.raises(ValueError, match="Non-finite"):
fmt(self.INF, precision=1)
with pytest.raises(ValueError, match="Non-finite"):
fmt(self.NAN, precision=1)
def test_message_names_divide_by_zero(self):
with pytest.raises(ValueError, match="divide-by-zero"):
fmt(self.INF, precision=0)
def test_guard_on_every_numeric_helper(self):
for call in (
lambda: fmt_int(self.INF),
lambda: fmt_usd(self.INF),
lambda: fmt_percent(self.NAN),
lambda: fmt_multiple(self.INF),
lambda: fmt_count(self.INF),
lambda: fmt_ratio(self.INF),
lambda: fmt_val(self.NAN),
lambda: fmt_sci(self.INF),
lambda: fmt_qty(self.INF * ureg.millisecond, ureg.millisecond),
lambda: fmt_time(self.INF, ureg.second),
lambda: fmt_rate(self.INF, "QPS"),
):
with pytest.raises(ValueError, match="Non-finite"):
call()
def test_finite_values_pass(self):
assert fmt(3.0, precision=0) == "3"
assert fmt_ratio(5.3, precision=1) == "5.3"
class TestFmtRatio:
def test_bare_number_no_decoration(self):
assert fmt_ratio(5.3, precision=1) == "5.3"
assert fmt_ratio(3.2) == "3.2"
assert fmt_ratio(5.0, precision=0) == "5"
def test_rejects_negative_by_default(self):
with pytest.raises(ValueError, match="non-negative ratio"):
fmt_ratio(-2.0)
def test_allows_signed_ratio_with_flag(self):
assert fmt_ratio(-2.0, precision=0, allow_negative=True) == "-2"
def test_rejects_dimensioned_quantity(self):
with pytest.raises(ValueError, match="dimensionless scalar"):
fmt_ratio(5 * GB)
def test_returns_markdown_str(self):
assert isinstance(fmt_ratio(1.5), MarkdownStr)
class TestFmtCount:
def test_no_scale_uses_commas(self):
assert fmt_count(8192) == "8,192"
assert fmt_count(1024, suffix=" GPUs") == "1,024 GPUs"
def test_structured_label_pluralizes_from_raw_count(self):
assert fmt_count(1, label="GPU") == "1 GPU"
assert fmt_count(2, label="GPU") == "2 GPUs"
assert fmt_count(1024, label="GPU") == "1,024 GPUs"
assert fmt_count(2, label="query") == "2 queries"
assert fmt_count(2, label="batch", plural_label="batches") == "2 batches"
def test_scale_glyphs(self):
assert fmt_count(5_000_000, scale="M") == "5M"
assert fmt_count(5_300_000, scale="M", precision=1) == "5.3M"
assert fmt_count(70e9, scale="B") == "70B"
assert fmt_count(70e9, scale="B", label="parameter") == "70B parameters"
def test_scale_words(self):
assert fmt_count(1_000_000, scale="M", scale_style="word") == "1 million"
assert fmt_count(1_000_000, scale="million") == "1 million"
assert fmt_count(1_000_000, scale="Million") == "1 Million"
assert (
fmt_count(
60_000_000,
scale="million",
label="parameter",
)
== "60 million parameters"
)
assert (
fmt_count(
70_000_000_000,
scale="billion",
precision=0,
commas=False,
label="parameter",
)
== "70 billion parameters"
)
def test_scale_word_attributive_modifier(self):
assert (
fmt_count(
7_000_000_000,
scale="billion",
precision=0,
commas=False,
attributive=True,
)
== "7-billion"
)
with pytest.raises(ValueError, match="requires scale"):
fmt_count(7, attributive=True)
with pytest.raises(ValueError, match="only the scaled modifier"):
fmt_count(
7_000_000_000,
scale="billion",
label="parameter",
attributive=True,
)
def test_scale_inherits_precision_guard(self):
# 5.3M at precision=0 would silently hide the .3 — guard refuses.
with pytest.raises(ValueError, match="not integer-like"):
fmt_count(5_300_000, scale="M", precision=0)
def test_rejects_negative_count(self):
with pytest.raises(ValueError, match="non-negative count"):
fmt_count(-5)
def test_rejects_fractional_count_by_default(self):
with pytest.raises(ValueError, match="whole-number count"):
fmt_count(1.5, label="GPU", precision=1)
assert fmt_count(1.5, label="GPU", precision=1, allow_fractional=True) == "1.5 GPUs"
def test_rejects_unknown_scale(self):
with pytest.raises(ValueError, match="scale must be"):
fmt_count(1000, scale="G")
def test_rejects_unknown_scale_style(self):
with pytest.raises(ValueError, match="scale_style"):
fmt_count(1000, scale="K", scale_style="long")
with pytest.raises(ValueError, match="requires scale"):
fmt_count(1000, scale_style="word")
def test_rejects_label_suffix_conflicts_and_unit_like_labels(self):
with pytest.raises(ValueError, match="structured label"):
fmt_count(2, label="GPU", suffix=" GPUs")
with pytest.raises(ValueError, match="looks like a unit"):
fmt_count(2, label="QPS")
def test_returns_markdown_str(self):
assert isinstance(fmt_count(1000, scale="K"), MarkdownStr)
class TestFmtRange:
def test_uses_en_dash_not_hyphen(self):
out = fmt_range(5, 10, precision=0)
assert out == "5\u201310"
assert "-" not in out # never an ASCII hyphen
def test_endpoints_written_in_full(self):
# MIT: 1992-1993, never 1992-93
assert fmt_range(1992, 1993, precision=0, commas=False) == "1992\u20131993"
def test_unit_appended_once(self):
assert fmt_range(5, 10, precision=0, unit="GB") == "5\u201310 GB"
assert fmt_range(2, 4, precision=0, unit="percent") == "2\u20134 percent"
def test_usd_kind_each_endpoint_carries_dollar(self):
assert fmt_range(0.10, 0.50, kind="usd", precision=2) == "\\$0.10\u2013\\$0.50"
def test_rejects_inverted_range(self):
with pytest.raises(ValueError, match="hi >= lo"):
fmt_range(10, 5, precision=0)
def test_rejects_non_finite_endpoint(self):
with pytest.raises(ValueError, match="finite|infinite"):
fmt_range(float("inf"), 5)
def test_rejects_unknown_kind(self):
with pytest.raises(ValueError, match="kind must be"):
fmt_range(5, 10, precision=0, kind="percent")
def test_returns_markdown_str(self):
assert isinstance(fmt_range(5, 10, precision=0), MarkdownStr)
class TestTypedRanges:
def test_quantity_range_appends_unit_once(self):
out = fmt_qty_range(
1 * ureg.GB,
2 * ureg.GB,
ureg.GB,
precision=0,
commas=False,
)
assert out == "1\u20132 GB"
assert (
fmt_qty_range(1 * ureg.GB, 2 * ureg.GB, unit=ureg.GB, precision=0, commas=False)
== "1\u20132 GB"
)
def test_quantity_range_accepts_checked_display_label(self):
out = fmt_qty_range(
1 * ureg.kilojoule,
2 * ureg.kilojoule,
ureg.kilojoule,
precision=0,
commas=False,
unit_label="kJ per hour",
)
assert out == "1\u20132 kJ per hour"
def test_percent_range_uses_ratio_domain_and_one_suffix(self):
assert (
fmt_percent_range(
0.846,
0.88,
precision=(1, 0),
commas=False,
style="prose",
)
== "84.6\u201388 percent"
)
assert (
fmt_percent_range(0.90, 0.95, precision=0, commas=False, style="symbol")
== "90\u201395%"
)
with pytest.raises(ValueError, match="0-1 ratio"):
fmt_percent_range(84.6, 88, precision=1)
def test_multiple_range_owns_times_glyph_and_is_checked(self):
assert fmt_multiple_range(3, 7.8, precision=(0, 1), commas=False) == "3\u20137.8×"
with pytest.raises(ValueError, match="non-negative"):
fmt_multiple_range(-1, 2)
with pytest.raises(ValueError, match="hi >= lo"):
fmt_multiple_range(3, 2)
def test_time_range_symbol_and_word_styles(self):
assert fmt_time_range(5, 20, ureg.millisecond, precision=0, commas=False) == "5\u201320 ms"
assert fmt_time_range(5, 20, ureg.millisecond, commas=False) == "5\u201320 ms"
assert fmt_time_range(5, 20, unit=ureg.millisecond, commas=False) == "5\u201320 ms"
assert (
fmt_time_range(1, 2, ureg.second, precision=0, style="word", commas=False)
== "1\u20132 seconds"
)
def test_count_range_pluralizes_from_raw_count(self):
assert fmt_count_range(1, 2, label="GPU", commas=False) == "1\u20132 GPUs"
assert (
fmt_count_range(
1_000_000,
2_000_000,
scale="M",
label="parameter",
commas=False,
)
== "1M\u20132M parameters"
)
assert (
fmt_count_range(
1_000_000,
2_000_000,
scale="million",
label="parameter",
commas=False,
)
== "1 million\u20132 million parameters"
)
def test_usd_range_supports_scale_and_denominator(self):
assert fmt_usd_range(10_000, 30_000, scale="K", commas=False) == "\\$10K\u2013\\$30K"
assert (
fmt_usd_range(25000, 30000, approx=True, repeat_symbol=False)
== "~\\$25,000\u201330,000"
)
assert (
fmt_usd_range(0.10, 0.50, precision=2, commas=False, per="GB")
== "\\$0.10\u2013\\$0.50/GB"
)
def test_ranges_reject_inverted_endpoints(self):
with pytest.raises(ValueError, match="hi >= lo"):
fmt_qty_range(2 * ureg.GB, 1 * ureg.GB, ureg.GB, precision=0)
with pytest.raises(ValueError, match="hi >= lo"):
fmt_count_range(2, 1)
with pytest.raises(ValueError, match="hi >= lo"):
fmt_usd_range(2, 1)
class TestFmtSciQty:
def test_scientific_quantity_appends_checked_unit(self):
out = fmt_sci_qty(
4.1e17 * ureg.flop,
ureg.flop,
precision=2,
unit_label="FLOPs",
)
assert out == "4.10 × 10¹⁷ FLOPs"
assert isinstance(out, MarkdownStr)
assert (
fmt_sci_qty(4.1e17 * ureg.flop, unit=ureg.flop, precision=2, unit_label="FLOPs")
== "4.10 × 10¹⁷ FLOPs"
)
def test_scientific_quantity_converts_before_formatting(self):
out = fmt_sci_qty(
4.1e8 * ureg.GFLOPs,
ureg.flop,
precision=2,
unit_label="FLOPs",
)
assert out == "4.10 × 10¹⁷ FLOPs"
def test_scientific_quantity_requires_quantity(self):
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_sci_qty(4.1e17, ureg.flop)
class TestDomainFormatters:
def test_fmt_power_scales_to_mw(self):
from mlsysim.fmt import fmt_power
from mlsysim.core.units import watt
out = fmt_power(17.5e6 * watt, precision=1, commas=False)
assert out == "17.5 MW"
def test_fmt_power_scales_to_gw(self):
from mlsysim.fmt import fmt_power
from mlsysim.core.units import GW
out = fmt_power(2.6 * GW, precision=1, commas=False)
assert out == "2.6 GW"
def test_fmt_energy_scales_to_kwh(self):
from mlsysim.fmt import fmt_energy
from mlsysim.core.units import kWh, watt, hour
out = fmt_energy(700 * watt * hour, precision=0, commas=False)
assert out == "700 Wh"
def test_fmt_bandwidth_scales(self):
from mlsysim.fmt import fmt_bandwidth
from mlsysim.core.units import GB, TB, second
out = fmt_bandwidth(3.35 * TB / second, precision=2, commas=False)
assert out == "3.35 TB/s"
def test_fmt_area_owns_square_unit_label(self):
assert (
fmt_area(814 * ureg.millimeter**2, unit=ureg.millimeter**2, commas=False)
== "814 mm²"
)
with pytest.raises(ValueError, match="area unit"):
fmt_area(814 * ureg.millimeter**2, unit=ureg.watt)
def test_fmt_heat_flux_owns_power_density_label(self):
assert (
fmt_heat_flux(
86.0 * ureg.watt / (ureg.centimeter**2),
unit=ureg.watt / (ureg.centimeter**2),
commas=False,
)
== "86 W/cm²"
)
with pytest.raises(ValueError, match="power/area"):
fmt_heat_flux(86 * ureg.watt / (ureg.centimeter**2), unit=ureg.watt)
def test_fmt_params_auto_precision(self):
from mlsysim.core.units import Bparam, Mparam
assert fmt_params(175 * Bparam) == "175B"
assert fmt_params(1.5 * Bparam) == "1.5B"
assert fmt_params(150 * Mparam) == "150M"
assert fmt_params(150 * Mparam, scale="B") == "0.15B"
def test_fmt_tokens_scales_checked_counts(self):
from mlsysim.core.units import count
assert fmt_tokens(300e9 * count, scale="B", commas=False) == "300B"
assert fmt_tokens(1.5e12 * count, scale="T", commas=False) == "1.5T"
def test_fmt_flop_rate_scales_to_tflop_per_second(self):
from mlsysim.core.units import TFLOP, second
out = fmt_flop_rate(989 * TFLOP / second, precision=0, commas=False)
assert out == "989 TFLOP/s"
def test_fmt_flop_rate_scales_to_pflop_per_second(self):
from mlsysim.core.units import PFLOP, TFLOP, second
out = fmt_flop_rate(1_979 * TFLOP / second, precision=3, commas=False)
assert out == "1.979 PFLOP/s"
assert fmt_flop_rate(2 * PFLOP / second, precision=0, commas=False) == "2 PFLOP/s"
def test_fmt_flop_rate_requires_quantity(self):
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_flop_rate(989)
def test_fmt_flops_scales_to_canonical_singular_units(self):
from mlsysim.core.units import GFLOP, MFLOP, TFLOP
assert fmt_flops(569 * MFLOP, precision=0, commas=False) == "569 MFLOP"
assert fmt_flops(4.1 * GFLOP, precision=1, commas=False) == "4.1 GFLOP"
assert fmt_flops(350 * TFLOP, precision=0, commas=False) == "350 TFLOP"
assert (
fmt_flops(4.1 * GFLOP, precision=1, commas=False, per="inference")
== "4.1 GFLOP/inference"
)
def test_fmt_sci_flops_owns_plural_scientific_label(self):
from mlsysim.core.units import GFLOP, flop
assert fmt_sci_flops(4.1e17 * flop, precision=2) == "4.10 × 10¹⁷ FLOPs"
assert fmt_sci_flops(4.1e8 * GFLOP, precision=2) == "4.10 × 10¹⁷ FLOPs"
def test_fmt_flops_requires_quantity(self):
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_flops(4.1e9)
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_sci_flops(4.1e9)
def test_fmt_arithmetic_intensity_owns_flop_per_byte_label(self):
from mlsysim.core.units import GB, TFLOP, byte, flop
assert fmt_arithmetic_intensity(5 * flop / byte, precision=0, commas=False) == "5 FLOP/byte"
assert (
fmt_arithmetic_intensity(1 * TFLOP / GB, precision=0, commas=False) == "1000 FLOP/byte"
)
def test_fmt_energy_density_helpers_own_readable_labels(self):
from mlsysim.core.units import bit, byte, flop, pJ
assert fmt_energy_per_byte(160 * pJ / byte, precision=0, commas=False) == "160 pJ/byte"
assert fmt_energy_per_bit(5 * pJ / bit, precision=0, commas=False) == "5 pJ/bit"
assert fmt_energy_per_flop(10 * pJ / flop, precision=0, commas=False) == "10 pJ/FLOP"
assert fmt_energy_per_op(0.9 * pJ / flop, commas=False) == "0.9 pJ/op"
assert fmt_energy_per_op(0.03 * pJ / flop, commas=False) == "0.03 pJ/op"
assert fmt_energy_per_op(0.03 * pJ / flop, precision=2, commas=False) == "0.03 pJ/op"
assert fmt_qty(160 * pJ / byte, pJ / byte, precision=0, commas=False) == "160 pJ/byte"
def test_fmt_energy_density_helpers_require_quantities(self):
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_energy_per_byte(160)
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_energy_per_bit(5)
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_energy_per_flop(10)
with pytest.raises(TypeError, match="requires a Pint Quantity"):
fmt_energy_per_op(10)
with pytest.raises(ValueError, match="energy/operation"):
fmt_energy_per_op(10 * ureg.picojoule, unit=ureg.picojoule)
with pytest.raises(ValueError, match="non-negative energy"):
fmt_energy_per_op(-1 * ureg.picojoule / ureg.flop)
def test_fmt_ops_rate_scales_integer_ops(self):
from mlsysim.core.units import TOPS
assert fmt_ops_rate(2 * TOPS, precision=0, commas=False) == "2 TOPS"
assert fmt_ops_rate(0.002 * TOPS, precision=0, commas=False) == "2 GOPS"
def test_fmt_rate_allows_iops(self):
assert fmt_rate(150, "IOPS", precision=0, commas=False) == "150 IOPS"
assert fmt_rate(6_000, "IOPS", scale="K", precision=0, commas=False) == "6K IOPS"
def test_fmt_rate_allows_macs_per_cycle(self):
assert fmt_rate(16_384, "MACs/cycle", precision=0, commas=True) == "16,384 MACs/cycle"
def test_fmt_rate_allows_event_and_inference_rates(self):
assert fmt_rate(20, "events/s", precision=0, commas=False) == "20 events/s"
assert fmt_rate(300, "inferences/s", precision=0, commas=False) == "300 inferences/s"
def test_fmt_rate_allows_book_service_rates(self):
assert fmt_rate(12.5, "failures/day", precision=1, commas=False) == "12.5 failures/day"
assert fmt_rate(90, "queries/hour", precision=0, commas=False) == "90 queries/hour"
assert fmt_rate(5000, "queries/class", precision=0, commas=True) == "5,000 queries/class"
assert fmt_rate(4, "deploys/week", precision=0, commas=False) == "4 deploys/week"
assert (
fmt_rate(40, "utterances/speaker", precision=0, commas=False) == "40 utterances/speaker"
)
assert fmt_rate(12, "cameras/store", precision=0, commas=False) == "12 cameras/store"
assert fmt_rate(3, "boards/store", precision=0, commas=False) == "3 boards/store"
assert fmt_rate(1000, "cases/day", precision=0, commas=True) == "1,000 cases/day"
assert fmt_rate(120, "km/h", precision=0, commas=False) == "120 km/h"
def test_fmt_named_markers_include_upper_bound(self):
from mlsysim.core.units import GB, TOPS, TFLOP, milliwatt, second
assert fmt(100, precision=0, lower_bound=True, suffix=" MB/s") == "> 100 MB/s"
assert fmt(100, precision=0, upper_bound=True, suffix=" MB/s") == "< 100 MB/s"
assert (
fmt_flop_rate(
100 * TFLOP / second,
unit=TFLOP / second,
precision=0,
commas=False,
lower_bound=True,
)
== "> 100 TFLOP/s"
)
assert (
fmt_bandwidth(
500 * GB / second,
unit=GB / second,
precision=0,
commas=False,
lower_bound=True,
)
== "> 500 GB/s"
)
assert (
fmt_ops_rate(1 * TOPS, unit=TOPS, precision=0, commas=False, upper_bound=True)
== "< 1 TOPS"
)
assert (
fmt_power(10 * milliwatt, unit=milliwatt, precision=0, commas=False, upper_bound=True)
== "< 10 mW"
)
with pytest.raises(ValueError, match="only one display marker"):
fmt(100, precision=0, approx=True, upper_bound=True)
def test_small_physical_label_helpers(self):
from mlsysim.core.units import second
assert fmt_decibel(ureg.Quantity(20, ureg.decibel), precision=0, commas=False) == "20 dB"
assert fmt_illuminance(100 * ureg.lux, precision=0, commas=False) == "100 lux"
assert fmt_temperature(ureg.Quantity(80, ureg.degC), precision=0, commas=False) == "80 °C"
assert (
fmt_temperature_rate(
1 * ureg.delta_degC / second,
precision=0,
commas=False,
)
== "1 °C/s"
)
def test_fmt_compute_efficiency_renders_full_unit(self):
from mlsysim.core.units import TFLOP, second, watt
out = fmt_compute_efficiency(
(989 * TFLOP / second) / (700 * watt),
precision=2,
commas=False,
)
assert out == "1.41 TFLOP/s/W"
def test_fmt_memory_scales(self):
from mlsysim.fmt import fmt_memory
from mlsysim.core.units import GB, byte
out = fmt_memory(14 * GB, precision=0, commas=False)
assert out == "14 GB"
assert fmt_memory(4 * byte, unit=byte, precision=0, commas=False) == "4 bytes"
def test_fmt_memory_capacity_preserves_binary_magnitude_with_vendor_label(self):
from mlsysim.core.units import GB, GiB, KiB, MiB
from mlsysim.fmt import fmt_memory
assert fmt_memory_capacity(80 * GiB, unit=GiB, precision=0, commas=False) == "80 GB"
assert fmt_memory_capacity(33 * MiB, unit=MiB, precision=0, commas=False) == "33 MB"
assert fmt_memory_capacity(256 * KiB, unit=KiB, precision=0, commas=False) == "256 KB"
assert fmt_memory(80 * GiB, unit=GB, precision=1, commas=False) == "85.9 GB"
def test_fmt_carbon_intensity_defaults_to_grams_per_kwh(self):
from mlsysim.core.units import gram, kilogram, kWh
assert fmt_carbon_intensity(429 * gram / kWh, precision=0, commas=False) == "429 g/kWh"
assert (
fmt_carbon_intensity(0.429 * kilogram / kWh, precision=0, commas=False) == "429 g/kWh"
)
def test_fmt_emissions_supports_display_markers(self):
from mlsysim.core.units import kilogram, metric_ton
assert (
fmt_emissions(
85_000 * kilogram,
unit=metric_ton,
precision=0,
commas=False,
approx=True,
)
== "~85 t"
)
def test_fmt_water_helpers_use_book_liter_labels(self):
from mlsysim.core.units import L, day, hour, kWh
assert fmt_water(18_000_000 * L, precision=0) == "18,000,000 L"
assert fmt_water_rate(12_000 * L / hour, unit=L / hour, precision=0) == "12,000 L/h"
assert fmt_water_rate(12_000 * L / hour, unit=L / day, precision=0) == "288,000 L/day"
assert fmt_water_intensity(1.8 * L / kWh, precision=1) == "1.8 L/kWh"
def test_fmt_water_helpers_reject_wrong_dimensions(self):
from mlsysim.core.units import L, watt
with pytest.raises(ValueError, match="volume unit"):
fmt_water(1 * L, unit=watt)
with pytest.raises(ValueError, match="volume/time"):
fmt_water_rate(1 * L, unit=L)
with pytest.raises(ValueError, match="volume/energy"):
fmt_water_intensity(1 * L, unit=L)
def test_usd_range_repeat_symbol_false_with_scale(self):
assert (
fmt_usd_range(10_000, 30_000, scale="K", commas=False, repeat_symbol=False)
== "\\$10K\u201330K"
)
class TestAuditRepairs:
"""Focused regressions for the 2026-06 verified audit findings.
Five findings: fmt_int silent zero + banker's rounding, the auto-scale
1000-mantissa boundary, fmt_unit/fmt_qty label divergence, fmt_pp
singular grammar on negatives, and fmt_usd negative sign placement.
"""
# --- Finding 1: fmt_int silent zero + round-half-away-from-zero --------
def test_fmt_int_rejects_nonzero_values_that_round_to_zero(self):
with pytest.raises(ValueError, match="rounds to '0'"):
fmt_int(0.4)
with pytest.raises(ValueError, match="rounds to '0'"):
fmt_int(-0.4)
with pytest.raises(ValueError, match="rounds to '0'"):
fmt_int(0.49999)
def test_fmt_int_true_zero_still_renders(self):
assert fmt_int(0) == "0"
assert fmt_int(0.0) == "0"
def test_fmt_int_rounds_half_away_from_zero(self):
# Python round() is banker's (2.5 -> 2, 3.5 -> 4); fmt_int must round
# adjacent halves consistently away from zero.
assert fmt_int(2.5, commas=False) == "3"
assert fmt_int(3.5, commas=False) == "4"
assert fmt_int(-2.5, commas=False) == "-3"
assert fmt_int(-3.5, commas=False) == "-4"
assert fmt_int(0.5, commas=False) == "1"
assert fmt_int(-0.5, commas=False) == "-1"
def test_fmt_int_still_absorbs_float_noise(self):
assert fmt_int(7.9999999999, commas=False) == "8"
assert fmt_int(362507.545, commas=True) == "362,508"
def test_fmt_int_keeps_commas_and_markers(self):
assert fmt_int(1500.5, commas=True) == "1,501"
assert fmt_int(80.2, commas=False, approx=True, suffix=" GB") == "~80 GB"
# --- Finding 2: auto-scale boundary promotion (M -> B -> T) ------------
def test_auto_scale_promotes_rounded_mantissa_at_boundary(self):
# 999,999,999 picks "M" from the raw value but ROUNDS to a 1000.0
# mantissa at display precision; it must promote to "1B".
assert fmt_params(999_999_999) == "1B"
assert fmt_params(999_999_999_999) == "1T"
def test_fmt_tokens_auto_scale_boundary(self):
from mlsysim.core.units import count
assert fmt_tokens(999_999_999 * count, scale="auto") == "1B"
def test_auto_scale_exact_boundaries_unchanged(self):
assert fmt_params(1_000_000_000) == "1B"
assert fmt_params(1_000_000_000_000) == "1T"
def test_auto_scale_below_boundary_does_not_promote(self):
assert fmt_params(999_400_000_000) == "999.4B"
def test_auto_scale_top_scale_keeps_value_with_commas(self):
# No scale above T: keep the T mantissa and group digits instead.
assert fmt_params(2_000_000_000_000_000) == "2,000T"
# --- Finding 3: fmt_unit routed through shared normalization -----------
def test_fmt_unit_normalizes_all_flops_rate_labels(self):
from mlsysim.core.units import Q_
assert fmt_unit(Q_(1, "EFLOPs/second")) == "EFLOP/s"
assert fmt_unit(Q_(1, "KFLOPs/second")) == "KFLOP/s"
assert fmt_unit(Q_(1, "TFLOPs/second")) == "TFLOP/s"
def test_fmt_unit_normalizes_bare_work_units(self):
from mlsysim.core.units import Q_
assert fmt_unit(Q_(1, "TFLOPs")) == "TFLOP"
assert fmt_unit(Q_(1, "EFLOPs")) == "EFLOP"
def test_fmt_unit_matches_fmt_qty_suffix_exactly(self):
from mlsysim.core.units import Q_
q = Q_(2, "EFLOPs/second")
qty_suffix = str(fmt_qty(q, q.units, precision=0, commas=False)).split(" ", 1)[1]
assert str(fmt_unit(q)) == qty_suffix
def test_fmt_unit_default_and_plain_units(self):
from mlsysim.core.units import Q_
assert fmt_unit(80) == "-"
assert fmt_unit(Q_(1, "GB")) == "GB"
assert isinstance(fmt_unit(Q_(1, "GB")), MarkdownStr)
# --- Finding 4: fmt_pp singular grammar on negatives -------------------
def test_fmt_pp_negative_one_is_singular(self):
assert fmt_pp(-1) == "-1 percentage point"
assert fmt_pp(-1.0, precision=0) == "-1 percentage point"
def test_fmt_pp_singular_plural_agreement_unchanged(self):
assert fmt_pp(1.0, precision=0) == "1 percentage point"
assert fmt_pp(-2.0, precision=0) == "-2 percentage points"
assert fmt_pp(7.0) == "7 percentage points"
assert fmt_pp(0.9, precision=1) == "0.9 percentage points"
# --- Finding 5: fmt_usd negative sign-first rendering -------------------
def test_fmt_usd_negative_renders_sign_first(self):
assert fmt_usd(-500) == "-\\$500"
assert fmt_usd(-12345.6) == "-\\$12,346"
def test_fmt_usd_negative_with_approx(self):
assert fmt_usd(-500, approx=True) == "~-\\$500"
def test_fmt_usd_negative_with_scale_and_per(self):
assert fmt_usd(-4_600_000, precision=1, scale="M") == "-\\$4.6M"
assert fmt_usd(-0.09, precision=2, commas=False, per="GB") == "-\\$0.09/GB"
assert fmt_usd(-12_000, commas=False, scale="K", per="year") == "-\\$12K/year"
def test_fmt_usd_positive_unchanged(self):
assert fmt_usd(15000) == "\\$15,000"
assert fmt_usd(8000, approx=True, marker="*") == "~\\$8,000*"
class TestFmtLength:
def test_fmt_length_meters_small_no_commas(self):
from mlsysim.core.units import meter
assert fmt_length(2.8 * meter, unit=meter, precision=1) == "2.8 m"
def test_fmt_length_kilometers_commas(self):
from mlsysim.core.units import kilometer
assert fmt_length(3600 * kilometer, unit=kilometer, precision=0) == "3,600 km"
def test_fmt_rate_kmh(self):
assert fmt_rate(120, "km/h", precision=0, commas=False) == "120 km/h"