import pytest from leonida.annotations import KINDS, AnnotationError, load_annotations, parse_annotations def test_missing_file_and_comment_only_file_mean_no_entries_and_no_grid(tmp_path): assert load_annotations(tmp_path / "fehlt.toml").annotations == [] (tmp_path / "leer.toml").write_text("# nur Kommentare\n") parsed = load_annotations(tmp_path / "leer.toml") assert parsed.annotations == [] and parsed.keep == [] and parsed.grid is None def test_all_spec_kinds_are_known(): assert set(KINDS) == {"text_white", "text_red", "marker", "symbol", "street_name", "region"} def test_entries_parse_with_normalised_boxes_and_chunk_names(): parsed = parse_annotations(""" [grid] spacing = 500 width = 6 [[annotation]] name = "VICE BEACH (MIAMI BEACH)" kind = "text_white" box = [[1900, 705], [1350, 870]] [[annotation]] name = "Rest am Marker S2/32" kind = "region" polygon = [[1905, 640], [1925, 640], [1925, 615], [1905, 615]] reason = "vom Nutzer markiert" [[keep]] box = [[-856, 194], [-794, -1]] reason = "knallrotes Gebäude, echt" """) first, second = parsed.annotations assert (first.index, first.kind, first.box) == (1, "text_white", (1350.0, 705.0, 1900.0, 870.0)) assert first.chunk == "K7" assert second.polygon[0] == (1905.0, 640.0) and second.box is None and second.reason == "vom Nutzer markiert" assert second.chunk == "L8" assert parsed.keep[0].box == (-856.0, -1.0, -794.0, 194.0) assert (parsed.grid.spacing, parsed.grid.width) == (500.0, 6.0) @pytest.mark.parametrize("body, message", [ ('name = "X"\nkind = "banner"\nbox = [[0, 0], [10, 10]]', "unbekanntes kind 'banner'"), ('kind = "marker"\nbox = [[0, 0], [10, 10]]', "Feld 'name' fehlt oder ist leer"), ('name = "X"\nkind = "marker"\nbox = [[0, 0], [10, 10]]\nhight = 3', "Feld 'hight' gibt es nicht"), ('name = "X"\nkind = "marker"', "Feld 'box' fehlt"), ('name = "X"\nkind = "marker"\nbox = [1, 2]', "Feld 'box' muss zwei Ecken"), ('name = "X"\nkind = "marker"\nbox = [[0, 0], [1, 5]]', "mindestens 2 m"), ('name = "X"\nkind = "marker"\nbox = [[1900, 0], [2100, 50]]', "außerhalb des Ausschnitts"), ('name = "X"\nkind = "marker"\npolygon = [[0, 0], [10, 0], [10, 10]]', "Feld 'polygon' gibt es nur bei region"), ('name = "X"\nkind = "region"\nbox = [[0, 0], [10, 10]]\npolygon = [[0, 0], [10, 0], [10, 10]]', "genau eines der Felder"), ('name = "X"\nkind = "region"\npolygon = [[0, 0], [10, 10], [10, 0], [0, 10]]', "ohne sich schneidende Kanten"), ('name = "X"\nkind = "region"\npolygon = [[0, 0], [10, 10]]', "mindestens 3 Punkte"), ('name = "X"\nkind = "marker"\nbox = [[0, 0], [10, 10]]\nreason = 7', "reason muss Text sein"), ]) def test_form_errors_stop_with_entry_number_and_field(body, message): text = ('[[annotation]]\nname = "OK"\nkind = "marker"\nbox = [[0, 0], [10, 10]]\n\n' f'[[annotation]]\n{body}\n') with pytest.raises(AnnotationError, match="Beschriftung 2") as err: parse_annotations(text) assert message in str(err.value) def test_keep_needs_a_reason(): with pytest.raises(AnnotationError, match="Ausnahme 1: Feld 'reason' fehlt oder ist leer"): parse_annotations("[[keep]]\nbox = [[0, 0], [10, 10]]\n") @pytest.mark.parametrize("body, message", [ ("spacing = 0\nwidth = 6", "Gitternetz: Feld 'spacing' muss eine Zahl größer als 0 sein"), ("spacing = 500", "Gitternetz: Feld 'width' fehlt"), ("spacing = 500\nwidth = 6\ncolour = 1", "Gitternetz: Feld 'colour' gibt es nicht"), ]) def test_grid_form_errors(body, message): with pytest.raises(AnnotationError, match=message): parse_annotations(f"[grid]\n{body}\n") def test_broken_toml_and_unknown_sections_are_form_errors(): with pytest.raises(AnnotationError, match="kein gültiges TOML"): parse_annotations("[[annotation]\n") with pytest.raises(AnnotationError, match="unbekannter Abschnitt 'label'"): parse_annotations('[[label]]\nname = "X"\n')