Files
wehub-resource-sync 09e9f3545f
Test / Code Quality (push) Has been cancelled
Test / Test (macos-latest, Python 3.10) (push) Has been cancelled
Test / Test (macos-latest, Python 3.11) (push) Has been cancelled
Test / Test (macos-latest, Python 3.12) (push) Has been cancelled
Test / Test (macos-latest, Python 3.13) (push) Has been cancelled
Test / Test (macos-latest, Python 3.14) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.10) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.11) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.12) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.13) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.14) (push) Has been cancelled
Test / Test (windows-latest, Python 3.10) (push) Has been cancelled
Test / Test (windows-latest, Python 3.11) (push) Has been cancelled
Test / Test (windows-latest, Python 3.12) (push) Has been cancelled
Test / Test (windows-latest, Python 3.13) (push) Has been cancelled
Test / Test (windows-latest, Python 3.14) (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
dependency-audit / pip-audit (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:30:13 +08:00

150 lines
6.5 KiB
Python

"""Tests for root-group flags on the top-level ``notebooklm`` Click group.
Covers the root-group pieces of ``--quiet`` (env-var precedence + global quiet mode):
* ``notebooklm --quiet ...`` suppresses INFO/WARN logs from the ``notebooklm``
package logger; only ERROR (and above) survive on stderr.
* ``notebooklm --quiet -v ...`` is rejected with a ``UsageError`` (exit 2)
because the two intents conflict — ``--quiet`` raises the floor to ERROR
while ``-v`` lowers it to INFO; honoring either silently would surprise
one of the two callers.
* ``--quiet`` does NOT collide with the existing subcommand-scoped
``auth refresh --quiet`` flag — Click parses the closer scope first, so
``notebooklm auth refresh --quiet`` continues to hit the subcommand flag.
Status-output suppression is covered in ``test_quiet_flag.py``.
The new ``NOTEBOOKLM_NOTEBOOK`` env-var integration is tested in
``test_helpers.py::TestRequireNotebook`` (the resolver covers both the direct
helper API and the Click ``envvar=`` wiring on ``notebook_option``).
"""
from __future__ import annotations
import logging
import pytest
from click.testing import CliRunner
from notebooklm.notebooklm_cli import cli
@pytest.fixture
def runner() -> CliRunner:
return CliRunner()
@pytest.fixture(autouse=True)
def _reset_notebooklm_logger():
"""Restore the ``notebooklm`` package logger level after every test.
The root ``cli()`` callback mutates ``logging.getLogger("notebooklm")``'s
level as a side effect of ``--quiet`` / ``-v`` / ``-vv``. Without this
fixture, the level set by one test leaks into the next via the shared
logger registry and turns the suite order-dependent.
"""
pkg_logger = logging.getLogger("notebooklm")
saved = pkg_logger.level
try:
yield
finally:
pkg_logger.setLevel(saved)
class TestQuietFlag:
def test_quiet_raises_notebooklm_logger_to_error(self, runner):
"""``notebooklm --quiet ...`` sets the ``notebooklm`` logger level to
ERROR so INFO and WARNING records emitted by the package are dropped
before they hit the configured StreamHandler.
We invoke a subcommand's ``--help`` (rather than the bare root
``--help``) because Click short-circuits ``cli --help`` inside the
parsing layer before the group callback runs; ``cli status --help``
invokes the callback first (so ``--quiet`` takes effect) and exits
with the subcommand help next.
"""
result = runner.invoke(cli, ["--quiet", "status", "--help"])
assert result.exit_code == 0, result.output
assert logging.getLogger("notebooklm").level == logging.ERROR
def test_no_quiet_keeps_notebooklm_logger_at_default(self, runner):
"""Baseline: omitting ``--quiet`` and ``-v`` leaves the package logger
untouched (configured by ``configure_logging()`` at import time, which
respects ``NOTEBOOKLM_LOG_LEVEL``; default is WARNING).
"""
before = logging.getLogger("notebooklm").level
result = runner.invoke(cli, ["status", "--help"])
assert result.exit_code == 0
assert logging.getLogger("notebooklm").level == before
def test_quiet_and_verbose_are_mutually_exclusive(self, runner):
"""``--quiet`` + ``-v`` together must exit 2 with a UsageError, since
the two flags resolve to incompatible log-level intents (ERROR vs INFO).
"""
result = runner.invoke(cli, ["--quiet", "-v", "status", "--help"])
assert result.exit_code == 2
# Click renders ``UsageError`` to stderr by default. ``CliRunner``
# mixes stdout + stderr in ``result.output``.
assert "--quiet" in result.output
assert "-v" in result.output or "verbose" in result.output.lower()
assert "mutually exclusive" in result.output.lower()
def test_quiet_and_double_verbose_are_mutually_exclusive(self, runner):
"""``--quiet`` + ``-vv`` (DEBUG) is also rejected — same conflict as
``--quiet -v``, just at a different verbosity step. Pinned separately
so future refactors can't accidentally narrow the check to ``-v``
only and let ``-vv`` slip through.
"""
result = runner.invoke(cli, ["--quiet", "-vv", "status", "--help"])
assert result.exit_code == 2
assert "mutually exclusive" in result.output.lower()
def test_quiet_advertised_in_root_help(self, runner):
"""``notebooklm --help`` must list the new ``--quiet`` flag so users
can discover it without reading the changelog.
"""
result = runner.invoke(cli, ["--help"])
assert result.exit_code == 0
assert "--quiet" in result.output
class TestNotebookOptionEnvVar:
"""The ``-n/--notebook`` option declared by ``cli/options.py:notebook_option``
must accept ``NOTEBOOKLM_NOTEBOOK`` as a fallback so Click documents the
binding in ``--help`` and resolves the env value natively.
Behavioral resolution (env > context > error when no flag) is exercised
in ``test_helpers.py::TestRequireNotebook`` against the resolver itself;
here we pin the wiring at the Click-option layer so the documented
``NOTEBOOKLM_NOTEBOOK`` binding cannot regress silently.
"""
def test_notebook_option_declares_envvar_binding(self):
"""The probe-decorator pattern used by ``test_helpers.py`` confirms
the canonical option declaration; here we assert the new ``envvar=``
was wired in.
"""
from click import Option
from notebooklm.cli.options import notebook_option
@notebook_option
def _probe(notebook_id): # pragma: no cover — never invoked
pass
for param in _probe.__click_params__: # type: ignore[attr-defined]
if isinstance(param, Option) and "--notebook" in param.opts:
assert param.envvar == "NOTEBOOKLM_NOTEBOOK", (
f"notebook_option must bind envvar=NOTEBOOKLM_NOTEBOOK so "
f"Click resolves and documents it natively, got {param.envvar!r}"
)
# Click renders ``[env var: NOTEBOOKLM_NOTEBOOK]`` in --help
# only when ``show_envvar=True``. Assert the surface is
# discoverable in ``--help`` (the dominant LLM-agent UX).
assert param.show_envvar is True, (
"notebook_option must set show_envvar=True so the env-var "
"binding shows up in --help output"
)
return
raise AssertionError("notebook_option did not declare a --notebook option")