DBG: improved display of watches

git-svn-id: trunk@28725 -
This commit is contained in:
martin 2010-12-16 01:43:28 +00:00
parent 4eb25d537b
commit e4121d2b0b
7 changed files with 1402 additions and 241 deletions

View File

@ -460,6 +460,10 @@ type
type
TDBGSymbolKind = (skClass, skRecord, skEnum, skSet, skProcedure, skFunction, skSimple, skPointer, skVariant);
TDBGSymbolAttribute = (saRefParam, // var, const, constref passed by reference
saInternalPointer // PointerToObject
);
TDBGSymbolAttributes = set of TDBGSymbolAttribute;
TDBGFieldLocation = (flPrivate, flProtected, flPublic, flPublished);
TDBGFieldFlag = (ffVirtual,ffConstructor,ffDestructor);
TDBGFieldFlags = set of TDBGFieldFlag;
@ -528,12 +532,12 @@ type
{ TDBGType }
TDBGType = class(TObject)
private
protected
FAncestor: String;
FResult: TDBGType;
FResultString: String;
FArguments: TDBGTypes;
FAttributes: TDBGSymbolAttributes;
FFields: TDBGFields;
FKind: TDBGSymbolKind;
FMembers: TStrings;
@ -548,6 +552,7 @@ type
property Arguments: TDBGTypes read FArguments;
property Fields: TDBGFields read FFields;
property Kind: TDBGSymbolKind read FKind;
property Attributes: TDBGSymbolAttributes read FAttributes;
property TypeName: String read FTypeName;
property Members: TStrings read FMembers;
property Result: TDBGType read FResult;

View File

@ -1189,12 +1189,11 @@ type
{ TGDBMIType }
TGDBMIType = class(TGDBType)
private
FIsAmpersandAddr: Boolean;
protected
public
constructor CreateFromResult(const AResult: TGDBMIExecResult);
property IsAmpersandAddr: Boolean read FIsAmpersandAddr; // for dwarf only "&TypeName" indicates a param by ref (var, const, constref)
constructor CreateFromResult(const AResult: TGDBMIExecResult;
const AWhatIsValue: String = '';
const AWhatIsType: String = '';
AClassIsPointer: Boolean = False);
end;
{ TGDBStringIterator }
@ -7707,29 +7706,11 @@ end;
{ TGDBMIType }
constructor TGDBMIType.CreateFromResult(const AResult: TGDBMIExecResult);
var
s: String;
i: Integer;
constructor TGDBMIType.CreateFromResult(const AResult: TGDBMIExecResult;
const AWhatIsValue: String = ''; const AWhatIsType: String = ''; AClassIsPointer: Boolean = False);
begin
// TODO: add check ?
// tfClassIsPointer can be ignored, because the "&" only occurs with dwarf, which always has tfClassIsPointer
FIsAmpersandAddr := False;
s := AResult.Values;
i := pos('type = &', s);
if i > 0 then begin
FIsAmpersandAddr := True;
if (copy(s, i+8, 15) = '__vtbl_ptr_type') or
//( (tfClassIsPointer in TargetInfo^.TargetFlags) and
(copy(s, i+8, 5) = 'class') //)
then
s[i+7] := '^'
else
Delete(s, i + 7, 1);
end;
CreateFromValues(s);
CreateFromValues(AResult.Values, AWhatIsValue, AWhatIsType, AClassIsPointer);
end;
{ TGDBStringIterator }
@ -8322,15 +8303,57 @@ end;
function TGDBMIDebuggerCommand.GetGDBTypeInfo(const AExpression: String): TGDBType;
var
R: TGDBMIExecResult;
WIExprRes, PTypeRes, WITypeRes: TGDBMIExecResult;
WIExprVal, WIExprValCln, WITypeValS2: String;
begin
if not ExecuteCommand('ptype %s', [AExpression], R)
or (R.State = dsError)
Result := nil;
WIExprValCln := '';
if ExecuteCommand('whatis %s', [AExpression], WIExprRes)
and (WIExprRes.State <> dsError)
then begin
WIExprVal := ParseTypeFromGdb(WIExprRes.Values);
WIExprValCln := WIExprVal;
while (WIExprValCln<>'') and (WIExprValCln[1] in ['^', '&']) do delete(WIExprValCln, 1, 1);
if (pos(' ', WIExprValCln) > 0) or (WIExprValCln = '') then begin
if ExecuteCommand('ptype %s', [AExpression], PTypeRes) // can not ptype with spaces
and (PTypeRes.State <> dsError)
then begin
Result := TGdbMIType.CreateFromResult(PTypeRes, WIExprRes.Values, '', tfClassIsPointer in TargetInfo^.TargetFlags);
exit;
end;
end
else begin
if ExecuteCommand('ptype %s', [WIExprValCln], PTypeRes)
and (PTypeRes.State <> dsError)
then begin
WITypeValS2 := '';
if (Pos(' = class ', PTypeRes.Values) > 0)
and (tfClassIsPointer in TargetInfo^.TargetFlags) // ptype will give ^ for pointer-to-class or just class
and (pos('type = ^^', PTypeRes.Values) <= 0) // not known to be a pointer (not sure it ever happens)
and (WIExprVal[1] <> '^') // not known to be a pointer (not sure it ever happens)
and ExecuteCommand('whatis %s', [WIExprValCln], WITypeRes)
and (PTypeRes.State <> dsError)
then WITypeValS2 := WITypeRes.Values;
Result := TGdbMIType.CreateFromResult(PTypeRes, WIExprRes.Values, WITypeValS2, tfClassIsPointer in TargetInfo^.TargetFlags);
exit;
end;
end;
end;
if (PTypeRes.State = dsError) and (pos('msg="No symbol ', PTypeRes.Values) > 0)
then exit;
// try ptype on the value
if not ExecuteCommand('ptype %s', [AExpression], PTypeRes)
or (PTypeRes.State = dsError)
then begin
Result := nil;
end
else begin
Result := TGdbMIType.CreateFromResult(R);
Result := TGdbMIType.CreateFromResult(PTypeRes, '', '', tfClassIsPointer in TargetInfo^.TargetFlags);
end;
end;
@ -9209,15 +9232,14 @@ function TGDBMIDebuggerCommandEvaluate.DoExecute: Boolean;
if ResultInfo = nil then
ResultInfo := GetGDBTypeInfo(AnExpression);
if (ResultInfo = nil) then Exit;
FTypeInfo := ResultInfo;
case ResultInfo.Kind of
skPointer: begin
AnExpression := GetPart([], [' '], FTextValue, False, False);
Val(AnExpression, addr, e);
if e <> 0 then begin
FreeAndNil(ResultInfo);
if e <> 0 then
Exit;
end;
AnExpression := Lowercase(ResultInfo.TypeName);
case StringCase(AnExpression, ['char', 'character', 'ansistring', '__vtbl_ptr_type',
@ -9262,7 +9284,7 @@ function TGDBMIDebuggerCommandEvaluate.DoExecute: Boolean;
AnExpression[1] := 'T';
if Length(AnExpression) > 1 then AnExpression[2] := UpperCase(AnExpression[2])[1];
end;
FTextValue := PascalizePointer(FTextValue, '^' + AnExpression);
FTextValue := PascalizePointer(FTextValue, AnExpression);
end;
end;
@ -9276,14 +9298,19 @@ function TGDBMIDebuggerCommandEvaluate.DoExecute: Boolean;
skClass: begin
Val(FTextValue, addr, e); //Get the class mem address
if e = 0 then begin //No error ?
if Addr = 0
then FTextValue := 'nil'
else begin
AnExpression := GetInstanceClassName(Addr);
if AnExpression = '' then AnExpression := '???'; //No instanced class found
FTextValue := 'class ' + AnExpression + ' ' + FTextValue;
end;
if (e = 0) and (addr = 0)
then FTextValue := 'nil';
if (FTextValue <> '') and (FTypeInfo <> nil)
then begin
FTextValue := '<' + FTypeInfo.TypeName + '> = ' + FTextValue;
end
else
if (e = 0) and (addr <> 0)
then begin //No error ?
AnExpression := GetInstanceClassName(Addr);
if AnExpression = '' then AnExpression := '???'; //No instanced class found
FTextValue := 'instance of ' + AnExpression + ' ' + FTextValue;
end;
end;
@ -9305,7 +9332,6 @@ function TGDBMIDebuggerCommandEvaluate.DoExecute: Boolean;
end;
end;
FTypeInfo := ResultInfo;
PutValuesInTree;
FTextValue := FormatResult(FTextValue);
end;
@ -9488,17 +9514,30 @@ function TGDBMIDebuggerCommandEvaluate.DoExecute: Boolean;
Result := False;
FTypeInfo := GetGDBTypeInfo(AnExpression);
if FTypeInfo = nil
then exit;
if TGdbMIType(FTypeInfo).IsAmpersandAddr and (FTypeInfo.TypeName <> '')
then begin
Result := ExecuteCommand('-data-evaluate-expression %s(%s)', [FTypeInfo.TypeName, AnExpression], R);
ResultList := TGDBMINameValueList.Create(LastExecResult.Values);
FTextValue := ResultList.Values['msg'];
FreeAndNil(ResultList);
exit;
end;
if (saInternalPointer in FTypeInfo.Attributes)
then begin
Result := ExecuteCommand('-data-evaluate-expression %s%s', [AnExpression, '^'], R);
Result := Result and (R.State <> dsError);
end;
if not Result then
Result := ExecuteCommand('-data-evaluate-expression %s', [AnExpression], R);
if (not Result)
and (saRefParam in FTypeInfo.Attributes) and (FTypeInfo.InternalTypeName <> '')
then begin
Result := ExecuteCommand('-data-evaluate-expression %s(%s)', [FTypeInfo.InternalTypeName, AnExpression], R);
Result := Result and (R.State <> dsError);
end;
if (not Result)
then Result := ExecuteCommand('-data-evaluate-expression %s', [AnExpression], R);
Result := Result and (R.State <> dsError);
if (not Result) and (not StoreError)
then exit;

View File

@ -61,12 +61,20 @@ type
{ TGDBType }
TGDBType = class(TDBGType)
private
FInternalTypeName: string;
public
constructor CreateFromValues(const AValues: String);
constructor CreateFromValues(const AValues: String;
AWhatIsValue: String = '';
const AWhatIsType: String = '';
AClassIsPointer: Boolean = False);
// InternalTypeName: include ^ for TObject, if needed
property InternalTypeName: string read FInternalTypeName;
end;
function CreatePTypeValueList(AResultValues: String): TStringList;
function ParseTypeFromGdb(const ATypeText: string): string;
implementation
@ -248,9 +256,38 @@ begin
end;
end;
function ParseTypeFromGdb(const ATypeText: string): string;
var
StartIdx, EndIdx, BracketCnt, ln: Integer;
EndPtr: PChar;
begin
Result := '';
StartIdx := pos('type = ', ATypeText);
if StartIdx <= 0 then exit;
inc(StartIdx, 7);
EndIdx := StartIdx;
EndPtr := @ATypeText[EndIdx];
ln := length(ATypeText);
BracketCnt := 0;
while (EndIdx <= ln) do begin
case EndPtr^ of
' ' : if BracketCnt = 0 then break;
'[', '{' : inc(BracketCnt);
']', '}' : dec(BracketCnt);
'\' : if (EndIdx < ln) and ((EndPtr+1)^ = 'n') then break;
#0..#31: break;
end;
inc(EndPtr);
inc(EndIdx);
end;
Result := copy(ATypeText, StartIdx, EndIdx-StartIdx);
end;
{ TGDBPType }
constructor TGDBType.CreateFromValues(const AValues: String);
constructor TGDBType.CreateFromValues(const AValues: String;
AWhatIsValue: String = ''; const AWhatIsType: String = '';
AClassIsPointer: Boolean = False);
var
S, Line: String;
Lines: TStringList;
@ -440,44 +477,104 @@ var
end;
var
HasClass: Boolean;
ParsedWhatIsValue, ParsedWhatIsType: string;
begin
Create(skSimple, '');
if AValues = '' then Exit;
ParsedWhatIsValue := ParseTypeFromGdb(AWhatIsValue);
ParsedWhatIsType := ParseTypeFromGdb(AWhatIsType);
Lines := TStringList.Create;
try
Lines.Text := AValues;
if Lines.Count = 0 then Exit;
Line := Lines[0];
Lines.Delete(0);
if Lines.Count > 0 then begin
Line := Lines[0];
Lines.Delete(0);
end
else Line := '';
S := ParseTypeFromGdb(Line);
S := GetPart(['type = '], [' '], Line);
if S = '' then Exit;
HasClass := Pos(' = class ', Line) > 0;
if HasClass
and (S[2] <> '^') // pointer to class is handled next
then begin
FKind:=skClass;
if S[1] = '^' then begin
FKind:=skPointer;
FTypeName := GetPart(['^'], [' '], S);
end else begin
FTypeName := GetPart([], ['{'], S);
DoClass;
FAttributes := [];
if (ParsedWhatIsValue <> '') and (ParsedWhatIsValue[1] = '&') then begin
Delete(ParsedWhatIsValue, 1, 1);
include(FAttributes, saRefParam);
end;
Create(skSimple, ParsedWhatIsValue);
FInternalTypeName := ParsedWhatIsValue;
if Pos(' = class ', Line) > 0 then begin
// Class or pointer to class
if AClassIsPointer and (S[1] = '^') then begin
// class: dwarf type, always pefixed with ^
if (length(s) >= 2) and (s[2] = '^')
then begin
FKind:=skPointer;
if FTypeName = ''
then FTypeName := copy(s, 3, length(s));
end
else if (ParsedWhatIsValue <> '') and (ParsedWhatIsValue[1] = '^')
and (pos(' = class', AWhatIsValue) <= 0)
then begin
FKind:=skPointer; // pointer to another named type
if FTypeName = ''
then FTypeName := copy(ParsedWhatIsValue, 2, length(ParsedWhatIsValue));
end
else if (ParsedWhatIsType <> '') and (ParsedWhatIsType[1] = '^')
and (pos(' = class', AWhatIsType) <= 0)
then begin
FKind:=skPointer; // pointer to another named type
if FTypeName = ''
then FTypeName := copy(ParsedWhatIsType, 2, length(ParsedWhatIsType));
end
else begin
include(FAttributes, saInternalPointer);
if FTypeName = ''
then FTypeName := GetPart([], ['{'], S);
DoClass;
end;
if FInternalTypeName = ''
then FInternalTypeName := FTypeName;
if (FInternalTypeName <> '') and (FInternalTypeName[1] <> '^')
and (saInternalPointer in FAttributes)
then FInternalTypeName := '^' + FInternalTypeName;
end
else begin
// class: stabs type, not normaly prefixed
if (length(s) >= 1) and (s[1] = '^')
then begin
FKind:=skPointer;
if FTypeName = ''
then FTypeName := copy(s, 2, length(s));
end
else begin
include(FAttributes, saInternalPointer);
if FTypeName = ''
then FTypeName := GetPart([], ['{'], S);
DoClass;
end;
if FInternalTypeName = ''
then FInternalTypeName := FTypeName;
end;
end
else if S[1] = '^'
else
if (S[1] = '^')
or ((ParsedWhatIsValue <> '') and (ParsedWhatIsValue[1] = '^'))
or ((ParsedWhatIsType <> '') and (ParsedWhatIsType[1] = '^'))
then begin
FKind := skPointer;
if HasClass
then FTypeName := GetPart(['^^'], [' ='], S)
else FTypeName := GetPart(['^'], [' ='], S);
if FTypeName = ''
then FTypeName := GetPart(['^'], [' ='], S);
// strip brackets
FTypeName := GetPart(['(', ''], [')'], FTypeName);
end
else if S = 'set'
then DoSet
else if S = 'procedure'
@ -488,7 +585,8 @@ begin
then DoEnum
else if Pos(' = record', Line) > 0
then begin
FTypeName := S;
if FTypeName = ''
then FTypeName := S;
DoRecord
end
else if S = 'record'
@ -498,7 +596,8 @@ begin
end
else begin
FKind := skSimple;
FTypeName := S;
if FTypeName = ''
then FTypeName := S;
end;
finally

View File

@ -176,7 +176,7 @@ begin
PropertiesPage.TabVisible:=false;
MethodsPage.TabVisible:=false;
if not Assigned(FDBGInfo) then exit;
EditInspected.Text:=FExpression+' : ^'+FDBGInfo.TypeName + ' = ' + FDBGInfo.Value.AsString;
EditInspected.Text:=FExpression+' : '+FDBGInfo.TypeName + ' = ' + FDBGInfo.Value.AsString;
GridDataSetup;
FGridData.Cells[0,1]:=FExpression;
FGridData.Cells[1,1]:='Pointer to '+FDBGInfo.TypeName;

View File

@ -3,38 +3,884 @@ program WatchesPrg;
uses sysutils;
procedure Foo(
ArgAnsiString1: AnsiString; var ArgAnsiString2: AnsiString; const ArgAnsiString3: AnsiString;
ArgChar1: Char; var ArgChar2: Char; const ArgChar3: Char
type
TFoo = class;
{ records }
TRec = record
ValInt: Integer;
ValFoo: TFoo;
end;
PRec = ^TRec;
PPRec = ^PRec;
TNewRec = type TRec;
{ Classes }
TFoo = class
public
ValueInt: Integer;
ValueFoo: TFoo;
ValueRec: TRec;
property PropInt: Integer read ValueInt write ValueInt;
end;
TFooChild = class(TFoo) end;
TFooKid = class(TFoo) end;
PFoo = ^TFoo;
PPFoo = ^PFoo;
TSamePFoo = PFoo;
TNewPFoo = {type} PFoo; // fpc crash
TSameFoo = TFoo;
TNewFoo = type TFoo;
PNewFoo = ^TNewFoo;
{ ClassesTyps }
TFooClass = Class of TFoo;
PFooClass = ^TFooClass;
PPFooClass = ^PFooClass;
TNewFooClass = class of TNewFoo;
PNewFooClass = ^TNewFooClass;
{ strings }
TMyAnsiString = AnsiString;
PMyAnsiString = ^TMyAnsiString;
PPMyAnsiString = ^PMyAnsiString;
TNewAnsiString = type AnsiString;
PNewAnsiString = ^TNewAnsiString;
TMyShortString = ShortString;
PMyShortString = ^TMyShortString;
PPMyShortString = ^PMyShortString;
TNewhortString = type ShortString;
PNewhortString = ^TNewhortString;
TMyWideString = WideString;
PMyWideString = ^TMyWideString;
PPMyWideString = ^PMyWideString;
TNewWideString = type WideString;
PNewWideString = ^TNewWideString;
TMyString10 = String[10];
PMyString10 = ^TMyString10;
PPMyString10 = ^PMyString10;
{ simple }
{ variants }
{ Array }
procedure FooFunc(
(*** parameter and var-param ***)
{ records }
ArgTRec: TRec; var VArgTRec: TRec;
ArgPRec: PRec; var VArgPRec: PRec;
ArgPPRec: PPRec; var VArgPPRec: PPRec;
ArgTNewRec: TNewRec; var VArgTNewRec: TNewRec;
{ Classes }
ArgTFoo: TFoo; var VArgTFoo: TFoo;
ArgPFoo: PFoo; var VArgPFoo: PFoo;
ArgPPFoo: PPFoo; var VArgPPFoo: PPFoo;
ArgTSamePFoo: TSamePFoo; var VArgTSamePFoo: TSamePFoo;
ArgTNewPFoo: TNewPFoo; var VArgTNewPFoo: TNewPFoo;
ArgTSameFoo: TSameFoo; var VArgTSameFoo: TSameFoo;
ArgTNewFoo: TNewFoo; var VArgTNewFoo: TNewFoo;
ArgPNewFoo: PNewFoo; var VArgPNewFoo: PNewFoo;
{ ClassesTyps }
ArgTFooClass: TFooClass; var VArgTFooClass: TFooClass;
ArgPFooClass: PFooClass; var VArgPFooClass: PFooClass;
ArgPPFooClass: PPFooClass; var VArgPPFooClass: PPFooClass;
ArgTNewFooClass: TNewFooClass; var VArgTNewFooClass: TNewFooClass;
ArgPNewFooClass: PNewFooClass; var VArgPNewFooClass: PNewFooClass;
{ strings }
ArgTMyAnsiString: TMyAnsiString; var VArgTMyAnsiString: TMyAnsiString;
ArgPMyAnsiString: PMyAnsiString; var VArgPMyAnsiString: PMyAnsiString;
ArgPPMyAnsiString: PPMyAnsiString; var VArgPPMyAnsiString: PPMyAnsiString;
ArgTNewAnsiString: TNewAnsiString; var VArgTNewAnsiString: TNewAnsiString;
ArgPNewAnsiString: PNewAnsiString; var VArgPNewAnsiString: PNewAnsiString;
ArgTMyShortString: TMyShortString; var VArgTMyShortString: TMyShortString;
ArgPMyShortString: PMyShortString; var VArgPMyShortString: PMyShortString;
ArgPPMyShortString: PPMyShortString; var VArgPPMyShortString: PPMyShortString;
ArgTNewhortString: TNewhortString; var VArgTNewhortString: TNewhortString;
ArgPNewhortString: PNewhortString; var VArgPNewhortString: PNewhortString;
ArgTMyWideString: TMyWideString; var VArgTMyWideString: TMyWideString;
ArgPMyWideString: PMyWideString; var VArgPMyWideString: PMyWideString;
ArgPPMyWideString: PPMyWideString; var VArgPPMyWideString: PPMyWideString;
ArgTNewWideString: TNewWideString; var VArgTNewWideString: TNewWideString;
ArgPNewWideString: PNewWideString; var VArgPNewWideString: PNewWideString;
ArgTMyString10: TMyString10; var VArgTMyString10: TMyString10;
ArgPMyString10: PMyString10; var VArgPMyString10: PMyString10;
ArgPPMyString10: PPMyString10; var VArgPPMyString10: PPMyString10;
{ simple }
ArgByte: Byte; var VArgByte: Byte;
ArgWord: Word; var VArgWord: Word;
ArgLongWord: LongWord; var VArgLongWord: LongWord;
ArgQWord: QWord; var VArgQWord: QWord;
ArgShortInt: ShortInt; var VArgShortInt: ShortInt;
ArgSmallInt: SmallInt; var VArgSmallInt: SmallInt;
ArgInt: Integer; var VArgInt: Integer;
ArgInt64: Int64; var VArgInt64: Int64;
ArgPByte: PByte; var VArgPByte: PByte;
ArgPWord: PWord; var VArgPWord: PWord;
ArgPLongWord: PLongWord; var VArgPLongWord: PLongWord;
ArgPQWord: PQWord; var VArgPQWord: PQWord;
ArgPShortInt: PShortInt; var VArgPShortInt: PShortInt;
ArgPSmallInt: PSmallInt; var VArgPSmallInt: PSmallInt;
ArgPInt: PInteger; var VArgPInt: PInteger;
ArgPInt64: PInt64; var VArgPInt64: PInt64;
ArgPointer: Pointer; var VArgPointer: Pointer;
ArgPPointer: PPointer; var VArgPPointer: PPointer;
ArgDouble: Double; var VArgDouble: Double;
ArgExtended: Extended; var VArgExtended: Extended;
Dummy: Integer
);
var
TestInt: Integer;
TesTShortString: String[10];
TestAnsiString: AnsiString;
TestPChar: PChar;
(*** local var ***)
{ records }
VarTRec: TRec;
VarPRec: PRec;
VarPPRec: PPRec;
VarTNewRec: TNewRec;
PVarTRec: ^TRec;
PVarTNewRec: ^TNewRec;
{ Classes }
VarTFoo: TFoo;
VarPFoo: PFoo;
VarPPFoo: PPFoo;
VarTSamePFoo: TSamePFoo;
VarTNewPFoo: TNewPFoo;
VarTSameFoo: TSameFoo;
VarTNewFoo: TNewFoo;
VarPNewFoo: PNewFoo;
PVarTFoo: ^TFoo;
PVarPFoo: ^PFoo;
PVarTSamePFoo: ^TSamePFoo;
PVarTSameFoo: ^TSameFoo;
{ ClassesTyps }
VarTFooClass: TFooClass;
VarPFooClass: PFooClass;
VarPPFooClass: PPFooClass;
VarTNewFooClass: TNewFooClass;
VarPNewFooClass: PNewFooClass;
PVarTFooClass: ^TFooClass;
{ strings }
VarTMyAnsiString: TMyAnsiString;
VarPMyAnsiString: PMyAnsiString;
VarPPMyAnsiString: PPMyAnsiString;
VarTNewAnsiString: TNewAnsiString;
VarPNewAnsiString: PNewAnsiString;
VarTMyShortString: TMyShortString;
VarPMyShortString: PMyShortString;
VarPPMyShortString: PPMyShortString;
VarTNewhortString: TNewhortString;
VarPNewhortString: PNewhortString;
VarTMyWideString: TMyWideString;
VarPMyWideString: PMyWideString;
VarPPMyWideString: PPMyWideString;
VarTNewWideString: TNewWideString;
VarPNewWideString: PNewWideString;
VarTMyString10: TMyString10;
VarPMyString10: PMyString10;
VarPPMyString10: PPMyString10;
PVarAnsiString: ^AnsiString;
PVarShortString: ^ShortString;
PVarWideString: ^WideString;
VarString15: string[15];
{ simple }
VarByte: Byte;
VarWord: Word;
VarLongWord: LongWord;
VarQWord: QWord;
VarShortInt: ShortInt;
varSmallInt: SmallInt;
VarInt: Integer;
VarInt64: Int64;
VarPByte: PByte;
VarPWord: PWord;
VarPLongWord: PLongWord;
VarPQWord: PQWord;
VarPShortInt: PShortInt;
varPSmallInt: PSmallInt;
VarPInt: PInteger;
VarPInt64: PInt64;
PVarByte: ^Byte;
PVarWord: ^Word;
PVarLongWord: ^LongWord;
PVarQWord: ^QWord;
PVarShortInt: ^ShortInt;
PvarSmallInt: ^SmallInt;
PVarInt: ^Integer;
PVarInt64: ^Int64;
VarPointer: Pointer;
VarPPointer: PPointer;
PVarPointer: ^Pointer;
VarDouble: Double;
VarExtended: Extended;
PVarDouble: ^Double;
PVarExtended: ^Extended;
function SubFoo(var AVal1: Integer; AVal2: Integer) : Integer;
begin
AVal1 := 2 * AVal2;
Result := AVal2;
inc(AVal2); // First BreakBoint
writeln(1);
end;
begin
TestInt := 3;
TesTShortString := IntToStr(TestInt) + ':';
TestAnsiString := TesTShortString + ' Foo';
TestPChar := @TestAnsiString[2];
SubFoo(TestInt, 5);
writeln(TestPChar);
writeln(ArgAnsiString1, ArgAnsiString2, ArgAnsiString3, ArgChar1, ArgChar2, ArgChar3); // breakpoint 2
{ records }
VarTRec := ArgTRec;
VarPRec := ArgPRec;
VarPPRec := ArgPPRec;
VarTNewRec := ArgTNewRec;
PVarTRec := @ArgTRec;
PVarTNewRec := @ArgTNewRec;
{ Classes }
VarTFoo := ArgTFoo;
VarPFoo := ArgPFoo;
VarPPFoo := ArgPPFoo;
VarTSamePFoo := ArgTSamePFoo;
VarTNewPFoo := ArgTNewPFoo;
VarTSameFoo := ArgTSameFoo;
VarTNewFoo := ArgTNewFoo;
VarPNewFoo := ArgPNewFoo;
PVarTFoo := @ArgTFoo;
PVarPFoo := @ArgPFoo;
PVarTSamePFoo := @ArgTSamePFoo;
PVarTSameFoo := @ArgTSameFoo;
{ ClassesTyps }
VarTFooClass := ArgTFooClass;
VarPFooClass := ArgPFooClass;
VarPPFooClass := ArgPPFooClass;
VarTNewFooClass := ArgTNewFooClass;
VarPNewFooClass := ArgPNewFooClass;
PVarTFooClass := @ArgTFooClass;
{ strings }
VarTMyAnsiString := ArgTMyAnsiString + '-var';
VarPMyAnsiString := ArgPMyAnsiString;
VarPPMyAnsiString := ArgPPMyAnsiString;
VarTNewAnsiString := ArgTNewAnsiString + '-var';
VarPNewAnsiString := ArgPNewAnsiString;
VarTMyShortString := ArgTMyShortString + '-var';
VarPMyShortString := ArgPMyShortString;
VarPPMyShortString := ArgPPMyShortString;
VarTNewhortString := ArgTNewhortString + '-var';
VarPNewhortString := ArgPNewhortString;
VarTMyWideString := ArgTMyWideString + '-var';
VarPMyWideString := ArgPMyWideString;
VarPPMyWideString := ArgPPMyWideString;
VarTNewWideString := ArgTNewWideString + '-var';
VarPNewWideString := ArgPNewWideString;
VarTMyString10 := ArgTMyString10 + '-var';
VarPMyString10 := ArgPMyString10;
VarPPMyString10 := ArgPPMyString10;
PVarAnsiString := @ArgTMyAnsiString;
PVarShortString := @ArgTMyShortString;
PVarWideString := @ArgTMyWideString;
VarString15 := 'T15' +#10#13 + 'L2' + #13 + 'L3' +#10 +'L4';
{ simple }
VarByte := ArgByte + 100;
VarWord := ArgWord + 100;
VarLongWord := ArgLongWord + 100;
VarQWord := ArgQWord + 100;
VarShortInt := ArgShortInt + 100;
VarSmallInt := ArgSmallInt + 100;
VarInt := ArgInt + 100;
VarInt64 := ArgInt64 + 100;
VarPByte := ArgPByte;
VarPWord := ArgPWord;
VarPLongWord := ArgPLongWord;
VarPQWord := ArgPQWord;
VarPShortInt := ArgPShortInt;
VarPSmallInt := ArgPSmallInt;
VarPInt := ArgPInt;
VarPInt64 := ArgPInt64;
PVarByte := @ArgByte;
PVarWord := @ArgWord;
PVarLongWord := @ArgLongWord;
PVarQWord := @ArgQWord;
PVarShortInt := @ArgShortInt;
PVarSmallInt := @ArgSmallInt;
PVarInt := @ArgInt;
PVarInt64 := @ArgInt64;
VarPointer := ArgPointer;
VarPPointer := ArgPPointer;
PVarPointer := ArgPointer;
VarDouble := ArgDouble;
VarExtended := ArgExtended;
PVarDouble := @ArgDouble;
PVarExtended := @ArgExtended;
SubFoo(VarInt, VarPInt^);
// break on next line
writeln(1);
end;
(*** global var (to feed var-param)-***)
var
a2: ansistring;
c2: Char;
{ records }
GlobTRec, GlobTRec1, GlobTRec2: TRec;
GlobPRec: PRec;
GlobPPRec: PPRec;
GlobTNewRec: TNewRec;
PGlobTRec: ^TRec;
PGlobTNewRec: ^TNewRec;
{ Classes }
GlobTFoo, GlobTFoo1, GlobTFoo2, GlobTFooNil: TFoo;
GlobPFoo: PFoo;
GlobPPFoo: PPFoo;
GlobTSamePFoo: TSamePFoo;
GlobTNewPFoo: TNewPFoo;
GlobTSameFoo: TSameFoo;
GlobTNewFoo: TNewFoo;
GlobPNewFoo: PNewFoo;
PGlobTFoo: ^TFoo;
PGlobPFoo: ^PFoo;
PGlobTSamePFoo: ^TSamePFoo;
PGlobTSameFoo: ^TSameFoo;
{ ClassesTyps }
GlobTFooClass: TFooClass;
GlobPFooClass: PFooClass;
GlobPPFooClass: PPFooClass;
GlobTNewFooClass: TNewFooClass;
GlobPNewFooClass: PNewFooClass;
PGlobTFooClass: ^TFooClass;
{ strings }
GlobTMyAnsiString: TMyAnsiString;
GlobPMyAnsiString: PMyAnsiString;
GlobPPMyAnsiString: PPMyAnsiString;
GlobTNewAnsiString: TNewAnsiString;
GlobPNewAnsiString: PNewAnsiString;
GlobTMyShortString: TMyShortString;
GlobPMyShortString: PMyShortString;
GlobPPMyShortString: PPMyShortString;
GlobTNewhortString: TNewhortString;
GlobPNewhortString: PNewhortString;
GlobTMyWideString: TMyWideString;
GlobPMyWideString: PMyWideString;
GlobPPMyWideString: PPMyWideString;
GlobTNewWideString: TNewWideString;
GlobPNewWideString: PNewWideString;
GlobTMyString10: TMyString10;
GlobPMyString10: PMyString10;
GlobPPMyString10: PPMyString10;
PGlobAnsiString: ^AnsiString;
PGlobShortString: ^ShortString;
PGlobWideString: ^WideString;
GlobString15: string[15];
{ simple }
GlobByte: Byte;
GlobWord: Word;
GlobLongWord: LongWord;
GlobQWord: QWord;
GlobShortInt: ShortInt;
GlobSmallInt: SmallInt;
GlobInt: Integer;
GlobInt64: Int64;
GlobPByte: PByte;
GlobPWord: PWord;
GlobPLongWord: PLongWord;
GlobPQWord: PQWord;
GlobPShortInt: PShortInt;
GlobPSmallInt: PSmallInt;
GlobPInt: PInteger;
GlobPInt64: PInt64;
PGlobByte: ^Byte;
PGlobWord: ^Word;
PGlobLongWord: ^LongWord;
PGlobQWord: ^QWord;
PGlobShortInt: ^ShortInt;
PGlobSmallInt: ^SmallInt;
PGlobInt: ^Integer;
PGlobInt64: ^Int64;
GlobPointer: Pointer;
GlobPPointer: PPointer;
PGlobPointer: ^Pointer;
GlobDouble: Double;
GlobExtended: Extended;
PGlobDouble: ^Double;
PGlobExtended: ^Extended;
begin
a2 := 'def';
c2 := 'Y';
Foo('abc', a2, 'ghi', 'X', c2, 'Z');
{ records }
GlobTRec.ValInt := -1;
GlobTRec.ValFoo := nil;
GlobTRec1.ValInt := 1;
GlobTRec1.ValFoo := TFoo.Create;
GlobTRec1.ValFoo.ValueInt := 11;
GlobTRec2.ValInt := 2;
GlobTRec2.ValFoo := TFoo.Create;
GlobTRec2.ValFoo.ValueInt := 22;
GlobPRec := @GlobTRec1;
GlobPPRec := @GlobPRec;
GlobTNewRec.ValInt := 3;
GlobTNewRec.ValFoo := nil;
PGlobTRec := @GlobTNewRec;
PGlobTNewRec := @GlobTNewRec;
{ Classes }
GlobTFoo := TFoo.Create;
GlobTFoo.ValueInt := -11;
GlobTFoo1 := TFoo.Create;
GlobTFoo1.ValueInt := 31;
GlobTFoo2 := TFoo.Create;
GlobTFoo2.ValueInt := 32;
GlobTFooNil := nil;
GlobPFoo := @GlobTFoo1;
GlobPPFoo := @GlobPFoo;
GlobTSamePFoo := @GlobTFoo2;
GlobTNewPFoo := @GlobTFoo;
GlobTSameFoo := TFoo.Create;
GlobTSameFoo.ValueInt := 41;
GlobTNewFoo := TNewFoo.Create;
GlobTNewFoo.ValueInt := 42;
GlobPNewFoo := @GlobTSameFoo;
PGlobTFoo := @GlobTFoo;
PGlobPFoo := @PGlobTFoo;
PGlobTSamePFoo := @GlobTFoo;
PGlobTSameFoo := @GlobTFoo;
{ ClassesTyps }
GlobTFooClass := TFooKid;
GlobPFooClass := @GlobTFooClass;
GlobPPFooClass := @GlobPFooClass;
GlobTNewFooClass := TNewFoo;
GlobPNewFooClass := @GlobTNewFooClass;
PGlobTFooClass := @GlobTNewFooClass;
{ strings }
GlobTMyAnsiString := 'ansi';
GlobPMyAnsiString := @GlobTMyAnsiString;
GlobPPMyAnsiString := @GlobPMyAnsiString;
GlobTNewAnsiString := 'newansi';
GlobPNewAnsiString := @GlobTNewAnsiString;
GlobTMyShortString := 'short';
GlobPMyShortString := @GlobTMyShortString;
GlobPPMyShortString := @GlobPMyShortString;
GlobTNewhortString := 'newshort';
GlobPNewhortString := @GlobTNewhortString;
GlobTMyWideString := 'wide';
GlobPMyWideString := @GlobTMyWideString;
GlobPPMyWideString := @GlobPMyWideString;
GlobTNewWideString := 'newwide';
GlobPNewWideString := @GlobTNewWideString;
GlobTMyString10 := 's10';
GlobPMyString10 := @GlobTMyString10;
GlobPPMyString10 := @GlobPMyString10;
PGlobAnsiString := @GlobTMyAnsiString;
PGlobShortString := @PGlobAnsiString;
PGlobWideString := @PGlobShortString;
GlobString15 := 'g15';
{ simple }
GlobByte := 25;
GlobWord := 26;
GlobLongWord := 27;
GlobQWord := 28;
GlobShortInt := 35;
GlobSmallInt := 36;
GlobInt := 37;
GlobInt64 := 38;
GlobPByte := @GlobByte;
GlobPWord := @GlobWord;
GlobPLongWord := @GlobLongWord;
GlobPQWord := @GlobQWord;
GlobPShortInt := @GlobShortInt;
GlobPSmallInt := @GlobSmallInt;
GlobPInt := @GlobInt;
GlobPInt64 := @GlobInt64;
PGlobByte := @GlobByte;
PGlobWord := @GlobWord;
PGlobLongWord := @GlobLongWord;
PGlobQWord := @GlobQWord;
PGlobShortInt := @GlobShortInt;
PGlobSmallInt := @GlobSmallInt;
PGlobInt := @GlobInt;
PGlobInt64 := @GlobInt64;
GlobPointer := @GlobByte;
GlobPPointer := @GlobPointer;
PGlobPointer := @GlobPointer;
GlobDouble := 1.123;
GlobExtended := 2.345;
PGlobDouble := @GlobDouble;
PGlobExtended := @GlobExtended;
FooFunc(
{ records }
GlobTRec, GlobTRec,
GlobPRec, GlobPRec,
GlobPPRec, GlobPPRec,
GlobTNewRec, GlobTNewRec,
{ Classes }
GlobTFoo, GlobTFoo,
GlobPFoo, GlobPFoo,
GlobPPFoo, GlobPPFoo,
GlobTSamePFoo, GlobTSamePFoo,
GlobTNewPFoo, GlobTNewPFoo,
GlobTSameFoo, GlobTSameFoo,
GlobTNewFoo, GlobTNewFoo,
GlobPNewFoo, GlobPNewFoo,
{ ClassesTyps }
GlobTFooClass, GlobTFooClass,
GlobPFooClass, GlobPFooClass,
GlobPPFooClass, GlobPPFooClass,
GlobTNewFooClass, GlobTNewFooClass,
GlobPNewFooClass, GlobPNewFooClass,
{ strings }
GlobTMyAnsiString, GlobTMyAnsiString,
GlobPMyAnsiString, GlobPMyAnsiString,
GlobPPMyAnsiString, GlobPPMyAnsiString,
GlobTNewAnsiString, GlobTNewAnsiString,
GlobPNewAnsiString, GlobPNewAnsiString,
GlobTMyShortString, GlobTMyShortString,
GlobPMyShortString, GlobPMyShortString,
GlobPPMyShortString, GlobPPMyShortString,
GlobTNewhortString, GlobTNewhortString,
GlobPNewhortString, GlobPNewhortString,
GlobTMyWideString, GlobTMyWideString,
GlobPMyWideString, GlobPMyWideString,
GlobPPMyWideString, GlobPPMyWideString,
GlobTNewWideString, GlobTNewWideString,
GlobPNewWideString, GlobPNewWideString,
GlobTMyString10, GlobTMyString10,
GlobPMyString10, GlobPMyString10,
GlobPPMyString10, GlobPPMyString10,
{ simple }
GlobByte, GlobByte,
GlobWord, GlobWord,
GlobLongWord, GlobLongWord,
GlobQWord, GlobQWord,
GlobShortInt, GlobShortInt,
GlobSmallInt, GlobSmallInt,
GlobInt, GlobInt,
GlobInt64, GlobInt64,
GlobPByte, GlobPByte,
GlobPWord, GlobPWord,
GlobPLongWord, GlobPLongWord,
GlobPQWord, GlobPQWord,
GlobPShortInt, GlobPShortInt,
GlobPSmallInt, GlobPSmallInt,
GlobPInt, GlobPInt,
GlobPInt64, GlobPInt64,
GlobPointer, GlobPointer,
GlobPPointer, GlobPPointer,
GlobDouble, GlobDouble,
GlobExtended, GlobExtended,
0
);
// same with nil
{ records }
//GlobTRec := nil;
GlobPRec := nil;
GlobPPRec := nil;
//GlobTNewRec := nil;
{ Classes }
GlobTFoo := nil;
GlobPFoo := nil;
GlobPPFoo := nil;
GlobTSamePFoo := nil;
GlobTNewPFoo := nil;
GlobTSameFoo := nil;
GlobTNewFoo := nil;
GlobPNewFoo := nil;
{ ClassesTyps }
GlobTFooClass := nil;
GlobPFooClass := nil;
GlobPPFooClass := nil;
GlobTNewFooClass := nil;
GlobPNewFooClass := nil;
{ strings }
GlobTMyAnsiString := '';
GlobPMyAnsiString := nil;
GlobPPMyAnsiString := nil;
GlobTNewAnsiString := '';
GlobPNewAnsiString := nil;
GlobTMyShortString := '';
GlobPMyShortString := nil;
GlobPPMyShortString := nil;
GlobTNewhortString := '';
GlobPNewhortString := nil;
GlobTMyWideString := '';
GlobPMyWideString := nil;
GlobPPMyWideString := nil;
GlobTNewWideString := '';
GlobPNewWideString := nil;
GlobTMyString10 := '';
GlobPMyString10 := nil;
GlobPPMyString10 := nil;
{ simple }
GlobByte := 0;
GlobWord := 0;
GlobLongWord := 0;
GlobQWord := 0;
GlobShortInt := 0;
GlobSmallInt := 0;
GlobInt := 0;
GlobInt64 := 0;
GlobPByte := nil;
GlobPWord := nil;
GlobPLongWord := nil;
GlobPQWord := nil;
GlobPShortInt := nil;
GlobPSmallInt := nil;
GlobPInt := nil;
GlobPInt64 := nil;
GlobPointer := nil;
GlobPPointer := nil;
GlobDouble := 0;
GlobExtended := 0;
FooFunc(
{ records }
GlobTRec, GlobTRec,
GlobPRec, GlobPRec,
GlobPPRec, GlobPPRec,
GlobTNewRec, GlobTNewRec,
{ Classes }
GlobTFoo, GlobTFoo,
GlobPFoo, GlobPFoo,
GlobPPFoo, GlobPPFoo,
GlobTSamePFoo, GlobTSamePFoo,
GlobTNewPFoo, GlobTNewPFoo,
GlobTSameFoo, GlobTSameFoo,
GlobTNewFoo, GlobTNewFoo,
GlobPNewFoo, GlobPNewFoo,
{ ClassesTyps }
GlobTFooClass, GlobTFooClass,
GlobPFooClass, GlobPFooClass,
GlobPPFooClass, GlobPPFooClass,
GlobTNewFooClass, GlobTNewFooClass,
GlobPNewFooClass, GlobPNewFooClass,
{ strings }
GlobTMyAnsiString, GlobTMyAnsiString,
GlobPMyAnsiString, GlobPMyAnsiString,
GlobPPMyAnsiString, GlobPPMyAnsiString,
GlobTNewAnsiString, GlobTNewAnsiString,
GlobPNewAnsiString, GlobPNewAnsiString,
GlobTMyShortString, GlobTMyShortString,
GlobPMyShortString, GlobPMyShortString,
GlobPPMyShortString, GlobPPMyShortString,
GlobTNewhortString, GlobTNewhortString,
GlobPNewhortString, GlobPNewhortString,
GlobTMyWideString, GlobTMyWideString,
GlobPMyWideString, GlobPMyWideString,
GlobPPMyWideString, GlobPPMyWideString,
GlobTNewWideString, GlobTNewWideString,
GlobPNewWideString, GlobPNewWideString,
GlobTMyString10, GlobTMyString10,
GlobPMyString10, GlobPMyString10,
GlobPPMyString10, GlobPPMyString10,
{ simple }
GlobByte, GlobByte,
GlobWord, GlobWord,
GlobLongWord, GlobLongWord,
GlobQWord, GlobQWord,
GlobShortInt, GlobShortInt,
GlobSmallInt, GlobSmallInt,
GlobInt, GlobInt,
GlobInt64, GlobInt64,
GlobPByte, GlobPByte,
GlobPWord, GlobPWord,
GlobPLongWord, GlobPLongWord,
GlobPQWord, GlobPQWord,
GlobPShortInt, GlobPShortInt,
GlobPSmallInt, GlobPSmallInt,
GlobPInt, GlobPInt,
GlobPInt64, GlobPInt64,
GlobPointer, GlobPointer,
GlobPPointer, GlobPPointer,
GlobDouble, GlobDouble,
GlobExtended, GlobExtended,
0
);
// no bother freeing mem
end.

View File

@ -102,38 +102,24 @@ type
TCompilerSuite = class(TTestSuite)
private
FCompilerInfo: TCompilerInfo;
public
constructor Create(ACompilerInfo: TCompilerInfo; ADebuggerList: TDebuggerList);
procedure RegisterDbgTest(ATestClass: TTestCaseClass);
public
property CompilerInfo: TCompilerInfo read FCompilerInfo;
end;
{ TCompilerOptionsSuite }
TCompilerOptionsSuite = class(TTestSuite)
private
FParent: TCompilerSuite;
FSymbolSwitch: String;
FSymbolType: TSymbolType;
FFileNameExt: String;
FCompiledList: TStringList;
FInRun: Boolean;
function GetCompilerInfo: TCompilerInfo;
protected
procedure Clear;
public
constructor Create(AParent: TCompilerSuite; ASymbolType: TSymbolType; ADebuggerList: TDebuggerList);
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 TestCompile(const PrgName: string; out ExeName: string);
public
property Parent: TCompilerSuite read FParent;
property SymbolType: TSymbolType read FSymbolType;
property SymbolSwitch: String read FSymbolSwitch;
property CompilerInfo: TCompilerInfo read GetCompilerInfo;
property CompilerInfo: TCompilerInfo read FCompilerInfo;
end;
{ TDebuggerSuite }
@ -141,15 +127,15 @@ type
TDebuggerSuite = class(TTestSuite)
private
FDebuggerInfo: TDebuggerInfo;
FParent: TCompilerOptionsSuite;
FParent: TCompilerSuite;
function GetCompilerInfo: TCompilerInfo;
function GetSymbolType: TSymbolType;
public
constructor Create(AParent: TCompilerOptionsSuite; ADebuggerInfo: TDebuggerInfo);
constructor Create(AParent: TCompilerSuite; ADebuggerInfo: TDebuggerInfo);
procedure RegisterDbgTest(ATestClass: TTestCaseClass);
Procedure TestCompile(const PrgName: string; out ExeName: string);
public
property Parent: TCompilerOptionsSuite read FParent;
property Parent: TCompilerSuite read FParent;
property DebuggerInfo: TDebuggerInfo read FDebuggerInfo;
property SymbolType: TSymbolType read GetSymbolType;
property CompilerInfo: TCompilerInfo read GetCompilerInfo;
@ -199,6 +185,7 @@ procedure RegisterDbgTest(ATestClass: TTestCaseClass);
var
AppDir: String;
ConfDir: String;
implementation
@ -226,30 +213,24 @@ end;
function GetCompilers: TCompilerList;
var
AppDir: String;
begin
if Compilers <> nil then exit(Compilers);
AppDir := ExtractFilePath(Paramstr(0));
Result := TCompilerList.Create;
if FileExists(AppDir + 'fpclist.txt') then
Result.LoadFromFile(AppDir + 'fpclist.txt');
if FileExists(ConfDir + 'fpclist.txt') then
Result.LoadFromFile(ConfDir + 'fpclist.txt');
if (Result.Count = 0) and (EnvironmentOptions.CompilerFilename <> '') then
Result.Add('fpc from conf', EnvironmentOptions.CompilerFilename);
Compilers := Result;
end;
function GetDebuggers: TDebuggerList;
var
AppDir: String;
begin
if Debuggers <> nil then exit(Debuggers);
AppDir := ExtractFilePath(Paramstr(0));
Result := TDebuggerList.Create;
if FileExists(AppDir + 'gdblist.txt') then
Result.LoadFromFile(AppDir + 'gdblist.txt');
if FileExists(ConfDir + 'gdblist.txt') then
Result.LoadFromFile(ConfDir + 'gdblist.txt');
if (Result.Count = 0) and (EnvironmentOptions.DebuggerFilename <> '') then
Result.Add('gdb from conf', EnvironmentOptions.DebuggerFilename);
Debuggers := Result;
@ -415,40 +396,7 @@ end;
{ TCompilerSuite }
constructor TCompilerSuite.Create(ACompilerInfo: TCompilerInfo; ADebuggerList: TDebuggerList);
var
st: TSymbolType;
SubSuite: TCompilerOptionsSuite;
begin
inherited Create(ACompilerInfo.Name);
FCompilerInfo := ACompilerInfo;
for st := low(TSymbolType) to high(TSymbolType) do begin
if not (st in FCompilerInfo.SymbolTypes) then
continue;
SubSuite := TCompilerOptionsSuite.Create(Self, st, ADebuggerList);
Self.AddTest(SubSuite);
end;
end;
procedure TCompilerSuite.RegisterDbgTest(ATestClass: TTestCaseClass);
var
i: Integer;
begin
for i := 0 to Tests.Count - 1 do
if Test[i] is TCompilerOptionsSuite then
TCompilerOptionsSuite(Test[i]).RegisterDbgTest(ATestClass);
end;
{ TCompilerOptionsSuite }
function TCompilerOptionsSuite.GetCompilerInfo: TCompilerInfo;
begin
Result := Parent.CompilerInfo;
end;
procedure TCompilerOptionsSuite.Clear;
procedure TCompilerSuite.Clear;
var
i: Integer;
begin
@ -457,14 +405,14 @@ begin
FCompiledList.Clear;
end;
constructor TCompilerOptionsSuite.Create(AParent: TCompilerSuite; ASymbolType: TSymbolType;
constructor TCompilerSuite.Create(ACompilerInfo: TCompilerInfo; ASymbolType: TSymbolType;
ADebuggerList: TDebuggerList);
var
i: Integer;
SubSuite: TDebuggerSuite;
begin
inherited Create(SymbolTypeNames[ASymbolType]);
FParent := AParent;
inherited Create(ACompilerInfo.Name + ' / ' + SymbolTypeNames[ASymbolType]);
FCompilerInfo := ACompilerInfo;
FSymbolType := ASymbolType;
FCompiledList := TStringList.Create;
@ -489,14 +437,14 @@ begin
end;
end;
destructor TCompilerOptionsSuite.Destroy;
destructor TCompilerSuite.Destroy;
begin
inherited Destroy;
Clear;
FreeAndNil(FCompiledList);
end;
procedure TCompilerOptionsSuite.Run(AResult: TTestResult);
procedure TCompilerSuite.Run(AResult: TTestResult);
begin
FInRun := True;
try
@ -507,7 +455,7 @@ begin
end;
end;
procedure TCompilerOptionsSuite.RunTest(ATest: TTest; AResult: TTestResult);
procedure TCompilerSuite.RunTest(ATest: TTest; AResult: TTestResult);
begin
try
inherited RunTest(ATest, AResult);
@ -516,7 +464,7 @@ begin
end;
end;
procedure TCompilerOptionsSuite.RegisterDbgTest(ATestClass: TTestCaseClass);
procedure TCompilerSuite.RegisterDbgTest(ATestClass: TTestCaseClass);
var
i: Integer;
begin
@ -525,7 +473,7 @@ begin
TDebuggerSuite(Test[i]).RegisterDbgTest(ATestClass);
end;
procedure TCompilerOptionsSuite.TestCompile(const PrgName: string; out ExeName: string);
procedure TCompilerSuite.TestCompile(const PrgName: string; out ExeName: string);
var
ExePath, ErrMsg: String;
begin
@ -561,10 +509,10 @@ begin
Result := Parent.SymbolType;
end;
constructor TDebuggerSuite.Create(AParent: TCompilerOptionsSuite;
constructor TDebuggerSuite.Create(AParent: TCompilerSuite;
ADebuggerInfo: TDebuggerInfo);
begin
inherited Create(ADebuggerInfo.Name);
inherited Create(ADebuggerInfo.Name + ' ('+AParent.TestName+')');
FParent := AParent;
FDebuggerInfo := ADebuggerInfo;
end;
@ -637,21 +585,28 @@ var
GdbList: TDebuggerList;
CompilerSuite: TCompilerSuite;
i: Integer;
st: TSymbolType;
begin
FpcList := GetCompilers;
GdbList := GetDebuggers;
for i := 0 to FpcList.Count - 1 do begin
CompilerSuite := TCompilerSuite.Create(FpcList.CompilerInfo[i], GdbList);
GetTestRegistry.AddTest(CompilerSuite);
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');
if Result then
AppDir := AppendPathDelim(AppDir + 'TestApps');
end;
function CheckAppDirLib(var AppDir: string): Boolean;
@ -664,7 +619,7 @@ begin
s := copy(AppDir, 1, length(AppDir) - length('lib' + DirectorySeparator));
Result := DirectoryExistsUTF8(s + 'TestApps');
if Result then
AppDir := AppendPathDelim(s + 'TestApps');
AppDir := s;
end;
end;
@ -694,7 +649,8 @@ initialization
Free;
end;
end;
ConfDir := AppDir;
AppDir := AppendPathDelim(AppDir + 'TestApps');
EnvironmentOptions := TEnvironmentOptions.Create;
with EnvironmentOptions do
@ -702,6 +658,7 @@ initialization
SetLazarusDefaultFilename;
Load(false);
end;
BuildTestSuites;
finalization

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, fpcunit, testutils, testregistry,
TestBase, Debugger, GDBMIDebugger, LCLProc;
TestBase, Debugger, GDBMIDebugger, LCLProc, SynRegExpr;
type
@ -18,8 +18,10 @@ type
FHasValue: Boolean;
FMaster: TDBGWatch;
FValue: String;
FTypeInfo: TDBGType;
protected
procedure DoChanged; override;
function GetTypeInfo: TDBGType; override;
public
constructor Create(AOwner: TBaseWatches; AMaster: TDBGWatch);
property Master: TDBGWatch read FMaster;
@ -33,21 +35,6 @@ type
TTestWatches = class(TGDBTestCase)
private
FWatches: TBaseWatches;
FAVal1Watch: TTestWatch;
FAVal2Watch: TTestWatch;
FTestIntWatch: TTestWatch;
FTestShortStringWatch: TTestWatch;
FTestAnsiStringWatch: TTestWatch;
FTestPCharWatch: TTestWatch;
FArgAnsisString1: TTestWatch;
FArgAnsisString2: TTestWatch;
FArgAnsisString3: TTestWatch;
FArgChar1: TTestWatch;
FArgChar2: TTestWatch;
FArgChar3: TTestWatch;
public
procedure DebugInteract(dbg: TGDBMIDebugger);
@ -58,21 +45,238 @@ type
implementation
const
RNoPreQuote = '(^|[^''])'; // No open qoute (Either at start, or other char)
RNoPostQuote = '($|[^''])'; // No close qoute (Either at end, or other char)
type
TWatchExpectationFlag = (fnoDwrf, fnoStabs, fTpMtch);
TWatchExpectationFlags = set of TWatchExpectationFlag;
TWatchExpectation = record
Exp: string;
Mtch: string;
Kind: TDBGSymbolKind;
TpNm: string;
Flgs: TWatchExpectationFlags;
end;
const
Match_Pointer = '(0x|\$)[0-9A-F]+';
Match_PasPointer = '\$[0-9A-F]+';
Match_ArgTRec = 'record TREC .+ valint = -1.+valfoo'; // record TREC { VALINT = -1, VALFOO = $0}
Match_ArgTRec1 = 'record TREC .+ valint = 1.+valfoo'; // record TREC { VALINT = 1, VALFOO = $xxx}
Match_ArgTRec2 = 'record TREC .+ valint = 2.+valfoo'; // record TREC { VALINT = 2, VALFOO = $xxx}
Match_ArgTNewRec = 'record TNEWREC .+ valint = 3.+valfoo'; // record TREC { VALINT = 3, VALFOO = $0}
Match_ArgTFoo = '<TFoo> = \{.+ValueInt = -1';
Match_ArgTFoo1 = '<TFoo> = \{.+ValueInt = 31';
// Todo: Dwarf fails with dereferenced var pointer types
ExpectBrk1NoneNil: Array [1..49] of TWatchExpectation = (
{ records }
(Exp: 'ArgTRec'; Mtch: Match_ArgTRec; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'VArgTRec'; Mtch: Match_ArgTRec; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'ArgPRec'; Mtch: '^PRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PRec'; Flgs: []),
(Exp: 'VArgPRec'; Mtch: '^PRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PRec'; Flgs: []),
(Exp: 'ArgPRec^'; Mtch: Match_ArgTRec1; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'VArgPRec^'; Mtch: Match_ArgTRec1; Kind: skRecord; TpNm: 'TRec'; Flgs: [fnoDwrf]),
(Exp: 'ArgPPRec'; Mtch: '^PPRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PPRec'; Flgs: []),
(Exp: 'VArgPPRec'; Mtch: '^PPRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PPRec'; Flgs: []),
(Exp: 'ArgPPRec^'; Mtch: '^PRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PRec'; Flgs: []),
(Exp: 'VArgPPRec^'; Mtch: '^PRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PRec'; Flgs: [fnoDwrf]),
(Exp: 'ArgPPRec^^'; Mtch: Match_ArgTRec1; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'VArgPPRec^^'; Mtch: Match_ArgTRec1; Kind: skRecord; TpNm: 'TRec'; Flgs: [fnoDwrf]),
(Exp: 'ArgTNewRec'; Mtch: Match_ArgTNewRec; Kind: skRecord; TpNm: 'TNewRec'; Flgs: []),
(Exp: 'VArgTNewRec'; Mtch: Match_ArgTNewRec; Kind: skRecord; TpNm: 'TNewRec'; Flgs: []),
(Exp: 'VarTRec'; Mtch: Match_ArgTRec; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'VarPRec'; Mtch: '^PRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PRec'; Flgs: []),
(Exp: 'VarPRec^'; Mtch: Match_ArgTRec1; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'VarPPRec'; Mtch: '^PPRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PPRec'; Flgs: []),
(Exp: 'VarPPRec^'; Mtch: '^PRec\('+Match_PasPointer; Kind: skPointer; TpNm: 'PRec'; Flgs: []),
(Exp: 'VarPPRec^^'; Mtch: Match_ArgTRec1; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'VarTNewRec'; Mtch: Match_ArgTNewRec; Kind: skRecord; TpNm: 'TNewRec'; Flgs: []),
(Exp: 'PVarTRec'; Mtch: '^(\^T|P)Rec\('+Match_PasPointer; Kind: skPointer; TpNm: '^(\^T|P)Rec$'; Flgs: [fTpMtch]), // TODO: stabs returns PRec
(Exp: 'PVarTRec^'; Mtch: Match_ArgTRec; Kind: skRecord; TpNm: 'TRec'; Flgs: []),
(Exp: 'PVarTNewRec'; Mtch: '^\^TNewRec\('+Match_PasPointer; Kind: skPointer; TpNm: '^TNewRec'; Flgs: []),
(Exp: 'PVarTNewRec^'; Mtch: Match_ArgTNewRec; Kind: skRecord; TpNm: 'TNewRec'; Flgs: []),
(Exp: 'ArgTFoo'; Mtch: Match_ArgTFoo; Kind: skClass; TpNm: 'TFoo'; Flgs: []),
(Exp: 'VArgTFoo'; Mtch: Match_ArgTFoo; Kind: skClass; TpNm: 'TFoo'; Flgs: []),
(Exp: 'ArgPFoo'; Mtch: 'PFoo\('+Match_PasPointer; Kind: skPointer; TpNm: 'PFoo'; Flgs: []),
(Exp: 'VArgPFoo'; Mtch: 'PFoo\('+Match_PasPointer; Kind: skPointer; TpNm: 'PFoo'; Flgs: []),
(Exp: 'ArgPFoo^'; Mtch: Match_ArgTFoo1; Kind: skClass; TpNm: 'TFoo'; Flgs: []),
(Exp: 'VArgPFoo^'; Mtch: Match_ArgTFoo1; Kind: skClass; TpNm: 'TFoo'; Flgs: [fnoDwrf]),
(*
{ Classes }
(Exp: 'ArgPPFoo'; Mtch: ''; Kind: sk; TpNm: 'PPFoo'; Flgs: []),
(Exp: 'VArgPPFoo'; Mtch: ''; Kind: sk; TpNm: 'PPFoo'; Flgs: []),
(Exp: 'ArgTSamePFoo'; Mtch: ''; Kind: sk; TpNm: 'TSamePFoo'; Flgs: []),
(Exp: 'VArgTSamePFoo'; Mtch: ''; Kind: sk; TpNm: 'TSamePFoo'; Flgs: []),
(Exp: 'ArgTNewPFoo'; Mtch: ''; Kind: sk; TpNm: 'TNewPFoo'; Flgs: []),
(Exp: 'VArgTNewPFoo'; Mtch: ''; Kind: sk; TpNm: 'TNewPFoo'; Flgs: []),
(Exp: 'ArgTSameFoo'; Mtch: ''; Kind: sk; TpNm: 'TSameFoo'; Flgs: []),
(Exp: 'VArgTSameFoo'; Mtch: ''; Kind: sk; TpNm: 'TSameFoo'; Flgs: []),
(Exp: 'ArgTNewFoo'; Mtch: ''; Kind: sk; TpNm: 'TNewFoo'; Flgs: []),
(Exp: 'VArgTNewFoo'; Mtch: ''; Kind: sk; TpNm: 'TNewFoo'; Flgs: []),
(Exp: 'ArgPNewFoo'; Mtch: ''; Kind: sk; TpNm: 'PNewFoo'; Flgs: []),
(Exp: 'VArgPNewFoo'; Mtch: ''; Kind: sk; TpNm: 'PNewFoo'; Flgs: []),
{ ClassesTyps }
(Exp: 'ArgTFooClass'; Mtch: ''; Kind: sk; TpNm: 'TFooClass'; Flgs: []),
(Exp: 'VArgTFooClass'; Mtch: ''; Kind: sk; TpNm: 'TFooClass'; Flgs: []),
(Exp: 'ArgPFooClass'; Mtch: ''; Kind: sk; TpNm: 'PFooClass'; Flgs: []),
(Exp: 'VArgPFooClass'; Mtch: ''; Kind: sk; TpNm: 'PFooClass'; Flgs: []),
(Exp: 'ArgPPFooClass'; Mtch: ''; Kind: sk; TpNm: 'PPFooClass'; Flgs: []),
(Exp: 'VArgPPFooClass'; Mtch: ''; Kind: sk; TpNm: 'PPFooClass'; Flgs: []),
(Exp: 'ArgTNewFooClass'; Mtch: ''; Kind: sk; TpNm: 'TNewFooClass'; Flgs: []),
(Exp: 'VArgTNewFooClass'; Mtch: ''; Kind: sk; TpNm: 'TNewFooClass'; Flgs: []),
(Exp: 'ArgPNewFooClass'; Mtch: ''; Kind: sk; TpNm: 'PNewFooClass'; Flgs: []),
(Exp: 'VArgPNewFooClass'; Mtch: ''; Kind: sk; TpNm: 'PNewFooClass'; Flgs: []),
*)
{ strings }
(Exp: 'ArgTMyAnsiString'; Mtch: '''ansi'''; Kind: skPointer; TpNm: '^(TMy)?AnsiString$'; Flgs: [fTpMtch]),
(Exp: 'VArgTMyAnsiString'; Mtch: '''ansi'''; Kind: skPointer; TpNm: '^(TMy)?AnsiString$'; Flgs: [fTpMtch]),
(Exp: 'ArgPMyAnsiString'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'PMyAnsiString'; Flgs: []),
(Exp: 'VArgPMyAnsiString'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'PMyAnsiString'; Flgs: []),
(Exp: 'ArgPMyAnsiString^'; Mtch: '''ansi'''; Kind: skPointer; TpNm: '^(TMy)?AnsiString$'; Flgs: [fTpMtch]),
(Exp: 'VArgPMyAnsiString^'; Mtch: '''ansi'''; Kind: skPointer; TpNm: '^(TMy)?AnsiString$'; Flgs: [fTpMtch, fnoDwrf]),
(Exp: 'ArgPPMyAnsiString'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'PPMyAnsiString'; Flgs: []),
(Exp: 'VArgPPMyAnsiString'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'PPMyAnsiString'; Flgs: []),
(Exp: 'ArgPPMyAnsiString^'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'PMyAnsiString'; Flgs: []),
(Exp: 'VArgPPMyAnsiString^'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'PMyAnsiString'; Flgs: [fnoDwrf]),
(Exp: 'ArgPPMyAnsiString^^'; Mtch: '''ansi'''; Kind: skPointer; TpNm: '^(TMy)?AnsiString$'; Flgs: [fTpMtch]),
(Exp: 'VArgPPMyAnsiString^^'; Mtch: '''ansi'''; Kind: skPointer; TpNm: '^(TMy)?AnsiString$'; Flgs: [fTpMtch, fnoDwrf]),
(*
(Exp: 'ArgTNewAnsiString'; Mtch: ''; Kind: sk; TpNm: 'TNewAnsiString'; Flgs: []),
(Exp: 'VArgTNewAnsiString'; Mtch: ''; Kind: sk; TpNm: 'TNewAnsiString'; Flgs: []),
(Exp: 'ArgPNewAnsiString'; Mtch: ''; Kind: sk; TpNm: 'PNewAnsiString'; Flgs: []),
(Exp: 'VArgPNewAnsiString'; Mtch: ''; Kind: sk; TpNm: 'PNewAnsiString'; Flgs: []),
*)
(Exp: 'ArgTMyShortString'; Mtch: '''short'''; Kind: skSimple; TpNm: '^(TMy)?ShortString$'; Flgs: [fTpMtch]),
(Exp: 'VArgTMyShortString'; Mtch: '''short'''; Kind: skSimple; TpNm: '^(TMy)?ShortString$'; Flgs: [fTpMtch]),
(Exp: 'ArgPMyShortString'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'P(My)?ShortString'; Flgs: [fTpMtch]),
(Exp: 'VArgPMyShortString'; Mtch: Match_Pointer; Kind: skPointer; TpNm: 'P(My)?ShortString'; Flgs: [fTpMtch]),
(Exp: 'ArgPMyShortString^'; Mtch: '''short'''; Kind: skSimple; TpNm: '^(TMy)?ShortString$'; Flgs: [fTpMtch]),
(Exp: 'VArgPMyShortString^'; Mtch: '''short'''; Kind: skSimple; TpNm: '^(TMy)?ShortString$'; Flgs: [fTpMtch, fnoDwrf])//,
(*
(Exp: 'ArgPPMyShortString'; Mtch: ''; Kind: sk; TpNm: 'PPMyShortString'; Flgs: []),
(Exp: 'VArgPPMyShortString'; Mtch: ''; Kind: sk; TpNm: 'PPMyShortString'; Flgs: []),
(Exp: 'ArgTNewhortString'; Mtch: ''; Kind: sk; TpNm: 'TNewhortString'; Flgs: []),
(Exp: 'VArgTNewhortString'; Mtch: ''; Kind: sk; TpNm: 'TNewhortString'; Flgs: []),
(Exp: 'ArgPNewhortString'; Mtch: ''; Kind: sk; TpNm: 'PNewhortString'; Flgs: []),
(Exp: 'VArgPNewhortString'; Mtch: ''; Kind: sk; TpNm: 'PNewhortString'; Flgs: []),
(Exp: 'ArgTMyWideString'; Mtch: ''; Kind: sk; TpNm: 'TMyWideString'; Flgs: []),
(Exp: 'VArgTMyWideString'; Mtch: ''; Kind: sk; TpNm: 'TMyWideString'; Flgs: []),
(Exp: 'ArgPMyWideString'; Mtch: ''; Kind: sk; TpNm: 'PMyWideString'; Flgs: []),
(Exp: 'VArgPMyWideString'; Mtch: ''; Kind: sk; TpNm: 'PMyWideString'; Flgs: []),
(Exp: 'ArgPPMyWideString'; Mtch: ''; Kind: sk; TpNm: 'PPMyWideString'; Flgs: []),
(Exp: 'VArgPPMyWideString'; Mtch: ''; Kind: sk; TpNm: 'PPMyWideString'; Flgs: []),
(Exp: 'ArgTNewWideString'; Mtch: ''; Kind: sk; TpNm: 'TNewWideString'; Flgs: []),
(Exp: 'VArgTNewWideString'; Mtch: ''; Kind: sk; TpNm: 'TNewWideString'; Flgs: []),
(Exp: 'ArgPNewWideString'; Mtch: ''; Kind: sk; TpNm: 'PNewWideString'; Flgs: []),
(Exp: 'VArgPNewWideString'; Mtch: ''; Kind: sk; TpNm: 'PNewWideString'; Flgs: []),
(Exp: 'ArgTMyString10'; Mtch: ''; Kind: sk; TpNm: 'TMyString10'; Flgs: []),
(Exp: 'VArgTMyString10'; Mtch: ''; Kind: sk; TpNm: 'TMyString10'; Flgs: []),
(Exp: 'ArgPMyString10'; Mtch: ''; Kind: sk; TpNm: 'PMyString10'; Flgs: []),
(Exp: 'VArgPMyString10'; Mtch: ''; Kind: sk; TpNm: 'PMyString10'; Flgs: []),
(Exp: 'ArgPPMyString10'; Mtch: ''; Kind: sk; TpNm: 'PPMyString10'; Flgs: []),
(Exp: 'VArgPPMyString10'; Mtch: ''; Kind: sk; TpNm: 'PPMyString10'; Flgs: []),
{ simple }
(Exp: 'ArgByte'; Mtch: ''; Kind: sk; TpNm: 'Byte'; Flgs: []),
(Exp: 'VArgByte'; Mtch: ''; Kind: sk; TpNm: 'Byte'; Flgs: []),
(Exp: 'ArgWord'; Mtch: ''; Kind: sk; TpNm: 'Word'; Flgs: []),
(Exp: 'VArgWord'; Mtch: ''; Kind: sk; TpNm: 'Word'; Flgs: []),
(Exp: 'ArgLongWord'; Mtch: ''; Kind: sk; TpNm: 'LongWord'; Flgs: []),
(Exp: 'VArgLongWord'; Mtch: ''; Kind: sk; TpNm: 'LongWord'; Flgs: []),
(Exp: 'ArgQWord'; Mtch: ''; Kind: sk; TpNm: 'QWord'; Flgs: []),
(Exp: 'VArgQWord'; Mtch: ''; Kind: sk; TpNm: 'QWord'; Flgs: []),
(Exp: 'ArgShortInt'; Mtch: ''; Kind: sk; TpNm: 'ShortInt'; Flgs: []),
(Exp: 'VArgShortInt'; Mtch: ''; Kind: sk; TpNm: 'ShortInt'; Flgs: []),
(Exp: 'ArgSmallInt'; Mtch: ''; Kind: sk; TpNm: 'SmallInt'; Flgs: []),
(Exp: 'VArgSmallInt'; Mtch: ''; Kind: sk; TpNm: 'SmallInt'; Flgs: []),
(Exp: 'ArgInt'; Mtch: ''; Kind: sk; TpNm: 'Integer'; Flgs: []),
(Exp: 'VArgInt'; Mtch: ''; Kind: sk; TpNm: 'Integer'; Flgs: []),
(Exp: 'ArgInt64'; Mtch: ''; Kind: sk; TpNm: 'Int64'; Flgs: []),
(Exp: 'VArgInt64'; Mtch: ''; Kind: sk; TpNm: 'Int64'; Flgs: []),
(Exp: 'ArgPByte'; Mtch: ''; Kind: sk; TpNm: 'PByte'; Flgs: []),
(Exp: 'VArgPByte'; Mtch: ''; Kind: sk; TpNm: 'PByte'; Flgs: []),
(Exp: 'ArgPWord'; Mtch: ''; Kind: sk; TpNm: 'PWord'; Flgs: []),
(Exp: 'VArgPWord'; Mtch: ''; Kind: sk; TpNm: 'PWord'; Flgs: []),
(Exp: 'ArgPLongWord'; Mtch: ''; Kind: sk; TpNm: 'PLongWord'; Flgs: []),
(Exp: 'VArgPLongWord'; Mtch: ''; Kind: sk; TpNm: 'PLongWord'; Flgs: []),
(Exp: 'ArgPQWord'; Mtch: ''; Kind: sk; TpNm: 'PQWord'; Flgs: []),
(Exp: 'VArgPQWord'; Mtch: ''; Kind: sk; TpNm: 'PQWord'; Flgs: []),
(Exp: 'ArgPShortInt'; Mtch: ''; Kind: sk; TpNm: 'PShortInt'; Flgs: []),
(Exp: 'VArgPShortInt'; Mtch: ''; Kind: sk; TpNm: 'PShortInt'; Flgs: []),
(Exp: 'ArgPSmallInt'; Mtch: ''; Kind: sk; TpNm: 'PSmallInt'; Flgs: []),
(Exp: 'VArgPSmallInt'; Mtch: ''; Kind: sk; TpNm: 'PSmallInt'; Flgs: []),
(Exp: 'ArgPInt'; Mtch: ''; Kind: sk; TpNm: 'PInteger'; Flgs: []),
(Exp: 'VArgPInt'; Mtch: ''; Kind: sk; TpNm: 'PInteger'; Flgs: []),
(Exp: 'ArgPInt64'; Mtch: ''; Kind: sk; TpNm: 'PInt64'; Flgs: []),
(Exp: 'VArgPInt64'; Mtch: ''; Kind: sk; TpNm: 'PInt64'; Flgs: []),
(Exp: 'ArgPointer'; Mtch: ''; Kind: sk; TpNm: 'Pointer'; Flgs: []),
(Exp: 'VArgPointer'; Mtch: ''; Kind: sk; TpNm: 'Pointer'; Flgs: []),
(Exp: 'ArgPPointer'; Mtch: ''; Kind: sk; TpNm: 'PPointer'; Flgs: []),
(Exp: 'VArgPPointer'; Mtch: ''; Kind: sk; TpNm: 'PPointer'; Flgs: []),
(Exp: 'ArgDouble'; Mtch: ''; Kind: sk; TpNm: 'Double'; Flgs: []),
(Exp: 'VArgDouble'; Mtch: ''; Kind: sk; TpNm: 'Double'; Flgs: []),
(Exp: 'ArgExtended'; Mtch: ''; Kind: sk; TpNm: 'Extended'; Flgs: []),
(Exp: 'VArgExtended'; Mtch: ''; Kind: sk; TpNm: 'Extended'; Flgs: []),
*)
);
{ TTestWatch }
procedure TTestWatch.DoChanged;
begin
if FMaster = nil then exit;;
if FMaster.Valid = vsValid then begin
if FHasValue and (FValue <> FMaster.Value) then
if FHasValue and (FValue <> FMaster.Value) then begin
FHasMultiValue := True;
FValue := FValue + LineEnding + FMaster.Value;
end
else
FValue := FMaster.Value;
FHasValue := True;
FValue := FMaster.Value;
FTypeInfo := Master.TypeInfo;
end;
end;
function TTestWatch.GetTypeInfo: TDBGType;
begin
Result := FTypeInfo;
end;
constructor TTestWatch.Create(AOwner: TBaseWatches; AMaster: TDBGWatch);
begin
inherited Create(AOwner);
Expression := AMaster.Expression;
FMaster := AMaster;
FMaster.Slave := Self;
FMaster.Enabled := True;
@ -92,61 +296,85 @@ end;
procedure TTestWatches.TestWatches;
var FailText: String;
procedure TestWatch(Name: String; AWatch: TTestWatch; Exp: String; StripQuotes: Boolean = False);
procedure TestWatch(Name: String; Data: TWatchExpectation);
const KindName: array [TDBGSymbolKind] of string =
('skClass', 'skRecord', 'skEnum', 'skSet', 'skProcedure', 'skFunction', 'skSimple', 'skPointer', 'skVariant');
var
AWatch: TTestWatch;
rx: TRegExpr;
s: String;
begin
rx := nil;
if (fnoDwrf in Data.Flgs) and (SymbolType = stDwarf) then exit;
if (fnoStabs in Data.Flgs) and (SymbolType = stStabs) then exit;
Name := Name + Data.Exp;
AWatch := TTestWatch(FWatches.Find(Data.Exp));
try
AWatch.Master.Value; // trigger read
AssertTrue (Name+ ' (HasValue)', AWatch.HasValue);
AssertFalse (Name+ ' (One Value)', AWatch.HasMultiValue);
s := AWatch.Value;
if StripQuotes and (length(s) > 1) and
(s[1] = '''') and (s[length(s)] = '''')
then
s := copy(s, 2, length(s)-2);
AssertEquals(Name+ ' (Value)', Exp, s);
rx := TRegExpr.Create;
rx.ModifierI := true;
rx.Expression := Data.Mtch;
if Data.Mtch <> ''
then AssertTrue(Name + ' Matches "'+Data.Mtch + '", but was "' + s + '"', rx.Exec(s));
except
on e: Exception do
FailText := FailText + e.Message + LineEnding;
FailText := FailText + LineEnding + e.Message;
end;
try
if Data.TpNm <> '' then begin;
AssertTrue(Name + ' has typeinfo', AWatch.TypeInfo <> nil);
AssertEquals(Name + ' kind', KindName[Data.Kind], KindName[AWatch.TypeInfo.Kind]);
if fTpMtch in Data.Flgs
then begin
FreeAndNil(rx);
s := AWatch.TypeInfo.TypeName;
rx := TRegExpr.Create;
rx.ModifierI := true;
rx.Expression := Data.TpNm;
AssertTrue(Name + ' TypeName matches '+Data.TpNm+' but was '+AWatch.TypeInfo.TypeName, rx.Exec(s))
end
else AssertEquals(Name + ' TypeName', LowerCase(Data.TpNm), LowerCase(AWatch.TypeInfo.TypeName));
end;
except
on e: Exception do
FailText := FailText + LineEnding + e.Message;
end;
FreeAndNil(rx);
end;
var
TestExeName: string;
dbg: TGDBMIDebugger;
i: Integer;
begin
TestCompile(AppDir + 'WatchesPrg.pas', TestExeName);
FTestIntWatch := nil;
try
FWatches := TBaseWatches.Create(TBaseWatch);
dbg := TGDBMIDebugger.Create(DebuggerInfo.ExeName);
//dbg.OnBreakPointHit := @DebuggerBreakPointHit;
with dbg.BreakPoints.Add('WatchesPrg.pas', 20) do begin
InitialEnabled := True;
Enabled := True;
end;
with dbg.BreakPoints.Add('WatchesPrg.pas', 30) do begin
(* Add breakpoints *)
//with dbg.BreakPoints.Add('WatchesPrg.pas', 44) do begin
// InitialEnabled := True;
// Enabled := True;
//end;
with dbg.BreakPoints.Add('WatchesPrg.pas', 395) do begin
InitialEnabled := True;
Enabled := True;
end;
FAVal1Watch := TTestWatch.Create(FWatches, dbg.Watches.Add('AVal1'));
FAVal2Watch := TTestWatch.Create(FWatches, dbg.Watches.Add('AVal2'));
(* Create all watches *)
for i := low(ExpectBrk1NoneNil) to high(ExpectBrk1NoneNil) do
TTestWatch.Create(FWatches, dbg.Watches.Add(ExpectBrk1NoneNil[i].Exp));
FTestIntWatch := TTestWatch.Create(FWatches, dbg.Watches.Add('TestInt'));
FTestShortStringWatch := TTestWatch.Create(FWatches, dbg.Watches.Add('TestShortString'));
FTestAnsiStringWatch := TTestWatch.Create(FWatches, dbg.Watches.Add('TestAnsiString'));
FTestPCharWatch := TTestWatch.Create(FWatches, dbg.Watches.Add('TestPChar'));
FArgAnsisString1 := TTestWatch.Create(FWatches, dbg.Watches.Add('ArgAnsiString1'));
FArgAnsisString2 := TTestWatch.Create(FWatches, dbg.Watches.Add('ArgAnsiString2'));
FArgAnsisString3 := TTestWatch.Create(FWatches, dbg.Watches.Add('ArgAnsiString3'));
FArgChar1 := TTestWatch.Create(FWatches, dbg.Watches.Add('ArgChar1'));
FArgChar2 := TTestWatch.Create(FWatches, dbg.Watches.Add('ArgChar2'));
FArgChar3 := TTestWatch.Create(FWatches, dbg.Watches.Add('ArgChar3'));
(* Start debugging *)
dbg.Init;
if dbg.State = dsError then
Fail(' Failed Init');
@ -157,28 +385,15 @@ begin
dbg.ShowConsole := True;
dbg.Run;
// hit breakpoint
//TestWatch('AVal1', FAVal1Watch, '10');
TestWatch('AVal2', FAVal2Watch, '5');
TestWatch('TestInt', FTestIntWatch, '10');
//TestWatch('TestShortString', FTestShortStringWatch, '3:', True);
TestWatch('TestAnsiString', FTestAnsiStringWatch, '3: Foo', True);
TestWatch('TestPChar', FTestPCharWatch, ': Foo', True);
(* Hit first breakpoint: Test *)
for i := low(ExpectBrk1NoneNil) to high(ExpectBrk1NoneNil) do
TestWatch('Brk1 ', ExpectBrk1NoneNil[i]);
dbg.Run;
// 2nd breakpoint
TestWatch('ArgAnsiString1', FArgAnsisString1, 'abc', True);
//TestWatch('ArgAnsiString2', FArgAnsisString2, 'def', True);
TestWatch('ArgAnsiString3', FArgAnsisString3, 'ghi', True);
TestWatch('ArgChar1', FArgChar1, '88 ''X''');
//TestWatch('ArgChar2', FArgChar2, '89 ''Y''');
TestWatch('ArgChar3', FArgChar3, '90 ''Z''');
//DebugInteract(dbg);
dbg.Stop;
finally
dbg.Free;