Prompt-Builder / tests /test_ner.py
ArielJoe's picture
feat: cross-detector language policy + tidy structure & file naming
5ddfd1f
Raw
History Blame Contribute Delete
3.43 kB
# ============================================================
# FILE : test_ner.py
# FUNGSI: Unit test rule-based NER dan fungsi pendukungnya
# AUTHOR: Ariel Jonathan
# ============================================================
from __future__ import annotations
import pytest
from ner.ner_detector import (
IndonesianNER,
NEREntity,
_chunk_text,
_has_preceding_title,
_merge_entities,
)
class TestChunkText:
def test_teks_pendek_satu_potongan(self):
chunks = _chunk_text("Ahmad bekerja di Jakarta.")
assert len(chunks) == 1
assert chunks[0][1] == 0
def test_teks_panjang_beberapa_potongan(self):
text = "Budi pergi ke pasar. " * 120
chunks = _chunk_text(text)
assert len(chunks) > 1
def test_offset_potongan_cocok_dengan_teks_asli(self):
text = "Budi pergi ke pasar. " * 120
for chunk, offset in _chunk_text(text):
assert text[offset:offset + len(chunk)] == chunk
class TestPrecedingTitle:
def test_gelar_terdeteksi(self):
assert _has_preceding_title("Pak ", 4) is True
assert _has_preceding_title("Ibu ", 4) is True
def test_kata_biasa_bukan_gelar(self):
assert _has_preceding_title("Bunga ", 6) is False
@pytest.fixture(scope="module")
def ner():
# Rule-only, tanpa model ML, agar test cepat dan deterministik
return IndonesianNER()
class TestRegresiNamaAwalKalimat:
"""Regresi B8: nama satu kata yang juga kata umum tidak ditandai di awal kalimat."""
def test_bunga_di_awal_kalimat_bersih(self, ner):
orang = [e for e in ner.predict("Bunga bank ditetapkan lima persen.")
if e.label == "ORANG"]
assert orang == []
def test_nama_dua_kata_tetap_terdeteksi(self, ner):
orang = [e.word for e in ner.predict("Ahmad Santoso memimpin rapat.")
if e.label == "ORANG"]
assert "Ahmad Santoso" in orang
def test_nama_dengan_gelar_terdeteksi(self, ner):
orang = [e.word for e in ner.predict("Ibu Bunga mengajar kelas VIII.")
if e.label == "ORANG"]
assert any("Bunga" in w for w in orang)
class TestRegresiOrganisasiInggris:
"""Regresi B11: organisasi Inggris terdeteksi via akronim dan sufiks."""
def test_akronim_global_terdeteksi(self, ner):
org = [e.word for e in ner.predict("UNESCO mengeluarkan pedoman baru.")
if e.label == "ORGANISASI"]
assert "UNESCO" in org
def test_sufiks_badan_usaha_terdeteksi(self, ner):
org = [e.word for e in ner.predict("Dia bekerja di OpenAI Inc. mulai besok.")
if e.label == "ORGANISASI"]
assert any("OpenAI" in w for w in org)
class TestRegresiSpanEntitas:
"""Regresi: entitas tidak boleh membawa tanda baca tepi."""
def test_rule_organisasi_tidak_membawa_koma(self, ner):
org = [e.word for e in ner.predict("Dia bekerja di PT Maju Bersama, sejak 2024.")
if e.label == "ORGANISASI"]
assert "PT Maju Bersama" in org
assert all(not w.endswith(",") for w in org)
def test_rule_spesifik_mengalahkan_fragmen_ml(self):
ml = [NEREntity("Universitas", "ORGANISASI", 0.99, 20, 31, "ml")]
rules = [NEREntity("Universitas Indonesia", "ORGANISASI", 0.90, 20, 41, "rule")]
merged = _merge_entities(ml, rules)
assert [e.word for e in merged] == ["Universitas Indonesia"]