#!/usr/bin/env python3
# Copyright: 2026, Maximiliano Curia <maxy@debian.org>
#
# License: ISC
#  Permission to use, copy, modify, and/or distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#  .
#  THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
#  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
#  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
#  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
#  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
#  PERFORMANCE OF THIS SOFTWARE.

"""Full-loop coverage over every SPDX exception in tests/testdata/exceptions/.

For each exception the loop is

    SPDX id  --exception_to_dep5-->  DEP-5 label  --exception_to_spdx-->  id'

and ``spdx-exception-roundtrip.tsv`` locks ``(label, id')`` for all 84 ids. An
exception with no row fails and a row with no exception fails, so a refreshed
SPDX exception set cannot slip coverage. Many-to-one collapses (the -generic /
-note / -short / dated variants share one label) and the single ``unmapped``
gap are recorded in the table rather than failing.

Regenerate with ``scripts/audit-spdx-roundtrip.py --exceptions``.
"""

import unittest
from pathlib import Path

from decopy.licensing import spdx

EXCEPTIONS_DIR = Path("tests/testdata/exceptions")
ROUNDTRIP_TSV = Path("tests/testdata/spdx-exception-roundtrip.tsv")
_LABEL_COL, _BACK_COL = 1, 2


def _load_table() -> dict[str, tuple[str, str]]:
    table: dict[str, tuple[str, str]] = {}
    for line in ROUNDTRIP_TSV.read_text().splitlines():
        if line.startswith("#") or not line.strip():
            continue
        cols = line.split("\t")
        label = cols[_LABEL_COL] if len(cols) > _LABEL_COL else ""
        back = cols[_BACK_COL] if len(cols) > _BACK_COL else ""
        table[cols[0]] = (label, back)
    return table


class TestSpdxExceptionRoundtrip(unittest.TestCase):
    table: dict[str, tuple[str, str]]
    files: list[Path]

    @classmethod
    def setUpClass(cls):
        cls.table = _load_table()
        cls.files = sorted(EXCEPTIONS_DIR.glob("*.json"))

    def test_every_exception_roundtrips(self):
        for path in self.files:
            spdx_id = path.stem
            with self.subTest(exception=spdx_id):
                self.assertIn(
                    spdx_id,
                    self.table,
                    msg="missing from spdx-exception-roundtrip.tsv; "
                    "run scripts/audit-spdx-roundtrip.py --exceptions",
                )
                label, back = self.table[spdx_id]
                # An empty label is the recorded "unmapped" gap.
                self.assertEqual(spdx.exception_to_dep5(spdx_id) or "", label)
                if label:
                    self.assertEqual(spdx.exception_to_spdx(label), back)

    def test_no_stale_table_rows(self):
        present = {path.stem for path in self.files}
        stale = sorted(set(self.table) - present)
        self.assertEqual(stale, [], msg="rows with no exception file")


if __name__ == "__main__":
    unittest.main()
