"""Comprehensive tests for the Porter stemmer (src/rbsp/core/stemmer.py)."""

import os
import sys
import unittest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
from rbsp.core.stemmer import stem, stem_tokens


class TestStep1a(unittest.TestCase):
    """Step 1a: plurals."""

    def test_sses(self):
        self.assertEqual(stem("caresses"), "caress")

    def test_ies(self):
        self.assertEqual(stem("ponies"), "poni")
        self.assertEqual(stem("ties"), "ti")

    def test_s(self):
        self.assertEqual(stem("cats"), "cat")

    def test_ss_unchanged(self):
        self.assertEqual(stem("sess"), "sess")


class TestStep1b(unittest.TestCase):
    """Step 1b: -eed, -ed, -ing."""

    def test_eed_no_change(self):
        self.assertEqual(stem("feed"), "feed")

    def test_ed_with_vowel(self):
        self.assertEqual(stem("agreed"), "agre")
        self.assertEqual(stem("plastered"), "plaster")

    def test_ed_no_vowel(self):
        self.assertEqual(stem("bled"), "bled")

    def test_ing_with_vowel(self):
        self.assertEqual(stem("motoring"), "motor")

    def test_ing_no_vowel(self):
        self.assertEqual(stem("sing"), "sing")


class TestStep1c(unittest.TestCase):
    """Step 1c: y -> i when stem has a vowel."""

    def test_y_to_i(self):
        self.assertEqual(stem("happy"), "happi")

    def test_y_no_vowel(self):
        self.assertEqual(stem("sky"), "sky")


class TestStep2(unittest.TestCase):
    """Step 2: suffix mappings."""

    def test_ational(self):
        self.assertEqual(stem("relational"), "relat")

    def test_tional(self):
        self.assertEqual(stem("conditional"), "condit")
        # "rational" base "ra" has m>0, so tional->tion applies -> "ration"
        self.assertEqual(stem("rational"), "ration")

    def test_enci(self):
        self.assertEqual(stem("valenci"), "valenc")

    def test_anci(self):
        self.assertEqual(stem("hesitanci"), "hesit")

    def test_izer(self):
        self.assertEqual(stem("digitizer"), "digit")

    def test_abli(self):
        self.assertEqual(stem("conformabli"), "conform")

    def test_alli(self):
        self.assertEqual(stem("radicalli"), "radic")

    def test_entli(self):
        self.assertEqual(stem("differentli"), "differ")

    def test_eli(self):
        self.assertEqual(stem("vileli"), "vile")

    def test_ousli(self):
        self.assertEqual(stem("analogousli"), "analog")

    def test_ization(self):
        self.assertEqual(stem("vietnamization"), "vietnam")

    def test_ation(self):
        self.assertEqual(stem("predication"), "predic")

    def test_ator(self):
        self.assertEqual(stem("operator"), "oper")

    def test_alism(self):
        self.assertEqual(stem("feudalism"), "feudal")

    def test_iveness(self):
        self.assertEqual(stem("decisiveness"), "decis")

    def test_fulness(self):
        self.assertEqual(stem("hopefulness"), "hope")

    def test_ousness(self):
        self.assertEqual(stem("callousness"), "callous")

    def test_aliti(self):
        self.assertEqual(stem("formaliti"), "formal")

    def test_iviti(self):
        self.assertEqual(stem("sensitiviti"), "sensit")

    def test_biliti(self):
        self.assertEqual(stem("sensibiliti"), "sensibl")


class TestStep3(unittest.TestCase):
    """Step 3: suffix removal/replacement."""

    def test_icate(self):
        self.assertEqual(stem("triplicate"), "triplic")

    def test_ative(self):
        self.assertEqual(stem("formative"), "form")

    def test_alize(self):
        self.assertEqual(stem("formalize"), "formal")

    def test_iciti(self):
        self.assertEqual(stem("electriciti"), "electr")

    def test_ical(self):
        self.assertEqual(stem("electrical"), "electr")

    def test_ful(self):
        self.assertEqual(stem("hopeful"), "hope")

    def test_ness(self):
        self.assertEqual(stem("goodness"), "good")


class TestStep4(unittest.TestCase):
    """Step 4: remove suffixes when m > 1."""

    def test_al(self):
        self.assertEqual(stem("revival"), "reviv")

    def test_ance(self):
        self.assertEqual(stem("allowance"), "allow")

    def test_ence(self):
        self.assertEqual(stem("inference"), "infer")

    def test_er(self):
        self.assertEqual(stem("airliner"), "airlin")

    def test_ic(self):
        self.assertEqual(stem("gyroscopic"), "gyroscop")

    def test_able(self):
        self.assertEqual(stem("adjustable"), "adjust")

    def test_ible(self):
        self.assertEqual(stem("defensible"), "defens")

    def test_ant(self):
        self.assertEqual(stem("irritant"), "irrit")

    def test_ement(self):
        self.assertEqual(stem("replacement"), "replac")

    def test_ment(self):
        self.assertEqual(stem("adjustment"), "adjust")

    def test_ent(self):
        self.assertEqual(stem("dependent"), "depend")

    def test_ion(self):
        self.assertEqual(stem("adoption"), "adopt")

    def test_ou(self):
        self.assertEqual(stem("homologou"), "homolog")

    def test_ism(self):
        self.assertEqual(stem("communism"), "commun")

    def test_ate(self):
        self.assertEqual(stem("activate"), "activ")

    def test_iti(self):
        self.assertEqual(stem("angulariti"), "angular")

    def test_ous(self):
        self.assertEqual(stem("homologous"), "homolog")

    def test_ive(self):
        self.assertEqual(stem("effective"), "effect")

    def test_ize(self):
        self.assertEqual(stem("bowdlerize"), "bowdler")


class TestStep5(unittest.TestCase):
    """Step 5a and 5b: final cleanup."""

    def test_remove_e(self):
        self.assertEqual(stem("probate"), "probat")

    def test_keep_e(self):
        self.assertEqual(stem("rate"), "rate")

    def test_remove_e_high_measure(self):
        self.assertEqual(stem("cease"), "ceas")

    def test_double_l(self):
        self.assertEqual(stem("controll"), "control")

    def test_keep_ll(self):
        self.assertEqual(stem("roll"), "roll")


class TestShortWords(unittest.TestCase):
    """Words with 2 or fewer characters are returned unchanged."""

    def test_single_char(self):
        self.assertEqual(stem("a"), "a")

    def test_two_char_be(self):
        self.assertEqual(stem("be"), "be")

    def test_two_char_go(self):
        self.assertEqual(stem("go"), "go")


class TestStemTokens(unittest.TestCase):
    """Tests for stem_tokens batch function."""

    def test_basic_list(self):
        result = stem_tokens(["running", "cats"])
        self.assertEqual(result, [stem("running"), stem("cats")])

    def test_empty_list(self):
        self.assertEqual(stem_tokens([]), [])

    def test_preserves_order(self):
        tokens = ["dogs", "running", "happy"]
        result = stem_tokens(tokens)
        self.assertEqual(len(result), 3)
        self.assertEqual(result, [stem(t) for t in tokens])

    def test_single_token(self):
        self.assertEqual(stem_tokens(["caresses"]), ["caress"])


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