File size: 4,146 Bytes
7535e76
 
 
 
 
 
 
 
2617189
7535e76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
"""Unit tests for the rule-based ABSA pipeline aspect extraction + fallbacks."""

from __future__ import annotations

import os

os.environ.setdefault("DATABASE_URL", "sqlite:///./tests/fixtures/test.db")

from absa.pipeline.absa_pipeline import pipeline


def _aspects(text: str) -> list[dict]:
    result = pipeline.predict(text, "en")
    return [a.model_dump() if hasattr(a, "model_dump") else dict(a) for a in result.aspects]


def _sentiment_of(aspects: list[dict], aspect: str) -> str | None:
    for a in aspects:
        if a["aspect"].lower() == aspect.lower():
            return a["sentiment"]
    return None


def test_food_and_service_extracted_from_sentiment_words():
    aspects = _aspects("The food was great but the service was terrible.")
    labels = [a["aspect"].lower() for a in aspects]
    assert "food" in labels
    assert "service" in labels
    assert _sentiment_of(aspects, "food") == "positive"
    assert _sentiment_of(aspects, "service") == "negative"


def test_noun_after_sentiment_word_extracted():
    aspects = _aspects("Great camera quality and a lovely experience overall.")
    labels = [a["aspect"].lower() for a in aspects]
    # "camera quality" is in the lexicon; "experience" must come from the fallback.
    assert any("camera" in label or "experience" in label for label in labels)


def test_product_target_fallback():
    aspects = _aspects("I absolutely love this product.")
    assert _sentiment_of(aspects, "product") == "positive"


def test_generic_overall_fallback_when_no_aspect_noun():
    aspects = _aspects("Absolutely terrible, do not recommend.")
    assert aspects, "should always return at least one aspect"
    assert _sentiment_of(aspects, "overall") == "negative"


def test_positive_bare_comment_returns_result():
    aspects = _aspects("Amazing!")
    assert aspects, "should always return at least one aspect"
    assert _sentiment_of(aspects, "overall") == "positive"


def test_neutral_text_returns_overall_neutral():
    aspects = _aspects("Hello there, just checking.")
    assert aspects
    assert _sentiment_of(aspects, "overall") == "neutral"


def test_devanagari_comment_gets_aspect_and_sentiment():
    aspects = _aspects("खाना बहुत अच्छा था।")
    assert aspects, "Devanagari comment should still produce a result"
    assert any(a["aspect"].lower() in ("खाना", "overall") for a in aspects)
    assert _sentiment_of(aspects, "खाना") == "positive"


def test_empty_text_never_crashes():
    aspects = _aspects("")
    assert aspects  # generic fallback keeps the response non-empty


def test_lexicon_still_used_first():
    aspects = _aspects("The battery life is amazing but the screen is too dim.")
    labels = [a["aspect"].lower() for a in aspects]
    assert "battery life" in labels or "battery" in labels
    assert _sentiment_of(aspects, "battery life") == "positive"
    assert _sentiment_of(aspects, "screen") == "negative"


def test_purchase_target_with_strong_negation():
    aspects = _aspects("Worst purchase ever, do not buy.")
    assert _sentiment_of(aspects, "purchase") == "negative"


def test_devanagari_mixed_clauses_split_on_lekin():
    aspects = _aspects("खाना बढ़िया था लेकिन सेवा खराब थी।")
    assert _sentiment_of(aspects, "खाना") == "positive"
    assert _sentiment_of(aspects, "सेवा") == "negative"


def test_hinglish_mixed_clauses_split_on_lekin():
    aspects = _aspects("The phone ka design badhiya hai lekin battery life kharab hai.")
    assert _sentiment_of(aspects, "design") == "positive"
    assert _sentiment_of(aspects, "battery life") == "negative"


def test_devanagari_word_never_split_inside():
    # Regression: "बढ़िया" used to be split by the "या" clause separator.
    aspects = _aspects("खाना बहुत बढ़िया था।")
    assert _sentiment_of(aspects, "खाना") == "positive"


def test_experience_positive():
    aspects = _aspects("Great experience overall, will order again.")
    assert _sentiment_of(aspects, "experience") == "positive"