mirror of
https://github.com/vibe-existing/pyfragment.git
synced 2026-07-25 06:54:31 +00:00
refactor: restructure as installable PyPI package
- Rename app/ → fragmentapi/ for proper package naming - Add FragmentClient class with gift_premium, gift_stars, topup_ton methods - Restructure core/ → types/ (exceptions, results, constants) - Merge utils/hash.py into utils/client.py - Replace _version.py with importlib.metadata - Add input validation with min/max bounds - Add unit tests: decode, client init/cookies - Rename 002_test_hash → 003_test_hash - Clean up pyproject.toml: pin deps, production classifiers
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
"""Tests for clean_decode() — BOC-encoded Fragment payloads decode to
|
||||
human-readable UTF-8 with the Telegram label and Ref# intact."""
|
||||
"""Tests for clean_decode() — BOC-encoded Fragment payloads decode to UTF-8."""
|
||||
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from app.utils.decoder import clean_decode
|
||||
from fragmentapi.types import RequestError
|
||||
from fragmentapi.utils.decoder import clean_decode
|
||||
|
||||
PAYLOADS = [
|
||||
pytest.param(
|
||||
@@ -24,12 +24,17 @@ PAYLOADS = [
|
||||
|
||||
|
||||
@pytest.mark.parametrize("payload", PAYLOADS)
|
||||
def test_payload(payload: str) -> None:
|
||||
def test_decode_payload(payload: str) -> None:
|
||||
result = clean_decode(payload)
|
||||
assert "Telegram" in result
|
||||
assert re.search(r"Ref#[A-Za-z0-9]+", result), f"no Ref# in {result!r}"
|
||||
assert all(ord(c) <= 127 for c in result), f"non-ASCII chars in {result!r}"
|
||||
assert all(ord(c) < 128 for c in result), f"non-ASCII chars in {result!r}"
|
||||
|
||||
|
||||
def test_empty_input_returns_string() -> None:
|
||||
assert isinstance(clean_decode(""), str)
|
||||
def test_empty_payload_returns_empty_string() -> None:
|
||||
assert clean_decode("") == ""
|
||||
|
||||
|
||||
def test_invalid_payload_raises_request_error() -> None:
|
||||
with pytest.raises(RequestError):
|
||||
clean_decode("!!!not-valid-base64!!!")
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
"""Unit tests for FragmentClient — init validation and cookie parsing (no network calls)."""
|
||||
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from fragmentapi import FragmentClient
|
||||
from fragmentapi.types import ConfigError, CookiesError
|
||||
|
||||
VALID_SEED = "abandon " * 23 + "about"
|
||||
VALID_API_KEY = "test_api_key"
|
||||
VALID_COOKIES = {
|
||||
"stel_ssid": "x",
|
||||
"stel_dt": "x",
|
||||
"stel_token": "x",
|
||||
"stel_ton_token": "x",
|
||||
}
|
||||
|
||||
|
||||
def test_valid_init() -> None:
|
||||
client = FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies=VALID_COOKIES)
|
||||
assert client.seed == VALID_SEED.strip()
|
||||
assert client.api_key == VALID_API_KEY
|
||||
assert client.wallet_version == "V5R1"
|
||||
|
||||
|
||||
def test_wallet_version_v4r2() -> None:
|
||||
client = FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies=VALID_COOKIES, wallet_version="V4R2")
|
||||
assert client.wallet_version == "V4R2"
|
||||
|
||||
|
||||
def test_wallet_version_is_case_insensitive() -> None:
|
||||
client = FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies=VALID_COOKIES, wallet_version="v5r1")
|
||||
assert client.wallet_version == "V5R1"
|
||||
|
||||
|
||||
def test_missing_seed_raises() -> None:
|
||||
with pytest.raises(ConfigError):
|
||||
FragmentClient(seed="", api_key=VALID_API_KEY, cookies=VALID_COOKIES)
|
||||
|
||||
|
||||
def test_whitespace_only_seed_raises() -> None:
|
||||
with pytest.raises(ConfigError):
|
||||
FragmentClient(seed=" ", api_key=VALID_API_KEY, cookies=VALID_COOKIES)
|
||||
|
||||
|
||||
def test_missing_api_key_raises() -> None:
|
||||
with pytest.raises(ConfigError):
|
||||
FragmentClient(seed=VALID_SEED, api_key="", cookies=VALID_COOKIES)
|
||||
|
||||
|
||||
def test_unsupported_wallet_version_raises() -> None:
|
||||
with pytest.raises(ConfigError):
|
||||
FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies=VALID_COOKIES, wallet_version="V3R2")
|
||||
|
||||
|
||||
def test_cookies_as_json_string() -> None:
|
||||
client = FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies=json.dumps(VALID_COOKIES))
|
||||
assert client.cookies == VALID_COOKIES
|
||||
|
||||
|
||||
def test_invalid_cookies_json_raises() -> None:
|
||||
with pytest.raises(CookiesError):
|
||||
FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies="{not valid json}")
|
||||
|
||||
|
||||
def test_missing_cookie_key_raises() -> None:
|
||||
with pytest.raises(CookiesError):
|
||||
FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies={"stel_ssid": "x"})
|
||||
|
||||
|
||||
def test_empty_cookie_value_raises() -> None:
|
||||
bad = {**VALID_COOKIES, "stel_token": ""}
|
||||
with pytest.raises(CookiesError):
|
||||
FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies=bad)
|
||||
|
||||
|
||||
def test_whitespace_cookie_value_raises() -> None:
|
||||
bad = {**VALID_COOKIES, "stel_ton_token": " "}
|
||||
with pytest.raises(CookiesError):
|
||||
FragmentClient(seed=VALID_SEED, api_key=VALID_API_KEY, cookies=bad)
|
||||
@@ -5,8 +5,8 @@ import re
|
||||
|
||||
import pytest
|
||||
|
||||
from app.core.constants import BASE_HEADERS, STARS_PAGE
|
||||
from app.utils.hash import get_fragment_hash
|
||||
from fragmentapi.types import BASE_HEADERS, STARS_PAGE
|
||||
from fragmentapi.utils import get_fragment_hash
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
+10
-6
@@ -1,13 +1,17 @@
|
||||
import pytest
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from app.core.cookies import load_cookies
|
||||
from app.core.exceptions import CookiesError
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cookies():
|
||||
"""Load Fragment cookies; skip the test if they are unavailable."""
|
||||
"""Load Fragment cookies from cookies.json; skip the test if unavailable."""
|
||||
cookies_path = Path(__file__).resolve().parents[1] / "cookies.json"
|
||||
if not cookies_path.exists():
|
||||
pytest.skip("cookies.json not found")
|
||||
try:
|
||||
return load_cookies()
|
||||
except CookiesError as exc:
|
||||
with cookies_path.open("r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except Exception as exc:
|
||||
pytest.skip(f"Cookies unavailable — {exc}")
|
||||
|
||||
Reference in New Issue
Block a user