@@ -104,3 +104,39 @@ def test_tampered_ciphertext_raises():
104104 tampered = base64 .b64encode (bytes (raw )).decode ()
105105 with pytest .raises (Exception ):
106106 encryption .decrypt (tampered )
107+
108+
109+ # ── #200: columns retyped NUMERIC/JSONB -> TEXT in the canonical schema ─────────
110+ # These hold encrypted base64 *text*, so the value each column stores must survive
111+ # the exact write->read helpers the routes use. The route-level coverage for
112+ # documents.concept_notes lives in the test_documents_routes module quarantined
113+ # under #210, so assert the round-trip here (non-quarantined) before that change
114+ # lands. summary_json/concept_notes -> encrypt_json/decrypt_json; points ->
115+ # encrypt_if_present/decrypt_numeric (see routes/learn.py, routes/documents.py,
116+ # routes/gradebook.py).
117+
118+ def test_summary_json_text_column_round_trip ():
119+ # sessions.summary_json — a JSON object (learn.py writes encrypt_json(summary))
120+ summary = {"concepts" : ["limits" , "derivatives" ], "score" : 0.82 , "notes" : "ünïcode" }
121+ assert encryption .decrypt_json (encryption .encrypt_json (summary )) == summary
122+
123+
124+ def test_concept_notes_text_column_round_trip ():
125+ # documents.concept_notes — a JSON array of {name, description}
126+ # (documents.py writes encrypt_json(concept_notes))
127+ concept_notes = [
128+ {"name" : "Eigenvalue" , "description" : "Scalar λ with Av = λv." },
129+ {"name" : "Span" , "description" : "All linear combinations of a set." },
130+ ]
131+ assert encryption .decrypt_json (encryption .encrypt_json (concept_notes )) == concept_notes
132+
133+
134+ def test_points_text_column_round_trip ():
135+ # assignments.points_possible / points_earned — numbers written via
136+ # encrypt_if_present and read back via decrypt_numeric.
137+ for value in (100 , 95.5 , 0 ):
138+ ct = encryption .encrypt_if_present (value )
139+ assert isinstance (ct , str ) # stored as TEXT, not NUMERIC
140+ assert encryption .decrypt_numeric (ct ) == float (value )
141+ assert encryption .encrypt_if_present (None ) is None
142+ assert encryption .decrypt_numeric (None ) is None
0 commit comments