diff --git a/mortie/tests/test_tools.py b/mortie/tests/test_tools.py index d8cdfea..2f1f0aa 100644 --- a/mortie/tests/test_tools.py +++ b/mortie/tests/test_tools.py @@ -45,6 +45,56 @@ def test_order2res_decreasing(self): assert all(resolutions[i] > resolutions[i+1] for i in range(len(resolutions)-1)) +class TestRes2Display: + """Test the resolution-ladder printer""" + + def test_prints_all_orders_through_max(self, capsys): + """One line per order 0..MAX_ORDER -- no silent drop above 19""" + tools.res2display() + lines = capsys.readouterr().out.strip().split('\n') + assert len(lines) == tools.MAX_ORDER + 1 + # every order 0..29 appears with its trailing phrasing + for order in range(tools.MAX_ORDER + 1): + assert any( + line.endswith('at tessellation order ' + str(order)) + for line in lines + ) + + def test_max_order_argument(self, capsys): + """max_order bounds the printed range inclusively""" + tools.res2display(max_order=5) + lines = capsys.readouterr().out.strip().split('\n') + assert len(lines) == 6 + assert lines[-1].endswith('at tessellation order 5') + + def test_unit_ladder_km_m_cm(self, capsys): + """Coarse orders read in km, sub-km in m, sub-m in cm""" + tools.res2display() + lines = capsys.readouterr().out.strip().split('\n') + by_order = {int(line.rsplit(' ', 1)[1]): line for line in lines} + # order 12 = 1.589 km, order 13 = 794.456 m (the issue's examples) + assert by_order[12] == '1.589 km at tessellation order 12' + assert by_order[13] == '794.456 m at tessellation order 13' + # finest orders drop to cm rather than tiny km/m fractions + assert by_order[25] == '19.396 cm at tessellation order 25' + assert by_order[29] == '1.212 cm at tessellation order 29' + + def test_rounds_within_bracket(self, capsys): + """Values are rounded to three decimals inside the chosen unit""" + tools.res2display() + lines = capsys.readouterr().out.strip().split('\n') + for line in lines: + number = line.split(' ', 1)[0] + # at most three digits after the decimal point + assert '.' in number and len(number.split('.')[1]) <= 3 + + def test_out_of_range_raises(self): + """max_order outside 0..MAX_ORDER is rejected""" + for bad in (-1, tools.MAX_ORDER + 1): + with pytest.raises(ValueError, match="max_order must be"): + tools.res2display(max_order=bad) + + class TestUnique2Parent: """Test UNIQ to parent cell conversion""" diff --git a/mortie/tools.py b/mortie/tools.py index c31108a..3c80971 100644 --- a/mortie/tools.py +++ b/mortie/tools.py @@ -24,10 +24,33 @@ def order2res(order): return res -def res2display(): - '''prints resolution levels''' - for res in range(20): - print(str(order2res(res)) + ' km at tessellation order ' + str(res)) +def res2display(max_order=MAX_ORDER): + '''prints resolution levels + + Prints one line per tessellation order from 0 through ``max_order`` + (default MAX_ORDER = 29, the finest order the packed-u64 kernel reaches). + Each resolution is rendered in the largest sensible unit -- km at coarse + orders, m once it drops below 1 km, cm once it drops below 1 m -- and + rounded to three decimals within that bracket, so fine orders read + naturally (e.g. order 12 -> ``1.589 km``, order 13 -> ``794.456 m``) + rather than as tiny km fractions. + + ``max_order`` must lie in 0..MAX_ORDER, the order range the packed-u64 + kernel encodes. + ''' + if not 0 <= max_order <= MAX_ORDER: + raise ValueError( + f"max_order must be between 0 and {MAX_ORDER}, got {max_order!r}") + for res in range(max_order + 1): + km = order2res(res) + if km >= 1.0: + value, unit = km, 'km' + elif km >= 1e-3: + value, unit = km * 1e3, 'm' + else: + value, unit = km * 1e5, 'cm' + print(str(round(value, 3)) + ' ' + unit + + ' at tessellation order ' + str(res)) def unique2parent(unique):