a digital entity named phi that roams bsky
phi.zzstoatzz.io
1"""Test cosmik record types — validation and serialization."""
2
3import pytest
4from pydantic import ValidationError
5
6from bot.types import (
7 CosmikCollection,
8 CosmikCollectionLink,
9 CosmikConnection,
10 CosmikNoteCard,
11 CosmikUrlCard,
12 NoteContent,
13 StrongRef,
14 UrlContent,
15)
16
17# --- CosmikConnection ---
18
19
20def test_connection_valid():
21 conn = CosmikConnection(
22 source="https://example.com",
23 target="at://did:plc:abc/app.bsky.feed.post/123",
24 connection_type="related",
25 note="test",
26 )
27 assert conn.source == "https://example.com"
28 assert conn.connection_type == "related"
29
30
31def test_connection_to_record_full():
32 conn = CosmikConnection(
33 source="https://a.com",
34 target="https://b.com",
35 connection_type="supports",
36 note="because reasons",
37 )
38 record = conn.to_record()
39 assert record["source"] == "https://a.com"
40 assert record["target"] == "https://b.com"
41 assert record["connectionType"] == "supports"
42 assert record["note"] == "because reasons"
43 assert "createdAt" in record
44 assert "updatedAt" in record
45
46
47def test_connection_to_record_minimal():
48 conn = CosmikConnection(source="https://a.com", target="https://b.com")
49 record = conn.to_record()
50 assert record["source"] == "https://a.com"
51 assert record["target"] == "https://b.com"
52 assert "connectionType" not in record
53 assert "note" not in record
54 assert "createdAt" in record
55 assert "updatedAt" in record
56
57
58def test_connection_rejects_bare_string():
59 with pytest.raises(ValidationError):
60 CosmikConnection(source="not-a-url", target="https://b.com")
61
62
63def test_connection_rejects_invalid_type():
64 with pytest.raises(ValidationError):
65 CosmikConnection(
66 source="https://a.com",
67 target="https://b.com",
68 connection_type="invented",
69 )
70
71
72# --- CosmikNoteCard ---
73
74
75def test_note_card_valid():
76 card = CosmikNoteCard(content=NoteContent(text="hello world"))
77 assert card.type == "NOTE"
78 assert card.content.text == "hello world"
79
80
81def test_note_card_to_record():
82 card = CosmikNoteCard(content=NoteContent(text="a thought"))
83 record = card.to_record()
84 assert record["type"] == "NOTE"
85 assert record["content"]["$type"] == "network.cosmik.card#noteContent"
86 assert record["content"]["text"] == "a thought"
87 assert "createdAt" in record
88 assert "parentCard" not in record
89
90
91def test_note_card_rejects_empty():
92 # pydantic allows empty string for str fields — max_length is the guard
93 card = CosmikNoteCard(content=NoteContent(text=""))
94 assert card.content.text == ""
95
96
97def test_note_card_rejects_too_long():
98 with pytest.raises(ValidationError):
99 CosmikNoteCard(content=NoteContent(text="x" * 10001))
100
101
102# --- CosmikUrlCard ---
103
104
105def test_url_card_valid():
106 card = CosmikUrlCard(
107 content=UrlContent(
108 url="https://example.com", title="Example", description="A site"
109 )
110 )
111 assert card.type == "URL"
112 assert card.content.url == "https://example.com"
113
114
115def test_url_card_to_record_full():
116 card = CosmikUrlCard(
117 content=UrlContent(url="https://example.com", title="Ex", description="desc")
118 )
119 record = card.to_record()
120 assert record["type"] == "URL"
121 assert record["content"]["$type"] == "network.cosmik.card#urlContent"
122 assert record["content"]["url"] == "https://example.com"
123 assert record["content"]["metadata"]["$type"] == "network.cosmik.card#urlMetadata"
124 assert record["content"]["metadata"]["title"] == "Ex"
125 assert record["content"]["metadata"]["description"] == "desc"
126 assert "createdAt" in record
127
128
129def test_url_card_to_record_minimal():
130 card = CosmikUrlCard(content=UrlContent(url="https://example.com"))
131 record = card.to_record()
132 assert record["type"] == "URL"
133 assert record["content"]["$type"] == "network.cosmik.card#urlContent"
134 assert record["content"]["url"] == "https://example.com"
135 assert "metadata" not in record["content"]
136 assert "createdAt" in record
137
138
139def test_url_card_rejects_bare_string():
140 with pytest.raises(ValidationError):
141 CosmikUrlCard(content=UrlContent(url="not-a-url"))
142
143
144def test_url_card_accepts_at_uri():
145 card = CosmikUrlCard(content=UrlContent(url="at://did:plc:abc/collection/rkey"))
146 assert card.content.url == "at://did:plc:abc/collection/rkey"
147
148
149# --- CosmikNoteCard with parentCard ---
150
151
152def test_note_card_with_parent():
153 parent = StrongRef(uri="at://did:plc:abc/network.cosmik.card/xyz", cid="bafyabc")
154 card = CosmikNoteCard(content=NoteContent(text="child note"), parent_card=parent)
155 record = card.to_record()
156 assert record["parentCard"] == {"uri": parent.uri, "cid": parent.cid}
157
158
159# --- CosmikCollection ---
160
161
162def test_collection_to_record():
163 coll = CosmikCollection(name="epistemology", description="memory and knowledge")
164 record = coll.to_record()
165 assert record == {
166 "name": "epistemology",
167 "accessType": "OPEN",
168 "description": "memory and knowledge",
169 }
170
171
172def test_collection_minimal():
173 coll = CosmikCollection(name="misc")
174 record = coll.to_record()
175 assert record == {"name": "misc", "accessType": "OPEN"}
176
177
178def test_collection_rejects_long_name():
179 with pytest.raises(ValidationError):
180 CosmikCollection(name="x" * 101)
181
182
183# --- CosmikCollectionLink ---
184
185
186def test_collection_link_to_record():
187 link = CosmikCollectionLink(
188 collection=StrongRef(
189 uri="at://did:plc:abc/network.cosmik.collection/c1", cid="bafycol"
190 ),
191 card=StrongRef(uri="at://did:plc:abc/network.cosmik.card/k1", cid="bafycard"),
192 added_by="did:plc:abc",
193 added_at="2026-04-01T00:00:00Z",
194 )
195 record = link.to_record()
196 assert (
197 record["collection"]["uri"] == "at://did:plc:abc/network.cosmik.collection/c1"
198 )
199 assert record["card"]["cid"] == "bafycard"
200 assert record["addedBy"] == "did:plc:abc"
201 assert record["addedAt"] == "2026-04-01T00:00:00Z"