feat: validate Anwarpy publication metadata
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import unittest
|
||||
|
||||
from publication_meta import (
|
||||
clean,
|
||||
mark_blocked,
|
||||
mark_published,
|
||||
mark_publishing,
|
||||
parse_meta,
|
||||
same_meta,
|
||||
)
|
||||
|
||||
|
||||
PENDING = "anwarpy: status=pending | access=vip | category=أدوات | queued_at=2026-10-09T15:12:00+03:00"
|
||||
|
||||
|
||||
class PublicationMetaTests(unittest.TestCase):
|
||||
def test_parses_pending_and_normalizes_formatting_controls(self):
|
||||
raw = "\ufeffanwarpy:\u00a0status=pending | access=vip | category=أدوات | queued_at=2026-10-09T15:12:00+03:00\u200f"
|
||||
meta = parse_meta(raw)
|
||||
self.assertEqual(meta["status"], "pending")
|
||||
self.assertEqual(meta["category"], "أدوات")
|
||||
|
||||
def test_rejects_invalid_values_and_dates(self):
|
||||
for raw in (
|
||||
PENDING.replace("access=vip", "access=paid"),
|
||||
PENDING.replace("category=أدوات", "category=عام"),
|
||||
PENDING.replace("2026-10-09", "2026-13-45"),
|
||||
PENDING.replace("+03:00", ""),
|
||||
):
|
||||
with self.subTest(raw=raw):
|
||||
with self.assertRaises(ValueError):
|
||||
parse_meta(raw)
|
||||
|
||||
def test_rejects_invalid_state_shapes(self):
|
||||
with self.assertRaisesRegex(ValueError, "slug"):
|
||||
parse_meta(PENDING.replace("status=pending", "status=publishing"))
|
||||
with self.assertRaisesRegex(ValueError, "blocked_reason"):
|
||||
parse_meta(PENDING.replace("status=pending", "status=blocked"))
|
||||
with self.assertRaisesRegex(ValueError, "not allowed"):
|
||||
parse_meta(PENDING + " | url=https://anwarpy.ai/posts/example")
|
||||
|
||||
def test_transitions_reparse_raw_input(self):
|
||||
publishing = mark_publishing(PENDING, "arabic-ai-guide")
|
||||
self.assertEqual(parse_meta(publishing)["status"], "publishing")
|
||||
published = mark_published(
|
||||
publishing,
|
||||
"2026-10-09T12:20:11+00:00",
|
||||
"https://anwarpy.ai/posts/arabic-ai-guide",
|
||||
)
|
||||
self.assertEqual(parse_meta(published)["status"], "published")
|
||||
|
||||
def test_blocked_is_terminal_and_carries_a_bounded_reason(self):
|
||||
blocked = mark_blocked(PENDING, "cover")
|
||||
self.assertEqual(parse_meta(blocked)["blocked_reason"], "cover")
|
||||
with self.assertRaises(ValueError):
|
||||
mark_blocked(PENDING, "network")
|
||||
|
||||
def test_canonical_url_and_slug_are_exact(self):
|
||||
publishing = mark_publishing(PENDING, "arabic-ai-guide")
|
||||
for url in (
|
||||
"http://anwarpy.ai/posts/arabic-ai-guide",
|
||||
"https://www.anwarpy.ai/posts/arabic-ai-guide",
|
||||
"https://anwarpy.ai/posts/arabic-ai-guide/",
|
||||
"https://anwarpy.ai/posts/other",
|
||||
):
|
||||
with self.subTest(url=url):
|
||||
with self.assertRaises(ValueError):
|
||||
mark_published(publishing, "2026-10-09T15:20:11+03:00", url)
|
||||
with self.assertRaises(ValueError):
|
||||
mark_publishing(PENDING, "عنوان-عربي")
|
||||
|
||||
def test_readback_comparison_is_semantic_after_cleaning(self):
|
||||
formatted = "\u200fanwarpy: status=pending|access=vip|category=أدوات|queued_at=2026-10-09T15:12:00+03:00"
|
||||
self.assertTrue(same_meta(PENDING, formatted))
|
||||
self.assertEqual(clean("\ufeff أداة\u00a0"), "أداة")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user