add a mirror and reorg mirrors
[lines.love.git] / drawing_tests.lua
blobede25f007a89d9d4904a9a92fe093330c6ea2b6c
1 -- major tests for drawings
2 -- We minimize assumptions about specific pixels, and try to test at the level
3 -- of specific shapes. In particular, no tests of freehand drawings.
5 function test_creating_drawing_saves()
6 App.screen.init{width=120, height=60}
7 Editor_state = edit.initialize_test_state()
8 Editor_state.filename = 'foo'
9 Editor_state.lines = load_array{}
10 Text.redraw_all(Editor_state)
11 edit.draw(Editor_state)
12 -- click on button to create drawing
13 edit.run_after_mouse_click(Editor_state, 8,Editor_state.top+8, 1)
14 -- file not immediately saved
15 edit.update(Editor_state, 0.01)
16 check_nil(App.filesystem['foo'], 'early')
17 -- wait until save
18 Current_time = Current_time + 3.1
19 edit.update(Editor_state, 0)
20 -- filesystem contains drawing and an empty line of text
21 check_eq(App.filesystem['foo'], '```lines\n```\n\n', 'check')
22 end
24 function test_draw_line()
25 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
26 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
27 Editor_state = edit.initialize_test_state()
28 Editor_state.filename = 'foo'
29 Editor_state.lines = load_array{'```lines', '```', ''}
30 Text.redraw_all(Editor_state)
31 Editor_state.current_drawing_mode = 'line'
32 edit.draw(Editor_state)
33 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
34 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
35 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
36 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
37 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
38 -- draw a line
39 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
40 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
41 local drawing = Editor_state.lines[1]
42 check_eq(#drawing.shapes, 1, '#shapes')
43 check_eq(#drawing.points, 2, '#points')
44 check_eq(drawing.shapes[1].mode, 'line', 'shape:1')
45 local p1 = drawing.points[drawing.shapes[1].p1]
46 local p2 = drawing.points[drawing.shapes[1].p2]
47 check_eq(p1.x, 5, 'p1:x')
48 check_eq(p1.y, 6, 'p1:y')
49 check_eq(p2.x, 35, 'p2:x')
50 check_eq(p2.y, 36, 'p2:y')
51 -- wait until save
52 Current_time = Current_time + 3.1
53 edit.update(Editor_state, 0)
54 -- The format on disk isn't perfectly stable. Table fields can be reordered.
55 -- So just reload from disk to verify.
56 load_from_disk(Editor_state)
57 Text.redraw_all(Editor_state)
58 local drawing = Editor_state.lines[1]
59 check_eq(#drawing.shapes, 1, 'save/#shapes')
60 check_eq(#drawing.points, 2, 'save/#points')
61 check_eq(drawing.shapes[1].mode, 'line', 'save/shape:1')
62 local p1 = drawing.points[drawing.shapes[1].p1]
63 local p2 = drawing.points[drawing.shapes[1].p2]
64 check_eq(p1.x, 5, 'save/p1:x')
65 check_eq(p1.y, 6, 'save/p1:y')
66 check_eq(p2.x, 35, 'save/p2:x')
67 check_eq(p2.y, 36, 'save/p2:y')
68 end
70 function test_draw_horizontal_line()
71 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
72 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
73 Editor_state = edit.initialize_test_state()
74 Editor_state.lines = load_array{'```lines', '```', ''}
75 Text.redraw_all(Editor_state)
76 Editor_state.current_drawing_mode = 'manhattan'
77 edit.draw(Editor_state)
78 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
79 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
80 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
81 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
82 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
83 -- draw a line that is more horizontal than vertical
84 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
85 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+26, 1)
86 local drawing = Editor_state.lines[1]
87 check_eq(#drawing.shapes, 1, '#shapes')
88 check_eq(#drawing.points, 2, '#points')
89 check_eq(drawing.shapes[1].mode, 'manhattan', 'shape_mode')
90 local p1 = drawing.points[drawing.shapes[1].p1]
91 local p2 = drawing.points[drawing.shapes[1].p2]
92 check_eq(p1.x, 5, 'p1:x')
93 check_eq(p1.y, 6, 'p1:y')
94 check_eq(p2.x, 35, 'p2:x')
95 check_eq(p2.y, p1.y, 'p2:y')
96 end
98 function test_draw_circle()
99 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
100 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
101 Editor_state = edit.initialize_test_state()
102 Editor_state.lines = load_array{'```lines', '```', ''}
103 Text.redraw_all(Editor_state)
104 Editor_state.current_drawing_mode = 'line'
105 edit.draw(Editor_state)
106 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
107 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
108 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
109 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
110 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
111 -- draw a circle
112 App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
113 edit.run_after_keychord(Editor_state, 'C-o', 'o')
114 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
115 edit.run_after_mouse_release(Editor_state, Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36, 1)
116 local drawing = Editor_state.lines[1]
117 check_eq(#drawing.shapes, 1, '#shapes')
118 check_eq(#drawing.points, 1, '#points')
119 check_eq(drawing.shapes[1].mode, 'circle', 'shape_mode')
120 check_eq(drawing.shapes[1].radius, 30, 'radius')
121 local center = drawing.points[drawing.shapes[1].center]
122 check_eq(center.x, 35, 'center:x')
123 check_eq(center.y, 36, 'center:y')
126 function test_cancel_stroke()
127 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
128 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
129 Editor_state = edit.initialize_test_state()
130 Editor_state.filename = 'foo'
131 Editor_state.lines = load_array{'```lines', '```', ''}
132 Text.redraw_all(Editor_state)
133 Editor_state.current_drawing_mode = 'line'
134 edit.draw(Editor_state)
135 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
136 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
137 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
138 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
139 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
140 -- start drawing a line
141 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
142 -- cancel
143 edit.run_after_keychord(Editor_state, 'escape', 'escape')
144 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
145 local drawing = Editor_state.lines[1]
146 check_eq(#drawing.shapes, 0, '#shapes')
149 function test_keys_do_not_affect_shape_when_mouse_up()
150 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
151 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
152 Editor_state = edit.initialize_test_state()
153 Editor_state.lines = load_array{'```lines', '```', ''}
154 Text.redraw_all(Editor_state)
155 Editor_state.current_drawing_mode = 'line'
156 edit.draw(Editor_state)
157 -- hover over drawing and press 'o' without holding mouse
158 App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
159 edit.run_after_keychord(Editor_state, 'o', 'o')
160 -- no change to drawing mode
161 check_eq(Editor_state.current_drawing_mode, 'line', 'drawing_mode')
162 -- no change to text either because we didn't run the text_input event
165 function test_draw_circle_mid_stroke()
166 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
167 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
168 Editor_state = edit.initialize_test_state()
169 Editor_state.lines = load_array{'```lines', '```', ''}
170 Text.redraw_all(Editor_state)
171 Editor_state.current_drawing_mode = 'line'
172 edit.draw(Editor_state)
173 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
174 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
175 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
176 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
177 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
178 -- draw a circle
179 App.mouse_move(Editor_state.left+4, Editor_state.top+Drawing_padding_top+4) -- hover on drawing
180 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
181 edit.run_after_text_input(Editor_state, 'o')
182 edit.run_after_mouse_release(Editor_state, Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36, 1)
183 local drawing = Editor_state.lines[1]
184 check_eq(#drawing.shapes, 1, '#shapes')
185 check_eq(#drawing.points, 1, '#points')
186 check_eq(drawing.shapes[1].mode, 'circle', 'shape_mode')
187 check_eq(drawing.shapes[1].radius, 30, 'radius')
188 local center = drawing.points[drawing.shapes[1].center]
189 check_eq(center.x, 35, 'center:x')
190 check_eq(center.y, 36, 'center:y')
193 function test_draw_arc()
194 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
195 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
196 Editor_state = edit.initialize_test_state()
197 Editor_state.lines = load_array{'```lines', '```', ''}
198 Text.redraw_all(Editor_state)
199 Editor_state.current_drawing_mode = 'circle'
200 edit.draw(Editor_state)
201 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
202 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
203 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
204 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
205 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
206 -- draw an arc
207 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
208 App.mouse_move(Editor_state.left+35+30, Editor_state.top+Drawing_padding_top+36)
209 edit.run_after_text_input(Editor_state, 'a') -- arc mode
210 edit.run_after_mouse_release(Editor_state, Editor_state.left+35+50, Editor_state.top+Drawing_padding_top+36+50, 1) -- 45°
211 local drawing = Editor_state.lines[1]
212 check_eq(#drawing.shapes, 1, '#shapes')
213 check_eq(#drawing.points, 1, '#points')
214 check_eq(drawing.shapes[1].mode, 'arc', 'shape_mode')
215 local arc = drawing.shapes[1]
216 check_eq(arc.radius, 30, 'radius')
217 local center = drawing.points[arc.center]
218 check_eq(center.x, 35, 'center:x')
219 check_eq(center.y, 36, 'center:y')
220 check_eq(arc.start_angle, 0, 'start:angle')
221 check_eq(arc.end_angle, math.pi/4, 'end:angle')
224 function test_draw_polygon()
225 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
226 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
227 Editor_state = edit.initialize_test_state()
228 Editor_state.lines = load_array{'```lines', '```', ''}
229 Text.redraw_all(Editor_state)
230 edit.draw(Editor_state)
231 check_eq(Editor_state.current_drawing_mode, 'line', 'baseline/drawing_mode')
232 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
233 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
234 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
235 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
236 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
237 -- first point
238 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
239 edit.run_after_text_input(Editor_state, 'g') -- polygon mode
240 -- second point
241 App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
242 edit.run_after_text_input(Editor_state, 'p') -- add point
243 -- final point
244 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+26, 1)
245 local drawing = Editor_state.lines[1]
246 check_eq(#drawing.shapes, 1, '#shapes')
247 check_eq(#drawing.points, 3, 'vertices')
248 local shape = drawing.shapes[1]
249 check_eq(shape.mode, 'polygon', 'shape_mode')
250 check_eq(#shape.vertices, 3, 'vertices')
251 local p = drawing.points[shape.vertices[1]]
252 check_eq(p.x, 5, 'p1:x')
253 check_eq(p.y, 6, 'p1:y')
254 local p = drawing.points[shape.vertices[2]]
255 check_eq(p.x, 65, 'p2:x')
256 check_eq(p.y, 36, 'p2:y')
257 local p = drawing.points[shape.vertices[3]]
258 check_eq(p.x, 35, 'p3:x')
259 check_eq(p.y, 26, 'p3:y')
262 function test_draw_rectangle()
263 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
264 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
265 Editor_state = edit.initialize_test_state()
266 Editor_state.lines = load_array{'```lines', '```', ''}
267 Text.redraw_all(Editor_state)
268 edit.draw(Editor_state)
269 check_eq(Editor_state.current_drawing_mode, 'line', 'baseline/drawing_mode')
270 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
271 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
272 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
273 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
274 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
275 -- first point
276 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
277 edit.run_after_text_input(Editor_state, 'r') -- rectangle mode
278 -- second point/first edge
279 App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
280 edit.run_after_text_input(Editor_state, 'p')
281 -- override second point/first edge
282 App.mouse_move(Editor_state.left+75, Editor_state.top+Drawing_padding_top+76)
283 edit.run_after_text_input(Editor_state, 'p')
284 -- release (decides 'thickness' of rectangle perpendicular to first edge)
285 edit.run_after_mouse_release(Editor_state, Editor_state.left+15, Editor_state.top+Drawing_padding_top+26, 1)
286 local drawing = Editor_state.lines[1]
287 check_eq(#drawing.shapes, 1, '#shapes')
288 check_eq(#drawing.points, 5, '#points') -- currently includes every point added
289 local shape = drawing.shapes[1]
290 check_eq(shape.mode, 'rectangle', 'shape_mode')
291 check_eq(#shape.vertices, 4, 'vertices')
292 local p = drawing.points[shape.vertices[1]]
293 check_eq(p.x, 35, 'p1:x')
294 check_eq(p.y, 36, 'p1:y')
295 local p = drawing.points[shape.vertices[2]]
296 check_eq(p.x, 75, 'p2:x')
297 check_eq(p.y, 76, 'p2:y')
298 local p = drawing.points[shape.vertices[3]]
299 check_eq(p.x, 70, 'p3:x')
300 check_eq(p.y, 81, 'p3:y')
301 local p = drawing.points[shape.vertices[4]]
302 check_eq(p.x, 30, 'p4:x')
303 check_eq(p.y, 41, 'p4:y')
306 function test_draw_rectangle_intermediate()
307 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
308 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
309 Editor_state = edit.initialize_test_state()
310 Editor_state.lines = load_array{'```lines', '```', ''}
311 Text.redraw_all(Editor_state)
312 edit.draw(Editor_state)
313 check_eq(Editor_state.current_drawing_mode, 'line', 'baseline/drawing_mode')
314 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
315 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
316 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
317 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
318 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
319 -- first point
320 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
321 edit.run_after_text_input(Editor_state, 'r') -- rectangle mode
322 -- second point/first edge
323 App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
324 edit.run_after_text_input(Editor_state, 'p')
325 -- override second point/first edge
326 App.mouse_move(Editor_state.left+75, Editor_state.top+Drawing_padding_top+76)
327 edit.run_after_text_input(Editor_state, 'p')
328 local drawing = Editor_state.lines[1]
329 check_eq(#drawing.points, 3, '#points') -- currently includes every point added
330 local pending = drawing.pending
331 check_eq(pending.mode, 'rectangle', 'shape_mode')
332 check_eq(#pending.vertices, 2, 'vertices')
333 local p = drawing.points[pending.vertices[1]]
334 check_eq(p.x, 35, 'p1:x')
335 check_eq(p.y, 36, 'p1:y')
336 local p = drawing.points[pending.vertices[2]]
337 check_eq(p.x, 75, 'p2:x')
338 check_eq(p.y, 76, 'p2:y')
339 -- outline of rectangle is drawn based on where the mouse is, but we can't check that so far
342 function test_draw_square()
343 -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
344 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
345 Editor_state = edit.initialize_test_state()
346 Editor_state.lines = load_array{'```lines', '```', ''}
347 Text.redraw_all(Editor_state)
348 edit.draw(Editor_state)
349 check_eq(Editor_state.current_drawing_mode, 'line', 'baseline/drawing_mode')
350 check_eq(#Editor_state.lines, 2, 'baseline/#lines')
351 check_eq(Editor_state.lines[1].mode, 'drawing', 'baseline/mode')
352 check_eq(Editor_state.line_cache[1].starty, Editor_state.top+Drawing_padding_top, 'baseline/y')
353 check_eq(Editor_state.lines[1].h, 128, 'baseline/y')
354 check_eq(#Editor_state.lines[1].shapes, 0, 'baseline/#shapes')
355 -- first point
356 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
357 edit.run_after_text_input(Editor_state, 's') -- square mode
358 -- second point/first edge
359 App.mouse_move(Editor_state.left+42, Editor_state.top+Drawing_padding_top+45)
360 edit.run_after_text_input(Editor_state, 'p')
361 -- override second point/first edge
362 App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+66)
363 edit.run_after_text_input(Editor_state, 'p')
364 -- release (decides which side of first edge to draw square on)
365 edit.run_after_mouse_release(Editor_state, Editor_state.left+15, Editor_state.top+Drawing_padding_top+26, 1)
366 local drawing = Editor_state.lines[1]
367 check_eq(#drawing.shapes, 1, '#shapes')
368 check_eq(#drawing.points, 5, '#points') -- currently includes every point added
369 check_eq(drawing.shapes[1].mode, 'square', 'shape_mode')
370 check_eq(#drawing.shapes[1].vertices, 4, 'vertices')
371 local p = drawing.points[drawing.shapes[1].vertices[1]]
372 check_eq(p.x, 35, 'p1:x')
373 check_eq(p.y, 36, 'p1:y')
374 local p = drawing.points[drawing.shapes[1].vertices[2]]
375 check_eq(p.x, 65, 'p2:x')
376 check_eq(p.y, 66, 'p2:y')
377 local p = drawing.points[drawing.shapes[1].vertices[3]]
378 check_eq(p.x, 35, 'p3:x')
379 check_eq(p.y, 96, 'p3:y')
380 local p = drawing.points[drawing.shapes[1].vertices[4]]
381 check_eq(p.x, 5, 'p4:x')
382 check_eq(p.y, 66, 'p4:y')
385 function test_name_point()
386 -- create a drawing with a line
387 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
388 Editor_state = edit.initialize_test_state()
389 Editor_state.filename = 'foo'
390 Editor_state.lines = load_array{'```lines', '```', ''}
391 Text.redraw_all(Editor_state)
392 Editor_state.current_drawing_mode = 'line'
393 edit.draw(Editor_state)
394 -- draw a line
395 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
396 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
397 local drawing = Editor_state.lines[1]
398 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
399 check_eq(#drawing.points, 2, 'baseline/#points')
400 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
401 local p1 = drawing.points[drawing.shapes[1].p1]
402 local p2 = drawing.points[drawing.shapes[1].p2]
403 check_eq(p1.x, 5, 'baseline/p1:x')
404 check_eq(p1.y, 6, 'baseline/p1:y')
405 check_eq(p2.x, 35, 'baseline/p2:x')
406 check_eq(p2.y, 36, 'baseline/p2:y')
407 check_nil(p2.name, 'baseline/p2:name')
408 -- enter 'name' mode without moving the mouse
409 edit.run_after_keychord(Editor_state, 'C-n', 'n')
410 check_eq(Editor_state.current_drawing_mode, 'name', 'mode:1')
411 edit.run_after_text_input(Editor_state, 'A')
412 check_eq(p2.name, 'A', 'check1')
413 -- still in 'name' mode
414 check_eq(Editor_state.current_drawing_mode, 'name', 'mode:2')
415 -- exit 'name' mode
416 edit.run_after_keychord(Editor_state, 'return', 'return')
417 check_eq(Editor_state.current_drawing_mode, 'line', 'mode:3')
418 check_eq(p2.name, 'A', 'check2')
419 -- wait until save
420 Current_time = Current_time + 3.1
421 edit.update(Editor_state, 0)
422 -- change is saved
423 load_from_disk(Editor_state)
424 Text.redraw_all(Editor_state)
425 local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
426 check_eq(p2.name, 'A', 'save')
429 function test_name_point_then_hit_backspace()
430 -- create a drawing with a line
431 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
432 Editor_state = edit.initialize_test_state()
433 Editor_state.filename = 'foo'
434 Editor_state.lines = load_array{'```lines', '```', ''}
435 Text.redraw_all(Editor_state)
436 Editor_state.current_drawing_mode = 'line'
437 edit.draw(Editor_state)
438 -- draw a line
439 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
440 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
441 local drawing = Editor_state.lines[1]
442 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
443 check_eq(#drawing.points, 2, 'baseline/#points')
444 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
445 local p1 = drawing.points[drawing.shapes[1].p1]
446 local p2 = drawing.points[drawing.shapes[1].p2]
447 check_eq(p1.x, 5, 'baseline/p1:x')
448 check_eq(p1.y, 6, 'baseline/p1:y')
449 check_eq(p2.x, 35, 'baseline/p2:x')
450 check_eq(p2.y, 36, 'baseline/p2:y')
451 check_nil(p2.name, 'baseline/p2:name')
452 -- enter 'name' mode without moving the mouse
453 edit.run_after_keychord(Editor_state, 'C-n', 'n')
454 check_eq(Editor_state.current_drawing_mode, 'name', 'mode:1')
455 -- hit backspace
456 edit.run_after_keychord(Editor_state, 'backspace', 'backspace')
457 -- no crash
460 function test_name_point_then_exit_drawing()
461 -- create a drawing with a line
462 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
463 Editor_state = edit.initialize_test_state()
464 Editor_state.filename = 'foo'
465 Editor_state.lines = load_array{'```lines', '```', ''}
466 Text.redraw_all(Editor_state)
467 edit.check_locs(Editor_state)
468 Editor_state.current_drawing_mode = 'line'
469 edit.draw(Editor_state)
470 -- draw a line
471 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
472 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
473 local drawing = Editor_state.lines[1]
474 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
475 check_eq(#drawing.points, 2, 'baseline/#points')
476 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
477 local p1 = drawing.points[drawing.shapes[1].p1]
478 local p2 = drawing.points[drawing.shapes[1].p2]
479 check_eq(p1.x, 5, 'baseline/p1:x')
480 check_eq(p1.y, 6, 'baseline/p1:y')
481 check_eq(p2.x, 35, 'baseline/p2:x')
482 check_eq(p2.y, 36, 'baseline/p2:y')
483 check_nil(p2.name, 'baseline/p2:name')
484 -- enter 'name' mode without moving the mouse
485 edit.run_after_keychord(Editor_state, 'C-n', 'n')
486 check_eq(Editor_state.current_drawing_mode, 'name', 'mode:1')
487 -- click outside the drawing
488 edit.run_after_mouse_click(Editor_state, App.screen.width-5, App.screen.height-5, 1)
489 -- press a key
490 edit.run_after_text_input(Editor_state, 'a')
491 -- key goes to text
492 check_eq(Editor_state.lines[2].data, 'a')
495 function test_move_point()
496 -- create a drawing with a line
497 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
498 Editor_state = edit.initialize_test_state()
499 Editor_state.filename = 'foo'
500 Editor_state.lines = load_array{'```lines', '```', ''}
501 Text.redraw_all(Editor_state)
502 Editor_state.current_drawing_mode = 'line'
503 edit.draw(Editor_state)
504 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
505 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
506 local drawing = Editor_state.lines[1]
507 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
508 check_eq(#drawing.points, 2, 'baseline/#points')
509 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
510 local p1 = drawing.points[drawing.shapes[1].p1]
511 local p2 = drawing.points[drawing.shapes[1].p2]
512 check_eq(p1.x, 5, 'baseline/p1:x')
513 check_eq(p1.y, 6, 'baseline/p1:y')
514 check_eq(p2.x, 35, 'baseline/p2:x')
515 check_eq(p2.y, 36, 'baseline/p2:y')
516 -- wait until save
517 Current_time = Current_time + 3.1
518 edit.update(Editor_state, 0)
519 -- line is saved to disk
520 load_from_disk(Editor_state)
521 Text.redraw_all(Editor_state)
522 local drawing = Editor_state.lines[1]
523 local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
524 check_eq(p2.x, 35, 'save/x')
525 check_eq(p2.y, 36, 'save/y')
526 edit.draw(Editor_state)
527 -- enter 'move' mode without moving the mouse
528 edit.run_after_keychord(Editor_state, 'C-u', 'u')
529 check_eq(Editor_state.current_drawing_mode, 'move', 'mode:1')
530 -- point is lifted
531 check_eq(drawing.pending.mode, 'move', 'mode:2')
532 check_eq(drawing.pending.target_point, p2, 'target')
533 -- move point
534 App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
535 edit.update(Editor_state, 0.05)
536 local p2 = drawing.points[drawing.shapes[1].p2]
537 check_eq(p2.x, 26, 'x')
538 check_eq(p2.y, 44, 'y')
539 -- exit 'move' mode
540 edit.run_after_mouse_click(Editor_state, Editor_state.left+26, Editor_state.top+Drawing_padding_top+44, 1)
541 check_eq(Editor_state.current_drawing_mode, 'line', 'mode:3')
542 check_eq(drawing.pending, {}, 'pending')
543 -- wait until save
544 Current_time = Current_time + 3.1
545 edit.update(Editor_state, 0)
546 -- change is saved
547 load_from_disk(Editor_state)
548 Text.redraw_all(Editor_state)
549 local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
550 check_eq(p2.x, 26, 'save/x')
551 check_eq(p2.y, 44, 'save/y')
554 function test_move_point_on_manhattan_line()
555 -- create a drawing with a manhattan line
556 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
557 Editor_state = edit.initialize_test_state()
558 Editor_state.filename = 'foo'
559 Editor_state.lines = load_array{'```lines', '```', ''}
560 Text.redraw_all(Editor_state)
561 Editor_state.current_drawing_mode = 'manhattan'
562 edit.draw(Editor_state)
563 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
564 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+46, 1)
565 local drawing = Editor_state.lines[1]
566 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
567 check_eq(#drawing.points, 2, 'baseline/#points')
568 check_eq(drawing.shapes[1].mode, 'manhattan', 'baseline/shape:1')
569 edit.draw(Editor_state)
570 -- enter 'move' mode
571 edit.run_after_keychord(Editor_state, 'C-u', 'u')
572 check_eq(Editor_state.current_drawing_mode, 'move', 'mode:1')
573 -- move point
574 App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
575 edit.update(Editor_state, 0.05)
576 -- line is no longer manhattan
577 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
580 function test_delete_lines_at_point()
581 -- create a drawing with two lines connected at a point
582 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
583 Editor_state = edit.initialize_test_state()
584 Editor_state.filename = 'foo'
585 Editor_state.lines = load_array{'```lines', '```', ''}
586 Text.redraw_all(Editor_state)
587 Editor_state.current_drawing_mode = 'line'
588 edit.draw(Editor_state)
589 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
590 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
591 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
592 edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
593 local drawing = Editor_state.lines[1]
594 check_eq(#drawing.shapes, 2, 'baseline/#shapes')
595 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
596 check_eq(drawing.shapes[2].mode, 'line', 'baseline/shape:2')
597 -- hover on the common point and delete
598 App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+36)
599 edit.run_after_keychord(Editor_state, 'C-d', 'd')
600 check_eq(drawing.shapes[1].mode, 'deleted', 'shape:1')
601 check_eq(drawing.shapes[2].mode, 'deleted', 'shape:2')
602 -- wait for some time
603 Current_time = Current_time + 3.1
604 edit.update(Editor_state, 0)
605 -- deleted points disappear after file is reloaded
606 load_from_disk(Editor_state)
607 Text.redraw_all(Editor_state)
608 check_eq(#Editor_state.lines[1].shapes, 0, 'save')
611 function test_delete_line_under_mouse_pointer()
612 -- create a drawing with two lines connected at a point
613 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
614 Editor_state = edit.initialize_test_state()
615 Editor_state.lines = load_array{'```lines', '```', ''}
616 Text.redraw_all(Editor_state)
617 Editor_state.current_drawing_mode = 'line'
618 edit.draw(Editor_state)
619 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
620 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
621 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
622 edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
623 local drawing = Editor_state.lines[1]
624 check_eq(#drawing.shapes, 2, 'baseline/#shapes')
625 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
626 check_eq(drawing.shapes[2].mode, 'line', 'baseline/shape:2')
627 -- hover on one of the lines and delete
628 App.mouse_move(Editor_state.left+25, Editor_state.top+Drawing_padding_top+26)
629 edit.run_after_keychord(Editor_state, 'C-d', 'd')
630 -- only that line is deleted
631 check_eq(drawing.shapes[1].mode, 'deleted', 'shape:1')
632 check_eq(drawing.shapes[2].mode, 'line', 'shape:2')
635 function test_delete_point_from_polygon()
636 -- create a drawing with two lines connected at a point
637 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
638 Editor_state = edit.initialize_test_state()
639 Editor_state.lines = load_array{'```lines', '```', ''}
640 Text.redraw_all(Editor_state)
641 Editor_state.current_drawing_mode = 'line'
642 edit.draw(Editor_state)
643 -- first point
644 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
645 edit.run_after_text_input(Editor_state, 'g') -- polygon mode
646 -- second point
647 App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
648 edit.run_after_text_input(Editor_state, 'p') -- add point
649 -- third point
650 App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+26)
651 edit.run_after_text_input(Editor_state, 'p') -- add point
652 -- fourth point
653 edit.run_after_mouse_release(Editor_state, Editor_state.left+14, Editor_state.top+Drawing_padding_top+16, 1)
654 local drawing = Editor_state.lines[1]
655 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
656 check_eq(drawing.shapes[1].mode, 'polygon', 'baseline/mode')
657 check_eq(#drawing.shapes[1].vertices, 4, 'baseline/vertices')
658 -- hover on a point and delete
659 App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+26)
660 edit.run_after_keychord(Editor_state, 'C-d', 'd')
661 -- just the one point is deleted
662 check_eq(drawing.shapes[1].mode, 'polygon', 'shape')
663 check_eq(#drawing.shapes[1].vertices, 3, 'vertices')
666 function test_delete_point_from_polygon()
667 -- create a drawing with two lines connected at a point
668 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
669 Editor_state = edit.initialize_test_state()
670 Editor_state.lines = load_array{'```lines', '```', ''}
671 Text.redraw_all(Editor_state)
672 Editor_state.current_drawing_mode = 'line'
673 edit.draw(Editor_state)
674 -- first point
675 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
676 edit.run_after_text_input(Editor_state, 'g') -- polygon mode
677 -- second point
678 App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
679 edit.run_after_text_input(Editor_state, 'p') -- add point
680 -- third point
681 edit.run_after_mouse_release(Editor_state, Editor_state.left+14, Editor_state.top+Drawing_padding_top+16, 1)
682 local drawing = Editor_state.lines[1]
683 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
684 check_eq(drawing.shapes[1].mode, 'polygon', 'baseline/mode')
685 check_eq(#drawing.shapes[1].vertices, 3, 'baseline/vertices')
686 -- hover on a point and delete
687 App.mouse_move(Editor_state.left+65, Editor_state.top+Drawing_padding_top+36)
688 edit.run_after_keychord(Editor_state, 'C-d', 'd')
689 -- there's < 3 points left, so the whole polygon is deleted
690 check_eq(drawing.shapes[1].mode, 'deleted', 'check')
693 function test_undo_name_point()
694 -- create a drawing with a line
695 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
696 Editor_state = edit.initialize_test_state()
697 Editor_state.filename = 'foo'
698 Editor_state.lines = load_array{'```lines', '```', ''}
699 Text.redraw_all(Editor_state)
700 Editor_state.current_drawing_mode = 'line'
701 edit.draw(Editor_state)
702 -- draw a line
703 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
704 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
705 local drawing = Editor_state.lines[1]
706 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
707 check_eq(#drawing.points, 2, 'baseline/#points')
708 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
709 local p1 = drawing.points[drawing.shapes[1].p1]
710 local p2 = drawing.points[drawing.shapes[1].p2]
711 check_eq(p1.x, 5, 'baseline/p1:x')
712 check_eq(p1.y, 6, 'baseline/p1:y')
713 check_eq(p2.x, 35, 'baseline/p2:x')
714 check_eq(p2.y, 36, 'baseline/p2:y')
715 check_nil(p2.name, 'baseline/p2:name')
716 check_eq(#Editor_state.history, 1, 'baseline/history:1')
717 --? print('a', Editor_state.lines.current_drawing)
718 -- enter 'name' mode without moving the mouse
719 edit.run_after_keychord(Editor_state, 'C-n', 'n')
720 edit.run_after_text_input(Editor_state, 'A')
721 edit.run_after_keychord(Editor_state, 'return', 'return')
722 check_eq(p2.name, 'A', 'baseline')
723 check_eq(#Editor_state.history, 3, 'baseline/history:2')
724 check_eq(Editor_state.next_history, 4, 'baseline/next_history')
725 --? print('b', Editor_state.lines.current_drawing)
726 -- undo
727 edit.run_after_keychord(Editor_state, 'C-z', 'z')
728 local drawing = Editor_state.lines[1]
729 local p2 = drawing.points[drawing.shapes[1].p2]
730 check_eq(Editor_state.next_history, 3, 'next_history')
731 check_eq(p2.name, '', 'undo') -- not quite what it was before, but close enough
732 -- wait until save
733 Current_time = Current_time + 3.1
734 edit.update(Editor_state, 0)
735 -- undo is saved
736 load_from_disk(Editor_state)
737 Text.redraw_all(Editor_state)
738 local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
739 check_eq(p2.name, '', 'save')
742 function test_undo_move_point()
743 -- create a drawing with a line
744 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
745 Editor_state = edit.initialize_test_state()
746 Editor_state.filename = 'foo'
747 Editor_state.lines = load_array{'```lines', '```', ''}
748 Text.redraw_all(Editor_state)
749 Editor_state.current_drawing_mode = 'line'
750 edit.draw(Editor_state)
751 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
752 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
753 local drawing = Editor_state.lines[1]
754 check_eq(#drawing.shapes, 1, 'baseline/#shapes')
755 check_eq(#drawing.points, 2, 'baseline/#points')
756 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
757 local p1 = drawing.points[drawing.shapes[1].p1]
758 local p2 = drawing.points[drawing.shapes[1].p2]
759 check_eq(p1.x, 5, 'baseline/p1:x')
760 check_eq(p1.y, 6, 'baseline/p1:y')
761 check_eq(p2.x, 35, 'baseline/p2:x')
762 check_eq(p2.y, 36, 'baseline/p2:y')
763 check_nil(p2.name, 'baseline/p2:name')
764 -- move p2
765 edit.run_after_keychord(Editor_state, 'C-u', 'u')
766 App.mouse_move(Editor_state.left+26, Editor_state.top+Drawing_padding_top+44)
767 edit.update(Editor_state, 0.05)
768 local p2 = drawing.points[drawing.shapes[1].p2]
769 check_eq(p2.x, 26, 'x')
770 check_eq(p2.y, 44, 'y')
771 -- exit 'move' mode
772 edit.run_after_mouse_click(Editor_state, Editor_state.left+26, Editor_state.top+Drawing_padding_top+44, 1)
773 check_eq(Editor_state.next_history, 4, 'next_history')
774 -- undo
775 edit.run_after_keychord(Editor_state, 'C-z', 'z')
776 edit.run_after_keychord(Editor_state, 'C-z', 'z') -- bug: need to undo twice
777 local drawing = Editor_state.lines[1]
778 local p2 = drawing.points[drawing.shapes[1].p2]
779 check_eq(Editor_state.next_history, 2, 'next_history')
780 check_eq(p2.x, 35, 'x')
781 check_eq(p2.y, 36, 'y')
782 -- wait until save
783 Current_time = Current_time + 3.1
784 edit.update(Editor_state, 0)
785 -- undo is saved
786 load_from_disk(Editor_state)
787 Text.redraw_all(Editor_state)
788 local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
789 check_eq(p2.x, 35, 'save/x')
790 check_eq(p2.y, 36, 'save/y')
793 function test_undo_delete_point()
794 -- create a drawing with two lines connected at a point
795 App.screen.init{width=Test_margin_left+256, height=300} -- drawing coordinates 1:1 with pixels
796 Editor_state = edit.initialize_test_state()
797 Editor_state.filename = 'foo'
798 Editor_state.lines = load_array{'```lines', '```', ''}
799 Text.redraw_all(Editor_state)
800 Editor_state.current_drawing_mode = 'line'
801 edit.draw(Editor_state)
802 edit.run_after_mouse_press(Editor_state, Editor_state.left+5, Editor_state.top+Drawing_padding_top+6, 1)
803 edit.run_after_mouse_release(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
804 edit.run_after_mouse_press(Editor_state, Editor_state.left+35, Editor_state.top+Drawing_padding_top+36, 1)
805 edit.run_after_mouse_release(Editor_state, Editor_state.left+55, Editor_state.top+Drawing_padding_top+26, 1)
806 local drawing = Editor_state.lines[1]
807 check_eq(#drawing.shapes, 2, 'baseline/#shapes')
808 check_eq(drawing.shapes[1].mode, 'line', 'baseline/shape:1')
809 check_eq(drawing.shapes[2].mode, 'line', 'baseline/shape:2')
810 -- hover on the common point and delete
811 App.mouse_move(Editor_state.left+35, Editor_state.top+Drawing_padding_top+36)
812 edit.run_after_keychord(Editor_state, 'C-d', 'd')
813 check_eq(drawing.shapes[1].mode, 'deleted', 'shape:1')
814 check_eq(drawing.shapes[2].mode, 'deleted', 'shape:2')
815 -- undo
816 edit.run_after_keychord(Editor_state, 'C-z', 'z')
817 local drawing = Editor_state.lines[1]
818 local p2 = drawing.points[drawing.shapes[1].p2]
819 check_eq(Editor_state.next_history, 3, 'next_history')
820 check_eq(drawing.shapes[1].mode, 'line', 'shape:1')
821 check_eq(drawing.shapes[2].mode, 'line', 'shape:2')
822 -- wait until save
823 Current_time = Current_time + 3.1
824 edit.update(Editor_state, 0)
825 -- undo is saved
826 load_from_disk(Editor_state)
827 Text.redraw_all(Editor_state)
828 check_eq(#Editor_state.lines[1].shapes, 2, 'save')