QModel / tests /test_eval_parsing.py
aelgendy's picture
QModel v8.5: accuracy release (code, 3,598-fatwa index, quran.com links)
c634c96
Raw History Blame Contribute Delete
4.08 kB
"""Tests for the answer-eval citation parser (eval/run_answers.py)."""
import unittest
from eval.run_answers import cited_ids, is_refusal, lang_ok
class TestCitedIds(unittest.TestCase):
def test_quran_urls(self):
answer = ("[[1](https://surahquran.com/aya-255-sora-2.html)] ๏ดฟ...๏ดพ "
"[[1](https://quran.ksu.edu.sa/tafseer/qortobi/sura24-aya35.html)]")
self.assertEqual(cited_ids(answer, {}), {"2:255", "24:35"})
self.assertEqual(cited_ids("[[1](https://quran.com/2/278)]", {}), {"2:278"})
def test_english_hadith_refs(self):
answer = ("Recorded in Sahih al-Bukhari 6116. Also Sunan Abu Dawood No. 4800 "
"and Jami' at-Tirmidhi #2516, Sunan Ibn Majah, hadith 224.")
self.assertEqual(cited_ids(answer, {}),
{"bukhari_6116", "abudawud_4800", "tirmidhi_2516", "ibnmajah_224"})
def test_arabic_hadith_refs(self):
answer = "ุฑูˆุงู‡ ุตุญูŠุญ ุงู„ุจุฎุงุฑูŠุŒ ุฑู‚ู… 13. ูˆููŠ ุตุญูŠุญ ู…ุณู„ู…ุŒ ุฑู‚ู… 45. ูˆููŠ ู…ูˆุทุฃ ู…ุงู„ูƒุŒ ุฑู‚ู… 1."
self.assertEqual(cited_ids(answer, {}), {"bukhari_13", "muslim_45", "malik_1"})
answer = ("ุงู„ุชุฑู…ุฐูŠุŒ ุฑู‚ู… ุงู„ุญุฏูŠุซ 2024. ูˆุตุญูŠุญ ู…ุณู„ู… ุจุฑู‚ู… 440. ูˆุณู†ู† ุงุจู† ู…ุงุฌู‡ุŒ ุงู„ุฑู‚ู… 4303. "
"ูˆุงู„ุจุฎุงุฑูŠุŒ ูƒุชุงุจ ุงู„ุฅูŠู…ุงู†ุŒ ุญุฏูŠุซ ุฑู‚ู… 1. ูˆุฑูˆุงู‡ ู…ุณู„ู… ููŠ ุตุญูŠุญู‡ (6382).")
self.assertEqual(cited_ids(answer, {}),
{"tirmidhi_2024", "muslim_440", "ibnmajah_4303", "bukhari_1", "muslim_6382"})
def test_hadith_ref_needs_adjacent_number(self):
# The number belongs to the collection right before it, not one earlier in the sentence
self.assertEqual(cited_ids("Sahih al-Bukhari and Sahih Muslim 1907", {}), {"muslim_1907"})
# "ู…ุณู„ู…" as an ordinary word ("every Muslim") is not a citation
self.assertEqual(cited_ids("ุทู„ุจ ุงู„ุนู„ู… ูุฑูŠุถุฉ ุนู„ู‰ ูƒู„ ู…ุณู„ู… 3 ู…ุฑุงุช", {}), set())
def test_fatwa_urls(self):
url_to_id = {"https://www.islamweb.net/ar/fatwa/857": "islamweb_857"}
answer = "ู…ุฑูƒุฒ ุงู„ูุชูˆู‰ [[1](https://www.islamweb.net/ar/fatwa/857/)]."
self.assertEqual(cited_ids(answer, url_to_id), {"islamweb_857"})
class TestAnswerChecks(unittest.TestCase):
def test_refusal_and_language(self):
not_found = {"arabic": "ู„ู… ุฃุฌุฏ", "english": "not found"}
self.assertTrue(is_refusal("The dataset does not contain sufficient information.", "en", not_found))
self.assertFalse(is_refusal("Yes, it is obligatory. And Allah knows best.", "en", not_found))
self.assertTrue(lang_ok("ู†ุนู…ุŒ ู‡ุฐุง ูˆุงุฌุจ. ูˆุงู„ู„ู‡ ุฃุนู„ู….", "ar"))
self.assertFalse(lang_ok("Yes, it is obligatory.", "ar"))
if __name__ == "__main__":
unittest.main()
class TestRequiredLabels(unittest.TestCase):
def test_hit_without_required_source_is_incomplete(self):
from eval.run_eval import score_case
case = {"id": "x", "category": "quran_topic", "query": "Is alcohol forbidden?",
"relevant": ["5:90", "2:219"], "required": ["5:90"]}
out = {"results": [{"id": "29:49"}, {"id": "2:219"}], "intent": "general", "top_score": 1.0,
"gated": False, "confidence": 0.9, "confidence_source": "reranker"}
row = score_case(case, out, 8, {})
self.assertEqual(row["hit@k"], 1) # still a hit, as before
self.assertEqual(row["complete@k"], 0) # but the decisive verse is missing
self.assertEqual(row["missing_required"], ["5:90"])
def test_required_must_be_subset_of_relevant(self):
import tempfile
from pathlib import Path
from eval.run_eval import load_golden
with tempfile.NamedTemporaryFile("w", suffix=".jsonl", delete=False, encoding="utf-8") as f:
f.write('{"id": "x", "category": "c", "query": "q", "relevant": ["2:219"], "required": ["5:90"]}\n')
with self.assertRaises(ValueError):
load_golden(Path(f.name), None)