Skip to content

Commit 5c32dc6

Browse files
committed
Add a test for reloading (on Python side)
Automatic application of license header
1 parent 16380fa commit 5c32dc6

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

tests/test_ynotebook.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Copyright (c) Jupyter Development Team.
2+
# Distributed under the terms of the Modified BSD License.
3+
4+
from pycrdt import Map
5+
6+
from jupyter_ydoc import YNotebook
7+
8+
9+
def make_code_cell(source: str):
10+
return {
11+
"cell_type": "code",
12+
"source": source,
13+
"metadata": {},
14+
"outputs": [],
15+
"execution_count": None,
16+
}
17+
18+
19+
class AnyInstanceOf:
20+
def __init__(self, cls):
21+
self.cls = cls
22+
23+
def __eq__(self, other):
24+
return isinstance(other, self.cls)
25+
26+
27+
def test_set_preserves_cells_when_unchanged():
28+
nb = YNotebook()
29+
nb.append_cell(make_code_cell("print('a')\n"))
30+
nb.append_cell(make_code_cell("print('b')\n"))
31+
32+
changes = []
33+
34+
def record_changes(topic, event):
35+
changes.append((topic, event))
36+
37+
nb.observe(record_changes)
38+
39+
model = nb.get()
40+
41+
# Call set with identical structure
42+
nb.set(model)
43+
44+
# No changes should be observed at all
45+
assert changes == []
46+
47+
48+
def test_set_preserves_cells_with_insert_and_remove():
49+
nb = YNotebook()
50+
nb.append_cell(make_code_cell("print('a')\n")) # original 0
51+
nb.append_cell(make_code_cell("print('b')\n")) # original 1 (will remove)
52+
nb.append_cell(make_code_cell("print('c')\n")) # original 2
53+
54+
# Capture textual content for sanity check
55+
cell0_source_text = str(nb.ycells[0]["source"])
56+
cell2_source_text = str(nb.ycells[2]["source"])
57+
58+
# Get the model as Python object
59+
model = nb.get()
60+
61+
# Remove the middle cell and insert a new one between the retained cells
62+
cells = model["cells"]
63+
assert len(cells) == 3
64+
65+
# The cell ids are needed for retention logic; keep first and last
66+
first = cells[0]
67+
last = cells[2]
68+
69+
# New inserted cell
70+
inserted = make_code_cell("print('x')\n")
71+
model["cells"] = [first, inserted, last]
72+
73+
changes = []
74+
75+
def record_changes(topic, event):
76+
changes.append((topic, event))
77+
78+
nb.observe(record_changes)
79+
nb.set(model)
80+
81+
assert nb.cell_number == 3
82+
83+
# Content of the first and last cells should remain the same
84+
assert str(nb.ycells[0]["source"]) == cell0_source_text
85+
assert str(nb.ycells[2]["source"]) == cell2_source_text
86+
87+
# The middle cell should have a different source now
88+
assert str(nb.ycells[1]["source"]) == "print('x')\n"
89+
90+
# We should have one cell event
91+
cell_events = [e for t, e in changes if t == "cells"]
92+
assert len(cell_events) == 1
93+
event_transactions = cell_events[0]
94+
assert len(event_transactions) == 1
95+
assert event_transactions[0].delta == [
96+
{"retain": 1},
97+
{"delete": 1},
98+
{"insert": [AnyInstanceOf(Map)]},
99+
]

0 commit comments

Comments
 (0)