mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 15:21:26 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			259 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|  Test with:
 | |
|      ./runtests --format=plain --suite=TTestMethodJumpTool
 | |
|      ./runtests --format=plain --suite=TestFindJumpPointIncFilewithIntfAndImpl
 | |
| }
 | |
| unit TestMethodJumpTool;
 | |
| 
 | |
| {$mode objfpc}{$H+}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   Classes, SysUtils, fpcunit, testregistry, LazLoggerBase,
 | |
|   CodeToolManager, StdCodeTools, CodeCache, LinkScanner, TestPascalParser;
 | |
| 
 | |
| type
 | |
| 
 | |
|   { TBaseTestMethodJumpTool }
 | |
| 
 | |
|   TBaseTestMethodJumpTool = class(TCustomTestPascalParser)
 | |
|   protected
 | |
|     procedure GetCTMarker(aCode: TCodeBuffer; Comment: string; out Position: TPoint;
 | |
|       LeftOfComment: boolean = true);
 | |
|     function GetInfo(aCode: TCodeBuffer; XY: TPoint): string;
 | |
|     procedure TestJumpToMethod(FromMarker: string; LeftFrom: boolean;
 | |
|       ToMarker: string; LeftTo: boolean; ToColOffset: integer = 0);
 | |
|   end;
 | |
| 
 | |
|   { TTestMethodJumpTool }
 | |
| 
 | |
|   TTestMethodJumpTool = class(TBaseTestMethodJumpTool)
 | |
|   published
 | |
|     procedure TestFindJumpPointIncFilewithIntfAndImpl;
 | |
|     procedure TestMethodJump_IntfToImplSingleProc;
 | |
|     procedure TestMethodJump_IntfToImplSingleProcWrongName;
 | |
|     procedure TestMethodJump_IntfToImplSingleProcWrongParam;
 | |
|     procedure TestMethodJump_SingleMethod;
 | |
|     procedure TestMethodJump_MultiMethodWrongName;
 | |
|   end;
 | |
| 
 | |
| implementation
 | |
| 
 | |
| { TBaseTestMethodJumpTool }
 | |
| 
 | |
| procedure TBaseTestMethodJumpTool.GetCTMarker(aCode: TCodeBuffer; Comment: string;
 | |
|   out Position: TPoint; LeftOfComment: boolean);
 | |
| var
 | |
|   p: SizeInt;
 | |
| begin
 | |
|   Position:=Point(0,0);
 | |
|   if Comment[1]<>'{' then
 | |
|     Comment:='{'+Comment+'}';
 | |
|   p:=System.Pos(Comment,aCode.Source);
 | |
|   if p<1 then begin
 | |
|     WriteSource(CodeXYPosition(1,1,Code));
 | |
|     Fail('TTestMethodJumpTool.GetCTMarker, missing marker "'+Comment+'" in "'+Code.Filename+'"');
 | |
|   end;
 | |
|   if not LeftOfComment then
 | |
|     inc(p,length(Comment));
 | |
|   aCode.AbsoluteToLineCol(p,Position.Y,Position.X);
 | |
|   if Position.Y<1 then begin
 | |
|     WriteSource(CodeXYPosition(Position.X,Position.Y,Code));
 | |
|     Fail('TTestMethodJumpTool.GetCTMarker, Code.AbsoluteToLineCol: "'+Comment+'" Pos='+dbgs(Position)+' in "'+Code.Filename+'"');
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TBaseTestMethodJumpTool.GetInfo(aCode: TCodeBuffer; XY: TPoint): string;
 | |
| var
 | |
|   Line: String;
 | |
| begin
 | |
|   Line:=aCode.GetLine(XY.Y-1);
 | |
|   Result:=dbgs(XY)+': '+copy(Line,1,XY.X-1)+'|'+copy(Line,XY.X,length(Line));
 | |
| end;
 | |
| 
 | |
| procedure TBaseTestMethodJumpTool.TestJumpToMethod(FromMarker: string;
 | |
|   LeftFrom: boolean; ToMarker: string; LeftTo: boolean; ToColOffset: integer);
 | |
| var
 | |
|   FromPos, ToPos: TPoint;
 | |
|   NewCode: TCodeBuffer;
 | |
|   NewX, NewY, NewTopLine, BlockTopLine, BlockBottomLine: integer;
 | |
|   RevertableJump: boolean;
 | |
| begin
 | |
|   GetCTMarker(Code,FromMarker,FromPos,LeftFrom);
 | |
|   GetCTMarker(Code,ToMarker,ToPos,LeftTo);
 | |
|   inc(ToPos.X,ToColOffset);
 | |
|   if not CodeToolBoss.JumpToMethod(Code,FromPos.X,FromPos.Y,NewCode, NewX, NewY,
 | |
|     NewTopLine, BlockTopLine, BlockBottomLine, RevertableJump) then begin
 | |
|     WriteSource(CodeXYPosition(FromPos.X,FromPos.Y,Code));
 | |
|     Fail('CodeToolBoss.JumpToMethod failed, From line='+IntToStr(FromPos.Y)+' col='+IntToStr(FromPos.X));
 | |
|   end;
 | |
|   if NewCode<>Code then begin
 | |
|     WriteSource(CodeXYPosition(FromPos.X,FromPos.Y,Code));
 | |
|     AssertEquals('JumpToMethod jumped to wrong file, From line='+IntToStr(FromPos.Y)+' col='+IntToStr(FromPos.X),
 | |
|       Code.Filename,NewCode.Filename);
 | |
|   end;
 | |
|   if NewY<>ToPos.Y then begin
 | |
|     WriteSource(CodeXYPosition(ToPos.X,ToPos.Y,Code));
 | |
|     AssertEquals('JumpToMethod jumped to wrong line, From line='+IntToStr(FromPos.Y)+' col='+IntToStr(FromPos.X),
 | |
|       ToPos.Y,NewY);
 | |
|   end;
 | |
|   if NewX<>ToPos.X then begin
 | |
|     WriteSource(CodeXYPosition(ToPos.X,ToPos.Y,Code));
 | |
|     AssertEquals('JumpToMethod jumped to wrong line, From line='+IntToStr(FromPos.Y)+' col='+IntToStr(FromPos.X),
 | |
|       ToPos.X,NewX);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| { TTestMethodJumpTool }
 | |
| 
 | |
| procedure TTestMethodJumpTool.TestFindJumpPointIncFilewithIntfAndImpl;
 | |
| 
 | |
|   procedure Test(aTitle: string; Code: TCodeBuffer;
 | |
|     StartMarker: string; LeftOfStart: boolean;
 | |
|     EndMarker: string; LeftOfEnd: boolean);
 | |
|   var
 | |
|     BlockStart: TPoint;
 | |
|     BlockEnd: TPoint;
 | |
|     NewCode: TCodeBuffer;
 | |
|     NewX: integer;
 | |
|     NewY: integer;
 | |
|     NewTopline, BlockTopLine, BlockBottomLine: integer;
 | |
|     RevertableJump: boolean;
 | |
|   begin
 | |
|     GetCTMarker(Code,StartMarker,BlockStart,LeftOfStart);
 | |
|     GetCTMarker(Code,EndMarker,BlockEnd,LeftOfEnd);
 | |
|     //debugln(['TTestCTStdCodetools.TestCTStdFindBlockStart BlockStart=',GetInfo(BlockStart),' BlockEnd=',GetInfo(BlockEnd)]);
 | |
|     if not CodeToolBoss.JumpToMethod(Code,BlockStart.X,BlockStart.Y,
 | |
|       NewCode,NewX,NewY,NewTopline,BlockTopLine,BlockBottomLine,RevertableJump)
 | |
|     then
 | |
|       AssertEquals(aTitle+': '+CodeToolBoss.ErrorMessage,true,false)
 | |
|     else
 | |
|       AssertEquals(aTitle,GetInfo(Code,BlockEnd),GetInfo(NewCode,Point(NewX,NewY)))
 | |
|   end;
 | |
| 
 | |
| var
 | |
|   IncCode: TCodeBuffer;
 | |
| begin
 | |
|   Code.Source:=''
 | |
|     +'unit Test1;'+LineEnding
 | |
|     +'interface'+LineEnding
 | |
|     +'{$DEFINE UseInterface}'
 | |
|     +'{$I TestMethodJumpTool2.inc}'+LineEnding
 | |
|     +'{$UNDEF UseInterface}'+LineEnding
 | |
|     +'implementation'+LineEnding
 | |
|     +'{$DEFINE UseImplementation}'
 | |
|     +'{$I TestMethodJumpTool2.inc}'+LineEnding
 | |
|     +'end.'+LineEnding;
 | |
|   IncCode:=CodeToolBoss.CreateFile('TestMethodJumpTool2.inc');
 | |
|   IncCode.Source:=''
 | |
|     +'{%MainUnit test1.pas}'+LineEnding
 | |
|     +'{$IFDEF UseInterface}'+LineEnding
 | |
|     +'procedure {ProcHeader}DoSomething;'+LineEnding
 | |
|     +'{$ENDIF}'+LineEnding
 | |
|     +'{$IFDEF UseImplementation}'+LineEnding
 | |
|     +'procedure DoSomething;'+LineEnding
 | |
|     +'begin'+LineEnding
 | |
|     +'  {ProcBody}writeln;'+LineEnding
 | |
|     +'end;'+LineEnding
 | |
|     +'{$ENDIF}'+LineEnding;
 | |
| 
 | |
|   Test('Method jump from interface to implementation in one include file',
 | |
|        IncCode,'ProcHeader',false,'ProcBody',true);
 | |
|   Test('Method jump from implementation to interface in one include file',
 | |
|        IncCode,'ProcBody',false,'ProcHeader',false);
 | |
| end;
 | |
| 
 | |
| procedure TTestMethodJumpTool.TestMethodJump_IntfToImplSingleProc;
 | |
| begin
 | |
|   Add([
 | |
|   'unit Test1;',
 | |
|   '{$mode objfpc}{$H+}',
 | |
|   'interface',
 | |
|   'procedure {a}DoIt;',
 | |
|   'implementation',
 | |
|   'procedure DoIt;',
 | |
|   'begin',
 | |
|   '  {b}',
 | |
|   'end;',
 | |
|   'end.']);
 | |
|   TestJumpToMethod('a',false,'b',true);
 | |
| end;
 | |
| 
 | |
| procedure TTestMethodJumpTool.TestMethodJump_IntfToImplSingleProcWrongName;
 | |
| begin
 | |
|   Add([
 | |
|   'unit Test1;',
 | |
|   '{$mode objfpc}{$H+}',
 | |
|   'interface',
 | |
|   'procedure {a}DoIt;',
 | |
|   'implementation',
 | |
|   'procedure {b}Do2It;',
 | |
|   'begin',
 | |
|   'end;',
 | |
|   'end.']);
 | |
|   TestJumpToMethod('a',false,'b',false,2);
 | |
| end;
 | |
| 
 | |
| procedure TTestMethodJumpTool.TestMethodJump_IntfToImplSingleProcWrongParam;
 | |
| begin
 | |
|   Add([
 | |
|   'unit Test1;',
 | |
|   '{$mode objfpc}{$H+}',
 | |
|   'interface',
 | |
|   'procedure {a}DoIt(s: string);',
 | |
|   'implementation',
 | |
|   'procedure DoIt(s: {b}ansistring);',
 | |
|   'begin',
 | |
|   'end;',
 | |
|   'end.']);
 | |
|   TestJumpToMethod('a',false,'b',false);
 | |
| end;
 | |
| 
 | |
| procedure TTestMethodJumpTool.TestMethodJump_SingleMethod;
 | |
| begin
 | |
|   Add([
 | |
|   'unit Test1;',
 | |
|   '{$mode objfpc}{$H+}',
 | |
|   'interface',
 | |
|   'type',
 | |
|   '  TBird = class',
 | |
|   '    procedure {a}DoIt(s: string);',
 | |
|   '  end;',
 | |
|   'implementation',
 | |
|   'procedure TBird.DoIt(s: string);',
 | |
|   'begin',
 | |
|   '  {b}',
 | |
|   'end;',
 | |
|   'end.']);
 | |
|   TestJumpToMethod('a',false,'b',true);
 | |
| end;
 | |
| 
 | |
| procedure TTestMethodJumpTool.TestMethodJump_MultiMethodWrongName;
 | |
| begin
 | |
|   Add([
 | |
|   'unit Test1;',
 | |
|   '{$mode objfpc}{$H+}',
 | |
|   'interface',
 | |
|   'type',
 | |
|   '  TBird = class',
 | |
|   '    procedure {a}DoIt(s: string);',
 | |
|   '    procedure DoIt;',
 | |
|   '  end;',
 | |
|   'implementation',
 | |
|   'procedure TBird.{b}Do2It(s: string);',
 | |
|   'begin',
 | |
|   'end;',
 | |
|   'procedure TBird.DoIt;',
 | |
|   'begin',
 | |
|   'end;',
 | |
|   'end.']);
 | |
|   TestJumpToMethod('a',false,'b',false,2);
 | |
| end;
 | |
| 
 | |
| initialization
 | |
|   RegisterTest(TTestMethodJumpTool);
 | |
| 
 | |
| end.
 | |
| 
 | 
