1 unit TestSynSharedEdits;
2 (* Test multiply edits sharing a textbuffer
3 *)
4
5 {$mode objfpc}{$H+}
6
7 interface
8
9 uses
10 Classes, SysUtils, testregistry, TestBase, LCLProc,
11 SynEdit, SynEditMarks, SynEditKeyCmds;
12
13 type
14
15 { TTestSynSharedEdits }
16
17 TTestSynSharedEdits = class(TTestBase)
18 private
19 FSynEdits : Array of TTestSynEdit;
20 protected
21 //procedure SetUp; override;
22 procedure TearDown; override;
23 procedure ReCreateEdit; reintroduce; overload;
24 procedure ReCreateEdit(Count: Integer); overload;
25 procedure SelectEdit(Index: Integer);
TestText1null26 function TestText1: TStringArray;
27 procedure CheckMarks(Name: String; EditIndex: Integer; MarkList: Array of Integer);
AddMarknull28 function AddMark(EditIndex: Integer; Y, X: Integer) : TSynEditMark;
29 published
30 procedure TestMarks;
31 procedure TestBookMarks;
32 end;
33
34 implementation
35
36
37 { TTestSynSharedEdits }
38
39 procedure TTestSynSharedEdits.TearDown;
40 var
41 i: Integer;
42 begin
43 FSynEdit := nil;
44 for i := 0 to length(FSynEdits) - 1 do
45 FSynEdits[i].Free;
46 SetLength(FSynEdits, 0);
47 inherited TearDown;
48 end;
49
50 procedure TTestSynSharedEdits.ReCreateEdit;
51 begin
52 ReCreateEdit(1);
53 end;
54
55 procedure TTestSynSharedEdits.ReCreateEdit(Count: Integer);
56 var
57 i: Integer;
58 begin
59 for i := 0 to length(FSynEdits) - 1 do
60 FSynEdits[i].Free;
61
62 SetLength(FSynEdits, Count);
63 Form.Height := 600;
64 Form.Width := 500;
65 for i := 0 to Count - 1 do begin
66 FSynEdits[i] := TTestSynEdit.Create(Form);
67 FSynEdits[i].Parent := Form;
68 FSynEdits[i].Top := 200 * i;
69 FSynEdits[i].Left := 0;
70 FSynEdits[i].Width:= 500;
71 FSynEdits[i].Height := 200; // FSynEdits[i].Font.Height * 20 + 2;
72 end;
73
74 FSynEdit := FSynEdits[0];
75 end;
76
77 procedure TTestSynSharedEdits.SelectEdit(Index: Integer);
78 begin
79 FSynEdit := FSynEdits[Index];
80 end;
81
TestText1null82 function TTestSynSharedEdits.TestText1: TStringArray;
83 begin
84 SetLength(Result, 8);
85 Result[0] := 'abc';
86 Result[1] := 'def 123;';
87 Result[2] := 'xyz 098765';
88 Result[3] := '';
89 Result[4] := '1';
90 Result[5] := ' mno...';
91 Result[6] := ' ABCDEF';
92 Result[7] := ' 321';
93 end;
94
95 procedure TTestSynSharedEdits.CheckMarks(Name: String; EditIndex: Integer;
96 MarkList: array of Integer);
97 var
98 m: TSynEditMark;
99 i: Integer;
100 begin
101 //for i := 0 to FSynEdits[EditIndex].Marks.Count - 1 do begin
102 // m := FSynEdits[EditIndex].Marks[i];
103 // debugln(['Mark ',i,' Line=',m.Line,' Col=',m.Column]);
104 //end;
105 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Count: ', length(MarkList) div 2, FSynEdits[EditIndex].Marks.Count);
106
107 for i := 0 to (length(MarkList) div 2) - 1 do begin
108 m := FSynEdits[EditIndex].Marks[i];
109 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Mark( '+IntToStr(i)+' ) Line: ', MarkList[i*2+0], m.Line);
110 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Mark( '+IntToStr(i)+' ) Column: ', MarkList[i*2+1], m.Column);
111 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Mark( '+IntToStr(i)+' ) IndexOf: ', i, FSynEdits[EditIndex].Marks.IndexOf(m));
112 end;
113 end;
114
AddMarknull115 function TTestSynSharedEdits.AddMark(EditIndex: Integer; Y, X: Integer): TSynEditMark;
116 begin
117 Result := TSynEditMark.Create(SynEdit);
118 Result.Line := Y;
119 Result.Column := X;
120 FSynEdits[EditIndex].Marks.Add(Result);
121 end;
122
123 procedure TTestSynSharedEdits.TestMarks;
124 begin
125 {%region share with marks}
126 ReCreateEdit(2);
127 PushBaseName('share with marks');
128
129 // default setting is shared marklist
130 FSynEdits[1].ShareOptions := [eosShareMarks];
131 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
132 SetLines(TestText1);
133
134 CheckMarks('empty', 0, []);
135 CheckMarks('empty', 1, []);
136
137 AddMark(0, 3,2);
138 CheckMarks('3/2', 0, [ 3,2 ]);
139 CheckMarks('3/2', 1, [ 3,2 ]);
140
141 AddMark(1, 5,2);
142 CheckMarks('3/2 - 5/1', 0, [ 3,2, 5,2 ]);
143 CheckMarks('3/2 - 5/1', 1, [ 3,2, 5,2 ]);
144
145 // move both
146 FSynEdits[0].CaretXY := Point(1, 4);
147 FSynEdits[0].CommandProcessor(ecLineBreak, ' ', nil);
148 CheckMarks('newline 3/2 - 6/1', 0, [ 3,2, 6,2 ]);
149 CheckMarks('newline 3/2 - 6/1', 1, [ 3,2, 6,2 ]);
150
151 // unshare again
152 FSynEdits[1].UnShareTextBuffer;
153 CheckMarks('unshared 3/2 - 5/1', 0, [ 3,2, 6,2 ]);
154 CheckMarks('unshared 3/2 - 5/1', 1, []); // empty has no marks of it's own
155
156 //move 1
157 FSynEdits[0].CaretXY := Point(1, 4); // after mark
158 FSynEdits[0].CommandProcessor(ecLineBreak, ' ', nil);
159
160 CheckMarks('unshared newline 3/2 - 5/1', 0, [ 3,2, 7,2 ]);
161 CheckMarks('unshared newline 3/2 - 5/1', 1, []); // empty has no marks of it's own
162
163 AddMark(0, 7,1);
164 CheckMarks('unshared add(0)', 0, [ 3,2, 7,2, 7,1 ]);
165 CheckMarks('unshared add(0)', 1, []);
166
167
168 AddMark(1, 3,1);
169 CheckMarks('unshared add(1)', 0, [ 3,2, 7,2, 7,1 ]);
170 CheckMarks('unshared add(1)', 1, [ 3,1]);
171
172 // delete mark from edit 0
173 FSynEdits[0].Marks[0].Free;
174 CheckMarks('unshared del(0)', 0, [7,2, 7,1 ]);
175 CheckMarks('unshared del(0)', 1, [ 3,1 ]);
176
177 {%endregion}
178
179 {%region share with marks / destroy 1st}
180 ReCreateEdit(2);
181 PopPushBaseName('share with marks / destroy 2nd');
182 // default setting is shared marklist
183 FSynEdits[1].ShareOptions := [eosShareMarks];
184 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
185 SetLines(TestText1);
186
187 // create setup
188 AddMark(0, 3,2);
189 AddMark(1, 5,2);
190 CheckMarks('3/2 - 5/1', 0, [ 3,2, 5,2 ]);
191 CheckMarks('3/2 - 5/1', 1, [ 3,2, 5,2 ]);
192
193 FreeAndNil(FSynEdits[0]);
194 CheckMarks('other destroyed', 1, [ 3,2, 5,2 ]);
195
196 //move 1
197 FSynEdits[1].CaretXY := Point(1, 4); // after mark
198 FSynEdits[1].CommandProcessor(ecLineBreak, ' ', nil);
199
200 CheckMarks('unshared newline 3/2 - 5/1', 1, [ 3,2, 6,2 ]);
201 {%endregion}
202
203 {%region share with marks / destroy 2nd}
204 ReCreateEdit(2);
205 PopPushBaseName('share with marks / destroy 2nd');
206 // default setting is shared marklist
207 FSynEdits[1].ShareOptions := [eosShareMarks];
208 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
209 SetLines(TestText1);
210
211 // create setup
212 AddMark(0, 3,2);
213 AddMark(1, 5,2);
214 CheckMarks('3/2 - 5/1', 0, [ 3,2, 5,2 ]);
215 CheckMarks('3/2 - 5/1', 1, [ 3,2, 5,2 ]);
216
217 FreeAndNil(FSynEdits[1]);
218 CheckMarks('other destroyed', 0, [ 3,2, 5,2 ]);
219
220 //move 1
221 FSynEdits[0].CaretXY := Point(1, 4); // after mark
222 FSynEdits[0].CommandProcessor(ecLineBreak, ' ', nil);
223
224 CheckMarks('unshared newline 3/2 - 5/1', 0, [ 3,2, 6,2 ]);
225 {%endregion}
226
227 {%region share, but separate marks}
228 ReCreateEdit(2);
229 PopPushBaseName('share, but separate marks');
230
231 // setting is not shared marklist
232 FSynEdits[1].ShareOptions := [];
233 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
234 SetLines(TestText1);
235
236 CheckMarks('empty', 0, []);
237 CheckMarks('empty', 1, []);
238
239 AddMark(0, 3,2);
240 CheckMarks('3/2', 0, [ 3,2 ]);
241 CheckMarks('3/2', 1, []);
242
243 AddMark(1, 5,2);
244 CheckMarks('3/2 - 5/1', 0, [ 3,2 ]);
245 CheckMarks('3/2 - 5/1', 1, [ 5,2 ]);
246
247 // unshare again
248 FSynEdits[1].UnShareTextBuffer;
249 CheckMarks('unshared', 0, [ 3,2 ]);
250 CheckMarks('unshared', 1, [ ]); // empty, even though it had own marks,. they were related to the text it has no longer
251
252 FSynEdits[0].CaretXY := Point(1, 1);
253 FSynEdits[0].CommandProcessor(ecLineBreak, ' ', nil);
254 CheckMarks('unshared newline', 0, [ 4,2 ]);
255 CheckMarks('unshared newline', 1, [ ]); // empty, even though it had own marks,. they were related to the text it has no longer
256
257 // delete mark from edit 0
258 FSynEdits[0].Marks[0].Free;
259 CheckMarks('unshared del', 0, [ ]);
260 CheckMarks('unshared del', 1, [ ]);
261 {%endregion}
262
263 {%region share but separate marks / destroy 1st}
264 ReCreateEdit(2);
265 PopPushBaseName('share with marks / destroy 2nd');
266 // default setting is shared marklist
267 FSynEdits[1].ShareOptions := [];
268 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
269 SetLines(TestText1);
270
271 // create setup
272 AddMark(0, 3,2);
273 AddMark(1, 5,2);
274 CheckMarks('3/2 - 5/1', 0, [ 3,2 ]);
275 CheckMarks('3/2 - 5/1', 1, [ 5,2 ]);
276
277 FreeAndNil(FSynEdits[0]);
278 CheckMarks('other destroyed', 1, [ 5,2 ]);
279
280 //move 1
281 FSynEdits[1].CaretXY := Point(1, 1);
282 FSynEdits[1].CommandProcessor(ecLineBreak, ' ', nil);
283
284 CheckMarks('unshared newline 3/2 - 5/1', 1, [ 6,2 ]);
285 {%endregion}
286
287 {%region share, but separate marks / destroy 2nd}
288 ReCreateEdit(2);
289 PopPushBaseName('share with marks / destroy 2nd');
290 // default setting is shared marklist
291 FSynEdits[1].ShareOptions := [];
292 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
293 SetLines(TestText1);
294
295 // create setup
296 AddMark(0, 3,2);
297 AddMark(1, 5,2);
298 CheckMarks('3/2 - 5/1', 0, [ 3,2 ]);
299 CheckMarks('3/2 - 5/1', 1, [ 5,2 ]);
300
301 FreeAndNil(FSynEdits[1]);
302 CheckMarks('other destroyed', 0, [ 3,2 ]);
303
304 //move 1
305 FSynEdits[0].CaretXY := Point(1, 1);
306 FSynEdits[0].CommandProcessor(ecLineBreak, ' ', nil);
307
308 CheckMarks('unshared newline 3/2 - 5/1', 0, [ 4,2 ]);
309 {%endregion}
310
311 end;
312
313 procedure TTestSynSharedEdits.TestBookMarks;
314 procedure CheckBMarks(Name: String; EditIndex: Integer; MarkList: Array of Integer);
315 var
316 m: TSynEditMark;
317 l: Array of Integer;
318 i, j: Integer;
319 begin
320 Name := BaseTestName + Name;
321 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Count: ', length(MarkList) div 2, FSynEdits[EditIndex].Marks.Count);
322
323 SetLength(l, FSynEdits[EditIndex].Lines.Count);
324 for i := 0 to length(l)-1 do
325 l[i] := 0;
326
327 for i := 0 to (length(MarkList) div 2) - 1 do begin
328 l[MarkList[i*2+0]] := l[MarkList[i*2+0]] + 1;
329 m := FSynEdits[EditIndex].Marks[i];
330 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Mark( '+IntToStr(i)+' ) Line: ', MarkList[i*2+0], m.Line);
331 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Mark( '+IntToStr(i)+' ) BookNum: ', MarkList[i*2+1], m.BookmarkNumber);
332 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Mark( '+IntToStr(i)+' ) IndexOf: ', i, FSynEdits[EditIndex].Marks.IndexOf(m));
333 end;
334
335 for i := 0 to length(l)-1 do begin
336 j := 0;
337 if FSynEdits[EditIndex].Marks.Line[i] <> nil then
338 j := FSynEdits[EditIndex].Marks.Line[i].Count;
339 AssertEquals(Name + ' Edit: '+IntToStr(EditIndex)+' Count in line '+IntToStr(i)+': ', l[i], j);
340 end;
341
342 end;
343
344 var
345 e1, e2, e3: Integer;
346 begin
347 {%region edits already shared }
348 ReCreateEdit(2);
349 // default setting is shared marklist
350 FSynEdits[1].ShareOptions := [eosShareMarks];
351 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
352 SetLines(TestText1);
353 PushBaseName('2 shared');
354
355 PushBaseName('');
356 for e1 := 0 to 1 do begin
357 for e2 := 0 to 1 do begin
358 PopPushBaseName('e1='+IntToStr(e1) + ' e2='+IntToStr(e2) );
359 // Set Mark
360 FSynEdits[e1].SetBookMark(1, 2, 4);
361 CheckBMarks('bm 1', 0, [ 4, 1 ]);
362 CheckBMarks('bm 1', 1, [ 4, 1 ]);
363
364 // goto
365 SelectEdit(0);
366 SynEdit.GotoBookMark(1);
367 TestIsCaret('Goto1 /0', 2, 4);
368 SelectEdit(1);
369 SynEdit.GotoBookMark(1);
370 TestIsCaret('Goto1 /1', 2, 4);
371
372 // clear
373 FSynEdits[e2].ClearBookMark(1);
374 CheckBMarks('bm clear', 0, [] );
375 CheckBMarks('bm clear', 1, [] );
376 end;
377 end;
378 PopBaseName;
379
380 PushBaseName('');
381 for e1 := 0 to 1 do begin
382 for e2 := 0 to 1 do begin
383 for e3 := 0 to 1 do begin
384 PopPushBaseName('e1='+IntToStr(e1) + ' e2='+IntToStr(e2) + ' e3='+IntToStr(e3));
385 FSynEdits[e1].ClearBookMark(1);
386 FSynEdits[e1].ClearBookMark(2);
387 // set 1 on ed1
388 FSynEdits[e1].SetBookMark(1, 2, 4);
389 CheckBMarks('bm set 1', 0, [ 4, 1 ]);
390 CheckBMarks('bm set 1', 1, [ 4, 1 ]);
391
392 // set 2 on ed2
393 FSynEdits[e2].SetBookMark(2, 2, 5);
394 CheckBMarks('bm set 2', 0, [ 4,1, 5,2 ]);
395 CheckBMarks('bm set 2', 1, [ 4,1, 5,2 ]);
396
397 // move 1 on ed3
398 FSynEdits[e3].SetBookMark(1, 2, 3);
399 CheckBMarks('bm move 1', 0, [ 3,1, 5,2 ]);
400 CheckBMarks('bm move 1', 1, [ 3,1, 5,2 ]);
401
402 // move 2 over 1 on ed3
403 FSynEdits[e3].SetBookMark(2, 3, 3);
404 CheckBMarks('bm move 2 over 1', 0, [ 3,2 ]);
405 CheckBMarks('bm move 2 over 1', 1, [ 3,2 ]);
406 end;
407 end;
408 end;
409 PopBaseName;
410 {%endregion}
411
412
413 {%region edits shared after bookmark set }
414 ReCreateEdit(2);
415 // default setting is shared marklist
416 FSynEdits[1].ShareOptions := [eosShareMarks];
417 SetLines(TestText1);
418 PopPushBaseName('2 shared after bm set');
419
420 FSynEdits[0].SetBookMark(1, 2, 4);
421 CheckBMarks('bm 1', 0, [ 4, 1 ]);
422 CheckBMarks('bm 1', 1, [ ]);
423
424 FSynEdits[1].ShareTextBufferFrom(FSynEdits[0]);
425
426 CheckBMarks('bm shared 1', 0, [ 4, 1 ]);
427 CheckBMarks('bm shared 1', 1, [ 4, 1 ]);
428
429 FSynEdits[1].ClearBookMark(1);
430
431 CheckBMarks('clear', 0, []);
432 CheckBMarks('clear', 1, []);
433
434 // unshare edits
435 FSynEdits[0].SetBookMark(1, 2, 4);
436 CheckBMarks('bm 1', 0, [ 4, 1 ]);
437 CheckBMarks('bm 1', 1, [ 4, 1 ]);
438
439 FSynEdits[1].UnShareTextBuffer;
440 CheckBMarks('unshare 1', 0, [ 4, 1 ]);
441 CheckBMarks('unshare 1', 1, [ ]);
442
443 FSynEdits[1].ClearBookMark(1);
444 CheckBMarks('unshare 1', 0, [ 4, 1 ]); // not affected
445 CheckBMarks('unshare 1', 1, [ ]);
446
447 FSynEdits[0].ClearBookMark(1);
448 CheckBMarks('unshare 1', 0, [ ]);
449 CheckBMarks('unshare 1', 1, [ ]);
450 {%endregion}
451 end;
452
453 initialization
454
455 RegisterTest(TTestSynSharedEdits);
456 end.
457
458