The server unfurls what detect_urls finds, trailing .,;:!? trimmed, and files the preview under that. The web and Android cards looked a lone link's preview up under body.trim(), punctuation included, so a note reading "https://example.com/a." never showed its card. - grammar.json gains a urls section: what the server finds in a body, and the link a lone-link note is filed under. - The web's rule moves out of NoteCard into notes/links.ts loneUrl(); Android's LinkPreviewRow gets the same loneUrl(); both trim like the server. - The server and web suites run the cases; Android's JVM test pins them by hand, as it does the tint. Fixes #5399. DRY pass #2, batch 3 (#5372). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
2.5 KiB
Python
68 lines
2.5 KiB
Python
"""The server's half of the shared grammar fixture (core/testdata/grammar.json).
|
|
|
|
The same cases run against the core (derive.rs) and the web (markdown.ts). A case
|
|
that passes in one language and fails in another is a note that changes shape when
|
|
it syncs — a checklist that stops being one, or a tag that is a label on the phone
|
|
and plain text on the server.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from inkwell.colors import NOTE_COLORS
|
|
from inkwell.notes.checklist import parse_items, render_item
|
|
from inkwell.notes.helpers import derive_display_title
|
|
from inkwell.notes.recurrence import REMINDER_RECURRENCES
|
|
from inkwell.notes.tags import parse_tags, split_body_tags
|
|
from inkwell.unfurl_queue import detect_urls
|
|
|
|
FIXTURE = json.loads(
|
|
(Path(__file__).resolve().parents[1] / "core" / "testdata" / "grammar.json").read_text(encoding="utf-8")
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("case", FIXTURE["task_lines"], ids=lambda c: repr(c["line"]))
|
|
def test_task_lines(case):
|
|
got = [(i.text, i.checked) for i in parse_items(case["line"])]
|
|
want = [] if case["item"] is None else [(case["item"]["text"], case["item"]["checked"])]
|
|
assert got == want
|
|
|
|
|
|
@pytest.mark.parametrize("case", FIXTURE["rendered_items"], ids=lambda c: repr(c["line"]))
|
|
def test_rendered_items(case):
|
|
assert render_item(case["text"], case["checked"]) == case["line"]
|
|
|
|
|
|
@pytest.mark.parametrize("case", FIXTURE["tags"], ids=lambda c: repr(c["body"]))
|
|
def test_tags(case):
|
|
assert parse_tags(case["body"]) == case["tags"]
|
|
|
|
|
|
@pytest.mark.parametrize("case", FIXTURE["lifts"], ids=lambda c: repr(c["body"]))
|
|
def test_lifts(case):
|
|
standalone, inline, lifted = split_body_tags(case["body"])
|
|
assert (standalone, inline, lifted) == (case["standalone"], case["inline"], case["lifted"])
|
|
|
|
|
|
@pytest.mark.parametrize("case", FIXTURE["display_titles"], ids=lambda c: repr(c["body"][:40]))
|
|
def test_display_titles(case):
|
|
assert derive_display_title(case["body"]) == case["title"]
|
|
|
|
|
|
def test_recurrences():
|
|
assert REMINDER_RECURRENCES == set(FIXTURE["recurrences"])
|
|
|
|
|
|
def test_palette_keys():
|
|
"""The palette the server accepts is the fixture's hues plus `default`, the key
|
|
unrecognised input lands on. The web checks the same hues (DERIVED_TINT_KEYS)."""
|
|
assert NOTE_COLORS == {"default", *FIXTURE["tint"]["keys"]}
|
|
|
|
|
|
@pytest.mark.parametrize("case", FIXTURE["urls"], ids=lambda c: repr(c["body"]))
|
|
def test_urls(case):
|
|
assert detect_urls(case["body"]) == case["found"]
|