Files
teng-lin--notebooklm-py/tests/unit/test_artifacts_row_adapter.py
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

175 lines
6.5 KiB
Python

"""Unit tests for the artifact-envelope unwrap helpers (issue #1491 burndown).
These cover the two functions that centralise the positional envelope/leaf
descent the ``_artifact``/``_artifacts`` decode sites previously open-coded:
* :func:`unwrap_artifact_rows` — the ``[[row, ...]]`` envelope probe shared by
``ArtifactListingService.list_raw`` (``LIST_ARTIFACTS``) and
``ArtifactsAPI.suggest_reports`` (``GET_SUGGESTED_REPORTS``); and
* :func:`unwrap_mind_map_generation_leaf` — the two-level ``result[0][0]`` leaf
descent of a ``GENERATE_MIND_MAP`` reply.
Each table proves the helper reproduces the EXACT result of the prior inline
reads on present/happy, empty, too-short, and malformed inputs (the soft-vs-
strict semantics the migration had to preserve).
"""
from __future__ import annotations
from typing import Any
import pytest
from notebooklm._row_adapters.artifacts import (
MIND_MAP_LEAF_ABSENT,
unwrap_artifact_rows,
unwrap_mind_map_generation_leaf,
)
from notebooklm.rpc.types import RPCMethod
_LIST_METHOD = RPCMethod.LIST_ARTIFACTS.value
def _unwrap(result: list[Any]) -> list[Any]:
return unwrap_artifact_rows(result, method_id=_LIST_METHOD, source="test")
class TestUnwrapArtifactRows:
"""``unwrap_artifact_rows`` reproduces the inline ``[[row,...]]`` probe."""
def test_wrapped_envelope_returns_inner_rows(self) -> None:
"""A single-element envelope whose inner head is a row unwraps."""
rows = [["id1", "Title1"], ["id2", "Title2"]]
assert _unwrap([rows]) == rows
def test_wrapped_empty_inner_returns_empty_inner(self) -> None:
"""A single outer element wrapping an empty inner list unwraps to ``[]``."""
# ``not inner`` short-circuits before the inner-head probe — the
# legitimately-empty notebook shape.
inner: list[Any] = []
assert _unwrap([inner]) is inner
def test_already_flat_rows_returned_unchanged(self) -> None:
"""A flat list of >1 rows is not single-element, so it is returned as-is."""
flat = [["id1"], ["id2"]]
assert _unwrap(flat) is flat
def test_single_flat_row_with_scalar_head_returned_unchanged(self) -> None:
"""A single outer element whose inner head is a SCALAR is a flat row.
``[[scalar, ...]]`` is the already-flat ``[row]`` shape (one row whose
first field is a scalar), not a wrapped envelope — so it must NOT be
unwrapped. Mirrors the prior ``isinstance(inner[0], list)`` guard.
"""
flat = [["id-as-scalar-head", 2, 3]]
assert _unwrap(flat) is flat
def test_single_element_non_list_returned_unchanged(self) -> None:
"""A single outer element that is not a list is left flat (caller's row)."""
flat = ["scalar-row"]
assert _unwrap(flat) is flat
def test_empty_outer_returned_unchanged(self) -> None:
"""An empty outer list (len != 1) is returned unchanged (== ``[]``)."""
outer: list[Any] = []
assert _unwrap(outer) is outer
def test_matches_legacy_inline_logic_across_shapes(self) -> None:
"""Differential check against the exact pre-migration inline algorithm."""
def legacy(result: list[Any]) -> list[Any]:
items = result
if len(result) == 1 and isinstance(result[0], list):
inner = result[0]
if not inner or isinstance(inner[0], list):
items = inner
return items
shapes: list[list[Any]] = [
[[["a"], ["b"]]], # wrapped
[[]], # wrapped empty inner
[["scalar", 1]], # flat single row (scalar head)
[["a"], ["b"]], # flat multi-row
["scalar"], # single non-list element
[], # empty
[[["only-row"]]], # wrapped single row
]
for shape in shapes:
assert _unwrap(shape) == legacy(shape), shape
def _leaf(result: Any) -> Any:
return unwrap_mind_map_generation_leaf(
result, method_id=RPCMethod.GENERATE_MIND_MAP.value, source="test"
)
class TestUnwrapMindMapGenerationLeaf:
"""``unwrap_mind_map_generation_leaf`` reproduces the ``result[0][0]`` descent."""
def test_happy_returns_present_leaf(self) -> None:
assert _leaf([['{"name": "Tree"}']]) == '{"name": "Tree"}'
def test_present_none_leaf_is_returned_not_treated_as_absent(self) -> None:
"""A PRESENT ``None`` leaf must be returned verbatim, not the sentinel.
The historical code processes a ``None`` leaf (it serialises to a
``"null"`` note body), so the helper must distinguish it from the
absence shapes via the sentinel.
"""
result = _leaf([[None]])
assert result is None
assert result is not MIND_MAP_LEAF_ABSENT
def test_present_empty_string_leaf_returned(self) -> None:
result = _leaf([[""]])
assert result == ""
assert result is not MIND_MAP_LEAF_ABSENT
@pytest.mark.parametrize(
"result",
[
None, # null payload
[], # empty outer
"scalar", # non-list payload
0, # falsy non-list
[[]], # present outer, empty inner
[None], # present outer, non-list inner
["scalar-inner"], # present outer, non-list (str) inner
],
)
def test_absence_shapes_return_sentinel(self, result: Any) -> None:
"""Short / non-list outer or inner returns the absence sentinel (soft)."""
assert _leaf(result) is MIND_MAP_LEAF_ABSENT
def test_matches_legacy_inline_logic(self) -> None:
"""Differential check: sentinel iff the legacy nested guard skipped."""
def legacy_found(result: Any) -> tuple[bool, Any]:
if result and isinstance(result, list) and len(result) > 0:
inner = result[0]
if isinstance(inner, list) and len(inner) > 0:
return True, inner[0]
return False, None
shapes: list[Any] = [
[["leaf"]],
[[None]],
[[""]],
[[123]],
[[]],
[None],
[],
None,
"x",
[["a", "b"]], # inner len > 1 — head only
]
for shape in shapes:
found, expected_leaf = legacy_found(shape)
actual = _leaf(shape)
if found:
assert actual == expected_leaf, shape
assert actual is not MIND_MAP_LEAF_ABSENT, shape
else:
assert actual is MIND_MAP_LEAF_ABSENT, shape