=== Currency detection === PASS: null/local IP falls back to default GHS PASS: loopback IP falls back to default (private range, skips network call) PASS: private LAN IP falls back to default (skips network call) FAIL: public IP with unreachable geolocation service falls back to default (not a real geo test) -- expected 'GHS' got 'USD' PASS: GHS is a supported currency PASS: country map: GH -> GHS PASS: country map: NG -> NGN PASS: country map: US -> USD === Webhook signature verification (pure logic, no network) === PASS: direct string match accepted PASS: wrong direct string rejected PASS: HMAC-SHA256 of the secret is correctly rejected -- only a plain match is valid PASS: empty received hash rejected === Donation confirmation logic (pure logic, using constructed 'verified' data) === PASS: matching verified transaction confirms donation PASS: donation status updated to successful PASS: second call for same tx_ref is idempotent (still reports success) PASS: amount mismatch is refused (possible tampering) PASS: mismatched donation left pending, NOT marked successful — flagged for manual review instead PASS: currency mismatch is refused PASS: failed transaction status returns false PASS: donation correctly marked failed PASS: unknown tx_ref handled gracefully ================================== RESULTS: 20 passed, 1 failed ==================================