mirror of
https://github.com/soxoj/maigret.git
synced 2026-08-17 19:25:41 +02:00
207 lines
7.1 KiB
Python
207 lines
7.1 KiB
Python
from colorama import Fore, Style
|
|
|
|
from maigret.errors import CheckError
|
|
from maigret.notify import QueryNotifyPrint
|
|
from maigret.result import MaigretCheckStatus, MaigretCheckResult
|
|
|
|
|
|
def test_notify_illegal():
|
|
n = QueryNotifyPrint(color=False)
|
|
|
|
assert (
|
|
n.update(
|
|
MaigretCheckResult(
|
|
username="test",
|
|
status=MaigretCheckStatus.ILLEGAL,
|
|
site_name="TEST_SITE",
|
|
site_url_user="http://example.com/test",
|
|
)
|
|
)
|
|
== "[-] TEST_SITE: Illegal Username Format For This Site!"
|
|
)
|
|
|
|
|
|
def test_notify_claimed():
|
|
n = QueryNotifyPrint(color=False)
|
|
|
|
assert (
|
|
n.update(
|
|
MaigretCheckResult(
|
|
username="test",
|
|
status=MaigretCheckStatus.CLAIMED,
|
|
site_name="TEST_SITE",
|
|
site_url_user="http://example.com/test",
|
|
)
|
|
)
|
|
== "[+] TEST_SITE: http://example.com/test"
|
|
)
|
|
|
|
|
|
def test_notify_available():
|
|
n = QueryNotifyPrint(color=False)
|
|
|
|
assert (
|
|
n.update(
|
|
MaigretCheckResult(
|
|
username="test",
|
|
status=MaigretCheckStatus.AVAILABLE,
|
|
site_name="TEST_SITE",
|
|
site_url_user="http://example.com/test",
|
|
)
|
|
)
|
|
== "[-] TEST_SITE: Not found!"
|
|
)
|
|
|
|
|
|
def test_notify_unknown():
|
|
n = QueryNotifyPrint(color=False)
|
|
result = MaigretCheckResult(
|
|
username="test",
|
|
status=MaigretCheckStatus.UNKNOWN,
|
|
site_name="TEST_SITE",
|
|
site_url_user="http://example.com/test",
|
|
)
|
|
result.error = CheckError('Type', 'Reason')
|
|
|
|
assert n.update(result) == "[?] TEST_SITE: Type error: Reason"
|
|
|
|
|
|
# `warning(message, symbol, advice=None)` was added so that the "Too many
|
|
# errors..." summary can render the count line bold and the advice in
|
|
# normal weight. The pieces must stay visually distinct because the advice
|
|
# is multi-line guidance, not part of the alarm.
|
|
|
|
|
|
def _capture_warning_string(monkeypatch, **warning_kwargs):
|
|
"""Patch builtins.print so we capture the *exact* string warning passed —
|
|
independent of colorama's terminal/TTY heuristics, which strip ANSI in
|
|
capsys mode. We care about what notify generated, not what colorama
|
|
decided to do with it on a captured pipe."""
|
|
captured = []
|
|
import builtins
|
|
monkeypatch.setattr(builtins, 'print', lambda *a, **kw: captured.append(a[0] if a else ''))
|
|
n = QueryNotifyPrint(color=warning_kwargs.pop('color', True))
|
|
n.warning(**warning_kwargs)
|
|
assert captured, "warning() did not call print()"
|
|
return captured[0]
|
|
|
|
|
|
def test_warning_no_advice_renders_as_single_yellow_bold_line(monkeypatch):
|
|
out = _capture_warning_string(
|
|
monkeypatch, color=True, message='something happened', symbol='!',
|
|
)
|
|
# Existing behaviour preserved for the no-advice path
|
|
assert out == Style.BRIGHT + Fore.YELLOW + '[!] something happened'
|
|
|
|
|
|
def test_warning_with_advice_keeps_header_bold_and_advice_normal(monkeypatch):
|
|
"""Advice must come after Style.NORMAL so terminals stop boldfacing it.
|
|
The Fore.YELLOW colour stays — the visual cue is weight, not colour."""
|
|
out = _capture_warning_string(
|
|
monkeypatch, color=True, message='count line', symbol='!', advice='do the thing',
|
|
)
|
|
# Header is bold...
|
|
assert out.startswith(Style.BRIGHT + Fore.YELLOW + '[!] count line')
|
|
# ...advice is preceded by Style.NORMAL so the boldface ends before it
|
|
assert Style.NORMAL + '. do the thing' in out
|
|
# ...and the whole line resets all SGR state at the end so no styling
|
|
# leaks into the next print
|
|
assert out.endswith(Style.RESET_ALL)
|
|
|
|
|
|
def test_warning_with_advice_no_color_uses_plain_dot_separator(monkeypatch):
|
|
"""In no-colour mode the visual distinction is impossible to render, so
|
|
a plain ". " separator between the count line and the advice is enough.
|
|
No ANSI codes must leak into the output."""
|
|
out = _capture_warning_string(
|
|
monkeypatch, color=False, message='count line', symbol='!', advice='do the thing',
|
|
)
|
|
assert out == '[!] count line. do the thing'
|
|
# Defence in depth: no escape codes survived the no-colour branch
|
|
assert '\x1b[' not in out
|
|
|
|
|
|
def _capture_print(monkeypatch):
|
|
captured = []
|
|
import builtins
|
|
monkeypatch.setattr(builtins, 'print', lambda *a, **kw: captured.append(a[0] if a else ''))
|
|
return captured
|
|
|
|
|
|
def _capture_stdout_writes(monkeypatch):
|
|
"""Capture both sys.stdout.write and print — enrich() writes a bare
|
|
line-clear escape via stdout.write and then calls print for the message."""
|
|
import builtins, sys
|
|
captured = []
|
|
monkeypatch.setattr(builtins, 'print', lambda *a, **kw: captured.append(a[0] if a else ''))
|
|
monkeypatch.setattr(sys.stdout, 'write', lambda s: captured.append(('write', s)))
|
|
return captured
|
|
|
|
|
|
def test_enrich_uses_magenta_and_star_symbol(monkeypatch):
|
|
captured = _capture_print(monkeypatch)
|
|
QueryNotifyPrint(color=True).enrich('hello')
|
|
assert Style.BRIGHT + Fore.MAGENTA + '[*] hello' in captured
|
|
|
|
|
|
def test_enrich_no_color_is_plain(monkeypatch):
|
|
captured = _capture_print(monkeypatch)
|
|
QueryNotifyPrint(color=False).enrich('hello')
|
|
assert '[*] hello' in captured
|
|
assert all('\x1b[' not in c for c in captured)
|
|
|
|
|
|
def test_enrich_writes_line_clear_before_print(monkeypatch):
|
|
"""Clears the alive_progress 'on N:' prefix from the current line before printing.
|
|
|
|
Colorama strips the ANSI escape when stdout looks non-TTY (monkeypatched
|
|
stdout does), collapsing '\\x1b[1K\\r' to '\\r'. Either form is a valid
|
|
line-clear signal to the terminal, so accept both."""
|
|
captured = _capture_stdout_writes(monkeypatch)
|
|
QueryNotifyPrint(color=False).enrich('hello')
|
|
op, text = captured[0]
|
|
assert op == 'write'
|
|
assert text in ('\x1b[1K\r', '\r')
|
|
assert '[*] hello' in captured
|
|
|
|
|
|
def test_enrich_verbose_only_hidden_by_default(monkeypatch):
|
|
captured = _capture_print(monkeypatch)
|
|
QueryNotifyPrint(color=False, verbose=False).enrich('diagnostic', verbose_only=True)
|
|
assert captured == []
|
|
|
|
|
|
def test_enrich_verbose_only_shown_when_verbose(monkeypatch):
|
|
captured = _capture_print(monkeypatch)
|
|
QueryNotifyPrint(color=False, verbose=True).enrich('diagnostic', verbose_only=True)
|
|
assert '[*] diagnostic' in captured
|
|
|
|
|
|
|
|
|
|
def _claimed_result_with_ids(ids_data):
|
|
r = MaigretCheckResult(
|
|
username="u", site_name="S", site_url_user="https://s/u",
|
|
status=MaigretCheckStatus.CLAIMED,
|
|
)
|
|
r.ids_data = ids_data
|
|
return r
|
|
|
|
|
|
def test_update_hides_extractor_field_by_default(monkeypatch):
|
|
captured = _capture_print(monkeypatch)
|
|
n = QueryNotifyPrint(color=False, verbose=False)
|
|
n.update(_claimed_result_with_ids({"uid": "42", "_extractor": "SomeSchemeAPI"}))
|
|
out = "\n".join(captured)
|
|
assert "uid: 42" in out
|
|
assert "_extractor" not in out
|
|
|
|
|
|
def test_update_shows_extractor_field_when_verbose(monkeypatch):
|
|
captured = _capture_print(monkeypatch)
|
|
n = QueryNotifyPrint(color=False, verbose=True)
|
|
n.update(_claimed_result_with_ids({"uid": "42", "_extractor": "SomeSchemeAPI"}))
|
|
out = "\n".join(captured)
|
|
assert "uid: 42" in out
|
|
assert "_extractor: SomeSchemeAPI" in out
|