"""
Lesson 25 — Exercise 2: Test Data Strategies
=============================================
Goal: Practice the three test-data strategies the HSC expects you to know.

  - BOUNDARY VALUE  → test the EDGES of valid input (and one step either side)
  - PATH COVERAGE   → write tests so EVERY branch in the code runs at least once
  - FAULTY/ABNORMAL → throw bad data at the function and see what breaks

Each task gives you a function. You write the tests.
"""


# ═══════════════════════════════════════════════════════════════
# TASK A — BOUNDARY VALUE TESTING
# ═══════════════════════════════════════════════════════════════
# This function accepts a percentage (0 to 100 INCLUSIVE).
# Identify the boundary inputs and test each one.

def validate_percentage(value):
    """Returns True if 0 ≤ value ≤ 100, otherwise False."""
    return 0 <= value <= 100


def test_boundary_values():
    # TODO: fill in (input, expected_output) for each boundary case.
    # Think: just below the low end, exactly at it, just inside, mid-range,
    #        just inside the high end, exactly at it, just above.
    # That's 7 cases.
    test_cases = [
        # (-1, False),
        # (0, True),
        # ... add the other 5
    ]
    for value, expected in test_cases:
        result = validate_percentage(value)
        status = '✅' if result == expected else '❌'
        print(f"  {status} validate_percentage({value}) = {result}  (expected {expected})")


# ═══════════════════════════════════════════════════════════════
# TASK B — PATH COVERAGE TESTING
# ═══════════════════════════════════════════════════════════════
# This function has 4 branches. Write ONE test per branch.

def classify_score(score):
    if score >= 90:
        return "Outstanding"
    elif score >= 75:
        return "Merit"
    elif score >= 50:
        return "Pass"
    else:
        return "Fail"


def test_path_coverage():
    # TODO: pick an input that lands in each branch (4 tests total).
    test_cases = [
        # (95, "Outstanding"),
        # ... add three more
    ]
    for score, expected in test_cases:
        result = classify_score(score)
        status = '✅' if result == expected else '❌'
        print(f"  {status} classify_score({score}) = {result!r}  (expected {expected!r})")


# ═══════════════════════════════════════════════════════════════
# TASK C — FAULTY / ABNORMAL DATA TESTING
# ═══════════════════════════════════════════════════════════════
# This discount function works fine on valid input.
# Your job: throw FAULTY data at it. What crashes? What silently
# returns nonsense? What handles gracefully?

def apply_discount(price, discount_percent):
    """e.g. apply_discount(100, 10) → 90.0"""
    return price * (1 - discount_percent / 100)


def test_faulty_data():
    # TODO: try at least 5 abnormal inputs.
    # Examples to include: negative price, string instead of number,
    # None, a discount above 100, a huge number.
    # For each, PREDICT what should happen, then run it.
    abnormal_inputs = [
        # (price, discount_percent, what_you_expect),
        # (-50, 10, "should probably reject negative price"),
        # ...
    ]
    for price, discount, expectation in abnormal_inputs:
        try:
            result = apply_discount(price, discount)
            print(f"  ⚠️  apply_discount({price!r}, {discount!r}) → {result}  |  {expectation}")
        except Exception as e:
            print(f"  💥 apply_discount({price!r}, {discount!r}) raised {type(e).__name__}  |  {expectation}")


# ═══════════════════════════════════════════════════════════════
# DISCUSSION (write your answers in comments)
# ═══════════════════════════════════════════════════════════════
# 1. Which strategy would catch a bug where validate_percentage used `<` instead of `<=`?
# 2. Which strategy would catch a missing `else` branch in classify_score?
# 3. Which strategy is the easiest one to forget when you're writing your own code?


if __name__ == '__main__':
    print("─── BOUNDARY VALUES ───")
    test_boundary_values()
    print()
    print("─── PATH COVERAGE ───")
    test_path_coverage()
    print()
    print("─── FAULTY DATA ───")
    test_faulty_data()
