|
1 | 1 | # Copyright (c) Jupyter Development Team. |
2 | 2 | # Distributed under the terms of the Modified BSD License. |
3 | 3 |
|
| 4 | +from dataclasses import dataclass |
4 | 5 |
|
5 | 6 | from pycrdt import ArrayEvent, Map, MapEvent, TextEvent |
6 | 7 | from pytest import mark |
@@ -118,17 +119,61 @@ def record_changes(topic, event): |
118 | 119 | ] |
119 | 120 |
|
120 | 121 |
|
| 122 | +@dataclass |
| 123 | +class ExpectedEvent: |
| 124 | + kind: type |
| 125 | + path: str | None = None |
| 126 | + |
| 127 | + def __eq__(self, other): |
| 128 | + if not isinstance(other, self.kind): |
| 129 | + return False |
| 130 | + if self.path is not None and self.path != other.path: |
| 131 | + return False |
| 132 | + return True |
| 133 | + |
| 134 | + def __repr__(self): |
| 135 | + if self.path is not None: |
| 136 | + return f"ExpectedEvent({self.kind.__name__}, path={self.path!r})" |
| 137 | + return f"ExpectedEvent({self.kind.__name__})" |
| 138 | + |
| 139 | + |
121 | 140 | @mark.parametrize( |
122 | 141 | "modifications, expected_events", |
123 | 142 | [ |
124 | 143 | # modifications of single attributes |
125 | | - ([["source", "'b'"]], {TextEvent}), |
126 | | - ([["outputs", []]], {ArrayEvent}), |
127 | | - ([["execution_count", 2]], {MapEvent}), |
128 | | - ([["metadata", {"tags": []}]], {MapEvent}), |
129 | | - ([["new_key", "test"]], {MapEvent}), |
| 144 | + ([["source", "'b'"]], [ExpectedEvent(TextEvent)]), |
| 145 | + ([["execution_count", 2]], [ExpectedEvent(MapEvent)]), |
| 146 | + ([["metadata", {"tags": []}]], [ExpectedEvent(MapEvent)]), |
| 147 | + ([["new_key", "test"]], [ExpectedEvent(MapEvent)]), |
| 148 | + # outputs can be cleared using granular logic |
| 149 | + ([["outputs", []]], [ExpectedEvent(ArrayEvent, path=[0, "outputs"])]), |
| 150 | + # stream outputs require a hard cell reload, which is why we expect top-level array change |
| 151 | + ( |
| 152 | + [["outputs", [{"name": "stdout", "output_type": "stream", "text": "b\n"}]]], |
| 153 | + [ExpectedEvent(ArrayEvent, path=[])], |
| 154 | + ), |
| 155 | + # other output types can be changed granularly |
| 156 | + ( |
| 157 | + [ |
| 158 | + [ |
| 159 | + "outputs", |
| 160 | + [ |
| 161 | + { |
| 162 | + "data": {"text/plain": ["1"]}, |
| 163 | + "execution_count": 1, |
| 164 | + "metadata": {}, |
| 165 | + "output_type": "execute_result", |
| 166 | + } |
| 167 | + ], |
| 168 | + ] |
| 169 | + ], |
| 170 | + [ExpectedEvent(ArrayEvent, path=[0, "outputs"])], |
| 171 | + ), |
130 | 172 | # multi-attribute modifications |
131 | | - ([["source", "10"], ["execution_count", 10]], {TextEvent, MapEvent}), |
| 173 | + ( |
| 174 | + [["source", "10"], ["execution_count", 10]], |
| 175 | + [ExpectedEvent(MapEvent), ExpectedEvent(TextEvent)], |
| 176 | + ), |
132 | 177 | ], |
133 | 178 | ) |
134 | 179 | def test_modify_single_cell(modifications, expected_events): |
@@ -177,5 +222,4 @@ def record_changes(topic, event): |
177 | 222 | assert len(cell_events) == 1 |
178 | 223 | # but it should be a change to cell data, not a change to the cell list |
179 | 224 | events = cell_events[0] |
180 | | - assert len(events) == len(expected_events) |
181 | | - assert {type(e) for e in events} == expected_events |
| 225 | + assert events == expected_events |
0 commit comments