1 unit TestMarkupHighAll;
2
3 {$mode objfpc}{$H+}
4
5 interface
6
7 uses
8 Classes, SysUtils, testregistry, TestBase, LCLProc, Controls,
9 Graphics, SynEdit, SynEditMarkupHighAll;
10
11 type
12
13 { TTestMarkupHighAll }
14
15 TTestMarkupHighAll = class(TTestBase)
16 private
17 FMatchList: Array of record
18 p: PChar;
19 l: Integer;
20 end;
21 FStopAtMatch, FNoMatchCount: Integer;
22 procedure DoDictMatch(Match: PChar; MatchIdx: Integer; var IsMatch: Boolean;
23 var StopSeach: Boolean);
24 protected
25 //procedure SetUp; override;
26 //procedure TearDown; override;
27 //procedure ReCreateEdit; reintroduce;
TestText1null28 //function TestText1: TStringArray;
29 published
30 procedure TestDictionary;
31 procedure TestValidateMatches;
32 end;
33
34 implementation
35
36 type
37
38 { TTestSynEditMarkupHighlightAllMulti }
39
40 TTestSynEditMarkupHighlightAllMulti = class(TSynEditMarkupHighlightAllMulti)
41 private
42 FScannedLineCount: Integer;
43 protected
FindMatchesnull44 function FindMatches(AStartPoint, AEndPoint: TPoint; var AIndex: Integer;
45 AStopAfterLine: Integer = - 1; ABackward: Boolean = False): TPoint; override;
46 public
47 procedure ResetScannedCount;
48 property Matches;
49 property ScannedLineCount: Integer read FScannedLineCount;
50 end;
51
52 { TTestSynEditMarkupHighlightAllMulti }
53
TTestSynEditMarkupHighlightAllMulti.FindMatchesnull54 function TTestSynEditMarkupHighlightAllMulti.FindMatches(AStartPoint, AEndPoint: TPoint;
55 var AIndex: Integer; AStopAfterLine: Integer; ABackward: Boolean): TPoint;
56 begin
57 FScannedLineCount := FScannedLineCount + AEndPoint.y - AStartPoint.y + 1;
58 Result := inherited FindMatches(AStartPoint, AEndPoint, AIndex, AStopAfterLine, ABackward);
59 end;
60
61 procedure TTestSynEditMarkupHighlightAllMulti.ResetScannedCount;
62 begin
63 FScannedLineCount := 0;
64 end;
65
66
67 { TTestMarkupHighAll }
68
69 procedure TTestMarkupHighAll.DoDictMatch(Match: PChar; MatchIdx: Integer;
70 var IsMatch: Boolean; var StopSeach: Boolean);
71 var
72 i: Integer;
73 begin
74 i := length(FMatchList);
75 SetLength(FMatchList, i+1);
76 DebugLn([copy(Match, 1, MatchIdx)]);
77 FMatchList[i].p := Match;
78 FMatchList[i].l := MatchIdx;
79 StopSeach := FStopAtMatch <> 0;
80 IsMatch := FNoMatchCount <= 0;
81 dec(FStopAtMatch);
82 dec(FNoMatchCount);
83 end;
84
85 procedure TTestMarkupHighAll.TestDictionary;
86 var
87 Dict: TSynSearchDictionary;
88 Name, LineText: String;
89 Res1, Res2: PChar;
90
91 procedure InitTest(AName, ALineText: String; AStopAtMatch: Integer = -1; ANoMatchCount: Integer = 0);
92 begin
93 Name := AName + '[in: "'+ALineText+'", StopAt='+IntToStr(AStopAtMatch)+', NoMatchCnt='+IntToStr(ANoMatchCount)+']';
94 LineText := ALineText;
95 SetLength(FMatchList, 0);
96 FStopAtMatch := AStopAtMatch;
97 FNoMatchCount := ANoMatchCount;;
98 if LineText = '' then begin
99 Res1 := Dict.Search(nil, Length(LineText), nil);
100 Res2 := Dict.Search(nil, Length(LineText), @DoDictMatch);
101 end
102 else begin
103 Res1 := Dict.Search(@LineText[1], Length(LineText), nil);
104 Res2 := Dict.Search(@LineText[1], Length(LineText), @DoDictMatch);
105 //dict.GetMatchAtChar();
106 end;
107 end;
108
109 procedure CheckExp(ExpRes1, ExpRes2: Integer);
110 begin
111 if ExpRes1 = 0
112 then AssertTrue(Name+' Result (no event)', nil = Res1)
113 else if ExpRes1 > 0
114 then AssertEquals(Name+' Result (no event)', ExpRes1, Res1 - @LineText[1]);
115 if ExpRes2 = 0
116 then AssertTrue(Name+' Result (event)', nil = Res2)
117 else if ExpRes2 > 0
118 then AssertEquals(Name+' Result (event)', ExpRes2, Res2 - @LineText[1]);
119 end;
120
121 procedure CheckExp(AExpCount: Integer; AExpList: array of Integer);
122 var
123 i: Integer;
124 begin
125 AssertEquals(Name+' (len list)', AExpCount, Length(FMatchList));
126 for i := 0 to Length(AExpList) div 2 -1 do begin
127 AssertEquals(Name+' (start '+IntToStr(i)+')', AExpList[i*2], FMatchList[i].p - @LineText[1]);
128 AssertEquals(Name+' (len '+IntToStr(i)+')', AExpList[i*2+1], FMatchList[i].l);
129 end;
130 end;
131
132 procedure CheckExp(ExpRes1, ExpRes2, AExpCount: Integer; AExpList: array of Integer);
133 begin
134 CheckExp(ExpRes1, ExpRes2);
135 CheckExp(AExpCount, AExpList);
136 end;
137
138
139 var
140 i: Integer;
141 begin
142 Dict := TSynSearchDictionary.Create;
143 Dict.Add('debugln',1);
144 Dict.Add('debuglnenter',2);
145 Dict.Add('debuglnexit',3);
146 Dict.Add('dbgout',4);
147 //Dict.DebugPrint();
148 Dict.Free;
149
150
151 Dict := TSynSearchDictionary.Create;
152 Dict.Add('foo' , 0);
153 Dict.Add('Hello' , 1);
154 Dict.Add('yello12345', 2);
155 Dict.Add( 'lo123' , 3);
156 Dict.Add( 'lo789' , 4);
157 Dict.Add('hell' , 5);
158 Dict.Add('hatter' , 6);
159 Dict.Add('log' , 7);
160 Dict.Add('lantern' , 8);
161 Dict.Add('terminal' , 9);
162 Dict.Add('all' ,10);
163 Dict.Add('alt' ,11);
164 Dict.Add('YESTERDAY' ,12);
165 Dict.Add( 'STER' ,13);
166 Dict.Add( 'TE' ,14);
167 Dict.Add( 'ER' ,15);
168 Dict.Add( 'DAY' ,16);
169
170 (*
171 Dict.Add('Algoritmus', 0);
172 Dict.Add('Aho', 0);
173 Dict.Add('Corasick', 0);
174 Dict.Add('je', 0);
175 Dict.Add('vyhledávací', 0);
176 Dict.Add('algoritmus', 0);
177 Dict.Add('vynalezený', 0);
178 Dict.Add('Alfredem', 0);
179 Dict.Add('Ahem', 0);
180 Dict.Add('a', 0);
181 Dict.Add('Margaret', 0);
182 Dict.Add('J', 0);
183 Dict.Add('Corasickovou', 0);
184 Dict.Add('Je', 0);
185 Dict.Add('to', 0);
186 Dict.Add('druh', 0);
187 Dict.Add('slovníkového', 0);
188 Dict.Add('vyhledávacího', 0);
189 Dict.Add('algoritmu', 0);
190 Dict.Add('který', 0);
191 Dict.Add('ve', 0);
192 Dict.Add('vstupním', 0);
193 Dict.Add('textu', 0);
194 Dict.Add('hledá', 0);
195 Dict.Add('prvky', 0);
196 Dict.Add('konečné', 0);
197 Dict.Add('množiny', 0);
198 Dict.Add('řetězců', 0);
199 Dict.Add('Vyhledává', 0);
200 Dict.Add('všechny', 0);
201 Dict.Add('prvky', 0);
202 Dict.Add('množiny', 0);
203 Dict.Add('najednou', 0);2 pi *
204 Dict.Add('jeho', 0);
205 Dict.Add('asymptotická', 0);
206 Dict.Add('složitost', 0);
207 Dict.Add('je', 0);
208 Dict.Add('proto', 0);
209 Dict.Add('lineární', 0);
210 Dict.Add('k', 0);
211 Dict.Add('délce', 0);
212 Dict.Add('všech', 0);
213 Dict.Add('vyhledávaných', 0);
214 Dict.Add('prvků', 0);
215 Dict.Add('plus', 0);
216 Dict.Add('délce', 0);
217 Dict.Add('vstupního', 0);
218 Dict.Add('textu', 0);
219 Dict.Add('plus', 0);
220 Dict.Add('délce', 0);
221 Dict.Add('výstupu', 0);
222 Dict.Add('Jelikož', 0);
223 Dict.Add('algoritmus', 0);
224 Dict.Add('najde', 0);
225 Dict.Add('všechny', 0);
226 Dict.Add('výskyty', 0);
227 Dict.Add('celkový', 0);
228 Dict.Add('počet', 0);
229 Dict.Add('výskytů', 0);
230 Dict.Add('pro', 0);
231 Dict.Add('celou', 0);
232 Dict.Add('množinu', 0);
233 Dict.Add('může', 0);
234 Dict.Add('být', 0);
235 Dict.Add('až', 0);
236 Dict.Add('kvadratický', 0);
237 Dict.Add('(například', 0);
238 Dict.Add('v', 0);
239 Dict.Add('případě', 0);
240 Dict.Add('kdy', 0);
241 Dict.Add('vyhledávané', 0);
242 Dict.Add('řetězce', 0);
243 Dict.Add('jsou', 0);
244 Dict.Add('a', 0);
245 Dict.Add('aa', 0);
246 Dict.Add('aaa', 0);
247 Dict.Add('aaaa', 0);
248 Dict.Add('a', 0);
249 Dict.Add('vstupní', 0);
250 Dict.Add('text', 0);
251 Dict.Add('je', 0);
252 Dict.Add('aaaa)', 0);
253 Dict.Add('Neformálně', 0);
254 Dict.Add('řečeno', 0);
255 Dict.Add('algoritmus', 0);
256 Dict.Add('konstruuje', 0);
257 Dict.Add('trie', 0);
258 Dict.Add('se', 0);
259 Dict.Add('zpětnými', 0);
260 Dict.Add('odkazy', 0);
261 Dict.Add('pro', 0);
262 Dict.Add('každý', 0);
263 Dict.Add('vrchol', 0);
264 Dict.Add('(například', 0);
265 Dict.Add('abc)', 0);
266 Dict.Add('na', 0);
267 Dict.Add('nejdelší', 0);
268 Dict.Add('vlastní', 0);
269 Dict.Add('sufix', 0);
270 Dict.Add('(pokud', 0);
271 Dict.Add('existuje', 0);
272 Dict.Add('tak', 0);
273 Dict.Add('bc', 0);
274 Dict.Add('jinak', 0);
275 Dict.Add('pokud', 0);
276 Dict.Add('existuje', 0);
277 Dict.Add('c', 0);
278 Dict.Add('jinak', 0);
279 Dict.Add('do', 0);
280 Dict.Add('kořene)', 0);
281 Dict.Add('Obsahuje', 0);
282 Dict.Add('také', 0);
283 Dict.Add('odkazy', 0);
284 Dict.Add('z', 0);
285 Dict.Add('každého', 0);
286 Dict.Add('vrcholu', 0);
287 Dict.Add('na', 0);
288 Dict.Add('prvek', 0);
289 Dict.Add('slovníku', 0);
290 Dict.Add('obsahující', 0);
291 Dict.Add('odpovídající', 0);
292 Dict.Add('nejdelší', 0);
293 Dict.Add('sufix', 0);
294 Dict.Add('Tudíž', 0);
295 Dict.Add('všechny', 0);
296 Dict.Add('výsledky', 0);
297 Dict.Add('mohou', 0);
298 Dict.Add('být', 0);
299 Dict.Add('vypsány', 0);
300 Dict.Add('procházením', 0);
301 Dict.Add('výsledného', 0);
302 Dict.Add('spojového', 0);
303 Dict.Add('seznamu', 0);
304 Dict.Add('Algoritmus', 0);
305 Dict.Add('pak', 0);
306 Dict.Add('pracuje', 0);
307 Dict.Add('tak', 0);
308 Dict.Add('že', 0);
309 Dict.Add('postupně', 0);
310 Dict.Add('zpracovává', 0);
311 Dict.Add('vstupní', 0);
312 Dict.Add('řetězec', 0);
313 Dict.Add('a', 0);
314 Dict.Add('pohybuje', 0);
315 Dict.Add('se', 0);
316 Dict.Add('po', 0);
317 Dict.Add('nejdelší', 0);
318 Dict.Add('odpovídající', 0);
319 Dict.Add('cestě', 0);
320 Dict.Add('stromu', 0);
321 Dict.Add('Pokud', 0);
322 Dict.Add('algoritmus', 0);
323 Dict.Add('načte', 0);
324 Dict.Add('znak', 0);
325 Dict.Add('který', 0);
326 Dict.Add('neodpovídá', 0);
327 Dict.Add('žádné', 0);
328 Dict.Add('další', 0);
329 Dict.Add('možné', 0);
330 Dict.Add('cestě', 0);
331 Dict.Add('přejde', 0);
332 Dict.Add('po', 0);
333 Dict.Add('zpětném', 0);
334 Dict.Add('odkazu', 0);
335 Dict.Add('na', 0);
336 Dict.Add('nejdelší', 0);
337 Dict.Add('odpovídající', 0);
338 Dict.Add('sufix', 0);
339 Dict.Add('a', 0);
340 Dict.Add('pokračuje', 0);
341 Dict.Add('tam', 0);
342 Dict.Add('(případně', 0);
343 Dict.Add('opět', 0);
344 Dict.Add('přejde', 0);
345 Dict.Add('zpět)', 0);
346 Dict.Add('Pokud', 0);
347 Dict.Add('je', 0);
348 Dict.Add('množina', 0);
349 Dict.Add('vyhledávaných', 0);
350 Dict.Add('řetězců', 0);
351 Dict.Add('známa', 0);
352 Dict.Add('předem', 0);
353 Dict.Add('(např', 0);
354 Dict.Add('databáze', 0);
355 Dict.Add('počítačových', 0);
356 Dict.Add('virů)', 0);
357 Dict.Add('je', 0);
358 Dict.Add('možné', 0);
359 Dict.Add('zkonstruovat', 0);
360 Dict.Add('automat', 0);
361 Dict.Add('předem', 0);
362 Dict.Add('a', 0);
363 Dict.Add('ten', 0);
364 Dict.Add('pak', 0);
365 Dict.Add('uložit', 0);
366 //*)
367
368 //Dict.Search('aallhellxlog', 12, nil);
369 //Dict.DebugPrint();
370
371 InitTest('Nothing to find: empty input', '', -1);
372 CheckExp(0, 0, 0, []);
373 InitTest('Nothing to find: short input', '@', -1);
374 CheckExp(0, 0, 0, []);
375 InitTest('Nothing to find: long input', StringOfChar('#',100), -1);
376 CheckExp(0, 0, 0, []);
377
378 // result points to end of word (0 based)
379 // end, end, count, idx(from add)
380 InitTest('find hell', 'hell', 0);
381 CheckExp(4, 4, 1, [4, 5]);
382 InitTest('find hell', 'hell', -1);
383 CheckExp(4, 4, 1, [4, 5]);
384
385 InitTest('find hell', 'hell1');
386 CheckExp(4, 4, 1, [4, 5]);
387
388 InitTest('find hell', '2hell');
389 CheckExp(5, 5, 1, [5, 5]);
390
391 InitTest('find hell', '2hell1');
392 CheckExp(5, 5, 1, [5, 5]);
393
394 InitTest('find hell', 'hell hell'); // no event stops after 1st
395 CheckExp(4, 9, 2, [4, 5, 9, 5]);
396
397 InitTest('find hell', 'hellhell'); // no event stops after 1st
398 CheckExp(4, 8, 2, [4, 5, 8, 5]);
399
400 InitTest('find hell', 'hell hell', 0);
401 CheckExp(4, 4, 1, [4, 5]);
402
403 InitTest('find hell', 'hellog', -1, 0); // hell is match, log can not be found
404 CheckExp(4, 4, 1, [4, 5]);
405
406 InitTest('find log', 'hellog', -1, 1); // skip hell (still in list), find log
407 CheckExp(-1, 6, 2, [4, 5, 6, 7]);
408
409 InitTest('find hell', 'hehell', 0);
410 CheckExp(6, 6, 1, [6, 5]);
411
412 InitTest('find hell', 'thehell', 0);
413 CheckExp(7, 7, 1, [7, 5]);
414
415 InitTest('lantern', 'lantern');
416 CheckExp(7, 7, 1, [7, 8]);
417
418 InitTest('find terminal', 'lanterminal');
419 CheckExp(11, 11, 1, [11, 9]);
420
421 InitTest('find lo123', 'yello123AA');
422 CheckExp(8, 8, 1, [8, 3]);
423
424 InitTest('find lo123', 'yello1234AA');
425 CheckExp(8, 8, 1, [8, 3]);
426
427 InitTest('find yello12345 and lo123', 'yello12345AA', -1, 99);
428 CheckExp(-1, 10, 2, [8, 3, 10, 2]);
429
430 InitTest('find many', 'YESTERDAY', -1, 99);
431 CheckExp(-1, 9, 5, [{TE} 5, 14, {STER} 6, 13, {ER} 6, 15, {YESTERDAY} 9, 12, {DAY} 9, 16 ]);
432
433 InitTest('find many', 'YESTERDAY'); // restart after each match
434 CheckExp(-1, 9, 2, [{TE} 5, 14, {DAY} 9, 16 ]);
435
436
437
438 Dict.Search('aallhellxlog', 12, @DoDictMatch);
439 //Dict.BuildDictionary;
440 //Dict.DebugPrint();
441
442 //Randomize;
443 //Dict.Clear;
444 //for i := 0 to 5000 do begin
445 // s := '';
446 // for j := 10 to 11+Random(20) do s := s + chr(Random(127));
447 // Dict.Add(s);
448 //end;
449 //Dict.BuildDictionary;
450 //Dict.DebugPrint(true);
451
452
453 Dict.Free;
454 end;
455
456 procedure TTestMarkupHighAll.TestValidateMatches;
457 type
458 TMatchLoc = record
459 y1, y2, x1, x2: Integer;
460 end;
461 var
462 M: TTestSynEditMarkupHighlightAllMulti;
463
lnull464 function l(y, x1, x2: Integer) : TMatchLoc;
465 begin
466 Result.y1 := y;
467 Result.x1 := x1;
468 Result.y2 := y;
469 Result.x2 := x2;
470 end;
471
472 procedure StartMatch(Words: Array of string);
473 var
474 i: Integer;
475 begin
476 SynEdit.BeginUpdate;
477 M.Clear;
478 for i := 0 to high(Words) do
479 M.AddSearchTerm(Words[i]);
480 SynEdit.EndUpdate;
481 m.MarkupInfo.Foreground := clRed;
482 end;
483
484 Procedure TestHasMCount(AName: String; AExpMin: Integer; AExpMax: Integer = -1);
485 begin
486 AName := AName + '(CNT)';
487 if AExpMax < 0 then begin
488 AssertEquals(BaseTestName+' '+AName, AExpMin, M.Matches.Count);
489 end
490 else begin
491 AssertTrue(BaseTestName+' '+AName+ '(Min)', AExpMin <= M.Matches.Count);
492 AssertTrue(BaseTestName+' '+AName+ '(Max)', AExpMax >= M.Matches.Count);
493 end;
494 end;
495
496 Procedure TestHasMatches(AName: String; AExp: Array of TMAtchLoc; ExpMusNotExist: Boolean = False);
497 var
498 i, j: Integer;
499 begin
500 for i := 0 to High(AExp) do begin
501 j := M.Matches.Count - 1;
502 while (j >= 0) and
503 ( (M.Matches.StartPoint[j].y <> AExp[i].y1) or (M.Matches.StartPoint[j].x <> AExp[i].x1) or
504 (M.Matches.EndPoint[j].y <> AExp[i].y2) or (M.Matches.EndPoint[j].x <> AExp[i].x2) )
505 do
506 dec(j);
507 AssertEquals(BaseTestName+' '+AName+'('+IntToStr(i)+')', not ExpMusNotExist, j >= 0);
508 end
509 end;
510
511 Procedure TestHasMatches(AName: String; AExpCount: Integer; AExp: Array of TMAtchLoc; ExpMusNotExist: Boolean = False);
512 begin
513 TestHasMatches(AName, AExp, ExpMusNotExist);
514 TestHasMCount(AName, AExpCount);
515 end;
516
517 Procedure TestHasMatches(AName: String; AExpCountMin, AExpCountMax: Integer; AExp: Array of TMAtchLoc; ExpMusNotExist: Boolean = False);
518 begin
519 TestHasMatches(AName, AExp, ExpMusNotExist);
520 TestHasMCount(AName, AExpCountMin, AExpCountMax);
521 end;
522
523 Procedure TestHasScanCnt(AName: String; AExpMin: Integer; AExpMax: Integer = -1);
524 begin
525 AName := AName + '(SCANNED)';
526 if AExpMax < 0 then begin
527 AssertEquals(BaseTestName+' '+AName, AExpMin, M.ScannedLineCount);
528 end
529 else begin
530 AssertTrue(BaseTestName+' '+AName+ '(Min)', AExpMin <= M.ScannedLineCount);
531 AssertTrue(BaseTestName+' '+AName+ '(Max)', AExpMax >= M.ScannedLineCount);
532 end;
533 end;
534
535 procedure SetText(ATopLine: Integer = 1; HideSingle: Boolean = False);
536 var
537 i: Integer;
538 begin
539 ReCreateEdit;
540 SynEdit.BeginUpdate;
541 for i := 1 to 700 do
542 SynEdit.Lines.Add(' a'+IntToStr(i)+'a b c'+IntToStr(i)+'d');
543 SynEdit.Align := alTop;
544 SynEdit.Height := SynEdit.LineHeight * 40 + SynEdit.LineHeight div 2;
545 M := TTestSynEditMarkupHighlightAllMulti.Create(SynEdit);
546 M.HideSingleMatch := HideSingle;
547 SynEdit.MarkupMgr.AddMarkUp(M);
548 SynEdit.TopLine := ATopLine;
549 SynEdit.EndUpdate;
550 end;
551
552 procedure SetTextAndMatch(ATopLine: Integer; HideSingle: Boolean;
553 Words: Array of string;
554 AName: String= ''; AExpMin: Integer = -1; AExpMax: Integer = -1);
555 begin
556 SetText(ATopLine, HideSingle);
557 StartMatch(Words);
558 if AExpMin >= 0 then
559 TestHasMCount(AName + ' init', AExpMin, AExpMax);
560 end;
561
Mtxtnull562 function Mtxt(i: Integer): String;
563 begin
564 Result := 'a'+IntToStr(i)+'a';
565 end;
566
567 var
568 N: string;
569 i, j: integer;
570 a, b: integer;
571 begin
572
573 {%region Searchrange}
574 PushBaseName('Searchrange');
575 PushBaseName('HideSingleMatch=False');
576
577 N := 'Find match on first line';
578 SetText(250);
579 M.HideSingleMatch := False;
580 StartMatch(['a250a']);
581 TestHasMCount (N, 1);
582 TestHasMatches(N, [l(250, 3, 8)]);
583
584 N := 'Find match on last line';
585 SetText(250);
586 M.HideSingleMatch := False;
587 StartMatch(['a289a']);
588 TestHasMCount (N, 1);
589 TestHasMatches(N, [l(289, 3, 8)]);
590
591 N := 'Find match on last part visible) line';
592 SetText(250);
593 M.HideSingleMatch := False;
594 StartMatch(['a290a']);
595 TestHasMCount (N, 1);
596 TestHasMatches(N, [l(290, 3, 8)]);
597
598 // Before topline
599 SetText(250);
600 M.HideSingleMatch := False;
601 StartMatch(['a249a']);
602 TestHasMCount ('NOT Found before topline', 0);
603
604 // after lastline
605 SetText(250);
606 M.HideSingleMatch := False;
607 StartMatch(['a291a']);
608 TestHasMCount ('NOT Found after lastline', 0);
609
610 // first and last
611 SetText(250);
612 M.HideSingleMatch := False;
613 StartMatch(['a250a', 'a290a']);
614 TestHasMCount ('Found on first and last line', 2);
615 TestHasMatches('Found on first and last line', [l(250, 3, 8), l(290, 3, 8)]);
616
617 // first and last + before
618 SetText(250);
619 M.HideSingleMatch := False;
620 StartMatch(['a250a', 'a290a', 'a249a']);
621 TestHasMCount ('Found on first/last (but not before) line', 2);
622 TestHasMatches('Found on first/last (but not before) line', [l(250, 3, 8), l(290, 3, 8)]);
623
624 // first and last + after
625 SetText(250);
626 M.HideSingleMatch := False;
627 StartMatch(['a250a', 'a290a', 'a291a']);
628 TestHasMCount ('Found on first/last (but not after) line', 2);
629 TestHasMatches('Found on first/last (but not after) line', [l(250, 3, 8), l(290, 3, 8)]);
630
631 PopPushBaseName('HideSingleMatch=True');
632
633 SetText(250);
634 M.HideSingleMatch := True;
635 StartMatch(['a250a']);
636 TestHasMCount ('Found on first line', 1);
637 TestHasMatches('Found on first line', [l(250, 3, 8)]);
638
639 SetText(250);
640 M.HideSingleMatch := True;
641 StartMatch(['a289a']);
642 TestHasMCount ('Found on last line', 1);
643 TestHasMatches('Found on last line', [l(289, 3, 8)]);
644
645 SetText(250);
646 M.HideSingleMatch := True;
647 StartMatch(['a290a']);
648 TestHasMCount ('Found on last (partly) line', 1);
649 TestHasMatches('Found on last (partly) line', [l(290, 3, 8)]);
650
651 // Before topline
652 SetText(250);
653 M.HideSingleMatch := True;
654 StartMatch(['a249a']);
655 TestHasMCount ('NOT Found before topline', 0);
656
657 // after lastline
658 SetText(250);
659 M.HideSingleMatch := True;
660 StartMatch(['a291a']);
661 TestHasMCount ('NOT Found after lastline', 0);
662
663 // first and last
664 SetText(250);
665 M.HideSingleMatch := True;
666 StartMatch(['a250a', 'a290a']);
667 TestHasMCount ('Found on first and last line', 2);
668 TestHasMatches('Found on first and last line', [l(250, 3, 8), l(290, 3, 8)]);
669
670 // first and last + before
671 SetText(250);
672 M.HideSingleMatch := True;
673 StartMatch(['a250a', 'a290a', 'a249a']);
674 TestHasMCount ('Found on first/last (but not before) line', 2);
675 TestHasMatches('Found on first/last (but not before) line', [l(250, 3, 8), l(290, 3, 8)]);
676
677 // first and last + after
678 SetText(250);
679 M.HideSingleMatch := True;
680 StartMatch(['a250a', 'a290a', 'a291a']);
681 TestHasMCount ('Found on first/last (but not after) line', 2);
682 TestHasMatches('Found on first/last (but not after) line', [l(250, 3, 8), l(290, 3, 8)]);
683
684 // extend for HideSingle, before
685 N := 'Look for 2nd match before startpoint (first match at topline)';
686 SetText(250);
687 M.HideSingleMatch := True;
688 StartMatch(['a250a', 'a249a']);
689 TestHasMCount (N, 2);
690 TestHasMatches(N, [l(250, 3, 8), l(249, 3, 8)]);
691
692 N := 'Look for 2nd match before startpoint (first match at lastline)';
693 SetText(250);
694 M.HideSingleMatch := True;
695 StartMatch(['a290a', 'a249a']);
696 TestHasMCount (N, 2);
697 TestHasMatches(N, [l(290, 3, 8), l(249, 3, 8)]);
698
699 N := 'Look for 2nd match FAR (99l) before startpoint (first match at topline)';
700 SetText(250);
701 M.HideSingleMatch := True;
702 StartMatch(['a250a', 'a151a']);
703 TestHasMCount (N, 2);
704 TestHasMatches(N, [l(250, 3, 8), l(151, 3, 8)]);
705
706 N := 'Look for 2nd match FAR (99l) before startpoint (first match at lastline)';
707 SetText(250);
708 M.HideSingleMatch := True;
709 StartMatch(['a290a', 'a151a']);
710 TestHasMCount (N, 2);
711 TestHasMatches(N, [l(290, 3, 8), l(151, 3, 8)]);
712
713 N := 'Look for 2nd match before startpoint, find ONE of TWO';
714 SetText(250);
715 M.HideSingleMatch := True;
716 StartMatch(['a250a', 'a200a', 'a210a']);
717 TestHasMCount (N, 2);
718 TestHasMatches(N, [l(250, 3, 8), l(210, 3, 8)]);
719
720 // TODO: Not extend too far...
721
722 // extend for HideSingle, after
723 SetText(250);
724 M.HideSingleMatch := True;
725 StartMatch(['a250a', 'a291a']);
726 TestHasMCount ('Found on first/ext-after line', 2);
727 TestHasMatches('Found on first/ext-after line', [l(250, 3, 8), l(291, 3, 8)]);
728
729 SetText(250);
730 M.HideSingleMatch := True;
731 StartMatch(['a290a', 'a291a']);
732 TestHasMCount ('Found on last/ext-after line', 2);
733 TestHasMatches('Found on last/ext-after line', [l(290, 3, 8), l(291, 3, 8)]);
734
735 SetText(250);
736 M.HideSingleMatch := True;
737 StartMatch(['a250a', 'a389a']);
738 TestHasMCount ('Found on first/ext-after-99 line', 2);
739 TestHasMatches('Found on first/ext-after-99 line', [l(250, 3, 8), l(389, 3, 8)]);
740
741 SetText(250);
742 M.HideSingleMatch := True;
743 StartMatch(['a290a', 'a389a']);
744 TestHasMCount ('Found on last/ext-after-99 line', 2);
745 TestHasMatches('Found on last/ext-after-99 line', [l(290, 3, 8), l(389, 3, 8)]);
746
747
748 PopBaseName;
749 PopBaseName;
750 {%endregion}
751
752 {%region Scroll / LinesInWindow}
753 PushBaseName('Scroll/LinesInWindow');
754 PushBaseName('HideSingleMatch=False');
755
756
757 SetText(250);
758 M.HideSingleMatch := False;
759 StartMatch(['a249a']);
760 TestHasMCount ('Not Found before first line', 0);
761
762 M.ResetScannedCount;
763 SynEdit.TopLine := 251;
764 TestHasMCount ('Not Found before first line (250=>251)', 0);
765 TestHasScanCnt('Not Found before first line (250=>251)', 1, 2); // Allow some range
766
767 M.ResetScannedCount;
768 SynEdit.TopLine := 249;
769 TestHasMCount ('Found on first line (251=<249', 1);
770 TestHasMatches('Found on first line (251=>249)', [l(249, 3, 8)]);
771 TestHasScanCnt('Found on first line (251=>249)', 1, 2); // Allow some range
772
773
774 SetText(250);
775 M.HideSingleMatch := False;
776 StartMatch(['a291a']);
777 TestHasMCount ('Not Found after last line', 0);
778
779 M.ResetScannedCount;
780 SynEdit.TopLine := 249;
781 TestHasMCount ('Not Found after last line (250=>249)', 0);
782 TestHasScanCnt('Not Found after last line (250=>249)', 1, 2); // Allow some range
783
784 M.ResetScannedCount;
785 SynEdit.TopLine := 251;
786 TestHasMCount ('Found on last line (249=<251', 1);
787 TestHasMatches('Found on last line (249=>251)', [l(291, 3, 8)]);
788 TestHasScanCnt('Found on last line (249=>251)', 1, 2); // Allow some range
789
790
791 SetText(250);
792 M.HideSingleMatch := False;
793 StartMatch(['a291a']);
794 TestHasMCount ('Not Found after last line', 0);
795
796 M.ResetScannedCount;
797 SynEdit.Height := SynEdit.LineHeight * 41 + SynEdit.LineHeight div 2;
798 TestHasMCount ('Found on last line (40=>41', 1);
799 TestHasMatches('Found on last line (40=>41)', [l(291, 3, 8)]);
800 TestHasScanCnt('Found on last line (40=>41)', 1, 2); // Allow some range
801
802
803 PopPushBaseName('HideSingleMatch=True');
804
805 SetText(250);
806 M.HideSingleMatch := True;
807 StartMatch(['a249a', 'a248a']);
808 TestHasMCount ('Not Found before first line', 0);
809
810 M.ResetScannedCount;
811 SynEdit.TopLine := 251;
812 TestHasMCount ('Not Found before first line (250=>251)', 0);
813 TestHasScanCnt('Not Found before first line (250=>251)', 1, 2); // Allow some range
814
815 M.ResetScannedCount;
816 SynEdit.TopLine := 249;
817 TestHasMCount ('Found on first line+ext (251=<249', 2);
818 TestHasMatches('Found on first line+ext (251=>249)', [l(249, 3, 8), l(248, 3, 8)]);
819
820
821 SetText(250);
822 M.HideSingleMatch := True;
823 StartMatch(['a291a', 'a292a']);
824 TestHasMCount ('Not Found after last line', 0);
825
826 M.ResetScannedCount;
827 SynEdit.TopLine := 249;
828 TestHasMCount ('Not Found after last line (250=>249)', 0);
829 TestHasScanCnt('Not Found after last line (250=>249)', 1, 2); // Allow some range
830
831 M.ResetScannedCount;
832 SynEdit.TopLine := 251;
833 TestHasMCount ('Found on last line+ext (249=<251', 2);
834 TestHasMatches('Found on last line+ext (249=>251)', [l(291, 3, 8), l(292, 3, 8)]);
835
836
837 for i := -205 to 205 do begin
838 if abs(i) in [0..2, 5..15, 25..35, 50..95, 105..195] then continue;
839
840 N := 'Far Scroll '+IntToStr(i)+' to %d matches top/last > last ';
841 SetTextAndMatch(250, False, [Mtxt(250), Mtxt(290), Mtxt(290+i)]);
842 SynEdit.TopLine := 250 + i;
843 TestHasMatches(N + 'Found ', [l(290+i, 3, 3+length(Mtxt(290+i)))]);
844
845
846 N := 'Far Scroll '+IntToStr(i)+' to %d matches top/last > top ';
847 SetTextAndMatch(250, False, [Mtxt(250), Mtxt(290), Mtxt(250+i)]);
848 SynEdit.TopLine := 250 + i;
849 TestHasMatches(N + 'Found ', [l(250+i, 3, 3+length(Mtxt(250+i)))]);
850
851
852 N := 'Far Scroll '+IntToStr(i)+' to %d matches top > last ';
853 SetTextAndMatch(250, False, [Mtxt(250), Mtxt(290+i)]);
854 SynEdit.TopLine := 250 + i;
855 TestHasMatches(N + 'Found ', [l(290+i, 3, 3+length(Mtxt(290+i)))]);
856
857
858 N := 'Far Scroll '+IntToStr(i)+' to %d matches top > top ';
859 SetTextAndMatch(250, False, [Mtxt(250), Mtxt(250+i)]);
860 SynEdit.TopLine := 250 + i;
861 TestHasMatches(N + 'Found ', [l(250+i, 3, 3+length(Mtxt(250+i)))]);
862
863
864 N := 'Far Scroll '+IntToStr(i)+' to %d matches last > last ';
865 SetTextAndMatch(250, False, [Mtxt(290), Mtxt(290+i)]);
866 SynEdit.TopLine := 250 + i;
867 TestHasMatches(N + 'Found ', [l(290+i, 3, 3+length(Mtxt(290+i)))]);
868
869
870 N := 'Far Scroll '+IntToStr(i)+' to %d matches last > top ';
871 SetTextAndMatch(250, False, [Mtxt(290), Mtxt(250+i)]);
872 SynEdit.TopLine := 250 + i;
873 TestHasMatches(N + 'Found ', [l(250+i, 3, 3+length(Mtxt(250+i)))]);
874
875
876 end;
877
878
879 PopBaseName;
880 PopBaseName;
881 {%endregion}
882
883 {%region edit}
884 PushBaseName('Searchrange');
885 //PushBaseName('HideSingleMatch=False');
886
887 for i := 245 to 295 do begin
888 if ((i > 259) and (i < 280)) then continue;
889
890 N := 'Edit at '+IntToStr(i)+' / NO match';
891 SetTextAndMatch(250, False, ['DontMatchMe'], N+' init/found', 0);
892 M.ResetScannedCount;
893 SynEdit.TextBetweenPoints[point(1, i), point(1, i)] := 'X';
894 SynEdit.SimulatePaintText;
895 TestHasMCount (N+' Found after edit', 0);
896 if (i >= 250) and (i <= 290)
897 then TestHasScanCnt(N+' Found after edit', 1, 3)
898 else
899 if (i < 247) or (i > 293)
900 then TestHasScanCnt(N+' Found after edit', 0)
901 else TestHasScanCnt(N+' Found after edit', 0, 3);
902
903
904 N := 'Edit (new line) at '+IntToStr(i)+' / NO match';
905 SetTextAndMatch(250, False, ['DontMatchMe'], N+' init/found', 0);
906 M.ResetScannedCount;
907 SynEdit.TextBetweenPoints[point(1, i), point(1, i)] := LineEnding;
908 SynEdit.SimulatePaintText;
909 TestHasMCount (N+' Found after edit', 0);
910 //if (i >= 250) and (i <= 290)
911 //then TestHasScanCnt(N+' Found after edit', 1, 3)
912 //else
913 //if (i < 247) or (i > 293)
914 //then TestHasScanCnt(N+' Found after edit', 0)
915 //else TestHasScanCnt(N+' Found after edit', 0, 3);
916
917
918 N := 'Edit (join line) at '+IntToStr(i)+' / NO match';
919 SetTextAndMatch(250, False, ['DontMatchMe'], N+' init/found', 0);
920 M.ResetScannedCount;
921 SynEdit.TextBetweenPoints[point(10, i), point(1, i+1)] := '';
922 SynEdit.SimulatePaintText;
923 TestHasMCount (N+' Found after edit', 0);
924 //if (i >= 250) and (i <= 290)
925 //then TestHasScanCnt(N+' Found after edit', 1, 3)
926 //else
927 //if (i < 247) or (i > 293)
928 //then TestHasScanCnt(N+' Found after edit', 0)
929 //else TestHasScanCnt(N+' Found after edit', 0, 3);
930
931 end;
932
933
934
935 for j := 245 to 295 do begin
936 if ((j > 255) and (j < 270)) or ((j > 270) and (j < 285)) then
937 continue;
938
939 for i := 245 to 295 do begin
940 N := 'Edit at '+IntToStr(i)+' / single match at '+IntToStr(j);
941 SetTextAndMatch(250, False, ['a'+IntToStr(j)+'a']);
942 if (j >= 250) and (j <= 290)
943 then TestHasMatches(N+' init/found', 1, [l(j, 3, 8)])
944 else TestHasMCount (N+' init/not found', 0);
945
946 M.ResetScannedCount;
947 SynEdit.TextBetweenPoints[point(1, i), point(1, i)] := 'X';
948 SynEdit.SimulatePaintText;
949 if (j >= 250) and (j <= 290) then begin
950 if i = j
951 then TestHasMatches(N+' Found after edit', 1, [l(j, 4, 9)])
952 else TestHasMatches(N+' Found after edit', 1, [l(j, 3, 8)]);
953 end
954 else
955 TestHasMCount (N+' still not Found after edit', 0);
956
957 if (i >= 250) and (i <= 290)
958 then TestHasScanCnt(N+' Found after edit', 1, 3)
959 else
960 if (i < 247) or (i > 293)
961 then TestHasScanCnt(N+' Found after edit', 0)
962 else TestHasScanCnt(N+' Found after edit', 0, 3);
963 end;
964
965
966 for i := 245 to 295 do begin
967 N := 'Edit (new line) at '+IntToStr(i)+' / single match at '+IntToStr(j);
968 SetTextAndMatch(250, False, ['a'+IntToStr(j)+'a']);
969 if (j >= 250) and (j <= 290)
970 then TestHasMatches(N+' init/found', 1, [l(j, 3, 8)])
971 else TestHasMCount (N+' init/not found', 0);
972
973 M.ResetScannedCount;
974 SynEdit.BeginUpdate;
975 SynEdit.TextBetweenPoints[point(1, i), point(1, i)] := LineEnding;
976 SynEdit.TopLine := 250;
977 SynEdit.EndUpdate;
978 SynEdit.SimulatePaintText;
979 a := j;
980 if i <= j then inc(a);
981 if (a >= 250) and (a <= 290) then begin
982 if i = a
983 then TestHasMatches(N+' Found after edit', 1, [l(a, 4, 9)])
984 else TestHasMatches(N+' Found after edit', 1, [l(a, 3, 8)]);
985 end
986 else
987 TestHasMCount (N+' still not Found after edit', 0);
988
989 //if (i >= 250) and (i <= 290)
990 //then TestHasScanCnt(N+' Found after edit', 1, 3)
991 //else
992 //if (i < 247) or (i > 293)
993 //then TestHasScanCnt(N+' Found after edit', 0)
994 //else TestHasScanCnt(N+' Found after edit', 0, 3);
995 end;
996
997 end;
998
999
1000
1001 for j := 0 to 6 do begin
1002 case j of
1003 0: begin a := 260; b := 270 end;
1004 1: begin a := 250; b := 270 end;
1005 2: begin a := 251; b := 270 end;
1006 3: begin a := 270; b := 288 end;
1007 4: begin a := 270; b := 289 end;
1008 5: begin a := 270; b := 290 end;
1009 6: begin a := 250; b := 290 end;
1010 end;
1011
1012 for i := 245 to 295 do begin
1013 N := 'Edit at '+IntToStr(i)+' / TWO match at '+IntToStr(a)+', '+IntToStr(b);
1014 SetTextAndMatch(250, False, ['a'+IntToStr(a)+'a', 'a'+IntToStr(b)+'a']);
1015 TestHasMatches(N+' init/found', 2, [l(a, 3, 8), l(b, 3,8)]);
1016
1017 M.ResetScannedCount;
1018 SynEdit.TextBetweenPoints[point(10, i), point(10, i)] := 'X';
1019 SynEdit.SimulatePaintText;
1020 TestHasMCount (N+' Found after edit', 2);
1021 TestHasMatches(N+' init/found', [l(a, 3, 8), l(b, 3,8)]);
1022
1023 if (i >= 250) and (i <= 290)
1024 then TestHasScanCnt(N+' Found after edit', 1, 3)
1025 else
1026 if (i < 247) or (i > 293)
1027 then TestHasScanCnt(N+' Found after edit', 0)
1028 else TestHasScanCnt(N+' Found after edit', 0, 3);
1029 end;
1030 end;
1031
1032
1033 N := 'Edit/Topline/LastLine ';
1034 SetTextAndMatch(250, False, ['a265a', 'a275a']);
1035 TestHasMatches(N+' init/found', 2, [l(265, 3, 8), l(275, 3,8)]);
1036 M.ResetScannedCount;
1037 SynEdit.BeginUpdate;
1038 SynEdit.TextBetweenPoints[point(10, i), point(10, i)] := 'X';
1039 SynEdit.TopLine := 248; // 2 new lines
1040 SynEdit.Height := SynEdit.LineHeight * 44 + SynEdit.LineHeight div 2; // another 2 lines
1041 SynEdit.EndUpdate;
1042 SynEdit.SimulatePaintText;
1043 TestHasMatches(N+' Found after edit', 2, [l(265, 3, 8), l(275, 3,8)]);
1044 TestHasScanCnt(N+' Found after edit', 1, 12);
1045
1046
1047 N := 'Edit/Topline/LastLine find new points';
1048 SetTextAndMatch(250, False, ['a265a', 'a275a', 'a248a', 'a292a']);
1049 TestHasMatches(N+' init/found', 2, [l(265, 3, 8), l(275, 3,8)]);
1050 M.ResetScannedCount;
1051 SynEdit.BeginUpdate;
1052 SynEdit.TextBetweenPoints[point(10, i), point(10, i)] := 'X';
1053 SynEdit.TopLine := 248; // 2 new lines
1054 SynEdit.Height := SynEdit.LineHeight * 44 + SynEdit.LineHeight div 2; // another 2 lines
1055 SynEdit.EndUpdate;
1056 SynEdit.SimulatePaintText;
1057 TestHasMatches(N+' Found after edit', 4, [l(265, 3, 8), l(275, 3,8), l(248, 3,8), l(292, 3,8)]);
1058 TestHasScanCnt(N+' Found after edit', 1, 12);
1059
1060
1061
1062
1063
1064 PopBaseName;
1065 {%endregion}
1066
1067
1068
1069 end;
1070
1071 initialization
1072
1073 RegisterTest(TTestMarkupHighAll);
1074 end.
1075
1076