mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-11 07:22:40 +02:00
1706 lines
50 KiB
ObjectPascal
1706 lines
50 KiB
ObjectPascal
unit TestBase;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, fpcunit, testutils, testregistry,
|
|
LCLProc, LazLogger, DbgIntfDebuggerBase, CompileHelpers, Dialogs, TestGDBMIControl,
|
|
GDBMIDebugger; // , FpGdbmiDebugger;
|
|
// EnvironmentOpts, ExtToolDialog, TransferMacros,
|
|
|
|
(*
|
|
fpclist.txt contains lines of format:
|
|
[Name]
|
|
exe=/path/fpc.exe
|
|
symbols=none,gs,gw,gwset,gw3
|
|
|
|
|
|
gdblist.txt contains lines of format:
|
|
[Name]
|
|
exe=/path/fpc.exe
|
|
version=070201
|
|
symbols=none,gs,gw,gwset,gw3
|
|
|
|
*)
|
|
|
|
type
|
|
TSymbolType = (stNone, stStabs, stDwarf, stDwarfSet, stDwarf3);
|
|
TSymbolTypes = set of TSymbolType;
|
|
|
|
const
|
|
SymbolTypeNames: Array [TSymbolType] of String = ('No_Dbg', 'Stabs', 'Dwarf', 'Dwarf+Sets', 'Dwarf3');
|
|
SymbolTypeSwitches: Array [TSymbolType] of String = ('', '-gs', '-gw', '-gw -godwarfsets', '-gw3');
|
|
|
|
stDwarf2All = [stDwarf, stDwarfSet];
|
|
stDwarfAll = [stDwarf, stDwarfSet, stDwarf3];
|
|
stSymAll = [stStabs, stDwarf, stDwarfSet, stDwarf3];
|
|
|
|
TWatchDisplayFormatNames: array [TWatchDisplayFormat] of string =
|
|
('wdfDefault',
|
|
'wdfStructure',
|
|
'wdfChar', 'wdfString',
|
|
'wdfDecimal', 'wdfUnsigned', 'wdfFloat', 'wdfHex',
|
|
'wdfPointer',
|
|
'wdfMemDump'
|
|
);
|
|
|
|
type
|
|
|
|
TGDBMIDebuggerClass = class of TGDBMIDebugger;
|
|
|
|
TCompilerInfo = record
|
|
Name: string;
|
|
ExeName: string;
|
|
SymbolTypes: TSymbolTypes;
|
|
ExtraOpts: string;
|
|
Version: Integer;
|
|
end;
|
|
|
|
TDebuggerInfo = record
|
|
Name: string;
|
|
ExeName: string;
|
|
SymbolTypes: TSymbolTypes;
|
|
Version: Integer;
|
|
end;
|
|
|
|
TUsesDir = record
|
|
DirName, ExeId: String; // dirname = filename
|
|
SymbolType: TSymbolType;
|
|
ExtraOpts, NamePostFix: string;
|
|
end;
|
|
|
|
{ TTestCallStackList }
|
|
|
|
TTestCallStackList = class(TCallStackList)
|
|
protected
|
|
function NewEntryForThread(const AThreadId: Integer): TCallStackBase; override;
|
|
end;
|
|
|
|
{ TTestCallStackMonitor }
|
|
|
|
TTestCallStackMonitor = class(TCallStackMonitor)
|
|
protected
|
|
function CreateCallStackList: TCallStackList; override;
|
|
end;
|
|
|
|
TTestThreadsMonitor = class;
|
|
{ TTestThreads }
|
|
|
|
TTestThreads = class(TThreads)
|
|
private
|
|
FMonitor: TTestThreadsMonitor;
|
|
FDataValidity: TDebuggerDataState;
|
|
public
|
|
constructor Create;
|
|
function Count: Integer; override;
|
|
procedure Clear; override;
|
|
procedure SetValidity(AValidity: TDebuggerDataState); override;
|
|
end;
|
|
|
|
{ TTestThreadsMonitor }
|
|
|
|
TTestThreadsMonitor = class(TThreadsMonitor)
|
|
protected
|
|
procedure DoStateEnterPause; override;
|
|
function CreateThreads: TThreads; override;
|
|
procedure RequestData;
|
|
end;
|
|
|
|
{ TTestWatchValue }
|
|
|
|
TTestWatchValue = class(TWatchValue)
|
|
protected
|
|
procedure RequestData;
|
|
function GetTypeInfo: TDBGType; override;
|
|
function GetValue: String; override;
|
|
public
|
|
constructor Create(AOwnerWatch: TWatch;
|
|
const AThreadId: Integer;
|
|
const AStackFrame: Integer
|
|
);
|
|
constructor Create(AOwnerWatch: TWatch);
|
|
end;
|
|
|
|
{ TTestWatchValueList }
|
|
|
|
TTestWatchValueList = class(TWatchValueList)
|
|
protected
|
|
function CopyEntry(AnEntry: TWatchValue): TWatchValue; override;
|
|
function CreateEntry(const {%H-}AThreadId: Integer; const {%H-}AStackFrame: Integer): TWatchValue; override;
|
|
end;
|
|
|
|
{ TTestWatch }
|
|
|
|
TTestWatch = class(TWatch)
|
|
function CreateValueList: TWatchValueList; override;
|
|
procedure RequestData(AWatchValue: TTestWatchValue);
|
|
public
|
|
end;
|
|
|
|
TTestWatchesMonitor = class;
|
|
{ TTestWatches }
|
|
|
|
TTestWatches = class(TWatches)
|
|
protected
|
|
FMonitor: TTestWatchesMonitor;
|
|
function WatchClass: TWatchClass; override;
|
|
procedure RequestData(AWatchValue: TWatchValue);
|
|
end;
|
|
|
|
{ TTestWatchesMonitor }
|
|
|
|
TTestWatchesMonitor = class(TWatchesMonitor)
|
|
protected
|
|
procedure DoStateChangeEx(const AOldState, ANewState: TDBGState); override;
|
|
procedure RequestData(AWatchValue: TWatchValue);
|
|
function CreateWatches: TWatches; override;
|
|
end;
|
|
|
|
TTestRegistersMonitor = class;
|
|
{ TTestRegisters }
|
|
|
|
TTestRegisters = class(TRegisters)
|
|
private
|
|
FMonitor: TTestRegistersMonitor;
|
|
protected
|
|
procedure DoDataValidityChanged(AnOldValidity: TDebuggerDataState); override;
|
|
public
|
|
function Count: Integer; reintroduce; override;
|
|
end;
|
|
|
|
{ TTEstRegistersList }
|
|
|
|
TTestRegistersList = class(TRegistersList)
|
|
private
|
|
FMonitor: TTestRegistersMonitor;
|
|
protected
|
|
function CreateEntry(AThreadId, AStackFrame: Integer): TRegisters; override;
|
|
end;
|
|
|
|
{ TTestRegistersMonitor }
|
|
|
|
TTestRegistersMonitor = class(TRegistersMonitor)
|
|
protected
|
|
function CreateRegistersList: TRegistersList; override;
|
|
procedure RequestData(ARegisters: TRegisters);
|
|
procedure DoStateEnterPause; override;
|
|
procedure DoStateLeavePause; override;
|
|
end;
|
|
|
|
{ TBaseList }
|
|
|
|
TBaseList = class
|
|
protected
|
|
function AddName(const AName: string): Integer; virtual; abstract;
|
|
procedure SetAttribute(AIndex: Integer; const AAttr, AValue: string); virtual; abstract;
|
|
public
|
|
procedure LoadFromFile(const AFileName: string);
|
|
end;
|
|
|
|
{ TCompilerList }
|
|
|
|
TCompilerList = class(TBaseList)
|
|
private
|
|
FList: array of TCompilerInfo;
|
|
function GetCompilerInfo(Index: Integer): TCompilerInfo;
|
|
function GetExeName(Index: Integer): string;
|
|
function GetName(Index: Integer): string;
|
|
function GetSymbolTypes(Index: Integer): TSymbolTypes;
|
|
protected
|
|
function AddName(const AName: string): Integer; override;
|
|
procedure SetAttribute(AIndex: Integer; const AAttr, AValue: string); override;
|
|
public
|
|
procedure Add(Name, Exe: string; Opts: String = '');
|
|
function Count: Integer;
|
|
property CompilerInfo[Index: Integer]: TCompilerInfo read GetCompilerInfo;
|
|
property Name[Index: Integer]: string read GetName;
|
|
property ExeName[Index: Integer]: string read GetExeName;
|
|
property SymbolTypes[Index: Integer]: TSymbolTypes read GetSymbolTypes;
|
|
end;
|
|
|
|
{ TDebuggerList }
|
|
|
|
TDebuggerList = class(TBaseList)
|
|
private
|
|
FList: array of TDebuggerInfo;
|
|
function GetDebuggerInfo(Index: Integer): TDebuggerInfo;
|
|
function GetExeName(Index: Integer): string;
|
|
function GetName(Index: Integer): string;
|
|
function GetSymbolTypes(Index: Integer): TSymbolTypes;
|
|
protected
|
|
function AddName(const AName: string): Integer; override;
|
|
procedure SetAttribute(AIndex: Integer; const AAttr, AValue: string); override;
|
|
public
|
|
procedure Add(Name, Exe: string);
|
|
function Count: Integer;
|
|
property DebuggerInfo[Index: Integer]: TDebuggerInfo read GetDebuggerInfo;
|
|
property Name[Index: Integer]: string read GetName;
|
|
property ExeName[Index: Integer]: string read GetExeName;
|
|
property SymbolTypes[Index: Integer]: TSymbolTypes read GetSymbolTypes;
|
|
end;
|
|
|
|
|
|
{ TCompilerSuite }
|
|
|
|
TCompilerSuite = class(TTestSuite)
|
|
private
|
|
FCompileCommandLine: String;
|
|
FCompilerInfo: TCompilerInfo;
|
|
FSymbolSwitch: String;
|
|
FSymbolType: TSymbolType;
|
|
FFileNameExt: String;
|
|
FCompiledList, FCompiledListCmdLines, FCompiledUsesList, FCompiledUsesListID: TStringList;
|
|
FInRun: Boolean;
|
|
protected
|
|
procedure Clear;
|
|
public
|
|
constructor Create(ACompilerInfo: TCompilerInfo; ASymbolType: TSymbolType; ADebuggerList: TDebuggerList);
|
|
destructor Destroy; override;
|
|
procedure Run(AResult: TTestResult); override;
|
|
procedure RunTest(ATest: TTest; AResult: TTestResult); override;
|
|
procedure RegisterDbgTest(ATestClass: TTestCaseClass);
|
|
procedure TestCompileUses(UsesDir: TUsesDir; out UsesLibDir: String; out ExeID:string);
|
|
Procedure TestCompile(const PrgName: string;
|
|
out ExeName: string;
|
|
NamePostFix: String=''; ExtraArgs: String=''
|
|
); overload;
|
|
Procedure TestCompile(const PrgName: string;
|
|
out ExeName: string;
|
|
UsesDirs: array of TUsesDir;
|
|
NamePostFix: String=''; ExtraArgs: String=''
|
|
); overload;
|
|
property CompileCommandLine: String read FCompileCommandLine;
|
|
public
|
|
property SymbolType: TSymbolType read FSymbolType;
|
|
property SymbolSwitch: String read FSymbolSwitch;
|
|
property CompilerInfo: TCompilerInfo read FCompilerInfo;
|
|
end;
|
|
|
|
{ TDebuggerSuite }
|
|
|
|
TDebuggerSuite = class(TTestSuite)
|
|
private
|
|
FDebuggerInfo: TDebuggerInfo;
|
|
FParent: TCompilerSuite;
|
|
function GetCompileCommandLine: String;
|
|
function GetCompilerInfo: TCompilerInfo;
|
|
function GetSymbolType: TSymbolType;
|
|
public
|
|
constructor Create(AParent: TCompilerSuite; ADebuggerInfo: TDebuggerInfo);
|
|
procedure RegisterDbgTest(ATestClass: TTestCaseClass);
|
|
Procedure TestCompile(const PrgName: string; out ExeName: string; UsesDirs: array of TUsesDir; NamePostFix: String=''; ExtraArgs: String='');
|
|
property CompileCommandLine: String read GetCompileCommandLine;
|
|
public
|
|
property Parent: TCompilerSuite read FParent;
|
|
property DebuggerInfo: TDebuggerInfo read FDebuggerInfo;
|
|
property SymbolType: TSymbolType read GetSymbolType;
|
|
property CompilerInfo: TCompilerInfo read GetCompilerInfo;
|
|
end;
|
|
|
|
{ TGDBTestsuite }
|
|
|
|
TGDBTestsuite = class(TTestSuite)
|
|
private
|
|
FParent: TDebuggerSuite;
|
|
function GetCompileCommandLine: String;
|
|
function GetCompilerInfo: TCompilerInfo;
|
|
function GetDebuggerInfo: TDebuggerInfo;
|
|
function GetSymbolType: TSymbolType;
|
|
public
|
|
constructor Create(AParent: TDebuggerSuite; AClass: TClass);
|
|
procedure AddTest(ATest: TTest); overload; override;
|
|
Procedure TestCompile(const PrgName: string; out ExeName: string; UsesDirs: array of TUsesDir; NamePostFix: String=''; ExtraArgs: String='');
|
|
property CompileCommandLine: String read GetCompileCommandLine;
|
|
public
|
|
property Parent: TDebuggerSuite read FParent;
|
|
property DebuggerInfo: TDebuggerInfo read GetDebuggerInfo;
|
|
property SymbolType: TSymbolType read GetSymbolType;
|
|
property CompilerInfo: TCompilerInfo read GetCompilerInfo;
|
|
end;
|
|
|
|
{ TGDBTestCase }
|
|
|
|
TGDBTestResult = class(TTestResult)
|
|
end;
|
|
|
|
TGDBTestCase = class(TTestCase)
|
|
private
|
|
// stuff for the debugger
|
|
FCallStack: TTestCallStackMonitor;
|
|
FDisassembler: TBaseDisassembler;
|
|
FExceptions: TBaseExceptions;
|
|
//FSignals: TBaseSignals;
|
|
//FBreakPoints: TIDEBreakPoints;
|
|
//FBreakPointGroups: TIDEBreakPointGroups;
|
|
FLocals: TLocalsMonitor;
|
|
FLineInfo: TBaseLineInfo;
|
|
FWatches: TTestWatchesMonitor;
|
|
FThreads: TTestThreadsMonitor;
|
|
FRegisters: TTestRegistersMonitor;
|
|
private
|
|
FParent: TGDBTestsuite;
|
|
FTestBaseName: String;
|
|
FTestResult: TGDBTestResult;
|
|
FTestErrors, FIgnoredErrors, FUnexpectedSuccess: String;
|
|
FTestCnt, FTestErrorCnt, FIgnoredErrorCnt, FUnexpectedSuccessCnt, FSucessCnt: Integer;
|
|
FTotalErrorCnt, FTotalIgnoredErrorCnt, FTotalUnexpectedSuccessCnt: Integer;
|
|
FCurrentPrgName, FCurrentExename: String;
|
|
FLogFile: TextFile;
|
|
FLogFileCreated: Boolean;
|
|
FLogFileName, FFinalLogFileName, FLogBufferText: String;
|
|
FLogDebuglnCount: Integer;
|
|
function GetCompilerInfo: TCompilerInfo;
|
|
function GetDebuggerInfo: TDebuggerInfo;
|
|
function GetSymbolType: TSymbolType;
|
|
procedure DoDbgOut(Sender: TObject; S: string; var Handled: Boolean);
|
|
procedure DoDebugln(Sender: TObject; S: string; var Handled: Boolean);
|
|
protected
|
|
function CreateResult: TTestResult; override;
|
|
function GetLogActive: Boolean;
|
|
procedure CreateLog;
|
|
procedure SetUp; override;
|
|
procedure TearDown; override;
|
|
procedure DoDbgOutPut(Sender: TObject; const AText: String); virtual;
|
|
procedure InternalDbgOutPut(Sender: TObject; const AText: String);
|
|
function InternalFeedBack(Sender: TObject; const AText, AInfo: String;
|
|
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
|
|
function GdbClass: TGDBMIDebuggerClass; virtual;
|
|
function StartGDB(AppDir, TestExeName: String): TGDBMIDebugger;
|
|
procedure CleanGdb;
|
|
procedure ClearTestErrors;
|
|
|
|
procedure AddTestError(s: string; MinGdbVers: Integer = 0; AIgnoreReason: String = '');
|
|
procedure AddTestError(s: string; MinGdbVers: Integer; MinFpcVers: Integer;AIgnoreReason: String = '');
|
|
procedure AddTestSuccess(s: string; MinGdbVers: Integer = 0; AIgnoreReason: String = '');
|
|
procedure AddTestSuccess(s: string; MinGdbVers: Integer; MinFpcVers: Integer;AIgnoreReason: String = '');
|
|
|
|
function TestEquals(Expected, Got: string): Boolean;
|
|
function TestEquals(Name: string; Expected, Got: string; MinGdbVers: Integer = 0; AIgnoreReason: String = ''): Boolean;
|
|
function TestEquals(Name: string; Expected, Got: string; MinGdbVers: Integer; MinFpcVers: Integer; AIgnoreReason: String = ''): Boolean;
|
|
|
|
function TestEquals(Expected, Got: integer): Boolean;
|
|
function TestEquals(Name: string; Expected, Got: integer; MinGdbVers: Integer = 0; AIgnoreReason: String = ''): Boolean;
|
|
function TestEquals(Name: string; Expected, Got: integer; MinGdbVers: Integer; MinFpcVers: Integer; AIgnoreReason: String = ''): Boolean;
|
|
|
|
function TestTrue(Name: string; Got: Boolean; MinGdbVers: Integer = 0; AIgnoreReason: String = ''): Boolean;
|
|
function TestTrue(Name: string; Got: Boolean; MinGdbVers: Integer; MinFpcVers: Integer; AIgnoreReason: String = ''): Boolean;
|
|
function TestFalse(Name: string; Got: Boolean; MinGdbVers: Integer = 0; AIgnoreReason: String = ''): Boolean;
|
|
function TestFalse(Name: string; Got: Boolean; MinGdbVers: Integer; MinFpcVers: Integer; AIgnoreReason: String = ''): Boolean;
|
|
|
|
procedure AssertTestErrors;
|
|
property TestErrors: string read FTestErrors;
|
|
public
|
|
Procedure TestCompile(const PrgName: string; out ExeName: string; NamePostFix: String=''; ExtraArgs: String=''); overload;
|
|
Procedure TestCompile(const PrgName: string; out ExeName: string; UsesDirs: array of TUsesDir;
|
|
NamePostFix: String=''; ExtraArgs: String=''); overload;
|
|
function SkipTest: Boolean;
|
|
procedure LogToFile(const s: string);
|
|
public
|
|
property Parent: TGDBTestsuite read FParent write FParent;
|
|
property DebuggerInfo: TDebuggerInfo read GetDebuggerInfo;
|
|
property SymbolType: TSymbolType read GetSymbolType;
|
|
property CompilerInfo: TCompilerInfo read GetCompilerInfo;
|
|
property TestBaseName: String read FTestBaseName write FTestBaseName;
|
|
public
|
|
//property BreakPoints: TIDEBreakPoints read FBreakpoints; // A list of breakpoints for the current project
|
|
//property BreakPointGroups: TIDEBreakPointGroups read FBreakPointGroups;
|
|
property Exceptions: TBaseExceptions read FExceptions; // A list of exceptions we should ignore
|
|
property CallStack: TTestCallStackMonitor read FCallStack;
|
|
property Disassembler: TBaseDisassembler read FDisassembler;
|
|
property Locals: TLocalsMonitor read FLocals;
|
|
property LineInfo: TBaseLineInfo read FLineInfo;
|
|
property Registers: TTestRegistersMonitor read FRegisters;
|
|
//property Signals: TBaseSignals read FSignals; // A list of actions for signals we know of
|
|
property Watches: TTestWatchesMonitor read FWatches;
|
|
property Threads: TTestThreadsMonitor read FThreads;
|
|
end;
|
|
|
|
function GetCompilers: TCompilerList;
|
|
function GetDebuggers: TDebuggerList;
|
|
|
|
procedure RegisterDbgTest(ATestClass: TTestCaseClass);
|
|
|
|
var
|
|
AppDir: String;
|
|
ConfDir: String;
|
|
Logdir: String;
|
|
WriteLog, WriteLogOnErr: Boolean;
|
|
|
|
TestGdbClass: TGDBMIDebuggerClass = TGDBMIDebugger;
|
|
// TestGdbClass: TGDBMIDebuggerClass = TFPGDBMIDebugger;
|
|
|
|
|
|
implementation
|
|
|
|
var
|
|
Compilers: TCompilerList = nil;
|
|
Debuggers: TDebuggerList = nil;
|
|
|
|
function StrToSymbolTypes(s: string): TSymbolTypes;
|
|
var
|
|
s2: string;
|
|
begin
|
|
Result := [];
|
|
while (s <> '') do begin
|
|
while (s <> '') and (s[1] in [' ', ',', #9, #10, #13]) do delete(s,1, 1);
|
|
s2 := '';
|
|
while (s <> '') and not (s[1] in [' ', ',', #9, #10, #13]) do begin
|
|
s2 := s2 + s[1];
|
|
delete(s,1, 1);
|
|
end;
|
|
if s2 = 'none' then Result := Result + [stNone];
|
|
if s2 = 'gs' then Result := Result + [stStabs];
|
|
if s2 = 'gw' then Result := Result + [stDwarf];
|
|
if s2 = 'gwset' then Result := Result + [stDwarfSet];
|
|
if s2 = 'gw3' then Result := Result + [stDwarf3];
|
|
end;
|
|
end;
|
|
|
|
function NameToFileName(AName: String): String;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := '';
|
|
for i := 1 to length(AName) do begin
|
|
if AName[i] in ['a'..'z', 'A'..'Z', '0'..'9', '.', '-'] then
|
|
Result := Result + AName[i]
|
|
else if AName[i] = ' ' then
|
|
Result := Result + '__'
|
|
else
|
|
Result := Result + '_' + IntToHex(ord(AName[i]), 2);
|
|
end;
|
|
end;
|
|
|
|
|
|
function GetCompilers: TCompilerList;
|
|
begin
|
|
if Compilers <> nil then exit(Compilers);
|
|
|
|
Result := TCompilerList.Create;
|
|
if FileExists(ConfDir + 'fpclist.txt') then
|
|
Result.LoadFromFile(ConfDir + 'fpclist.txt');
|
|
//if (Result.Count = 0) and (EnvironmentOptions.GetParsedCompilerFilename <> '') then begin
|
|
// Result.Add('fpc from conf', EnvironmentOptions.GetParsedCompilerFilename);
|
|
// Result.Add('fpc from conf -Xe', EnvironmentOptions.GetParsedCompilerFilename, '-Xe');
|
|
//end;
|
|
Compilers := Result;
|
|
end;
|
|
|
|
function GetDebuggers: TDebuggerList;
|
|
begin
|
|
if Debuggers <> nil then exit(Debuggers);
|
|
|
|
Result := TDebuggerList.Create;
|
|
if FileExists(ConfDir + 'gdblist.txt') then
|
|
Result.LoadFromFile(ConfDir + 'gdblist.txt');
|
|
//if (Result.Count = 0) and (EnvironmentOptions.GetParsedDebuggerFilename <> '') then
|
|
// Result.Add('gdb from conf', EnvironmentOptions.GetParsedDebuggerFilename);
|
|
Debuggers := Result;
|
|
end;
|
|
|
|
{ TTestThreads }
|
|
|
|
constructor TTestThreads.Create;
|
|
begin
|
|
inherited Create;
|
|
FDataValidity := ddsUnknown;
|
|
end;
|
|
|
|
function TTestThreads.Count: Integer;
|
|
begin
|
|
if (FDataValidity = ddsUnknown) then begin
|
|
FDataValidity := ddsRequested;
|
|
FMonitor.RequestData;
|
|
end;
|
|
|
|
Result := inherited Count;
|
|
end;
|
|
|
|
procedure TTestThreads.Clear;
|
|
begin
|
|
FDataValidity := ddsUnknown;
|
|
inherited Clear;
|
|
end;
|
|
|
|
procedure TTestThreads.SetValidity(AValidity: TDebuggerDataState);
|
|
begin
|
|
if FDataValidity = AValidity then exit;
|
|
FDataValidity := AValidity;
|
|
if FDataValidity = ddsUnknown then Clear;
|
|
end;
|
|
|
|
{ TTestThreadsMonitor }
|
|
|
|
procedure TTestThreadsMonitor.DoStateEnterPause;
|
|
begin
|
|
inherited DoStateEnterPause;
|
|
TTestThreads(Threads).SetValidity(ddsUnknown);
|
|
end;
|
|
|
|
function TTestThreadsMonitor.CreateThreads: TThreads;
|
|
begin
|
|
Result := TTestThreads.Create;
|
|
TTestThreads(Result).FMonitor := Self;
|
|
end;
|
|
|
|
procedure TTestThreadsMonitor.RequestData;
|
|
begin
|
|
if Supplier <> nil
|
|
then Supplier.RequestMasterData;
|
|
end;
|
|
|
|
{ TTestRegistersMonitor }
|
|
|
|
function TTestRegistersMonitor.CreateRegistersList: TRegistersList;
|
|
begin
|
|
Result := TTestRegistersList.Create;
|
|
TTestRegistersList(Result).FMonitor := Self;
|
|
end;
|
|
|
|
procedure TTestRegistersMonitor.RequestData(ARegisters: TRegisters);
|
|
begin
|
|
if Supplier <> nil
|
|
then Supplier.RequestData(ARegisters)
|
|
else ARegisters.DataValidity := ddsInvalid;
|
|
end;
|
|
|
|
procedure TTestRegistersMonitor.DoStateEnterPause;
|
|
begin
|
|
inherited DoStateEnterPause;
|
|
RegistersList.Clear;
|
|
end;
|
|
|
|
procedure TTestRegistersMonitor.DoStateLeavePause;
|
|
begin
|
|
inherited DoStateLeavePause;
|
|
RegistersList.Clear;
|
|
end;
|
|
|
|
{ TTEstRegistersList }
|
|
|
|
function TTestRegistersList.CreateEntry(AThreadId, AStackFrame: Integer): TRegisters;
|
|
begin
|
|
Result := TTestRegisters.Create(AThreadId, AStackFrame);
|
|
TTestRegisters(Result).FMonitor := FMonitor;
|
|
end;
|
|
|
|
{ TTestRegisters }
|
|
|
|
procedure TTestRegisters.DoDataValidityChanged(AnOldValidity: TDebuggerDataState);
|
|
begin
|
|
inherited DoDataValidityChanged(AnOldValidity);
|
|
end;
|
|
|
|
function TTestRegisters.Count: Integer;
|
|
begin
|
|
case DataValidity of
|
|
ddsUnknown: begin
|
|
AddReference;
|
|
try
|
|
Result := 0;
|
|
DataValidity := ddsRequested;
|
|
FMonitor.RequestData(Self); // Locals can be cleared, if debugger is "run" again
|
|
if DataValidity = ddsValid then Result := inherited Count();
|
|
finally
|
|
ReleaseReference;
|
|
end;
|
|
end;
|
|
ddsRequested, ddsEvaluating: Result := 0;
|
|
ddsValid: Result := inherited Count;
|
|
ddsInvalid, ddsError: Result := 0;
|
|
end;
|
|
end;
|
|
|
|
{ TTestWatches }
|
|
|
|
function TTestWatches.WatchClass: TWatchClass;
|
|
begin
|
|
Result := TTestWatch;
|
|
end;
|
|
|
|
procedure TTestWatches.RequestData(AWatchValue: TWatchValue);
|
|
begin
|
|
TTestWatchesMonitor(FMonitor).RequestData(AWatchValue);
|
|
end;
|
|
|
|
{ TTestWatchesMonitor }
|
|
|
|
procedure TTestWatchesMonitor.DoStateChangeEx(const AOldState, ANewState: TDBGState);
|
|
begin
|
|
inherited DoStateChangeEx(AOldState, ANewState);
|
|
Watches.ClearValues;
|
|
end;
|
|
|
|
procedure TTestWatchesMonitor.RequestData(AWatchValue: TWatchValue);
|
|
begin
|
|
if Supplier <> nil
|
|
then Supplier.RequestData(AWatchValue)
|
|
else AWatchValue.Validity := ddsInvalid;
|
|
end;
|
|
|
|
function TTestWatchesMonitor.CreateWatches: TWatches;
|
|
begin
|
|
Result := TTestWatches.Create;
|
|
TTestWatches(Result).FMonitor := Self;
|
|
end;
|
|
|
|
{ TTestWatchValue }
|
|
|
|
procedure TTestWatchValue.RequestData;
|
|
begin
|
|
TTestWatch(Watch).RequestData(self);
|
|
end;
|
|
|
|
function TTestWatchValue.GetTypeInfo: TDBGType;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
if not Watch.Enabled then
|
|
exit;
|
|
i := DbgStateChangeCounter; // workaround for state changes during TWatchValue.GetValue
|
|
if Validity = ddsUnknown then begin
|
|
Validity := ddsRequested;
|
|
RequestData;
|
|
if i <> DbgStateChangeCounter then exit;
|
|
end;
|
|
case Validity of
|
|
ddsRequested,
|
|
ddsEvaluating: Result := nil;
|
|
ddsValid: Result := inherited GetTypeInfo;
|
|
ddsInvalid,
|
|
ddsError: Result := nil;
|
|
end;
|
|
end;
|
|
|
|
function TTestWatchValue.GetValue: String;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if not Watch.Enabled then begin
|
|
Result := '<disabled>';
|
|
exit;
|
|
end;
|
|
i := DbgStateChangeCounter; // workaround for state changes during TWatchValue.GetValue
|
|
if Validity = ddsUnknown then begin
|
|
Result := '<evaluating>';
|
|
Validity := ddsRequested;
|
|
RequestData;
|
|
if i <> DbgStateChangeCounter then exit; // in case the debugger did run.
|
|
// TODO: The watch can also be deleted by the user
|
|
end;
|
|
case Validity of
|
|
ddsRequested, ddsEvaluating: Result := '<evaluating>';
|
|
ddsValid: Result := inherited GetValue;
|
|
ddsInvalid: Result := '<invalid>';
|
|
ddsError: Result := '<Error: '+ (inherited GetValue) +'>';
|
|
end;
|
|
end;
|
|
|
|
constructor TTestWatchValue.Create(AOwnerWatch: TWatch; const AThreadId: Integer;
|
|
const AStackFrame: Integer);
|
|
begin
|
|
inherited Create(AOwnerWatch);
|
|
Validity := ddsUnknown;
|
|
FDisplayFormat := Watch.DisplayFormat;
|
|
FEvaluateFlags := Watch.EvaluateFlags;
|
|
FRepeatCount := Watch.RepeatCount;
|
|
FThreadId := AThreadId;
|
|
FStackFrame := AStackFrame;
|
|
end;
|
|
|
|
constructor TTestWatchValue.Create(AOwnerWatch: TWatch);
|
|
begin
|
|
inherited Create(AOwnerWatch);
|
|
Validity := ddsUnknown;
|
|
FDisplayFormat := Watch.DisplayFormat;
|
|
FEvaluateFlags := Watch.EvaluateFlags;
|
|
FRepeatCount := Watch.RepeatCount;
|
|
end;
|
|
|
|
{ TTestWatchValueList }
|
|
|
|
function TTestWatchValueList.CopyEntry(AnEntry: TWatchValue): TWatchValue;
|
|
begin
|
|
Result := TTestWatchValue.Create(Watch);
|
|
Result.Assign(AnEntry);
|
|
end;
|
|
|
|
function TTestWatchValueList.CreateEntry(const AThreadId: Integer;
|
|
const AStackFrame: Integer): TWatchValue;
|
|
begin
|
|
Result := TTestWatchValue.Create(Watch, AThreadId, AStackFrame);
|
|
Add(Result);
|
|
end;
|
|
|
|
{ TTestWatch }
|
|
|
|
function TTestWatch.CreateValueList: TWatchValueList;
|
|
begin
|
|
Result := TTestWatchValueList.Create(Self);
|
|
end;
|
|
|
|
procedure TTestWatch.RequestData(AWatchValue: TTestWatchValue);
|
|
begin
|
|
if Collection <> nil
|
|
then TTestWatches(Collection).RequestData(AWatchValue)
|
|
else AWatchValue.Validity := ddsInvalid;
|
|
end;
|
|
|
|
{ TTestCallStackMonitor }
|
|
|
|
function TTestCallStackMonitor.CreateCallStackList: TCallStackList;
|
|
begin
|
|
Result := TTestCallStackList.Create;
|
|
end;
|
|
|
|
{ TTestCallStackList }
|
|
|
|
function TTestCallStackList.NewEntryForThread(const AThreadId: Integer): TCallStackBase;
|
|
begin
|
|
Result := TCallStackBase.Create;
|
|
Result.ThreadId := AThreadId;
|
|
add(Result);
|
|
end;
|
|
|
|
{ TGDBTestCase }
|
|
|
|
procedure TGDBTestCase.DoDbgOutPut(Sender: TObject; const AText: String);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TGDBTestCase.InternalDbgOutPut(Sender: TObject; const AText: String);
|
|
begin
|
|
//LogToFile(AText);
|
|
DoDbgOutPut(Sender, AText);
|
|
end;
|
|
|
|
function TGDBTestCase.GdbClass: TGDBMIDebuggerClass;
|
|
begin
|
|
Result := TestGdbClass;
|
|
end;
|
|
|
|
procedure TGDBTestCase.DoDbgOut(Sender: TObject; S: string; var Handled: Boolean);
|
|
begin
|
|
DoDebugln(Sender, '| '+S, Handled);
|
|
end;
|
|
|
|
procedure TGDBTestCase.DoDebugln(Sender: TObject; S: string; var Handled: Boolean);
|
|
begin
|
|
if GetLogActive then begin
|
|
CreateLog;
|
|
writeln(FLogFile, s);
|
|
end
|
|
else begin
|
|
if length(FLogBufferText) + length(s) < 50000000 then
|
|
FLogBufferText := FLogBufferText + s + LineEnding;
|
|
end;
|
|
|
|
Handled := True;
|
|
|
|
if pos('(gdb)', s) > 0 then begin
|
|
inc(FLogDebuglnCount);
|
|
if FLogDebuglnCount mod 10 = 0 then begin
|
|
DebugLogger.OnDebugLn := nil;
|
|
DebugLn([FLogDebuglnCount]);
|
|
DebugLogger.OnDebugLn := @DoDebugln;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TGDBTestCase.InternalFeedBack(Sender: TObject; const AText, AInfo: String;
|
|
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
|
|
begin
|
|
Result := frOk;
|
|
end;
|
|
|
|
function TGDBTestCase.GetCompilerInfo: TCompilerInfo;
|
|
begin
|
|
Result := Parent.CompilerInfo;
|
|
end;
|
|
|
|
function TGDBTestCase.GetDebuggerInfo: TDebuggerInfo;
|
|
begin
|
|
Result := Parent.DebuggerInfo;
|
|
end;
|
|
|
|
function TGDBTestCase.GetSymbolType: TSymbolType;
|
|
begin
|
|
Result := Parent.SymbolType;
|
|
end;
|
|
|
|
function TGDBTestCase.CreateResult: TTestResult;
|
|
begin
|
|
FTestResult := TGDBTestResult.Create;
|
|
Result := FTestResult;
|
|
end;
|
|
|
|
function TGDBTestCase.GetLogActive: Boolean;
|
|
begin
|
|
Result := WriteLog or FLogFileCreated;
|
|
end;
|
|
|
|
procedure TGDBTestCase.CreateLog;
|
|
var
|
|
name: String;
|
|
i: Integer;
|
|
dir: String;
|
|
begin
|
|
if FLogFileCreated then exit;
|
|
//if GetLogActive then begin
|
|
name := TestName
|
|
+ '_' + NameToFileName(GetCompilerInfo.Name)
|
|
+ '_' + SymbolTypeNames[GetSymbolType]
|
|
+ '_' + NameToFileName(GetDebuggerInfo.Name)
|
|
;
|
|
|
|
dir := ConfDir;
|
|
if DirectoryExistsUTF8(Logdir) then
|
|
dir := Logdir;
|
|
|
|
for i := 1 to length(name) do
|
|
if name[i] in ['/', '\', '*', '?', ':'] then
|
|
name[i] := '_';
|
|
|
|
FFinalLogFileName := dir + name;
|
|
FLogFileName := dir + name + '.log.running';
|
|
|
|
AssignFile(FLogFile, FLogFileName);
|
|
Rewrite(FLogFile);
|
|
FLogFileCreated := True;
|
|
|
|
writeln(FLogFile, FLogBufferText);
|
|
FLogBufferText := '';
|
|
//end;
|
|
end;
|
|
|
|
procedure TGDBTestCase.SetUp;
|
|
begin
|
|
FLogDebuglnCount := 0;
|
|
FLogFileCreated := False;
|
|
FLogBufferText := '';
|
|
ClearTestErrors;
|
|
FTotalErrorCnt := 0;
|
|
FTotalIgnoredErrorCnt := 0;
|
|
FTotalUnexpectedSuccessCnt := 0;
|
|
DebugLogger.OnDbgOut := @DoDbgOut;
|
|
DebugLogger.OnDebugLn := @DoDebugln;
|
|
inherited SetUp;
|
|
end;
|
|
|
|
procedure TGDBTestCase.TearDown;
|
|
begin
|
|
inherited TearDown;
|
|
DebugLogger.OnDbgOut := nil;
|
|
DebugLogger.OnDebugLn := nil;
|
|
if FLogFileCreated then begin
|
|
CloseFile(FLogFile);
|
|
|
|
FTotalErrorCnt := FTotalErrorCnt + FTestErrorCnt;
|
|
FTotalIgnoredErrorCnt := FTotalIgnoredErrorCnt + FIgnoredErrorCnt;
|
|
FTotalUnexpectedSuccessCnt := FTotalUnexpectedSuccessCnt + FUnexpectedSuccessCnt;
|
|
if (FTotalIgnoredErrorCnt > 0)
|
|
then FFinalLogFileName := FFinalLogFileName + '.ignored_'+IntToStr(FTotalIgnoredErrorCnt);
|
|
if (FTotalUnexpectedSuccessCnt > 0)
|
|
then FFinalLogFileName := FFinalLogFileName + '.unexpected_'+IntToStr(FTotalUnexpectedSuccessCnt);
|
|
if (FTotalErrorCnt > 0)
|
|
then FFinalLogFileName := FFinalLogFileName + '.failed_'+IntToStr(FTotalErrorCnt);
|
|
|
|
FFinalLogFileName := FFinalLogFileName + '.log';
|
|
RenameFileUTF8(FLogFileName, FFinalLogFileName);
|
|
end;
|
|
DebugLogger.OnDbgOut := nil;
|
|
DebugLogger.OnDebugLn := nil;
|
|
FLogBufferText := '';
|
|
end;
|
|
|
|
function TGDBTestCase.StartGDB(AppDir, TestExeName: String): TGDBMIDebugger;
|
|
begin
|
|
//FBreakPoints := TManagedBreakPoints.Create(Self);
|
|
//FBreakPointGroups := TIDEBreakPointGroups.Create;
|
|
FWatches := TTestWatchesMonitor.Create;
|
|
FThreads := TTestThreadsMonitor.Create;
|
|
FExceptions := TBaseExceptions.Create(TBaseException);
|
|
//FSignals := TBaseSignals.Create(TBaseSignal);
|
|
FLocals := TLocalsMonitor.Create;
|
|
FLineInfo := TBaseLineInfo.Create;
|
|
FCallStack := TTestCallStackMonitor.Create;
|
|
FDisassembler := TBaseDisassembler.Create;
|
|
FRegisters := TTestRegistersMonitor.Create;
|
|
|
|
Result := GdbClass.Create(DebuggerInfo.ExeName);
|
|
Result.OnDbgOutput := @InternalDbgOutPut;
|
|
Result.OnFeedback := @InternalFeedBack;
|
|
|
|
//TManagedBreakpoints(FBreakpoints).Master := FDebugger.BreakPoints;
|
|
FWatches.Supplier := Result.Watches;
|
|
FThreads.Supplier := Result.Threads;
|
|
FLocals.Supplier := Result.Locals;
|
|
//FLineInfo.Master := Result.LineInfo;
|
|
FCallStack.Supplier := Result.CallStack;
|
|
//FDisassembler.Master := Result.Disassembler;
|
|
Result.Exceptions := FExceptions;
|
|
//FSignals.Master := Result.Signals;
|
|
FRegisters.Supplier := Result.Registers;
|
|
|
|
Result.Init;
|
|
if Result.State = dsError then
|
|
Fail(' Failed Init');
|
|
Result.WorkingDir := AppDir;
|
|
Result.FileName := TestExeName;
|
|
Result.Arguments := '';
|
|
Result.ShowConsole := True;
|
|
|
|
end;
|
|
|
|
procedure TGDBTestCase.CleanGdb;
|
|
begin
|
|
//TManagedBreakpoints(FBreakpoints).Master := nil;
|
|
FWatches.Supplier := nil;
|
|
FThreads.Supplier := nil;
|
|
FLocals.Supplier := nil;
|
|
//FLineInfo.Master := nil;
|
|
FCallStack.Supplier := nil;
|
|
//FDisassembler.Master := nil;
|
|
//FExceptions.Master := nil;
|
|
//FSignals.Master := nil;
|
|
// FRegisters.Master := nil;
|
|
|
|
FreeAndNil(FWatches);
|
|
FreeAndNil(FThreads);
|
|
//FreeAndNil(FBreakPoints);
|
|
//FreeAndNil(FBreakPointGroups);
|
|
FreeAndNil(FCallStack);
|
|
FreeAndNil(FDisassembler);
|
|
FreeAndNil(FExceptions);
|
|
//FreeAndNil(FSignals);
|
|
FreeAndNil(FLocals);
|
|
FreeAndNil(FLineInfo);
|
|
FreeAndNil(FRegisters);
|
|
end;
|
|
|
|
procedure TGDBTestCase.ClearTestErrors;
|
|
begin
|
|
FTotalErrorCnt := FTotalErrorCnt + FTestErrorCnt;
|
|
FTotalIgnoredErrorCnt := FTotalIgnoredErrorCnt + FIgnoredErrorCnt;
|
|
FTotalUnexpectedSuccessCnt := FTotalUnexpectedSuccessCnt + FUnexpectedSuccessCnt;
|
|
|
|
FTestErrors := '';
|
|
FIgnoredErrors := '';
|
|
FUnexpectedSuccess := '';
|
|
FTestErrorCnt := 0;
|
|
FIgnoredErrorCnt := 0;
|
|
FUnexpectedSuccessCnt := 0;
|
|
FSucessCnt := 0;
|
|
FTestCnt := 0;
|
|
FTestBaseName := '';
|
|
end;
|
|
|
|
procedure TGDBTestCase.AddTestError(s: string; MinGdbVers: Integer = 0; AIgnoreReason: String = '');
|
|
begin
|
|
AddTestError(s, MinGdbVers, 0, AIgnoreReason);
|
|
end;
|
|
|
|
procedure TGDBTestCase.AddTestError(s: string; MinGdbVers: Integer; MinFpcVers: Integer;
|
|
AIgnoreReason: String);
|
|
var
|
|
IgnoreReason: String;
|
|
i: Integer;
|
|
begin
|
|
inc(FTestCnt);
|
|
IgnoreReason := '';
|
|
s := FTestBaseName + s;
|
|
if MinGdbVers > 0 then begin
|
|
i := GetDebuggerInfo.Version;
|
|
if (i > 0) and (i < MinGdbVers) then
|
|
IgnoreReason := 'GDB ('+IntToStr(i)+') to old, required:'+IntToStr(MinGdbVers);
|
|
end;
|
|
if MinFpcVers > 0 then begin
|
|
i := GetCompilerInfo.Version;
|
|
if (i > 0) and (i < MinFpcVers) then
|
|
IgnoreReason := 'FPC ('+IntToStr(i)+') to old, required:'+IntToStr(MinFpcVers);
|
|
end;
|
|
IgnoreReason := IgnoreReason + AIgnoreReason;
|
|
|
|
if IgnoreReason <> '' then begin
|
|
FIgnoredErrors := FIgnoredErrors + IntToStr(FTestCnt) + ': ' + '### '+IgnoreReason +' >>> '+s+LineEnding;
|
|
inc(FIgnoredErrorCnt);
|
|
end else begin
|
|
FTestErrors := FTestErrors + IntToStr(FTestCnt) + ': ' + s + LineEnding;
|
|
inc(FTestErrorCnt);
|
|
end;
|
|
end;
|
|
|
|
procedure TGDBTestCase.AddTestSuccess(s: string; MinGdbVers: Integer; AIgnoreReason: String = '');
|
|
begin
|
|
AddTestSuccess(s, MinGdbVers, 0, AIgnoreReason);
|
|
end;
|
|
|
|
procedure TGDBTestCase.AddTestSuccess(s: string; MinGdbVers: Integer; MinFpcVers: Integer;
|
|
AIgnoreReason: String);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
s := FTestBaseName + s;
|
|
inc(FTestCnt);
|
|
if (MinGdbVers > 0) then begin
|
|
i := GetDebuggerInfo.Version;
|
|
if (i > 0) and (i < MinGdbVers) then
|
|
AIgnoreReason := AIgnoreReason
|
|
+ 'GDB ('+IntToStr(i)+') to old, required:'+IntToStr(MinGdbVers);
|
|
end;
|
|
if (MinFpcVers > 0) then begin
|
|
i := GetCompilerInfo.Version;
|
|
if (i > 0) and (i < MinFpcVers) then
|
|
AIgnoreReason := AIgnoreReason
|
|
+ 'FPC ('+IntToStr(i)+') to old, required:'+IntToStr(MinFpcVers);
|
|
end;
|
|
|
|
if AIgnoreReason <> '' then begin
|
|
FUnexpectedSuccess:= FUnexpectedSuccess + IntToStr(FTestCnt) + ': ' + '### '+AIgnoreReason +' >>> '+s+LineEnding;
|
|
inc(FUnexpectedSuccessCnt);
|
|
end
|
|
else
|
|
inc(FSucessCnt);
|
|
end;
|
|
|
|
function TGDBTestCase.TestEquals(Expected, Got: string): Boolean;
|
|
begin
|
|
Result := TestEquals('', Expected, Got);
|
|
end;
|
|
|
|
function TGDBTestCase.TestEquals(Name: string; Expected, Got: string; MinGdbVers: Integer = 0; AIgnoreReason: String = ''): Boolean;
|
|
begin
|
|
Result := TestEquals(Name, Expected, Got, MinGdbVers, 0, AIgnoreReason);
|
|
end;
|
|
|
|
function TGDBTestCase.TestEquals(Name: string; Expected, Got: string; MinGdbVers: Integer;
|
|
MinFpcVers: Integer; AIgnoreReason: String): Boolean;
|
|
begin
|
|
Result := Got = Expected;
|
|
if Result
|
|
then AddTestSuccess(Name + ': Expected to fail with, but succeded, Got "'+Got+'"', MinGdbVers, MinFpcVers, AIgnoreReason)
|
|
else AddTestError(Name + ': Expected "'+Expected+'", Got "'+Got+'"', MinGdbVers, MinFpcVers, AIgnoreReason);
|
|
end;
|
|
|
|
function TGDBTestCase.TestEquals(Expected, Got: integer): Boolean;
|
|
begin
|
|
Result := TestEquals('', Expected, Got);
|
|
end;
|
|
|
|
function TGDBTestCase.TestEquals(Name: string; Expected, Got: integer; MinGdbVers: Integer = 0; AIgnoreReason: String = ''): Boolean;
|
|
begin
|
|
Result := TestEquals(Name, Expected, Got, MinGdbVers, 0, AIgnoreReason);
|
|
end;
|
|
|
|
function TGDBTestCase.TestEquals(Name: string; Expected, Got: integer; MinGdbVers: Integer;
|
|
MinFpcVers: Integer; AIgnoreReason: String): Boolean;
|
|
begin
|
|
Result := Got = Expected;
|
|
if Result
|
|
then AddTestSuccess(Name + ': Expected to fail with, but succeded, Got "'+IntToStr(Got)+'"', MinGdbVers, MinFpcVers, AIgnoreReason)
|
|
else AddTestError(Name + ': Expected "'+IntToStr(Expected)+'", Got "'+IntToStr(Got)+'"', MinGdbVers, MinFpcVers, AIgnoreReason);
|
|
end;
|
|
|
|
function TGDBTestCase.TestTrue(Name: string; Got: Boolean; MinGdbVers: Integer; AIgnoreReason: String = ''): Boolean;
|
|
begin
|
|
Result := TestTrue(Name, Got, MinGdbVers, 0, AIgnoreReason);
|
|
end;
|
|
|
|
function TGDBTestCase.TestTrue(Name: string; Got: Boolean; MinGdbVers: Integer;
|
|
MinFpcVers: Integer; AIgnoreReason: String): Boolean;
|
|
begin
|
|
Result := Got;
|
|
if Result
|
|
then AddTestSuccess(Name + ': Expected to fail with, but succeded, Got "True"', MinGdbVers, MinFpcVers, AIgnoreReason)
|
|
else AddTestError(Name + ': Expected "True", Got "False"', MinGdbVers, MinFpcVers, AIgnoreReason);
|
|
end;
|
|
|
|
function TGDBTestCase.TestFalse(Name: string; Got: Boolean; MinGdbVers: Integer; AIgnoreReason: String = ''): Boolean;
|
|
begin
|
|
Result := TestFalse(Name, Got, MinGdbVers, 0, AIgnoreReason);
|
|
end;
|
|
|
|
function TGDBTestCase.TestFalse(Name: string; Got: Boolean; MinGdbVers: Integer;
|
|
MinFpcVers: Integer; AIgnoreReason: String): Boolean;
|
|
begin
|
|
Result := not Got;
|
|
if Result
|
|
then AddTestSuccess(Name + ': Expected to fail with, but succeded, Got "False"', MinGdbVers, MinFpcVers, AIgnoreReason)
|
|
else AddTestError(Name + ': Expected "False", Got "True"', MinGdbVers, MinFpcVers, AIgnoreReason);
|
|
end;
|
|
|
|
procedure TGDBTestCase.AssertTestErrors;
|
|
var
|
|
s, s1: String;
|
|
begin
|
|
s := FTestErrors;
|
|
s1 := Format('Failed: %d of %d - Ignored: %d Unexpected: %d - Success: %d',
|
|
[FTestErrorCnt, FTestCnt, FIgnoredErrorCnt, FUnexpectedSuccessCnt, FSucessCnt ]);
|
|
FTestErrors := '';
|
|
if GetLogActive or (WriteLogOnErr and (FTestErrorCnt > 0)) then begin
|
|
CreateLog;
|
|
writeln(FLogFile, '***' + s1 + '***' +LineEnding);
|
|
writeln(FLogFile, '================= Failed:'+LineEnding);
|
|
writeln(FLogFile, s);
|
|
writeln(FLogFile, '================= Ignored'+LineEnding);
|
|
writeln(FLogFile, FIgnoredErrors);
|
|
writeln(FLogFile, '================= Unexpected Success'+LineEnding);
|
|
writeln(FLogFile, FUnexpectedSuccess);
|
|
writeln(FLogFile, '================='+LineEnding);
|
|
end;
|
|
if s <> '' then begin
|
|
Fail(s1+ LineEnding + s);
|
|
end;
|
|
end;
|
|
|
|
procedure TGDBTestCase.TestCompile(const PrgName: string; out ExeName: string;
|
|
NamePostFix: String=''; ExtraArgs: String='');
|
|
begin
|
|
TestCompile(PrgName, ExeName, [], NamePostFix, ExtraArgs);
|
|
end;
|
|
|
|
procedure TGDBTestCase.TestCompile(const PrgName: string; out ExeName: string;
|
|
UsesDirs: array of TUsesDir; NamePostFix: String; ExtraArgs: String);
|
|
begin
|
|
LogToFile(LineEnding+LineEnding + '******************* compile '+PrgName + ' ' + ExtraArgs +LineEnding );
|
|
Parent.TestCompile(PrgName, ExeName, UsesDirs, NamePostFix, ExtraArgs);
|
|
LogToFile(Parent.CompileCommandLine+LineEnding + '*******************' +LineEnding+LineEnding );
|
|
FCurrentPrgName := PrgName;
|
|
FCurrentExename := ExeName;
|
|
end;
|
|
|
|
function TGDBTestCase.SkipTest: Boolean;
|
|
begin
|
|
Result := not TestControlForm.chkGDB.Checked[TestControlForm.chkGDB.Items.IndexOf(DebuggerInfo.Name)];
|
|
Result := Result or
|
|
not TestControlForm.chkFPC.Checked[TestControlForm.chkFPC.Items.IndexOf(CompilerInfo.Name)];
|
|
end;
|
|
|
|
procedure TGDBTestCase.LogToFile(const s: string);
|
|
begin
|
|
DebugLn('## '+s);
|
|
end;
|
|
|
|
{ TBaseList }
|
|
|
|
procedure TBaseList.LoadFromFile(const AFileName: string);
|
|
var
|
|
txt: TStringList;
|
|
s: string;
|
|
i, j, k: Integer;
|
|
begin
|
|
txt := TStringList.Create;
|
|
txt.LoadFromFile(AFileName);
|
|
j := -1;
|
|
for i := 0 to txt.Count - 1 do begin
|
|
s := txt[i];
|
|
if Trim(s) = '' then continue;
|
|
if copy(s, 1, 1) = '[' then begin
|
|
j := AddName(GetPart(['['], [']'], s));
|
|
continue;
|
|
end;
|
|
if j < 0 then continue;
|
|
k := pos('=', s);
|
|
SetAttribute(j, copy(s, 1, k-1), copy(s, k + 1, length(s)));
|
|
end;
|
|
txt.Free;
|
|
end;
|
|
|
|
{ TCompilerList }
|
|
|
|
function TCompilerList.GetExeName(Index: Integer): string;
|
|
begin
|
|
Result := FList[Index].ExeName;
|
|
end;
|
|
|
|
function TCompilerList.GetCompilerInfo(Index: Integer): TCompilerInfo;
|
|
begin
|
|
Result := FList[Index];
|
|
end;
|
|
|
|
function TCompilerList.GetName(Index: Integer): string;
|
|
begin
|
|
Result := FList[Index].Name;
|
|
end;
|
|
|
|
function TCompilerList.GetSymbolTypes(Index: Integer): TSymbolTypes;
|
|
begin
|
|
Result := FList[Index].SymbolTypes;
|
|
end;
|
|
|
|
function TCompilerList.AddName(const AName: string): Integer;
|
|
begin
|
|
Result := length(FList);
|
|
SetLength(FList, Result + 1);
|
|
FList[Result].Name := AName;
|
|
FList[Result].SymbolTypes := [];
|
|
FList[Result].ExtraOpts := '';
|
|
end;
|
|
|
|
procedure TCompilerList.SetAttribute(AIndex: Integer; const AAttr, AValue: string);
|
|
begin
|
|
case StringCase(AAttr, ['exe', 'symbols', 'opts', 'vers', 'version'], True, False) of
|
|
0: begin // exe
|
|
FList[AIndex].ExeName := AValue;
|
|
end;
|
|
1: begin // symbols
|
|
FList[AIndex].SymbolTypes := StrToSymbolTypes(AValue);
|
|
end;
|
|
2: begin //opts
|
|
FList[AIndex].ExtraOpts := AValue;
|
|
end;
|
|
3,4: begin
|
|
FList[AIndex].Version := StrToIntDef(AValue,-1);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCompilerList.Add(Name, Exe: string; Opts: String = '');
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
i := AddName(Name);
|
|
FList[i].ExeName := Exe;
|
|
FList[i].SymbolTypes := [stStabs, stDwarf, stDwarfSet];
|
|
FList[i].ExtraOpts := Opts;
|
|
end;
|
|
|
|
function TCompilerList.Count: Integer;
|
|
begin
|
|
Result := length(FList);
|
|
end;
|
|
|
|
{ TDebuggerList }
|
|
|
|
function TDebuggerList.GetExeName(Index: Integer): string;
|
|
begin
|
|
Result := FList[Index].ExeName;
|
|
end;
|
|
|
|
function TDebuggerList.GetDebuggerInfo(Index: Integer): TDebuggerInfo;
|
|
begin
|
|
Result := FList[Index];
|
|
end;
|
|
|
|
function TDebuggerList.GetName(Index: Integer): string;
|
|
begin
|
|
Result := FList[Index].Name;
|
|
end;
|
|
|
|
function TDebuggerList.GetSymbolTypes(Index: Integer): TSymbolTypes;
|
|
begin
|
|
Result := FList[Index].SymbolTypes;
|
|
end;
|
|
|
|
function TDebuggerList.AddName(const AName: string): Integer;
|
|
begin
|
|
Result := length(FList);
|
|
SetLength(FList, Result + 1);
|
|
FList[Result].Name := AName;
|
|
FList[Result].SymbolTypes := [];
|
|
end;
|
|
|
|
procedure TDebuggerList.SetAttribute(AIndex: Integer; const AAttr, AValue: string);
|
|
begin
|
|
case StringCase(AAttr, ['exe', 'symbols', 'vers', 'version'], True, False) of
|
|
0: begin // exe
|
|
FList[AIndex].ExeName := AValue;
|
|
end;
|
|
1: begin // symbols
|
|
FList[AIndex].SymbolTypes := StrToSymbolTypes(AValue);
|
|
end;
|
|
2,3: begin
|
|
FList[AIndex].Version := StrToIntDef(AValue,-1);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TDebuggerList.Add(Name, Exe: string);
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
i := AddName(Name);
|
|
FList[i].ExeName := Exe;
|
|
FList[i].SymbolTypes := [stStabs, stDwarf, stDwarfSet];
|
|
end;
|
|
|
|
function TDebuggerList.Count: Integer;
|
|
begin
|
|
Result := length(FList);
|
|
end;
|
|
|
|
{ TCompilerSuite }
|
|
|
|
procedure TCompilerSuite.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to FCompiledList.Count - 1 do
|
|
DeleteFile(FCompiledList[i]);
|
|
for i := 0 to FCompiledUsesList.Count - 1 do
|
|
DeleteDirectory(FCompiledUsesList[i], False);
|
|
FCompiledList.Clear;
|
|
FCompiledListCmdLines.Clear;
|
|
FCompiledUsesList.Clear;
|
|
FCompiledUsesListID.Clear;
|
|
end;
|
|
|
|
constructor TCompilerSuite.Create(ACompilerInfo: TCompilerInfo; ASymbolType: TSymbolType;
|
|
ADebuggerList: TDebuggerList);
|
|
var
|
|
i: Integer;
|
|
SubSuite: TDebuggerSuite;
|
|
begin
|
|
inherited Create(ACompilerInfo.Name + ' / ' + SymbolTypeNames[ASymbolType]);
|
|
FCompilerInfo := ACompilerInfo;
|
|
FSymbolType := ASymbolType;
|
|
|
|
FCompiledList := TStringList.Create;
|
|
FCompiledListCmdLines := TStringList.Create;
|
|
FCompiledUsesList := TStringList.Create;
|
|
FCompiledUsesListID := TStringList.Create;
|
|
FSymbolSwitch := SymbolTypeSwitches[FSymbolType];
|
|
FInRun := False;
|
|
|
|
FFileNameExt := SymbolTypeNames[FSymbolType] + '_' + NameToFileName(CompilerInfo.Name);
|
|
|
|
for i := 0 to ADebuggerList.Count - 1 do begin
|
|
if not (FSymbolType in ADebuggerList.SymbolTypes[i]) then
|
|
continue;
|
|
SubSuite := TDebuggerSuite.Create(Self, ADebuggerList.DebuggerInfo[i]);
|
|
Self.AddTest(SubSuite);
|
|
end;
|
|
end;
|
|
|
|
destructor TCompilerSuite.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
Clear;
|
|
FreeAndNil(FCompiledList);
|
|
FreeAndNil(FCompiledListCmdLines);
|
|
FreeAndNil(FCompiledUsesList);
|
|
FreeAndNil(FCompiledUsesListID);
|
|
end;
|
|
|
|
procedure TCompilerSuite.Run(AResult: TTestResult);
|
|
begin
|
|
FInRun := True;
|
|
try
|
|
inherited Run(AResult);
|
|
finally
|
|
FInRun := False;
|
|
Clear;
|
|
end;
|
|
end;
|
|
|
|
procedure TCompilerSuite.RunTest(ATest: TTest; AResult: TTestResult);
|
|
begin
|
|
try
|
|
inherited RunTest(ATest, AResult);
|
|
finally
|
|
if not FInRun then Clear;
|
|
end;
|
|
end;
|
|
|
|
procedure TCompilerSuite.RegisterDbgTest(ATestClass: TTestCaseClass);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to Tests.Count - 1 do
|
|
if Test[i] is TDebuggerSuite then
|
|
TDebuggerSuite(Test[i]).RegisterDbgTest(ATestClass);
|
|
end;
|
|
|
|
procedure TCompilerSuite.TestCompileUses(UsesDir: TUsesDir; out UsesLibDir: String; out ExeID:string);
|
|
var
|
|
Opts: String;
|
|
i: Integer;
|
|
DirPostFix: String;
|
|
begin
|
|
DirPostFix := SymbolTypeNames[UsesDir.SymbolType] + '_' + NameToFileName(CompilerInfo.Name);
|
|
UsesLibDir := AppendPathDelim(ExtractFilePath(UsesDir.DirName)) + 'lib__'
|
|
+ DirPostFix;
|
|
if UsesDir.NamePostFix <> '' then
|
|
UsesLibDir := UsesLibDir + '__' + UsesDir.NamePostFix;
|
|
|
|
i := FCompiledUsesList.IndexOf(UsesLibDir);
|
|
if i < 0 then begin
|
|
if DirectoryExists(AppendPathDelim(UsesLibDir)) then
|
|
raise EAssertionFailedError.Create('Found existing dir before compiling: ' + UsesLibDir);
|
|
i := FCompiledUsesList.Add(UsesLibDir);
|
|
ExeID := '_U'+IntToStr(i)+UsesDir.ExeId+'_'+DirPostFix+'__';
|
|
FCompiledUsesListID.Add(ExeID);
|
|
|
|
CreateDirUTF8(UsesLibDir);
|
|
|
|
Opts := SymbolTypeSwitches[UsesDir.SymbolType] + ' ' + UsesDir.ExtraOpts;
|
|
if not CompileHelper.TestCompileUnits(CompilerInfo.ExeName, Opts, UsesDir.DirName, UsesLibDir)
|
|
then
|
|
raise EAssertionFailedError.Create('Compilation Failed: ' + UsesDir.DirName + LineEnding + CompileHelper.LastError);
|
|
end
|
|
else begin
|
|
ExeID := FCompiledUsesListID[i];
|
|
end;
|
|
end;
|
|
|
|
procedure TCompilerSuite.TestCompile(const PrgName: string; out ExeName: string;
|
|
NamePostFix: String=''; ExtraArgs: String='');
|
|
begin
|
|
TestCompile(PrgName, ExeName, [], NamePostFix, ExtraArgs);
|
|
end;
|
|
|
|
procedure TCompilerSuite.TestCompile(const PrgName: string; out ExeName: string;
|
|
UsesDirs: array of TUsesDir; NamePostFix: String; ExtraArgs: String);
|
|
var
|
|
ExePath, ErrMsg, ExtraFUPath: String;
|
|
i: Integer;
|
|
NewLibDir, NewExeID: string;
|
|
begin
|
|
FCompileCommandLine := '';
|
|
ExePath := ExtractFileNameWithoutExt(PrgName);
|
|
ExeName := ExtractFileNameOnly(ExePath);
|
|
ExePath := AppendPathDelim(copy(ExePath, 1, length(ExePath) - length(ExeName)));
|
|
if DirectoryExistsUTF8(ExePath + 'lib') then
|
|
ExePath := AppendPathDelim(ExePath + 'lib');
|
|
|
|
ExtraFUPath := '';
|
|
for i := low(UsesDirs) to high(UsesDirs) do begin
|
|
TestCompileUses(UsesDirs[i], NewLibDir, NewExeID);
|
|
ExtraFUPath := ExtraFUPath + ' -Fu'+NewLibDir;
|
|
NamePostFix := NamePostFix + NewExeID;
|
|
end;
|
|
|
|
ExeName := ExePath + ExeName + FFileNameExt + NamePostFix + GetExeExt;
|
|
|
|
if ExtraArgs <> '' then
|
|
ExtraArgs := ' '+ExtraArgs;
|
|
i := FCompiledList.IndexOf(ExeName);
|
|
if i < 0 then begin
|
|
if FileExists(ExeName) then
|
|
raise EAssertionFailedError.Create('Found existing file before compiling: ' + ExeName);
|
|
i := FCompiledList.Add(ExeName);
|
|
ErrMsg := CompileHelper.TestCompile(PrgName,
|
|
FSymbolSwitch + ' ' + ExtraFUPath + ' ' + FCompilerInfo.ExtraOpts + ExtraArgs,
|
|
ExeName,
|
|
CompilerInfo.ExeName);
|
|
FCompileCommandLine := CompileHelper.CommandLine;
|
|
FCompiledListCmdLines.Add(FCompileCommandLine);
|
|
if ErrMsg <> '' then begin
|
|
debugln(ErrMsg);
|
|
raise EAssertionFailedError.Create('Compilation Failed: ' + ExeName + LineEnding + ErrMsg);
|
|
end;
|
|
end
|
|
else
|
|
FCompileCommandLine := FCompiledListCmdLines[i];
|
|
|
|
if not FileExists(ExeName) then
|
|
raise EAssertionFailedError.Create('Missing compiled exe ' + ExeName);
|
|
end;
|
|
|
|
{ TDebuggerSuite }
|
|
|
|
function TDebuggerSuite.GetCompilerInfo: TCompilerInfo;
|
|
begin
|
|
Result := Parent.CompilerInfo;
|
|
end;
|
|
|
|
function TDebuggerSuite.GetCompileCommandLine: String;
|
|
begin
|
|
Result := Parent.CompileCommandLine;
|
|
end;
|
|
|
|
function TDebuggerSuite.GetSymbolType: TSymbolType;
|
|
begin
|
|
Result := Parent.SymbolType;
|
|
end;
|
|
|
|
constructor TDebuggerSuite.Create(AParent: TCompilerSuite;
|
|
ADebuggerInfo: TDebuggerInfo);
|
|
begin
|
|
inherited Create(ADebuggerInfo.Name + ' ('+AParent.TestName+')');
|
|
FParent := AParent;
|
|
FDebuggerInfo := ADebuggerInfo;
|
|
end;
|
|
|
|
procedure TDebuggerSuite.RegisterDbgTest(ATestClass: TTestCaseClass);
|
|
var
|
|
NewTest: TGDBTestsuite;
|
|
begin
|
|
NewTest := TGDBTestsuite.Create(Self, ATestClass);
|
|
AddTest(NewTest);
|
|
end;
|
|
|
|
procedure TDebuggerSuite.TestCompile(const PrgName: string; out ExeName: string;
|
|
UsesDirs: array of TUsesDir; NamePostFix: String=''; ExtraArgs: String='');
|
|
begin
|
|
Parent.TestCompile(PrgName, ExeName, UsesDirs, NamePostFix, ExtraArgs);
|
|
end;
|
|
|
|
{ TGDBTestsuite }
|
|
|
|
function TGDBTestsuite.GetCompilerInfo: TCompilerInfo;
|
|
begin
|
|
Result := Parent.CompilerInfo;
|
|
end;
|
|
|
|
function TGDBTestsuite.GetCompileCommandLine: String;
|
|
begin
|
|
Result := Parent.CompileCommandLine;
|
|
end;
|
|
|
|
function TGDBTestsuite.GetDebuggerInfo: TDebuggerInfo;
|
|
begin
|
|
Result := Parent.DebuggerInfo;
|
|
end;
|
|
|
|
function TGDBTestsuite.GetSymbolType: TSymbolType;
|
|
begin
|
|
Result := Parent.SymbolType;
|
|
end;
|
|
|
|
constructor TGDBTestsuite.Create(AParent: TDebuggerSuite; AClass: TClass);
|
|
begin
|
|
inherited Create(AClass);
|
|
FParent := AParent;
|
|
end;
|
|
|
|
procedure TGDBTestsuite.AddTest(ATest: TTest);
|
|
begin
|
|
inherited AddTest(ATest);
|
|
if ATest is TGDBTestCase then
|
|
TGDBTestCase(ATest).Parent := Self;
|
|
end;
|
|
|
|
procedure TGDBTestsuite.TestCompile(const PrgName: string; out ExeName: string;
|
|
UsesDirs: array of TUsesDir; NamePostFix: String=''; ExtraArgs: String='');
|
|
begin
|
|
Parent.TestCompile(PrgName, ExeName, UsesDirs, NamePostFix, ExtraArgs);
|
|
end;
|
|
|
|
{ --- }
|
|
|
|
procedure RegisterDbgTest(ATestClass: TTestCaseClass);
|
|
var
|
|
Suite: TTestSuite;
|
|
i: Integer;
|
|
begin
|
|
Suite := GetTestRegistry;
|
|
for i := 0 to Suite.Tests.Count - 1 do
|
|
if Suite.Test[i] is TCompilerSuite then
|
|
TCompilerSuite(Suite.Test[i]).RegisterDbgTest(ATestClass);
|
|
end;
|
|
|
|
|
|
procedure BuildTestSuites;
|
|
var
|
|
FpcList: TCompilerList;
|
|
GdbList: TDebuggerList;
|
|
CompilerSuite: TCompilerSuite;
|
|
i: Integer;
|
|
st: TSymbolType;
|
|
begin
|
|
FpcList := GetCompilers;
|
|
GdbList := GetDebuggers;
|
|
|
|
for i := 0 to FpcList.Count - 1 do begin
|
|
for st := low(TSymbolType) to high(TSymbolType) do begin
|
|
if not (st in FpcList.CompilerInfo[i].SymbolTypes) then
|
|
continue;
|
|
|
|
CompilerSuite := TCompilerSuite.Create(FpcList.CompilerInfo[i], st, GdbList);
|
|
if CompilerSuite.Tests.Count >0 then
|
|
GetTestRegistry.AddTest(CompilerSuite)
|
|
else
|
|
CompilerSuite.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function CheckAppDir(var AppDir: string): Boolean;
|
|
begin
|
|
Result := DirectoryExistsUTF8(AppDir + 'TestApps');
|
|
end;
|
|
|
|
function CheckAppDirLib(var AppDir: string): Boolean;
|
|
var
|
|
s: string;
|
|
begin
|
|
Result := False;
|
|
if RightStr(AppDir, length('lib' + DirectorySeparator)) = 'lib' + DirectorySeparator
|
|
then begin
|
|
s := copy(AppDir, 1, length(AppDir) - length('lib' + DirectorySeparator));
|
|
Result := DirectoryExistsUTF8(s + 'TestApps');
|
|
if Result then
|
|
AppDir := s;
|
|
end;
|
|
end;
|
|
|
|
function AppDirStripAppBundle(AppDir: string): String;
|
|
var
|
|
p: LongInt;
|
|
begin
|
|
Result := AppDir;
|
|
p := pos('.app' + DirectorySeparator, AppDir);
|
|
while (p > 1) and (AppDir[p-1] <> DirectorySeparator) do
|
|
dec(p);
|
|
if p > 1 then
|
|
Result := Copy(AppDir, 1, p - 1);
|
|
end;
|
|
|
|
initialization
|
|
// GDBMIDebugger is un uses
|
|
DebugLogger.FindOrRegisterLogGroup('DBG_CMD_ECHO' , True )^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('DBGMI_QUEUE_DEBUG' , True )^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('DBGMI_STRUCT_PARSER' , True )^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('DBG_VERBOSE' , True )^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS', True )^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('DBG_DISASSEMBLER', True )^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('DBGMI_TYPE_INFO', True )^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('DBGMI_TIMEOUT_DEBUG', True )^.Enabled := True;
|
|
|
|
DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_ERRORS', True);
|
|
DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_SEARCH', True)^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_WARNINGS', True)^.Enabled := True;
|
|
DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_VERBOSE', True);
|
|
DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_DATA_WARNINGS', True);
|
|
|
|
|
|
AppDir := AppendPathDelim(ExtractFilePath(Paramstr(0)));
|
|
if not(CheckAppDir(AppDir))
|
|
and not(CheckAppDirLib(AppDir))
|
|
then begin
|
|
AppDir := AppDirStripAppBundle(AppDir);
|
|
if not(CheckAppDir(AppDir))
|
|
and not(CheckAppDirLib(AppDir))
|
|
then
|
|
with TSelectDirectoryDialog.Create(nil) do begin
|
|
if Execute then AppDir := AppendPathDelim(FileName);
|
|
Free;
|
|
end;
|
|
end;
|
|
ConfDir := AppDir;
|
|
AppDir := AppendPathDelim(AppDir + 'TestApps');
|
|
|
|
|
|
//EnvironmentOptions := TEnvironmentOptions.Create;
|
|
//with EnvironmentOptions do
|
|
//begin
|
|
// CreateConfig;
|
|
// Load(false);
|
|
//end;
|
|
//GlobalMacroList:=TTransferMacroList.Create;
|
|
|
|
BuildTestSuites;
|
|
|
|
finalization
|
|
FreeAndNil(Compilers);
|
|
FreeAndNil(Debuggers);
|
|
//FreeAndNil(EnvironmentOptions);
|
|
|
|
end.
|
|
|