#!/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 licence in tests/testdata/licenses/.

For each licence the loop is

    SPDX id  --replace_spdx-->  DEP-5 name  --dep5_to_spdx-->  SPDX id'

and ``spdx-name-roundtrip.tsv`` locks ``(DEP-5 name, SPDX id')`` for all 729
ids. This proves both conversion directions are covered and agree: a licence
with no row fails, a row with no licence fails, and any changed conversion
fails. A ``wrong:`` row still asserts its *recorded* values, so a known
asymmetry stays locked (and visible) until fixed rather than silently drifting.

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

import unittest
from pathlib import Path

from decopy.licensing import spdx

LICENSES_DIR = Path("tests/testdata/licenses")
ROUNDTRIP_TSV = Path("tests/testdata/spdx-name-roundtrip.tsv")
_DEP5_COL, _BACK_COL, _STATUS_COL = 1, 2, 3


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")
        table[cols[0]] = (cols[_DEP5_COL], cols[_BACK_COL])
    return table


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

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

    def test_every_licence_roundtrips(self):
        for path in self.files:
            spdx_id = path.stem
            with self.subTest(licence=spdx_id):
                self.assertIn(
                    spdx_id,
                    self.table,
                    msg="missing from spdx-name-roundtrip.tsv; "
                    "run scripts/audit-spdx-roundtrip.py",
                )
                dep5_name, back = self.table[spdx_id]
                self.assertEqual(spdx.replace_spdx(spdx_id), dep5_name)
                self.assertEqual(spdx.dep5_to_spdx(dep5_name), 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 licence file")

    def test_no_unreviewed_wrong_rows(self):
        """Every licence round-trips: no bare 'wrong' status remains.

        A genuinely non-invertible row would carry an explicit
        'wrong:<reason>' annotation; a bare 'wrong' is an unfixed --spdx
        conversion asymmetry (a new SPDX data drop or a regression).
        """
        bare_wrong = []
        for line in ROUNDTRIP_TSV.read_text().splitlines():
            if line.startswith("#") or not line.strip():
                continue
            cols = line.split("\t")
            if len(cols) > _STATUS_COL and cols[_STATUS_COL] == "wrong":
                bare_wrong.append(cols[0])
        self.assertEqual(bare_wrong, [], msg="unfixed --spdx asymmetries")


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