Files

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