from __future__ import annotations from unittest.mock import AsyncMock, MagicMock, patch import pytest from yuxi.channels.adapters.nostr.zap import NostrZapManager class TestNostrZapManager: @pytest.fixture def crypto(self): crypto = MagicMock() crypto.build_and_sign_event.return_value = { "id": "zap_event_id", "kind": 9734, "content": "", "tags": [["p", "receiver_hex"], ["amount", "1000"]], } return crypto @pytest.fixture def relay_manager(self): rm = MagicMock() rm.broadcast = AsyncMock(return_value=3) return rm @pytest.fixture def zap_manager(self, crypto, relay_manager): return NostrZapManager(crypto, relay_manager) def test_parse_zap_receipt_valid(self, zap_manager): raw_event = { "id": "zap_receipt_001", "kind": 9735, "pubkey": "sender_pubkey_hex", "tags": [ ["bolt11", "lnbc1invoice"], ["amount", "5000000"], ["p", "receiver_pubkey_hex"], ["e", "event_id_001"], ], } result = zap_manager.parse_zap_receipt(raw_event) assert result is not None assert result["event_id"] == "zap_receipt_001" assert result["sender_pubkey"] == "sender_pubkey_hex" assert result["amount_msat"] == 5000000 assert result["amount_sats"] == 5000 assert result["bolt11"] == "lnbc1invoice" assert result["zapped_pubkey"] == "receiver_pubkey_hex" assert result["zapped_event_id"] == "event_id_001" def test_parse_zap_receipt_wrong_kind(self, zap_manager): raw_event = { "id": "not_a_zap", "kind": 1, "pubkey": "sender_hex", "tags": [], } result = zap_manager.parse_zap_receipt(raw_event) assert result is None def test_parse_zap_receipt_minimal(self, zap_manager): raw_event = { "id": "minimal_zap", "kind": 9735, "pubkey": "sender_hex", "tags": [], } result = zap_manager.parse_zap_receipt(raw_event) assert result is not None assert result["amount_msat"] == 0 assert result["amount_sats"] == 0 assert result["bolt11"] == "" def test_parse_zap_receipt_invalid_amount(self, zap_manager): raw_event = { "id": "bad_amount_zap", "kind": 9735, "pubkey": "sender_hex", "tags": [ ["amount", "not_a_number"], ], } result = zap_manager.parse_zap_receipt(raw_event) assert result is not None assert result["amount_msat"] == 0 def test_parse_zap_receipt_missing_tags(self, zap_manager): raw_event = { "id": "no_tags_zap", "kind": 9735, "pubkey": "sender_hex", } result = zap_manager.parse_zap_receipt(raw_event) assert result is not None assert result["amount_msat"] == 0 def test_parse_zap_receipt_empty_tags_list(self, zap_manager): raw_event = { "id": "zap_empty", "kind": 9735, "pubkey": "sender_hex", "tags": [[]], } result = zap_manager.parse_zap_receipt(raw_event) assert result is not None def test_build_zap_request_basic(self, zap_manager): event = zap_manager.build_zap_request("receiver_hex") assert event is not None assert event["kind"] == 9734 assert event["content"] == "" def test_build_zap_request_with_event_id(self, zap_manager): event = zap_manager.build_zap_request("receiver_hex", event_id="evt_001") assert event is not None def test_build_zap_request_with_amount(self, zap_manager): event = zap_manager.build_zap_request("receiver_hex", amount_msat=21000) assert event is not None def test_build_zap_request_full(self, zap_manager): event = zap_manager.build_zap_request("receiver_hex", "evt_001", 42000) assert event["kind"] == 9734 @pytest.mark.asyncio async def test_broadcast_zap_request_success(self, zap_manager): count = await zap_manager.broadcast_zap_request("receiver_hex", "evt_001", 1000) assert count == 3 @pytest.mark.asyncio async def test_broadcast_zap_request_zero_relays(self, zap_manager): zap_manager._relay_manager.broadcast = AsyncMock(return_value=0) count = await zap_manager.broadcast_zap_request("receiver_hex") assert count == 0