Compare commits
2 Commits
fix/59
...
burn/123-1
| Author | SHA1 | Date | |
|---|---|---|---|
| b9f66410ef | |||
| 69dc695e73 |
@@ -105,12 +105,6 @@ MEDIUM_INDICATORS = [
|
||||
r"\bno\s+tomorrow\b",
|
||||
# Contextual versions (from crisis_detector.py legacy)
|
||||
r"\bfeel(?:s|ing)?\s+(?:so\s+)?worthless\b",
|
||||
r"\bfeel(?:s|ing)?\s+(?:so\s+)?hopeless\b",
|
||||
r"\bfeel(?:s|ing)?\s+trapped\b",
|
||||
r"\bfeel(?:s|ing)?\s+desperate\b",
|
||||
r"\bno\s+future\s+(?:for\s+me|ahead|left)\b",
|
||||
r"\bnothing\s+left\s+(?:to\s+(?:live|hope)\s+for|inside)\b",
|
||||
r"\bgive(?:n)?\s*up\s+on\s+myself\b",
|
||||
]
|
||||
|
||||
LOW_INDICATORS = [
|
||||
|
||||
@@ -680,7 +680,7 @@ html, body {
|
||||
|
||||
<!-- Footer -->
|
||||
<footer id="footer">
|
||||
<a href="/about.html" aria-label="About The Door">about</a>
|
||||
<a href="/about" aria-label="About The Door">about</a>
|
||||
<button id="safety-plan-btn" aria-label="Open My Safety Plan">my safety plan</button>
|
||||
<button id="clear-chat-btn" aria-label="Clear chat history">clear chat</button>
|
||||
</footer>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import pathlib
|
||||
import unittest
|
||||
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
INDEX_HTML = ROOT / 'index.html'
|
||||
ABOUT_HTML = ROOT / 'about.html'
|
||||
|
||||
|
||||
class TestAboutLink(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.html = INDEX_HTML.read_text(encoding='utf-8')
|
||||
|
||||
def test_about_page_exists(self):
|
||||
self.assertTrue(ABOUT_HTML.exists(), 'about.html should exist for static serving')
|
||||
|
||||
def test_footer_about_link_targets_static_about_html(self):
|
||||
self.assertIn('href="/about.html"', self.html)
|
||||
self.assertNotIn('href="/about"', self.html)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
104
tests/test_crisis_indicator_dedup.py
Normal file
104
tests/test_crisis_indicator_dedup.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import re
|
||||
import unittest
|
||||
|
||||
from crisis.detect import (
|
||||
CRITICAL_INDICATORS,
|
||||
HIGH_INDICATORS,
|
||||
MEDIUM_INDICATORS,
|
||||
LOW_INDICATORS,
|
||||
detect_crisis,
|
||||
scan,
|
||||
)
|
||||
|
||||
|
||||
class TestNoDuplicatePatternsAcrossTiers(unittest.TestCase):
|
||||
"""Verify no regex pattern appears in more than one tier (issue #123)."""
|
||||
|
||||
def test_high_and_medium_no_overlap(self):
|
||||
"""Patterns in HIGH_INDICATORS must not appear in MEDIUM_INDICATORS."""
|
||||
high_set = set(HIGH_INDICATORS)
|
||||
medium_set = set(MEDIUM_INDICATORS)
|
||||
overlap = high_set & medium_set
|
||||
self.assertEqual(
|
||||
overlap, set(),
|
||||
f"Found {len(overlap)} duplicate patterns between HIGH and MEDIUM: {overlap}",
|
||||
)
|
||||
|
||||
def test_critical_and_high_no_overlap(self):
|
||||
"""CRITICAL and HIGH should not share patterns."""
|
||||
overlap = set(CRITICAL_INDICATORS) & set(HIGH_INDICATORS)
|
||||
self.assertEqual(
|
||||
overlap, set(),
|
||||
f"Found {len(overlap)} duplicates between CRITICAL and HIGH: {overlap}",
|
||||
)
|
||||
|
||||
def test_medium_and_low_no_overlap(self):
|
||||
"""MEDIUM and LOW should not share patterns."""
|
||||
overlap = set(MEDIUM_INDICATORS) & set(LOW_INDICATORS)
|
||||
self.assertEqual(
|
||||
overlap, set(),
|
||||
f"Found {len(overlap)} duplicates between MEDIUM and LOW: {overlap}",
|
||||
)
|
||||
|
||||
def test_no_pattern_in_three_tiers(self):
|
||||
"""No pattern should appear in more than one tier."""
|
||||
all_tiers = {
|
||||
"CRITICAL": set(CRITICAL_INDICATORS),
|
||||
"HIGH": set(HIGH_INDICATORS),
|
||||
"MEDIUM": set(MEDIUM_INDICATORS),
|
||||
"LOW": set(LOW_INDICATORS),
|
||||
}
|
||||
violations = []
|
||||
tier_names = list(all_tiers.keys())
|
||||
for i, t1 in enumerate(tier_names):
|
||||
for t2 in tier_names[i + 1:]:
|
||||
overlap = all_tiers[t1] & all_tiers[t2]
|
||||
for p in overlap:
|
||||
violations.append(f"{t1} & {t2}: {p}")
|
||||
self.assertEqual(
|
||||
violations, [],
|
||||
f"Found {len(violations)} cross-tier duplicates:\n" + "\n".join(violations[:10]),
|
||||
)
|
||||
|
||||
|
||||
class TestRemovedPatternsStillDetected(unittest.TestCase):
|
||||
"""Patterns removed from MEDIUM should still be caught by HIGH tier."""
|
||||
|
||||
def test_feel_hopeless_detected(self):
|
||||
result = detect_crisis("I feel so hopeless about everything")
|
||||
self.assertIn(result.level, ("HIGH", "CRITICAL"))
|
||||
|
||||
def test_feel_trapped_detected(self):
|
||||
result = detect_crisis("I feel trapped and can\'t escape")
|
||||
self.assertIn(result.level, ("HIGH", "CRITICAL"))
|
||||
|
||||
def test_feel_desperate_detected(self):
|
||||
result = detect_crisis("I feel desperate for help")
|
||||
self.assertIn(result.level, ("HIGH", "CRITICAL"))
|
||||
|
||||
def test_no_future_detected(self):
|
||||
result = detect_crisis("There is no future ahead for me")
|
||||
self.assertIn(result.level, ("HIGH", "CRITICAL"))
|
||||
|
||||
def test_nothing_left_detected(self):
|
||||
result = detect_crisis("There is nothing left inside")
|
||||
self.assertIn(result.level, ("HIGH", "CRITICAL"))
|
||||
|
||||
def test_give_up_on_myself_detected(self):
|
||||
result = detect_crisis("I have given up on myself")
|
||||
self.assertIn(result.level, ("HIGH", "CRITICAL"))
|
||||
|
||||
|
||||
class TestWorthlessPatternRemainsInMedium(unittest.TestCase):
|
||||
"""The 'feel worthless' pattern should remain in MEDIUM (not a duplicate)."""
|
||||
|
||||
def test_feel_worthless_in_medium(self):
|
||||
self.assertIn(r"\bfeel(?:s|ing)?\s+(?:so\s+)?worthless\b", MEDIUM_INDICATORS)
|
||||
|
||||
def test_feel_worthless_detected(self):
|
||||
result = detect_crisis("I feel so worthless")
|
||||
self.assertIn(result.level, ("MEDIUM", "LOW", "HIGH"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user