FpDebug: tests for step over

git-svn-id: trunk@61879 -
This commit is contained in:
martin 2019-09-14 14:33:07 +00:00
parent c5fe550fbe
commit 1c5491c441
7 changed files with 457 additions and 12 deletions

3
.gitattributes vendored
View File

@ -2630,9 +2630,12 @@ components/lazdebuggers/lazdebuggerfp/test/LazDebFpTest.lpi svneol=native#text/p
components/lazdebuggers/lazdebuggerfp/test/LazDebFpTest.lpr svneol=native#text/plain
components/lazdebuggers/lazdebuggerfp/test/fpclist.txt.sample svneol=native#text/plain
components/lazdebuggers/lazdebuggerfp/test/testapps/BreakPointPrg.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/testapps/BreakPointThread2Prg.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/testapps/BreakPointThreadPrg.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/testapps/StepOverPrg.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/testbase.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/testbreakpoint.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/teststepping.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/testvarious.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfp/test/testwatches.pas svneol=native#text/pascal
components/lazdebuggers/lazdebuggerfpdserver/fpdserverdebugger.pas svneol=native#text/plain

View File

@ -41,7 +41,7 @@
<PackageName Value="FCL"/>
</Item5>
</RequiredPackages>
<Units Count="5">
<Units Count="6">
<Unit0>
<Filename Value="LazDebFpTest.lpr"/>
<IsPartOfProject Value="True"/>
@ -66,6 +66,11 @@
<IsPartOfProject Value="True"/>
<UnitName Value="TestBreakPoint"/>
</Unit4>
<Unit5>
<Filename Value="teststepping.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="TestStepping"/>
</Unit5>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -7,7 +7,7 @@ uses
cthreads,
{$ENDIF}
TestDbgControlForm, Interfaces, Forms, GuiTestRunner, TestVarious,
TestWatches, TestBase, TestBreakPoint;
TestWatches, TestBase, TestBreakPoint, TestStepping;
{$R *.res}

View File

@ -0,0 +1,102 @@
program BreakPointThread2Prg;
{$asmMode intel}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
sysutils, Classes;
type
{ TTestThread }
TTestThread = class(TThread)
procedure Execute; override;
end;
{ TTestThread2 }
TTestThread2 = class(TThread)
procedure Execute; override;
end;
var
T1, x, BreakDummy: Integer;
label
testasmlbl1;
{ TTestThread }
procedure TTestThread.Execute;
var
i: Integer;
t: array [0..5] of TTestThread2;
begin
for i := 0 to high(t) do
t[i] := TTestThread2.Create(False);
InterLockedIncrement(T1);
while not Terminated do
for i := 0 to high(t) do begin
t[i].WaitFor;
t[i].Free;
t[i] := TTestThread2.Create(False);
end;
end;
{ TTestThread2 }
procedure TTestThread2.Execute;
begin
//
end;
begin
TTestThread.Create(False);
TTestThread.Create(False);
TTestThread.Create(False);
TTestThread.Create(False);
TTestThread.Create(False);
while InterLockedExchangeAdd(T1, 0) < 4 do
sleep(10);
BreakDummy := 1;
asm
nop // TEST_BREAKPOINT=BrkMainBegin
xor eax, eax
xor ebx, ebx
add eax, 20
testasmlbl1:
sub eax, 20
add eax, 1 // TEST_BREAKPOINT=BrkMain0
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain1
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain2
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain3
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain4
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain5
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain6
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain7
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain8
add eax, 1
add eax, 1 // TEST_BREAKPOINT=BrkMain9
add eax, 1
add ebx, 1
jmp testasmlbl1
nop
nop // TEST_BREAKPOINT=BrkMainEnd
end;
end.

View File

@ -0,0 +1,108 @@
program StepOverPrg;
{$asmMode intel}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
sysutils, Classes;
type
{ TTestThread1 }
TTestThread1 = class(TThread)
procedure Execute; override;
end;
var
x, BreakDummy: Integer;
T1, T1Interfere: Integer;
T1Stop: Boolean;
label
testasmlbl1, testasmlbl2;
Procedure MyNorm;
begin
x := 1;
end;
Procedure MySleep;
begin
Sleep(50);
end;
Procedure MyBrkDis;
begin
x := 1; // TEST_BREAKPOINT=BrkDisabled
end;
Procedure MyBrkHitCnt;
begin
x := 1; // TEST_BREAKPOINT=BrkHitCnt
end;
(* Try to step over a line, while another thread is also going through the line *)
Procedure MyInterfereByThread(a: Boolean = false);
Procedure MyInterfereSleep;
begin
if a then Sleep(10); // threads do not stop / while the test waits here, other threads should hit the calling line
end;
begin
if a then
x := 1; // TEST_BREAKPOINT=BrkInterfereByThread
if a then InterLockedExchange(T1Interfere, 0); while (InterLockedExchangeAdd(T1Interfere,0)=0) do begin MyInterfereSleep; if not a then break; end;
x := 1; // TEST_BREAKPOINT=AfterInterfereByThread
InterLockedIncrement(T1Interfere); // Other threads will increment
end;
{ TTestThread1 }
procedure TTestThread1.Execute;
begin
InterLockedIncrement(T1);
while not (Terminated or T1Stop) do MyInterfereByThread;
InterLockedDecrement(T1);
end;
begin
x := 1;
x := x + 1; // TEST_BREAKPOINT=BrkStart
x := x + 1; x := x + 2; x := x + 3; // TEST_BREAKPOINT=AfterStep
MyNorm(); // TEST_BREAKPOINT=AfterStepLongLine
x := 1; MyNorm(); x := x + 1; MyNorm(); x := x + 1; MyNorm(); x := x + 1; // TEST_BREAKPOINT=AfterStepProc
MySleep(); // TEST_BREAKPOINT=AfterStepProcLong
sleep(50); // TEST_BREAKPOINT=AfterStepSleepProc
MyBrkDis; // TEST_BREAKPOINT=AfterStepSleep
MyBrkHitCnt; // TEST_BREAKPOINT=AfterStepBrkDis
x := 1; // TEST_BREAKPOINT=AfterStepBrkHitCnt
x := 1;
T1 := 0;
T1Stop := False;
TTestThread1.Create(False); while not (InterLockedExchangeAdd(T1,0)=1) do x:=1; // TEST_BREAKPOINT=BrkThreadCreateInStep
x := 1; // TEST_BREAKPOINT=AfterThreadCreateInStep
(* Prepare for threads to interfare with the hidden breakpoint *)
// create a few threads to interfer
TTestThread1.Create(False); TTestThread1.Create(False); TTestThread1.Create(False);
TTestThread1.Create(False); TTestThread1.Create(False); TTestThread1.Create(False);
while not (InterLockedExchangeAdd(T1,0)>=5) do sleep(10); // at least 5 running
MyInterfereByThread(True);
T1Stop := True;
while not (InterLockedExchangeAdd(T1,0)<=1) do x:=1; // TEST_BREAKPOINT=BrkThreadExitInStep
x := 1; // TEST_BREAKPOINT=AfterThreadExitInStep
//sleep(500);
BreakDummy := 1;
end.

View File

@ -69,16 +69,23 @@ type
// check that each brk point hit was reported (one per thread)
procedure TestBreakThreadsHitBreak;
(* TODO: All breakpoint-hits must be reported. Hits happening together with an event
in another thread must still be reported.
(* Only ONE thread running the breakpoints. Plenty of events from other
threads (including thread-exit).
Hit each breakpoint in order, WITHOUT ever re-hitting the last brk.
*HOPE* is that some events will happen while the main thread single steps
over a temp-removed break, and the single step has NOT yet moved.
So the single step will still need the brk to be tmp-removed when it
continues.
*)
procedure TestBreakThreadsIgnoreOther;
end;
implementation
var
ControlTest, ControlTestBreak, ControlTestThreadNoSkip,
ControlTestThreadMove1, ControlTestThreadMove2, ControlTestThreadHit: Pointer;
ControlTestThreadMove1, ControlTestThreadMove2, ControlTestThreadHit,
ControlTestThreadIgnoreOther: Pointer;
procedure TTestBreakPoint.TestLocation(ATestName, ABrkName: String;
ABreakHitCount: Integer);
@ -746,7 +753,7 @@ var
MainBrk, Brk1, Brk2, Brk3, Brk4, Brk5: TDBGBreakPoint;
begin
if SkipTest then exit;
if not TestControlCanTest(ControlTestThreadMove2) then exit;
if not TestControlCanTest(ControlTestThreadHit) then exit;
Src := GetCommonSourceFor(AppDir + 'BreakPointThreadPrg.pas');
TestCompile(Src, ExeName);
@ -804,15 +811,68 @@ begin
end;
end;
procedure TTestBreakPoint.TestBreakThreadsIgnoreOther;
var
ExeName: String;
i, j, ThreadIdMain: Integer;
Brk: array [0..9] of TDBGBreakPoint;
begin
if SkipTest then exit;
if not TestControlCanTest(ControlTestThreadIgnoreOther) then exit;
Src := GetCommonSourceFor(AppDir + 'BreakPointThread2Prg.pas');
TestCompile(Src, ExeName);
TestTrue('Start debugger', Debugger.StartDebugger(AppDir, ExeName));
dbg := Debugger.LazDebugger;
try
Debugger.SetBreakPoint(Src, 'BrkMainBegin');
for i := 0 to 9 do
Brk[i] := Debugger.SetBreakPoint(Src, 'BrkMain'+IntToStr(i));
AssertDebuggerNotInErrorState;
Debugger.RunToNextPause(dcRun);
AssertDebuggerState(dsPause, 'main init');
ThreadIdMain := dbg.Threads.CurrentThreads.CurrentThreadId;
for j := 1 to 70 do begin
for i := 0 to 9 do begin
Debugger.RunToNextPause(dcRun);
AssertDebuggerState(dsPause, 'in loop');
TestEquals('ThreadId', ThreadIdMain, dbg.Threads.CurrentThreads.CurrentThreadId);
TestLocation('loop '+IntToStr(j)+', '+IntToStr(i), 'BrkMain'+IntToStr(i), j);
if i > 0 then
TestEquals('prev brk hitcnt '+IntToStr(j)+', '+IntToStr(i),
j, Debugger.BreakPointByName('BrkMain'+IntToStr(i)).HitCount)
else
TestEquals('prev brk hitcnt '+IntToStr(j)+', '+IntToStr(i),
j-1, Debugger.BreakPointByName('BrkMain9').HitCount);
end;
end;
dbg.Stop;
finally
Debugger.ClearDebuggerMonitors;
Debugger.FreeDebugger;
AssertTestErrors;
end;
end;
initialization
RegisterDbgTest(TTestBreakPoint);
ControlTest := TestControlRegisterTest('TTestBreak');
ControlTestBreak := TestControlRegisterTest('TTestBreakPoint', ControlTest);
ControlTestThreadNoSkip := TestControlRegisterTest('TTestBreakThreadNoSkip', ControlTest);
ControlTestThreadMove1 := TestControlRegisterTest('TTestBreakThreadMove1', ControlTest);
ControlTestThreadMove2 := TestControlRegisterTest('TTestBreakThreadMove2', ControlTest);
ControlTestThreadHit := TestControlRegisterTest('TTestBreakThreadHit', ControlTest);
ControlTest := TestControlRegisterTest('TTestBreak');
ControlTestBreak := TestControlRegisterTest('TTestBreakPoint', ControlTest);
ControlTestThreadNoSkip := TestControlRegisterTest('TTestBreakThreadNoSkip', ControlTest);
ControlTestThreadMove1 := TestControlRegisterTest('TTestBreakThreadMove1', ControlTest);
ControlTestThreadMove2 := TestControlRegisterTest('TTestBreakThreadMove2', ControlTest);
ControlTestThreadHit := TestControlRegisterTest('TTestBreakThreadHit', ControlTest);
ControlTestThreadIgnoreOther := TestControlRegisterTest('TTestBreakThreadIgnoreOther', ControlTest);
end.

View File

@ -0,0 +1,167 @@
unit TestStepping;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, math, TestDbgControl, TestDbgTestSuites,
TTestWatchUtilities, TestCommonSources, TestDbgConfig, TestOutputLogger,
DbgIntfDebuggerBase, DbgIntfBaseTypes, LazLoggerBase, Forms;
type
{ TTestStepping }
TTestStepping = class(TDBGTestCase)
protected
Src: TCommonSource;
Dbg: TDebuggerIntf;
procedure TestLocation(ATestName, ABrkName: String; ABreakHitCount: Integer = 1); // only line-number
function IsAtLocation(ABrkName: String): Boolean; // only line-number
published
(* Step over to work with various events happening during the step
- creation/exit of threads
- ignored breakpoints (same thread / other thread)
- TODO: ignored exception: caught inside the step
- TODO: ignored exception: caught caught outside the step (step to except/finally)
*)
procedure TestStepOver;
end;
implementation
var
ControlTest, ControlTestStepOver: Pointer;
procedure TTestStepping.TestLocation(ATestName, ABrkName: String;
ABreakHitCount: Integer);
var
lc: TDBGLocationRec;
begin
AssertDebuggerState(dsPause);
lc := Debugger.LazDebugger.GetLocation;
TestEquals(ATestName+' '+ABrkName+' Loc', Src.BreakPoints[ABrkName], lc.SrcLine);
if ABreakHitCount >= 0 then
TestEquals(ATestName+' '+ABrkName+' HitCnt', Debugger.BreakPointByName(ABrkName).HitCount, ABreakHitCount);
end;
function TTestStepping.IsAtLocation(ABrkName: String): Boolean;
var
lc: TDBGLocationRec;
begin
lc := Debugger.LazDebugger.GetLocation;
Result := Src.BreakPoints[ABrkName] = lc.SrcLine;
end;
procedure TTestStepping.TestStepOver;
var
ExeName: String;
MainBrk, BrkDis, BrkHitCnt: TDBGBreakPoint;
ThreadIdMain: Integer;
begin
if SkipTest then exit;
if not TestControlCanTest(ControlTestStepOver) then exit;
Src := GetCommonSourceFor(AppDir + 'StepOverPrg.pas');
TestCompile(Src, ExeName);
TestTrue('Start debugger', Debugger.StartDebugger(AppDir, ExeName));
dbg := Debugger.LazDebugger;
try
MainBrk := Debugger.SetBreakPoint(Src, 'BrkStart');
Debugger.SetBreakPoint(Src, 'BrkThreadCreateInStep');
Debugger.SetBreakPoint(Src, 'BrkInterfereByThread');
BrkDis := Debugger.SetBreakPoint(Src, 'BrkDisabled');
BrkHitCnt := Debugger.SetBreakPoint(Src, 'BrkHitCnt');
BrkDis.Enabled := False;
BrkHitCnt.Enabled := False;
BrkHitCnt.BreakHitCount := 999;
AssertDebuggerNotInErrorState;
Debugger.RunToNextPause(dcRun);
AssertDebuggerState(dsPause);
TestLocation('Init', 'BrkStart');
ThreadIdMain := dbg.Threads.CurrentThreads.CurrentThreadId;
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStep', 'AfterStep', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStepLongLine', 'AfterStepLongLine', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStepProc', 'AfterStepProc', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStepProcLong', 'AfterStepProcLong', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStepSleepProc', 'AfterStepSleepProc', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStepSleep', 'AfterStepSleep', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStepBrkDis', 'AfterStepBrkDis', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterStepBrkHitCnt', 'AfterStepBrkHitCnt', -1);
TestEquals('No Hit for disabled break', 0, BrkDis.HitCount);
//TestEquals('No Hit for skipped break', 1, BrkHitCnt.HitCount);
(* The debugger will encounter a thread create event, during the stepping
This will mean the main-loop's FCurrentThread is the new thread
*)
Debugger.RunToNextPause(dcRun);
AssertDebuggerState(dsPause);
TestLocation('At BrkThreadCreateInStep', 'BrkThreadCreateInStep', -1);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterThreadCreateInStep', 'AfterThreadCreateInStep', -1);
TestEquals('ThreadId AfterThreadCreateInStep', ThreadIdMain, dbg.Threads.CurrentThreads.CurrentThreadId);
(* The debugger will step over a call.
Other threads will hit the FHiddenBreakpoint
*)
Debugger.RunToNextPause(dcRun);
AssertDebuggerState(dsPause);
TestLocation('At BrkInterfereByThread', 'BrkInterfereByThread', -1);
Debugger.RunToNextPause(dcStepOver);
Debugger.RunToNextPause(dcStepOver);
AssertDebuggerState(dsPause);
TestLocation('At AfterInterfereByThread', 'AfterInterfereByThread', -1);
TestEquals('ThreadId AfterInterfereByThread', ThreadIdMain, dbg.Threads.CurrentThreads.CurrentThreadId);
dbg.Stop;
finally
Debugger.ClearDebuggerMonitors;
Debugger.FreeDebugger;
AssertTestErrors;
end;
end;
initialization
RegisterDbgTest(TTestStepping);
ControlTest := TestControlRegisterTest('TTestStepping');
ControlTestStepOver := TestControlRegisterTest('TTestStepOver', ControlTest);
end.