main.py (5146 lines, 106 routes) becomes an assembly only: one package per domain — core, files, settings, dashboards, conversations, diff, notifications, forms, runs, accounts, workers, models, cron, agents, projects, services, goals, memories, plans, templates — each exposing an APIRouter; the flat domain modules move into their package behind a barrel that keeps the old `import conversations` / `import projects` spellings. The shared singletons (store, meta_store, hub, indexer, …) are built once by core.state.build_state() and attached to app.state.ai; routes take them as the `deps: State` dependency and helpers as an explicit `deps: AppState`. conversations/pricing.py carries the per-model rates out of the parser. Verified: route table and OpenAPI byte-identical; 90 read endpoints golden-diffed against the monolith on a copy of the live data (identical); write routes smoke-tested; 66 backend tests pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
106 lines
4.7 KiB
Python
106 lines
4.7 KiB
Python
"""forms.valid_fields / check_answers — the display blocks (markdown, html)."""
|
|
import unittest
|
|
|
|
import forms
|
|
|
|
|
|
|
|
class HtmlBlockTest(unittest.TestCase):
|
|
def test_html_block_is_display_only(self):
|
|
out = forms.valid_fields([
|
|
{"type": "html", "label": "Chart", "html": "<svg><rect/></svg>"},
|
|
{"key": "ok", "label": "Fine?", "type": "checkbox"},
|
|
])
|
|
blk = out[0]
|
|
self.assertEqual(blk["type"], "html")
|
|
self.assertEqual(blk["key"], "chart")
|
|
self.assertEqual(blk["html"], "<svg><rect/></svg>")
|
|
self.assertFalse(blk["required"])
|
|
self.assertFalse(blk["sandbox"])
|
|
self.assertNotIn("text", blk)
|
|
# Never answered: ignored by answer validation and the recap.
|
|
self.assertEqual(forms.check_answers(out, {"chart": "x", "ok": True}), {"ok": True})
|
|
self.assertEqual(forms.answer_lines(out, {"ok": True}), ["- **Fine?** — yes"])
|
|
|
|
def test_script_implies_sandbox_and_height_is_kept(self):
|
|
out = forms.valid_fields([
|
|
{"type": "html", "html": "<div id=c></div><SCRIPT>draw()</SCRIPT>", "height": "320.0"},
|
|
])
|
|
self.assertTrue(out[0]["sandbox"])
|
|
self.assertEqual(out[0]["height"], 320)
|
|
self.assertEqual(out[0]["key"], "html-1")
|
|
self.assertEqual(out[0]["label"], "")
|
|
|
|
def test_explicit_sandbox_and_text_alias(self):
|
|
out = forms.valid_fields([{"type": "html", "text": "<b>hi</b>", "sandbox": True}])
|
|
self.assertEqual(out[0]["html"], "<b>hi</b>")
|
|
self.assertTrue(out[0]["sandbox"])
|
|
self.assertNotIn("height", out[0])
|
|
|
|
def test_style_sheet_implies_sandbox(self):
|
|
out = forms.valid_fields([{"type": "html", "html": "<style>b{color:red}</style><b>hi</b>"}])
|
|
self.assertTrue(out[0]["sandbox"])
|
|
out = forms.valid_fields([{"type": "html", "html": "<b style='color:red'>hi</b>"}])
|
|
self.assertFalse(out[0]["sandbox"])
|
|
|
|
def test_empty_or_oversized_html_rejected(self):
|
|
with self.assertRaises(ValueError):
|
|
forms.valid_fields([{"type": "html", "label": "x"}])
|
|
with self.assertRaises(ValueError):
|
|
forms.valid_fields([{"type": "html", "html": "<p>" + "a" * (600 * 1024)}])
|
|
|
|
def test_markdown_block_unchanged(self):
|
|
out = forms.valid_fields([{"type": "markdown", "text": "**hi**"}])
|
|
self.assertEqual(out[0]["text"], "**hi**")
|
|
self.assertNotIn("html", out[0])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|
|
|
|
|
|
class OtherOptionTest(unittest.TestCase):
|
|
FIELDS = [
|
|
{"key": "stack", "label": "Stack", "type": "radio", "required": True,
|
|
"options": ["Vite", "Next"]},
|
|
{"key": "feat", "label": "Features", "type": "multiselect",
|
|
"options": ["auth", "db"]},
|
|
{"key": "pick", "label": "Pick", "type": "select", "options": ["a", "b"],
|
|
"other": True},
|
|
]
|
|
|
|
def test_other_defaults_to_required(self):
|
|
out = forms.valid_fields(self.FIELDS)
|
|
self.assertTrue(out[0]["other"]) # required ⇒ on
|
|
self.assertFalse(out[1]["other"]) # optional ⇒ off
|
|
self.assertTrue(out[2]["other"]) # explicit
|
|
off = forms.valid_fields([dict(self.FIELDS[0], other=False)])
|
|
self.assertFalse(off[0]["other"])
|
|
|
|
def test_free_text_accepted_only_with_other(self):
|
|
out = forms.valid_fields(self.FIELDS)
|
|
ans = forms.check_answers(out, {"stack": "Astro", "pick": "zzz", "feat": ["auth"]})
|
|
self.assertEqual(ans, {"stack": "Astro", "pick": "zzz", "feat": ["auth"]})
|
|
with self.assertRaises(ValueError):
|
|
forms.check_answers(out, {"stack": "Vite", "feat": ["nope"]})
|
|
|
|
def test_sentinel_counts_as_unanswered(self):
|
|
out = forms.valid_fields(self.FIELDS)
|
|
with self.assertRaises(ValueError):
|
|
forms.check_answers(out, {"stack": forms.OTHER})
|
|
ans = forms.check_answers(out, {"stack": "Vite", "pick": forms.OTHER,
|
|
"feat": [forms.OTHER, "db"]})
|
|
self.assertEqual(ans, {"stack": "Vite", "feat": ["db"]})
|
|
lines = forms.answer_lines(out, ans)
|
|
self.assertEqual(lines, ["- **Stack** — Vite", "- **Features** — db"])
|
|
|
|
|
|
class AssetsTest(unittest.TestCase):
|
|
def test_apply_assets_recurses_and_keeps_unknown(self):
|
|
spec = [{"type": "html", "html": '<img src="{{asset:shot.png}}"> {{ asset:nope }}',
|
|
"nested": {"x": ["{{asset:shot.png}}"]}}]
|
|
out = forms.apply_assets(spec, {"shot.png": "/api/upload-file?path=b/shot.png"})
|
|
self.assertEqual(out[0]["html"],
|
|
'<img src="/api/upload-file?path=b/shot.png"> {{ asset:nope }}')
|
|
self.assertEqual(out[0]["nested"]["x"], ["/api/upload-file?path=b/shot.png"])
|