diff --git a/tests/test_utils_printing.py b/tests/test_utils_printing.py new file mode 100644 index 000000000..267ef7076 --- /dev/null +++ b/tests/test_utils_printing.py @@ -0,0 +1,214 @@ +import pytest +import sys +import os +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from slic.utils.ask_yes_no import * + +# maxlen / maxstrlen / strlen +@pytest.mark.parametrize("seq,expected", [ + (["a", "abc", ""], 3), + ([], 0), + ([[1, 2], [3], [4, 5, 6]], 3), + ([{"a": 2, "b": 3}, {}, {"c": 4}], 2), +]) +def test_maxlen_valid(seq, expected): + assert maxlen(seq) == expected + +@pytest.mark.parametrize("seq,expected", [ + ([1, True, 3.1415], 6), # "3.1415" + (["aa", "bbb", "c"], 3), # "bbb" + ([[1, 2], [], [1, 2, 3]], 9), # "[1, 2, 3]" + ([{"a": 1}, {}, {"a": 1, "b": 2}], 17), # "{'a': 1, 'b': 2}" + ([None, False, 12345], 5), # "12345" +]) +def test_maxstrlen(seq, expected): + assert maxstrlen(seq) == expected + +@pytest.mark.parametrize("value,expected", [ + (42, 2, # int → "42" + ("hello", 5), # str → "hello" + (False, 5), # bool → "False" + (None, 4), # None → "None" + ([1, 2, 3], len(str([1, 2, 3]))), # list → "[1, 2, 3]" + ({'a': 1}, len(str({'a': 1}))), # dict → "{'a': 1}" + ((1, 2), len(str((1, 2)))), # tuple → "(1, 2)" + ("", 0), # empty string + ("ok ok", 5), +]) +def test_strlen(value, expected): + assert strlen(value) == expected + +# mk_pad +@pytest.mark.parametrize("x,length,expected", [ + ("a", 4, " "), + ("abc", 4, " "), + ("abcd", 4, ""), +]) +def test_mk_pad(x, length, expected): + assert mk_pad(x, length) == expected + +# format_header +@pytest.mark.parametrize("msg,line,expected", [ + ("Title", "-", "Title:\n------"), + ("Hello", "=", "Hello:\n====="), +]) +def test_format_header(msg, line, expected): + assert format_header(msg, line) == expected + +# itemize +@pytest.mark.parametrize("items,header,bullet,expected_lines", [ + (["apple", "banana"], None, "-", ["- apple", "- banana"]), + (["x", "y"], "Vars", "*", ["Vars:\n-----", "* x", "* y"]), + (["one"], "+", None, ["+ one"]), +]) +def test_itemize(items, header, bullet, expected_lines): + result = itemize(items, header=header, bullet=bullet or "-") + for expected in expected_lines: + assert expected in result + +# printable_dict +@pytest.mark.parametrize("d,header,sorter,expected_lines", [ + ( + {"x": 1, "medium": True, "very_long_key": 3.14}, + "HeaderTest", + sorted, + [ + "HeaderTest:\n-----------", + "medium :True", + "very_long_key:3.14", + "x :1" + ] + ), + ( + {"short": None, "loooooongkey": [1, 2]}, + None, + None, + [ + "short :None", + "loooooongkey:[1, 2]" + ] + ), +]) +def test_printable_dict_variants_with_alignment(d, header, sorter, expected_lines): + out = printable_dict(d, header=header, sorter=sorter) + for expected in expected_lines: + assert expected in out, f"Missing or misaligned line: {expected}" + if header: + assert format_header(header) in out + + +# printable_dict_of_dicts +@pytest.mark.parametrize("d,expected_blocks", [ + ( + { + "General": { + "a": 1, + "long_key": True, + "very_very_long_key": 3.14 + }, + "MetaInfo": { + "short": None, + "a_much_longer_key": {"x": 1} + } + }, + [ + format_header("General"), + "a :1", + "long_key :True", + "very_very_long_key :3.14", + format_header("MetaInfo"), + "short :None", + "a_much_longer_key :{'x': 1}" + ] + ), +]) +def test_printable_dict_of_dicts_complete(d, expected_blocks): + out = printable_dict_of_dicts(d) + for line in expected_blocks: + assert line in out, f"Expected line not found or misaligned: {line}" + assert out.endswith("\n") or out.endswith("\n\n") # blank line at the end + + +#_transpose +@pytest.mark.parametrize("data,expected", [ + ([[1, 2], [3, 4]], [(1, 3), (2, 4)]), # ints + ([["a", "b"], ["c", "d"]], [("a", "c"), ("b", "d")]), # strings + ([[{"x": 1}, {"y": 2}], [{"x": 3}, {"y": 4}]], [({"x": 1}, {"x": 3}), ({"y": 2}, {"y": 4})]), # dict +]) +def test_transpose_matrix(data, expected): + assert _transpose(data) == expected + + +# _prepend +@pytest.mark.parametrize("initial,prepend,expected", [ + ([2, 3], 1, [1, 2, 3]), # int + (["b", "c"], "a", ["a", "b", "c"]), # str + ([{"b": 2}], {"a": 1}, [{"a": 1}, {"b": 2}]), # dict + ([[2], [3]], [1], [[1], [2], [3]]), # list of lists +]) +def test_prepend(initial, prepend, expected): + _prepend(prepend, initial) + assert initial == expected + + +# _fmt_table_line +@pytest.mark.parametrize("entries, widths, expected", [ + (["a", "bbb"], [3, 5], " a bbb"), # simple string + ([1, 2], [2, 2], " 1 2"), # int + (["long", "val"], [6, 4], " long val"), # more padding + ([True, False], [5, 6], " True False"), # bool + ([123, 4567], [5, 5], " 123 4567"), # numbers + (["text with space", "end"], [16, 5], " text with space end"), # long text + ([{"a": 1}, {"b": 2}], [12, 12], " {'a': 1} {'b': 2}"), # dicts + ([[1, 2], [3, 4]], [10, 10], " [1, 2] [3, 4]"), # lists + ([[{"x": 1}], [{"y": 2}]], [16, 16], " [{'x': 1}] [{'y': 2}]"), # list of dict + ([[1, [2, 3]], [4, [5, 6]]], [18, 18], " [1, [2, 3]] [4, [5, 6]]"), # nested lists +]) +def test_fmt_table_line(entries, widths, expected): + assert _fmt_table_line(entries, widths) == expected + +# _fmt_label_sep +@pytest.mark.parametrize("widths,line,expected", [ + ([3, 4], "-", "--- ----"), # standard + ([2, 3], "=", "== ==="), # custom char + ([10, 12], "-", "---------- ------------"), # colonnes larges + ([len(str([1, 2, 3])), len(str({'a': 1}))], "-", + "--------- ----------"), # largeur basée sur list/dict str + ([len(str([{'x': 1}]))] * 2, "=", + "============== =============="), # list of dict + ([len(str([1, [2, 3]])), len(str([4, [5, 6]]))], "#", + "############## ##############"), # nested lists +]) +def test_fmt_label_sep(widths, line, expected): + assert _fmt_label_sep(widths, line) == expected + + +# printable_table +def test_printable_table_exact_output(): + data = [ + ["X1", True, 0.1234, {"meta": "ok"}], + ["AnotherSample", False, 98765.4321, {"meta": [1, 2, 3]}], + ["Z", None, 0.0, {"meta": {"nested_key": 42}}] + ] + labels = ["ID", "✓ Success?", "SuperPrecisionValue", "Result Metadata"] + + expected = ( + "A: ID\n" + "B: ✓ Success?\n" + "C: SuperPrecisionValue\n" + "D: Result Metadata\n" + "# A B C D\n" + "-------------------------------------------------------------------------------\n" + "0 X1 True 0.1234 {'meta': 'ok'}\n" + "1 AnotherSample False 98765.4321 {'meta': [1, 2, 3]}\n" + "2 Z None 0.0 {'meta': {'nested_key': 42}}\n" +) + + out = printable_table( + data, + labels=labels, + enumerate_lines=True, + make_legend=True + ) + + assert out == expected