Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,27 @@ def _body_detail(s: int) -> str:


def _derive_grade(score: float) -> str:
# 1. Type validation checking: Reject anything that isn't an integer or float
if not isinstance(score, (int, float)) or isinstance(score, bool):
raise ValueError(
f"Invalid input type: {type(score)}. Score must be a numeric float/int."
)

# 2. Scale boundaries validation: Must reside strictly between 0.0 and 100.0 inclusive
if score < 0 or score > 100:
raise ValueError(f"Score {score} is out of valid scale range (0.0 - 100.0).")

# 3. Proceed safely with the evaluation hierarchy
if score >= 92:
return "A+"
if score >= 80:
elif score >= 80:
return "A"
if score >= 65:
elif score >= 65:
return "B"
if score >= 50:
elif score >= 50:
return "C"
return "D"
else:
return "D"


def _to_db_grade(grade: str) -> str:
Expand Down
92 changes: 92 additions & 0 deletions backend/tests/test_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@
# Ensure the backend directory is on the path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# ---------------------------------------------------------------------------
# INTERCEPT MOCKS (Must run BEFORE importing any app modules)
# ---------------------------------------------------------------------------
from unittest.mock import MagicMock

# Inject dummy modules into sys.modules to stop Python from loading heavy/broken packages
mock_supabase = MagicMock()
sys.modules['supabase'] = mock_supabase

mock_inference = MagicMock()
mock_inference.load_models = MagicMock()
mock_inference.predict_stream_a = MagicMock()
mock_inference.predict_stream_b = MagicMock()
sys.modules['inference'] = mock_inference

import numpy as np


Expand Down Expand Up @@ -100,3 +115,80 @@ def test_dev_bypass_constants_are_readable():
assert hasattr(auth, "DEV_BYPASS_TOKEN")
assert isinstance(auth.DEV_BYPASS_AUTH, bool)
assert isinstance(auth.DEV_BYPASS_TOKEN, str)


# ---------------------------------------------------------------------------
# main.py — Grade Derivation Logic & Validation Checks
# ---------------------------------------------------------------------------




# Now we can safely import from main without needing the actual package installed!
import pytest
from main import _derive_grade

# 1. Test Boundary Values and Valid Grade Ranges
@pytest.mark.parametrize("score, expected_grade", [
(100, "A+"),
(92, "A+"), # Exact boundary for A+
(91.9, "A"), # Just below A+ boundary
(80, "A"), # Exact boundary for A
(79.9, "B"), # Just below A boundary
(65, "B"), # Exact boundary for B
(64.9, "C"), # Just below B boundary
(50, "C"), # Exact boundary for C
(49.9, "D"), # Just below C boundary
(0, "D"), # Minimum standard boundary
])
def test_derive_grade_boundaries(score, expected_grade):
assert _derive_grade(score) == expected_grade


# 2. Test Out-of-Scale Inputs (Expected to raise ValueError)
@pytest.mark.parametrize("invalid_score", [
(-1), # Negative scale boundary
(-50.5), # Extreme negative
(101), # Just over maximum scale
(200.0), # Extreme over-scale
])
def test_derive_grade_out_of_scale(invalid_score):
with pytest.raises(ValueError):
_derive_grade(invalid_score)


# 3. Test Incorrect Data Types (Expected to raise ValueError)
@pytest.mark.parametrize("bad_type", [
("95"), # String containing numbers
("fresh_fish"), # Regular text string
(None), # None Type
([],), # List/Iterable object
])
def test_derive_grade_invalid_types(bad_type):
with pytest.raises(ValueError):
_derive_grade(bad_type)



# ---------------------------------------------------------------------------
# main.py — Grade Derivation Logic & Validation Checks
# ---------------------------------------------------------------------------


from unittest.mock import MagicMock

# 1. Trick Python into thinking 'supabase' is already loaded
mock_supabase = MagicMock()
sys.modules['supabase'] = mock_supabase

# 2. Trick Python into bypassing 'inference' entirely to avoid the broken PyTorch DLLs
mock_inference = MagicMock()
# Provide dummy mock functions so main.py can unpack them during import
mock_inference.load_models = MagicMock()
mock_inference.predict_stream_a = MagicMock()
mock_inference.predict_stream_b = MagicMock()
sys.modules['inference'] = mock_inference

# Now we can safely import from main in total isolation!
import pytest

Loading