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
74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
"""Tests for the notebook row adapters.
|
|
|
|
Covers the ``GeneratePromptSuggestions`` (``otmP3b`` / ``SUGGEST_PROMPTS``)
|
|
suggestion-list unwrap and per-row reads that back
|
|
``NotebooksAPI.suggest_prompts``:
|
|
|
|
1. **Position-contract pin** — the canary that fails loudly if a position
|
|
constant is edited (the wire-shape change signal).
|
|
2. **Shape handling** — happy-path reads plus the permissive "absent / short /
|
|
non-list → default" degrade (a suggestion list is best-effort UI sugar).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from notebooklm._row_adapters.notebooks import (
|
|
PromptSuggestionRow,
|
|
unwrap_prompt_suggestions,
|
|
)
|
|
|
|
|
|
class TestPromptSuggestionPositionContract:
|
|
def test_positions_pinned(self) -> None:
|
|
assert (
|
|
PromptSuggestionRow._TITLE_POS,
|
|
PromptSuggestionRow._PROMPT_POS,
|
|
PromptSuggestionRow._MIN_LEN,
|
|
) == (0, 1, 2)
|
|
|
|
|
|
class TestPromptSuggestionRow:
|
|
"""Permissive position reads for one ``SUGGEST_PROMPTS`` suggestion row."""
|
|
|
|
def test_well_formed_row(self) -> None:
|
|
row = PromptSuggestionRow(["Professional Briefing", "\n- Summarize."])
|
|
assert row.is_well_formed
|
|
assert row.title == "Professional Briefing"
|
|
assert row.prompt == "\n- Summarize."
|
|
|
|
def test_short_row_degrades_without_raise(self) -> None:
|
|
# Missing the prompt slot (< _MIN_LEN): not well-formed; reads degrade to "".
|
|
row = PromptSuggestionRow(["Only a title"])
|
|
assert not row.is_well_formed
|
|
assert row.title == "Only a title"
|
|
assert row.prompt == ""
|
|
|
|
def test_non_string_and_non_list_shapes_degrade(self) -> None:
|
|
# Non-string fields and non-list rows degrade to "" / not-well-formed,
|
|
# never raising — a suggestion list is best-effort UI sugar.
|
|
assert PromptSuggestionRow([None, 7]).title == ""
|
|
assert PromptSuggestionRow([None, 7]).prompt == ""
|
|
for raw in (None, "x", 7, {"k": 1}):
|
|
row = PromptSuggestionRow(raw)
|
|
assert not row.is_well_formed
|
|
assert (row.title, row.prompt) == ("", "")
|
|
|
|
|
|
class TestUnwrapPromptSuggestions:
|
|
"""``result[0]`` envelope-unwrap for ``SUGGEST_PROMPTS`` replies."""
|
|
|
|
def test_wrapped_envelope_returns_inner_rows(self) -> None:
|
|
rows = [["A", "\n- a"], ["B", "\n- b"]]
|
|
assert unwrap_prompt_suggestions([rows], source="t") == rows
|
|
|
|
@pytest.mark.parametrize("payload", [None, [], "unexpected", 7, [None], [[]]])
|
|
def test_degenerate_payloads_yield_empty(self, payload: object) -> None:
|
|
assert unwrap_prompt_suggestions(payload, source="t") == []
|
|
|
|
def test_never_raises(self) -> None:
|
|
# Best-effort: every shape degrades, never UnknownRPCMethodError.
|
|
for raw in (None, "x", 7, {"k": 1}, [7], [[1, 2]]):
|
|
unwrap_prompt_suggestions(raw, source="t")
|