mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 09:06:02 +02:00
+ add RTTI unit from Joost's Attribute branch
* adjust unit to work without attributes * adjust unit to work without unit list (TRttiContext.GetTypes is disabled due to this) + add ShortString support (due to an intermediary test I had done in $H-) + add unit test from Joost's Attribute branch * adjust unit test accordingly (no attributes, no TRttiContext.GetTypes) + add ShortString tests + add testrunner for RTL-ObjPas tests using the new simpletestrunner git-svn-id: trunk@35096 -
This commit is contained in:
parent
933e449848
commit
3e5f8af01d
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -7148,6 +7148,7 @@ packages/rtl-objpas/Makefile svneol=native#text/plain
|
|||||||
packages/rtl-objpas/Makefile.fpc svneol=native#text/plain
|
packages/rtl-objpas/Makefile.fpc svneol=native#text/plain
|
||||||
packages/rtl-objpas/Makefile.fpc.fpcmake svneol=native#text/plain
|
packages/rtl-objpas/Makefile.fpc.fpcmake svneol=native#text/plain
|
||||||
packages/rtl-objpas/fpmake.pp svneol=native#text/plain
|
packages/rtl-objpas/fpmake.pp svneol=native#text/plain
|
||||||
|
packages/rtl-objpas/src/common/rtti.pp svneol=native#text/plain
|
||||||
packages/rtl-objpas/src/common/varutils.pp svneol=native#text/plain
|
packages/rtl-objpas/src/common/varutils.pp svneol=native#text/plain
|
||||||
packages/rtl-objpas/src/inc/convutil.inc svneol=native#text/plain
|
packages/rtl-objpas/src/inc/convutil.inc svneol=native#text/plain
|
||||||
packages/rtl-objpas/src/inc/convutil.pp svneol=native#text/plain
|
packages/rtl-objpas/src/inc/convutil.pp svneol=native#text/plain
|
||||||
@ -7165,6 +7166,8 @@ packages/rtl-objpas/src/inc/varutilh.inc svneol=native#text/plain
|
|||||||
packages/rtl-objpas/src/inc/varutils.inc svneol=native#text/plain
|
packages/rtl-objpas/src/inc/varutils.inc svneol=native#text/plain
|
||||||
packages/rtl-objpas/src/inc/widestrutils.pp svneol=native#text/plain
|
packages/rtl-objpas/src/inc/widestrutils.pp svneol=native#text/plain
|
||||||
packages/rtl-objpas/src/win/varutils.pp svneol=native#text/plain
|
packages/rtl-objpas/src/win/varutils.pp svneol=native#text/plain
|
||||||
|
packages/rtl-objpas/tests/testrunner.rtlobjpas.pp svneol=native#text/pascal
|
||||||
|
packages/rtl-objpas/tests/tests.rtti.pas svneol=native#text/plain
|
||||||
packages/rtl-unicode/Makefile svneol=native#text/plain
|
packages/rtl-unicode/Makefile svneol=native#text/plain
|
||||||
packages/rtl-unicode/Makefile.fpc svneol=native#text/plain
|
packages/rtl-unicode/Makefile.fpc svneol=native#text/plain
|
||||||
packages/rtl-unicode/fpmake.pp svneol=native#text/plain
|
packages/rtl-unicode/fpmake.pp svneol=native#text/plain
|
||||||
|
@ -116,6 +116,9 @@ begin
|
|||||||
AddUnit('varutils');
|
AddUnit('varutils');
|
||||||
// AddUnit('Math');
|
// AddUnit('Math');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
T:=P.Targets.AddUnit('rtti.pp',CommonSrcOSes);
|
||||||
|
T.ResourceStrings:=true;
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
929
packages/rtl-objpas/src/common/rtti.pp
Normal file
929
packages/rtl-objpas/src/common/rtti.pp
Normal file
@ -0,0 +1,929 @@
|
|||||||
|
{
|
||||||
|
This file is part of the Free Pascal run time library.
|
||||||
|
Copyright (C) 2013 Joost van der Sluis joost@cnoc.nl
|
||||||
|
member of the Free Pascal development team.
|
||||||
|
|
||||||
|
Extended RTTI compatibility unit
|
||||||
|
|
||||||
|
See the file COPYING.FPC, included in this distribution,
|
||||||
|
for details about the copyright.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
}
|
||||||
|
unit Rtti;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch advancedrecords}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes,
|
||||||
|
SysUtils,
|
||||||
|
typinfo;
|
||||||
|
|
||||||
|
type
|
||||||
|
TRttiType = class;
|
||||||
|
TRttiProperty = class;
|
||||||
|
TRttiInstanceType = class;
|
||||||
|
|
||||||
|
IValueData = interface
|
||||||
|
['{1338B2F3-2C21-4798-A641-CA2BC5BF2396}']
|
||||||
|
procedure ExtractRawData(ABuffer: pointer);
|
||||||
|
procedure ExtractRawDataNoCopy(ABuffer: pointer);
|
||||||
|
function GetDataSize: integer;
|
||||||
|
function GetReferenceToRawData: pointer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TValueData = record
|
||||||
|
FTypeInfo: PTypeInfo;
|
||||||
|
FValueData: IValueData;
|
||||||
|
case integer of
|
||||||
|
0: (FAsUByte: Byte);
|
||||||
|
1: (FAsUWord: Word);
|
||||||
|
2: (FAsULong: LongWord);
|
||||||
|
3: (FAsObject: Pointer);
|
||||||
|
4: (FAsClass: TClass);
|
||||||
|
5: (FAsSByte: Shortint);
|
||||||
|
9: (FAsDouble: Double);
|
||||||
|
10: (FAsExtenden: Extended);
|
||||||
|
12: (FAsCurr: Currency);
|
||||||
|
14: (FAsSInt64: Int64);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TValue }
|
||||||
|
|
||||||
|
TValue = object
|
||||||
|
private
|
||||||
|
FData: TValueData;
|
||||||
|
function GetTypeDataProp: PTypeData;
|
||||||
|
function GetTypeInfo: PTypeInfo;
|
||||||
|
function GetTypeKind: TTypeKind;
|
||||||
|
function GetIsEmpty: boolean;
|
||||||
|
public
|
||||||
|
class function Empty: TValue;
|
||||||
|
class procedure Make(ABuffer: pointer; ATypeInfo: PTypeInfo; out result: TValue);
|
||||||
|
function IsArray: boolean;
|
||||||
|
function AsString: string;
|
||||||
|
function AsExtended: Extended;
|
||||||
|
function IsClass: boolean;
|
||||||
|
function AsClass: TClass;
|
||||||
|
function IsObject: boolean;
|
||||||
|
function AsObject: TObject;
|
||||||
|
function IsOrdinal: boolean;
|
||||||
|
function AsOrdinal: Int64;
|
||||||
|
function AsBoolean: boolean;
|
||||||
|
function AsCurrency: Currency;
|
||||||
|
function AsInteger: Integer;
|
||||||
|
function ToString: string;
|
||||||
|
function IsType(ATypeInfo: PTypeInfo): boolean;
|
||||||
|
function TryAsOrdinal(out AResult: int64): boolean;
|
||||||
|
property Kind: TTypeKind read GetTypeKind;
|
||||||
|
property TypeData: PTypeData read GetTypeDataProp;
|
||||||
|
property TypeInfo: PTypeInfo read GetTypeInfo;
|
||||||
|
property IsEmpty: boolean read GetIsEmpty;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiContext }
|
||||||
|
|
||||||
|
TRttiContext = record
|
||||||
|
private
|
||||||
|
FContextToken: IInterface;
|
||||||
|
public
|
||||||
|
class function Create: TRttiContext; static;
|
||||||
|
procedure Free;
|
||||||
|
function GetType(ATypeInfo: PTypeInfo): TRttiType;
|
||||||
|
function GetType(AClass: TClass): TRttiType;
|
||||||
|
//function GetTypes: specialize TArray<TRttiType>;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiObject }
|
||||||
|
|
||||||
|
TRttiObject = class
|
||||||
|
public
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiNamedObject }
|
||||||
|
|
||||||
|
TRttiNamedObject = class(TRttiObject)
|
||||||
|
protected
|
||||||
|
function GetName: string; virtual;
|
||||||
|
public
|
||||||
|
property Name: string read GetName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiType }
|
||||||
|
|
||||||
|
TRttiType = class(TRttiNamedObject)
|
||||||
|
private
|
||||||
|
FTypeInfo: PTypeInfo;
|
||||||
|
FPropertiesResolved: boolean;
|
||||||
|
FProperties: specialize TArray<TRttiProperty>;
|
||||||
|
function GetAsInstance: TRttiInstanceType;
|
||||||
|
protected
|
||||||
|
FTypeData: PTypeData;
|
||||||
|
function GetName: string; override;
|
||||||
|
function GetIsInstance: boolean; virtual;
|
||||||
|
function GetIsManaged: boolean; virtual;
|
||||||
|
function GetIsOrdinal: boolean; virtual;
|
||||||
|
function GetIsRecord: boolean; virtual;
|
||||||
|
function GetIsSet: boolean; virtual;
|
||||||
|
function GetTypeKind: TTypeKind; virtual;
|
||||||
|
function GetTypeSize: integer; virtual;
|
||||||
|
function GetBaseType: TRttiType; virtual;
|
||||||
|
public
|
||||||
|
constructor create(ATypeInfo : PTypeInfo);
|
||||||
|
function GetProperties: specialize TArray<TRttiProperty>;
|
||||||
|
function GetProperty(const AName: string): TRttiProperty; virtual;
|
||||||
|
destructor destroy; override;
|
||||||
|
property IsInstance: boolean read GetIsInstance;
|
||||||
|
property isManaged: boolean read GetIsManaged;
|
||||||
|
property IsOrdinal: boolean read GetIsOrdinal;
|
||||||
|
property IsRecord: boolean read GetIsRecord;
|
||||||
|
property IsSet: boolean read GetIsSet;
|
||||||
|
property BaseType: TRttiType read GetBaseType;
|
||||||
|
property AsInstance: TRttiInstanceType read GetAsInstance;
|
||||||
|
property TypeKind: TTypeKind read GetTypeKind;
|
||||||
|
property TypeSize: integer read GetTypeSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TRttiStructuredType = class(TRttiType)
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiFloatType }
|
||||||
|
|
||||||
|
TRttiFloatType = class(TRttiType)
|
||||||
|
private
|
||||||
|
function GetFloatType: TFloatType;
|
||||||
|
public
|
||||||
|
property FloatType: TFloatType read GetFloatType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
TRttiStringKind = (skShortString, skAnsiString, skWideString, skUnicodeString);
|
||||||
|
|
||||||
|
{ TRttiStringType }
|
||||||
|
|
||||||
|
TRttiStringType = class(TRttiType)
|
||||||
|
private
|
||||||
|
function GetStringKind: TRttiStringKind;
|
||||||
|
public
|
||||||
|
property StringKind: TRttiStringKind read GetStringKind;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TRttiInstanceType }
|
||||||
|
|
||||||
|
TRttiInstanceType = class(TRttiStructuredType)
|
||||||
|
private
|
||||||
|
function GetDeclaringUnitName: string;
|
||||||
|
function GetMetaClassType: TClass;
|
||||||
|
protected
|
||||||
|
function GetIsInstance: boolean; override;
|
||||||
|
function GetTypeSize: integer; override;
|
||||||
|
function GetBaseType: TRttiType; override;
|
||||||
|
public
|
||||||
|
property MetaClassType: TClass read GetMetaClassType;
|
||||||
|
property DeclaringUnitName: string read GetDeclaringUnitName;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiMember }
|
||||||
|
|
||||||
|
TMemberVisibility=(mvPrivate, mvProtected, mvPublic, mvPublished);
|
||||||
|
|
||||||
|
TRttiMember = class(TRttiNamedObject)
|
||||||
|
private
|
||||||
|
FParent: TRttiType;
|
||||||
|
protected
|
||||||
|
function GetVisibility: TMemberVisibility; virtual;
|
||||||
|
public
|
||||||
|
constructor create(AParent: TRttiType);
|
||||||
|
property Visibility: TMemberVisibility read GetVisibility;
|
||||||
|
property Parent: TRttiType read FParent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiProperty }
|
||||||
|
|
||||||
|
TRttiProperty = class(TRttiMember)
|
||||||
|
private
|
||||||
|
FPropInfo: PPropInfo;
|
||||||
|
function GetPropertyType: TRttiType;
|
||||||
|
function GetIsWritable: boolean;
|
||||||
|
function GetIsReadable: boolean;
|
||||||
|
protected
|
||||||
|
function GetVisibility: TMemberVisibility; override;
|
||||||
|
function GetName: string; override;
|
||||||
|
public
|
||||||
|
constructor create(AParent: TRttiType; APropInfo: PPropInfo);
|
||||||
|
function GetValue(Instance: pointer): TValue;
|
||||||
|
procedure SetValue(Instance: pointer; const AValue: TValue);
|
||||||
|
property PropertyType: TRttiType read GetPropertyType;
|
||||||
|
property IsReadable: boolean read GetIsReadable;
|
||||||
|
property IsWritable: boolean read GetIsWritable;
|
||||||
|
property Visibility: TMemberVisibility read GetVisibility;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsManaged(TypeInfo: PTypeInfo): boolean;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TRttiPool }
|
||||||
|
|
||||||
|
TRttiPool = class
|
||||||
|
private
|
||||||
|
FTypesList: specialize TArray<TRttiType>;
|
||||||
|
FTypeCount: LongInt;
|
||||||
|
FLock: TRTLCriticalSection;
|
||||||
|
public
|
||||||
|
function GetTypes: specialize TArray<TRttiType>;
|
||||||
|
function GetType(ATypeInfo: PTypeInfo): TRttiType;
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
IPooltoken = interface
|
||||||
|
['{3CDB3CE9-AB55-CBAA-7B9D-2F3BB1CF5AF8}']
|
||||||
|
function RttiPool: TRttiPool;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TPoolToken }
|
||||||
|
|
||||||
|
TPoolToken = class(TInterfacedObject, IPooltoken)
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
function RttiPool: TRttiPool;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TValueDataIntImpl }
|
||||||
|
|
||||||
|
TValueDataIntImpl = class(TInterfacedObject, IValueData)
|
||||||
|
private
|
||||||
|
FDataSize: integer;
|
||||||
|
FBuffer: pointer;
|
||||||
|
public
|
||||||
|
constructor Create(ACopyFromBuffer: Pointer; ALen: integer);
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure ExtractRawData(ABuffer: pointer);
|
||||||
|
procedure ExtractRawDataNoCopy(ABuffer: pointer);
|
||||||
|
function GetDataSize: integer;
|
||||||
|
function GetReferenceToRawData: pointer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
resourcestring
|
||||||
|
SErrUnableToGetValueForType = 'Unable to get value for type %s';
|
||||||
|
SErrUnableToSetValueForType = 'Unable to set value for type %s';
|
||||||
|
SErrInvalidTypecast = 'Invalid class typecast';
|
||||||
|
|
||||||
|
var
|
||||||
|
PoolRefCount : integer;
|
||||||
|
GRttiPool : TRttiPool;
|
||||||
|
|
||||||
|
function IsManaged(TypeInfo: PTypeInfo): boolean;
|
||||||
|
begin
|
||||||
|
result := TypeInfo^.Kind in [tkString, tkAString, tkLString, tkInterface, tkArray, tkDynArray];
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiPool }
|
||||||
|
|
||||||
|
function TRttiPool.GetTypes: specialize TArray<TRttiType>;
|
||||||
|
begin
|
||||||
|
if not Assigned(FTypesList) then
|
||||||
|
Exit(Nil);
|
||||||
|
EnterCriticalsection(FLock);
|
||||||
|
Result := Copy(FTypesList, 0, FTypeCount);
|
||||||
|
LeaveCriticalsection(FLock);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiPool.GetType(ATypeInfo: PTypeInfo): TRttiType;
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
if not Assigned(ATypeInfo) then
|
||||||
|
Exit(Nil);
|
||||||
|
EnterCriticalsection(FLock);
|
||||||
|
Result := Nil;
|
||||||
|
for i := 0 to FTypeCount - 1 do
|
||||||
|
begin
|
||||||
|
if FTypesList[i].FTypeInfo = ATypeInfo then
|
||||||
|
begin
|
||||||
|
Result := FTypesList[i];
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if not Assigned(Result) then
|
||||||
|
begin
|
||||||
|
if FTypeCount = Length(FTypesList) then
|
||||||
|
begin
|
||||||
|
SetLength(FTypesList, FTypeCount * 2);
|
||||||
|
end;
|
||||||
|
case ATypeInfo^.Kind of
|
||||||
|
tkClass : Result := TRttiInstanceType.Create(ATypeInfo);
|
||||||
|
tkSString,
|
||||||
|
tkLString,
|
||||||
|
tkAString,
|
||||||
|
tkUString,
|
||||||
|
tkWString : Result := TRttiStringType.Create(ATypeInfo);
|
||||||
|
tkFloat : Result := TRttiFloatType.Create(ATypeInfo);
|
||||||
|
else
|
||||||
|
Result := TRttiType.Create(ATypeInfo);
|
||||||
|
end;
|
||||||
|
FTypesList[FTypeCount] := Result;
|
||||||
|
Inc(FTypeCount);
|
||||||
|
end;
|
||||||
|
LeaveCriticalsection(FLock);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TRttiPool.Create;
|
||||||
|
begin
|
||||||
|
InitCriticalSection(FLock);
|
||||||
|
SetLength(FTypesList, 32);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TRttiPool.Destroy;
|
||||||
|
var
|
||||||
|
i: LongInt;
|
||||||
|
begin
|
||||||
|
for i := 0 to length(FTypesList)-1 do
|
||||||
|
FTypesList[i].Free;
|
||||||
|
DoneCriticalsection(FLock);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TPoolToken }
|
||||||
|
|
||||||
|
constructor TPoolToken.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
if InterlockedIncrement(PoolRefCount)=1 then
|
||||||
|
GRttiPool := TRttiPool.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TPoolToken.Destroy;
|
||||||
|
begin
|
||||||
|
if InterlockedDecrement(PoolRefCount)=0 then
|
||||||
|
GRttiPool.Free;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TPoolToken.RttiPool: TRttiPool;
|
||||||
|
begin
|
||||||
|
result := GRttiPool;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TValueDataIntImpl }
|
||||||
|
|
||||||
|
constructor TValueDataIntImpl.create(ACopyFromBuffer: Pointer; ALen: integer);
|
||||||
|
begin
|
||||||
|
FDataSize:=ALen;
|
||||||
|
if ALen>0 then
|
||||||
|
begin
|
||||||
|
Getmem(FBuffer,FDataSize);
|
||||||
|
system.move(ACopyFromBuffer^,FBuffer^,FDataSize);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TValueDataIntImpl.Destroy;
|
||||||
|
begin
|
||||||
|
if assigned(FBuffer) then
|
||||||
|
Freemem(FBuffer);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TValueDataIntImpl.ExtractRawData(ABuffer: pointer);
|
||||||
|
begin
|
||||||
|
system.move(FBuffer^,ABuffer^,FDataSize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TValueDataIntImpl.ExtractRawDataNoCopy(ABuffer: pointer);
|
||||||
|
begin
|
||||||
|
system.move(FBuffer^,ABuffer^,FDataSize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValueDataIntImpl.GetDataSize: integer;
|
||||||
|
begin
|
||||||
|
result := FDataSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValueDataIntImpl.GetReferenceToRawData: pointer;
|
||||||
|
begin
|
||||||
|
result := FBuffer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiFloatType }
|
||||||
|
|
||||||
|
function TRttiFloatType.GetFloatType: TFloatType;
|
||||||
|
begin
|
||||||
|
result := FTypeData^.FloatType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TValue }
|
||||||
|
|
||||||
|
class function TValue.Empty: TValue;
|
||||||
|
begin
|
||||||
|
result.FData.FTypeInfo := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class procedure TValue.Make(ABuffer: pointer; ATypeInfo: PTypeInfo; out result: TValue);
|
||||||
|
begin
|
||||||
|
result.FData.FTypeInfo:=ATypeInfo;
|
||||||
|
case ATypeInfo^.Kind of
|
||||||
|
tkSString : result.FData.FValueData := TValueDataIntImpl.Create(@PShortString(ABuffer)^[1],Length(PShortString(ABuffer)^));
|
||||||
|
tkAString : result.FData.FValueData := TValueDataIntImpl.Create(@PAnsiString(ABuffer)^[1],length(PAnsiString(ABuffer)^));
|
||||||
|
tkClass : result.FData.FAsObject := PPointer(ABuffer)^;
|
||||||
|
tkInteger : result.FData.FAsSInt64 := PInt64(ABuffer)^;
|
||||||
|
tkBool : result.FData.FAsSInt64 := Int64(PBoolean(ABuffer)^);
|
||||||
|
tkFloat : begin
|
||||||
|
case GetTypeData(ATypeInfo)^.FloatType of
|
||||||
|
ftCurr : result.FData.FAsCurr := PCurrency(ABuffer)^;
|
||||||
|
ftDouble : result.FData.FAsDouble := PDouble(ABuffer)^;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
raise Exception.CreateFmt(SErrUnableToGetValueForType,[ATypeInfo^.Name]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TValue.GetTypeDataProp: PTypeData;
|
||||||
|
begin
|
||||||
|
result := GetTypeData(FData.FTypeInfo);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.GetTypeInfo: PTypeInfo;
|
||||||
|
begin
|
||||||
|
result := FData.FTypeInfo;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.GetTypeKind: TTypeKind;
|
||||||
|
begin
|
||||||
|
result := FData.FTypeInfo^.Kind;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.GetIsEmpty: boolean;
|
||||||
|
begin
|
||||||
|
result := (FData.FTypeInfo=nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.IsArray: boolean;
|
||||||
|
begin
|
||||||
|
result := kind in [tkArray, tkDynArray];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsString: string;
|
||||||
|
var
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
case Kind of
|
||||||
|
tkSString,
|
||||||
|
tkAString : begin
|
||||||
|
setlength(s,FData.FValueData.GetDataSize);
|
||||||
|
system.move(FData.FValueData.GetReferenceToRawData^,s[1],FData.FValueData.GetDataSize);
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
result := s;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsExtended: Extended;
|
||||||
|
begin
|
||||||
|
if Kind = tkFloat then
|
||||||
|
begin
|
||||||
|
case TypeData^.FloatType of
|
||||||
|
ftDouble : result := FData.FAsDouble;
|
||||||
|
ftExtended : result := FData.FAsExtenden;
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsObject: TObject;
|
||||||
|
begin
|
||||||
|
if IsObject then
|
||||||
|
result := TObject(FData.FAsObject)
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.IsObject: boolean;
|
||||||
|
begin
|
||||||
|
result := fdata.FTypeInfo^.Kind = tkClass;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.IsClass: boolean;
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsClass: TClass;
|
||||||
|
begin
|
||||||
|
if IsClass then
|
||||||
|
result := FData.FAsClass
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.IsOrdinal: boolean;
|
||||||
|
begin
|
||||||
|
result := Kind in [tkInteger, tkInt64, tkBool];
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsBoolean: boolean;
|
||||||
|
begin
|
||||||
|
if (Kind = tkBool) then
|
||||||
|
result := boolean(FData.FAsSInt64)
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsOrdinal: int64;
|
||||||
|
begin
|
||||||
|
if IsOrdinal then
|
||||||
|
result := FData.FAsSInt64
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsCurrency: Currency;
|
||||||
|
begin
|
||||||
|
if (Kind = tkFloat) and (TypeData^.FloatType=ftCurr) then
|
||||||
|
result := FData.FAsCurr
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.AsInteger: Integer;
|
||||||
|
begin
|
||||||
|
if Kind in [tkInteger, tkInt64] then
|
||||||
|
result := integer(FData.FAsSInt64)
|
||||||
|
else
|
||||||
|
raise EInvalidCast.Create(SErrInvalidTypecast);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.ToString: String;
|
||||||
|
begin
|
||||||
|
case Kind of
|
||||||
|
tkSString,
|
||||||
|
tkAString : result := AsString;
|
||||||
|
tkInteger : result := IntToStr(AsInteger);
|
||||||
|
tkBool : result := BoolToStr(AsBoolean, True);
|
||||||
|
else
|
||||||
|
result := '';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.IsType(ATypeInfo: PTypeInfo): boolean;
|
||||||
|
begin
|
||||||
|
result := ATypeInfo = TypeInfo;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TValue.TryAsOrdinal(out AResult: int64): boolean;
|
||||||
|
begin
|
||||||
|
result := IsOrdinal;
|
||||||
|
if result then
|
||||||
|
AResult := AsOrdinal;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TRttiStringType }
|
||||||
|
|
||||||
|
function TRttiStringType.GetStringKind: TRttiStringKind;
|
||||||
|
begin
|
||||||
|
case TypeKind of
|
||||||
|
tkSString : result := skShortString;
|
||||||
|
tkLString : result := skAnsiString;
|
||||||
|
tkAString : result := skAnsiString;
|
||||||
|
tkUString : result := skUnicodeString;
|
||||||
|
tkWString : result := skWideString;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiInstanceType }
|
||||||
|
|
||||||
|
function TRttiInstanceType.GetMetaClassType: TClass;
|
||||||
|
begin
|
||||||
|
result := FTypeData^.ClassType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiInstanceType.GetDeclaringUnitName: string;
|
||||||
|
begin
|
||||||
|
result := FTypeData^.UnitName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiInstanceType.GetBaseType: TRttiType;
|
||||||
|
var
|
||||||
|
AContext: TRttiContext;
|
||||||
|
begin
|
||||||
|
AContext := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
result := AContext.GetType(FTypeData^.ParentInfo);
|
||||||
|
finally
|
||||||
|
AContext.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiInstanceType.GetIsInstance: boolean;
|
||||||
|
begin
|
||||||
|
Result:=True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiInstanceType.GetTypeSize: integer;
|
||||||
|
begin
|
||||||
|
Result:=sizeof(TObject);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiMember }
|
||||||
|
|
||||||
|
function TRttiMember.GetVisibility: TMemberVisibility;
|
||||||
|
begin
|
||||||
|
result := mvPublished;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TRttiMember.create(AParent: TRttiType);
|
||||||
|
begin
|
||||||
|
inherited create();
|
||||||
|
FParent := AParent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiProperty }
|
||||||
|
|
||||||
|
function TRttiProperty.GetPropertyType: TRttiType;
|
||||||
|
begin
|
||||||
|
result := GRttiPool.GetType(FPropInfo^.PropType);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiProperty.GetIsReadable: boolean;
|
||||||
|
begin
|
||||||
|
result := assigned(FPropInfo^.GetProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiProperty.GetIsWritable: boolean;
|
||||||
|
begin
|
||||||
|
result := assigned(FPropInfo^.SetProc);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiProperty.GetVisibility: TMemberVisibility;
|
||||||
|
begin
|
||||||
|
// At this moment only pulished rtti-property-info is supported by fpc
|
||||||
|
result := mvPublished;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiProperty.GetName: string;
|
||||||
|
begin
|
||||||
|
Result:=FPropInfo^.Name;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TRttiProperty.create(AParent: TRttiType; APropInfo: PPropInfo);
|
||||||
|
begin
|
||||||
|
inherited create(AParent);
|
||||||
|
FPropInfo := APropInfo;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiProperty.GetValue(Instance: pointer): TValue;
|
||||||
|
var
|
||||||
|
s: string;
|
||||||
|
ss: ShortString;
|
||||||
|
i: int64;
|
||||||
|
begin
|
||||||
|
case FPropinfo^.PropType^.Kind of
|
||||||
|
tkSString:
|
||||||
|
begin
|
||||||
|
ss := GetStrProp(TObject(Instance), FPropInfo);
|
||||||
|
TValue.Make(@ss, FPropInfo^.PropType, result);
|
||||||
|
end;
|
||||||
|
tkAString:
|
||||||
|
begin
|
||||||
|
s := GetStrProp(TObject(Instance), FPropInfo);
|
||||||
|
TValue.Make(@s, FPropInfo^.PropType, result);
|
||||||
|
end;
|
||||||
|
tkInteger,
|
||||||
|
tkInt64,
|
||||||
|
tkQWord,
|
||||||
|
tkChar,
|
||||||
|
tkBool,
|
||||||
|
tkWChar:
|
||||||
|
begin
|
||||||
|
i := GetOrdProp(TObject(Instance), FPropInfo);
|
||||||
|
TValue.Make(@i, FPropInfo^.PropType, result);
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
result := TValue.Empty;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRttiProperty.SetValue(Instance: pointer; const AValue: TValue);
|
||||||
|
begin
|
||||||
|
case FPropinfo^.PropType^.Kind of
|
||||||
|
tkSString,
|
||||||
|
tkAString:
|
||||||
|
SetStrProp(TObject(Instance), FPropInfo, AValue.AsString);
|
||||||
|
tkInteger,
|
||||||
|
tkInt64,
|
||||||
|
tkQWord,
|
||||||
|
tkChar,
|
||||||
|
tkBool,
|
||||||
|
tkWChar:
|
||||||
|
SetOrdProp(TObject(Instance), FPropInfo, AValue.AsOrdinal);
|
||||||
|
else
|
||||||
|
raise exception.createFmt(SErrUnableToSetValueForType, [PropertyType.Name]);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetIsInstance: boolean;
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetIsManaged: boolean;
|
||||||
|
begin
|
||||||
|
result := Rtti.IsManaged(FTypeInfo);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetIsOrdinal: boolean;
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetIsRecord: boolean;
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
end;
|
||||||
|
function TRttiType.GetIsSet: boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetAsInstance: TRttiInstanceType;
|
||||||
|
begin
|
||||||
|
// This is a ridicoulous design, but Delphi-compatible...
|
||||||
|
result := TRttiInstanceType(self);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetBaseType: TRttiType;
|
||||||
|
begin
|
||||||
|
result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetTypeKind: TTypeKind;
|
||||||
|
begin
|
||||||
|
result := FTypeInfo^.Kind;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetTypeSize: integer;
|
||||||
|
begin
|
||||||
|
result := -1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetName: string;
|
||||||
|
begin
|
||||||
|
Result:=FTypeInfo^.Name;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TRttiType.create(ATypeInfo: PTypeInfo);
|
||||||
|
begin
|
||||||
|
inherited create();
|
||||||
|
FTypeInfo:=ATypeInfo;
|
||||||
|
if assigned(FTypeInfo) then
|
||||||
|
FTypeData:=GetTypeData(ATypeInfo);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function aligntoptr(p : pointer) : pointer;inline;
|
||||||
|
begin
|
||||||
|
{$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
|
||||||
|
result:=align(p,sizeof(p));
|
||||||
|
{$else FPC_REQUIRES_PROPER_ALIGNMENT}
|
||||||
|
result:=p;
|
||||||
|
{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetProperties: specialize TArray<TRttiProperty>;
|
||||||
|
type
|
||||||
|
PPropData = ^TPropData;
|
||||||
|
var
|
||||||
|
TypeInfo: PTypeInfo;
|
||||||
|
TypeRttiType: TRttiType;
|
||||||
|
TD: PTypeData;
|
||||||
|
PPD: PPropData;
|
||||||
|
TP: PPropInfo;
|
||||||
|
Count: longint;
|
||||||
|
begin
|
||||||
|
if not FPropertiesResolved then
|
||||||
|
begin
|
||||||
|
TypeInfo := FTypeInfo;
|
||||||
|
|
||||||
|
// Get the total properties count
|
||||||
|
SetLength(FProperties,FTypeData^.PropCount);
|
||||||
|
// Clear list
|
||||||
|
FillChar(FProperties[0],FTypeData^.PropCount*sizeof(TRttiProperty),0);
|
||||||
|
TypeRttiType:= self;
|
||||||
|
repeat
|
||||||
|
TD:=GetTypeData(TypeInfo);
|
||||||
|
|
||||||
|
// published properties count for this object
|
||||||
|
// skip the attribute-info if available
|
||||||
|
PPD := PPropData(pointer(@TD^.UnitName)+PByte(@TD^.UnitName)^+1);
|
||||||
|
Count:=PPD^.PropCount;
|
||||||
|
// Now point TP to first propinfo record.
|
||||||
|
TP:=PPropInfo(@PPD^.PropList);
|
||||||
|
While Count>0 do
|
||||||
|
begin
|
||||||
|
// Don't overwrite properties with the same name
|
||||||
|
if FProperties[TP^.NameIndex]=nil then
|
||||||
|
FProperties[TP^.NameIndex]:=TRttiProperty.Create(TypeRttiType, TP);
|
||||||
|
|
||||||
|
// Point to TP next propinfo record.
|
||||||
|
// Located at Name[Length(Name)+1] !
|
||||||
|
TP:=aligntoptr(PPropInfo(pointer(@TP^.Name)+PByte(@TP^.Name)^+1));
|
||||||
|
Dec(Count);
|
||||||
|
end;
|
||||||
|
TypeInfo:=TD^.Parentinfo;
|
||||||
|
TypeRttiType:= GRttiPool.GetType(TypeInfo);
|
||||||
|
until TypeInfo=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
result := FProperties;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiType.GetProperty(const AName: string): TRttiProperty;
|
||||||
|
var
|
||||||
|
FPropList: specialize TArray<TRttiProperty>;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
result := nil;
|
||||||
|
FPropList := GetProperties;
|
||||||
|
for i := 0 to length(FPropList)-1 do
|
||||||
|
if sametext(FPropList[i].Name,AName) then
|
||||||
|
begin
|
||||||
|
result := FPropList[i];
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TRttiType.Destroy;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to high(FProperties) do
|
||||||
|
FProperties[i].Free;
|
||||||
|
inherited destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiNamedObject }
|
||||||
|
|
||||||
|
function TRttiNamedObject.GetName: string;
|
||||||
|
begin
|
||||||
|
result := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TRttiContext }
|
||||||
|
|
||||||
|
class function TRttiContext.Create: TRttiContext;
|
||||||
|
begin
|
||||||
|
result.FContextToken := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRttiContext.Free;
|
||||||
|
begin
|
||||||
|
FContextToken := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRttiContext.GetType(ATypeInfo: PTypeInfo): TRttiType;
|
||||||
|
begin
|
||||||
|
if not assigned(FContextToken) then
|
||||||
|
FContextToken := TPoolToken.Create;
|
||||||
|
result := (FContextToken as IPooltoken).RttiPool.GetType(ATypeInfo);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TRttiContext.GetType(AClass: TClass): TRttiType;
|
||||||
|
begin
|
||||||
|
if assigned(AClass) then
|
||||||
|
result := GetType(PTypeInfo(AClass.ClassInfo))
|
||||||
|
else
|
||||||
|
result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{function TRttiContext.GetTypes: specialize TArray<TRttiType>;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if not assigned(FContextToken) then
|
||||||
|
FContextToken := TPoolToken.Create;
|
||||||
|
result := (FContextToken as IPooltoken).RttiPool.GetTypes;
|
||||||
|
end;}
|
||||||
|
|
||||||
|
initialization
|
||||||
|
PoolRefCount := 0;
|
||||||
|
end.
|
||||||
|
|
18
packages/rtl-objpas/tests/testrunner.rtlobjpas.pp
Normal file
18
packages/rtl-objpas/tests/testrunner.rtlobjpas.pp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
program testrunner.rtlobjpas;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
simpletestrunner,
|
||||||
|
tests.rtti;
|
||||||
|
|
||||||
|
var
|
||||||
|
Application: TTestRunner;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Application := TTestRunner.Create(nil);
|
||||||
|
Application.Initialize;
|
||||||
|
Application.Title := 'RTL-ObjPas unit tests';
|
||||||
|
Application.Run;
|
||||||
|
Application.Free;
|
||||||
|
end.
|
698
packages/rtl-objpas/tests/tests.rtti.pas
Normal file
698
packages/rtl-objpas/tests/tests.rtti.pas
Normal file
@ -0,0 +1,698 @@
|
|||||||
|
unit tests.rtti;
|
||||||
|
|
||||||
|
{$ifdef fpc}
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
{$IFDEF FPC}
|
||||||
|
fpcunit,testregistry, testutils,
|
||||||
|
{$ELSE FPC}
|
||||||
|
TestFramework,
|
||||||
|
{$ENDIF FPC}
|
||||||
|
Classes, SysUtils, typinfo,
|
||||||
|
Rtti;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TTestCase1 }
|
||||||
|
|
||||||
|
TTestCase1= class(TTestCase)
|
||||||
|
published
|
||||||
|
//procedure GetTypes;
|
||||||
|
procedure GetTypeInteger;
|
||||||
|
procedure GetClassProperties;
|
||||||
|
|
||||||
|
procedure GetClassPropertiesValue;
|
||||||
|
|
||||||
|
procedure TestTRttiTypeProperties;
|
||||||
|
procedure TestPropGetValueString;
|
||||||
|
procedure TestPropGetValueInteger;
|
||||||
|
procedure TestPropGetValueBoolean;
|
||||||
|
procedure TestPropGetValueShortString;
|
||||||
|
procedure TestPropGetValueProcString;
|
||||||
|
procedure TestPropGetValueProcInteger;
|
||||||
|
procedure TestPropGetValueProcBoolean;
|
||||||
|
procedure TestPropGetValueProcShortString;
|
||||||
|
|
||||||
|
procedure TestPropSetValueString;
|
||||||
|
procedure TestPropSetValueInteger;
|
||||||
|
procedure TestPropSetValueBoolean;
|
||||||
|
procedure TestPropSetValueShortString;
|
||||||
|
|
||||||
|
procedure TestGetValueStringCastError;
|
||||||
|
procedure TestMakeObject;
|
||||||
|
procedure TestGetIsReadable;
|
||||||
|
procedure TestIsWritable;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
TGetClassProperties = class
|
||||||
|
private
|
||||||
|
FPubPropRO: integer;
|
||||||
|
FPubPropRW: integer;
|
||||||
|
published
|
||||||
|
property PubPropRO: integer read FPubPropRO;
|
||||||
|
property PubPropRW: integer read FPubPropRW write FPubPropRW;
|
||||||
|
property PubPropSetRO: integer read FPubPropRO;
|
||||||
|
property PubPropSetRW: integer read FPubPropRW write FPubPropRW;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TTestValueClass }
|
||||||
|
|
||||||
|
TTestValueClass = class
|
||||||
|
private
|
||||||
|
FAInteger: integer;
|
||||||
|
FAString: string;
|
||||||
|
FABoolean: boolean;
|
||||||
|
FAShortString: ShortString;
|
||||||
|
function GetAInteger: integer;
|
||||||
|
function GetAString: string;
|
||||||
|
function GetABoolean: boolean;
|
||||||
|
function GetAShortString: ShortString;
|
||||||
|
procedure SetWriteOnly(AValue: integer);
|
||||||
|
published
|
||||||
|
property AInteger: Integer read FAInteger write FAInteger;
|
||||||
|
property AString: string read FAString write FAString;
|
||||||
|
property ABoolean: boolean read FABoolean write FABoolean;
|
||||||
|
property AShortString: ShortString read FAShortString write FAShortString;
|
||||||
|
property AGetInteger: Integer read GetAInteger;
|
||||||
|
property AGetString: string read GetAString;
|
||||||
|
property AGetBoolean: boolean read GetABoolean;
|
||||||
|
property AGetShortString: ShortString read GetAShortString;
|
||||||
|
property AWriteOnly: integer write SetWriteOnly;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TTestValueClass }
|
||||||
|
|
||||||
|
function TTestValueClass.GetAInteger: integer;
|
||||||
|
begin
|
||||||
|
result := FAInteger;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TTestValueClass.GetAString: string;
|
||||||
|
begin
|
||||||
|
result := FAString;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TTestValueClass.GetABoolean: boolean;
|
||||||
|
begin
|
||||||
|
result := FABoolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TTestValueClass.GetAShortString: ShortString;
|
||||||
|
begin
|
||||||
|
Result := FAShortString;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestValueClass.SetWriteOnly(AValue: integer);
|
||||||
|
begin
|
||||||
|
// Do nothing
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Note: GetTypes currently only returns those types that had been acquired using
|
||||||
|
GetType, so GetTypes itself can't be really tested currently }
|
||||||
|
(*procedure TTestCase1.GetTypes;
|
||||||
|
var
|
||||||
|
LContext: TRttiContext;
|
||||||
|
LType: TRttiType;
|
||||||
|
IsTestCaseClassFound: boolean;
|
||||||
|
begin
|
||||||
|
LContext := TRttiContext.Create;
|
||||||
|
|
||||||
|
{ Enumerate all types declared in the application }
|
||||||
|
for LType in LContext.GetTypes() do
|
||||||
|
begin
|
||||||
|
if LType.Name='TTestCase1' then
|
||||||
|
IsTestCaseClassFound:=true;
|
||||||
|
end;
|
||||||
|
LContext.Free;
|
||||||
|
CheckTrue(IsTestCaseClassFound, 'RTTI information does not contain class of testcase.');
|
||||||
|
end;*)
|
||||||
|
|
||||||
|
procedure TTestCase1.TestGetValueStringCastError;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AValue: TValue;
|
||||||
|
i: integer;
|
||||||
|
HadException: boolean;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AString := '12';
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
AValue := ARttiType.GetProperty('astring').GetValue(ATestClass);
|
||||||
|
HadException := false;
|
||||||
|
try
|
||||||
|
i := AValue.AsInteger;
|
||||||
|
except
|
||||||
|
on E: Exception do
|
||||||
|
if E.ClassType=EInvalidCast then
|
||||||
|
HadException := true;
|
||||||
|
end;
|
||||||
|
Check(HadException, 'No or invalid exception on invalid cast');
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestMakeObject;
|
||||||
|
var
|
||||||
|
AValue: TValue;
|
||||||
|
ATestClass: TTestValueClass;
|
||||||
|
begin
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AInteger := 54329;
|
||||||
|
TValue.Make(@ATestClass, TypeInfo(TTestValueClass),AValue);
|
||||||
|
CheckEquals(AValue.IsClass, False);
|
||||||
|
CheckEquals(AValue.IsObject, True);
|
||||||
|
Check(AValue.AsObject=ATestClass);
|
||||||
|
CheckEquals(TTestValueClass(AValue.AsObject).AInteger, 54329);
|
||||||
|
ATestClass.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestGetIsReadable;
|
||||||
|
var
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(TTestValueClass);
|
||||||
|
AProperty := ARttiType.GetProperty('aBoolean');
|
||||||
|
CheckEquals(AProperty.IsReadable, true);
|
||||||
|
AProperty := ARttiType.GetProperty('aGetBoolean');
|
||||||
|
CheckEquals(AProperty.IsReadable, true);
|
||||||
|
AProperty := ARttiType.GetProperty('aWriteOnly');
|
||||||
|
CheckEquals(AProperty.IsReadable, False);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestIsWritable;
|
||||||
|
var
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(TTestValueClass);
|
||||||
|
AProperty := ARttiType.GetProperty('aBoolean');
|
||||||
|
CheckEquals(AProperty.IsWritable, true);
|
||||||
|
AProperty := ARttiType.GetProperty('aGetBoolean');
|
||||||
|
CheckEquals(AProperty.IsWritable, false);
|
||||||
|
AProperty := ARttiType.GetProperty('aWriteOnly');
|
||||||
|
CheckEquals(AProperty.IsWritable, True);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueBoolean;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.ABoolean := true;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('aBoolean');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals(true,AValue.AsBoolean);
|
||||||
|
ATestClass.ABoolean := false;
|
||||||
|
CheckEquals(true, AValue.AsBoolean);
|
||||||
|
CheckEquals('True', AValue.ToString);
|
||||||
|
CheckEquals(True, AValue.IsOrdinal);
|
||||||
|
CheckEquals(1, AValue.AsOrdinal);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals(True,AValue.AsBoolean);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueShortString;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AShortString := 'Hello World';
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('aShortString');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
ATestClass.AShortString := 'Foobar';
|
||||||
|
CheckEquals('Hello World', AValue.AsString);
|
||||||
|
CheckEquals(False, AValue.IsOrdinal);
|
||||||
|
CheckEquals(False, AValue.IsObject);
|
||||||
|
CheckEquals(False, AValue.IsArray);
|
||||||
|
CheckEquals(False, AValue.IsClass);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueInteger;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AInteger := 472349;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('ainteger');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals(472349,AValue.AsInteger);
|
||||||
|
ATestClass.AInteger := 12;
|
||||||
|
CheckEquals(472349, AValue.AsInteger);
|
||||||
|
CheckEquals('472349', AValue.ToString);
|
||||||
|
CheckEquals(True, AValue.IsOrdinal);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals(472349,AValue.AsInteger);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueString;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
i: int64;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AString := 'Hello World';
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('astring');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
ATestClass.AString := 'Goodbye World';
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
CheckEquals('Hello World',AValue.ToString);
|
||||||
|
Check(TypeInfo(string)=AValue.TypeInfo);
|
||||||
|
Check(AValue.TypeData=GetTypeData(AValue.TypeInfo));
|
||||||
|
Check(AValue.IsEmpty=false);
|
||||||
|
Check(AValue.IsObject=false);
|
||||||
|
Check(AValue.IsClass=false);
|
||||||
|
CheckEquals(AValue.IsOrdinal, false);
|
||||||
|
CheckEquals(AValue.TryAsOrdinal(i), false);
|
||||||
|
CheckEquals(AValue.IsType(TypeInfo(string)), true);
|
||||||
|
CheckEquals(AValue.IsType(TypeInfo(integer)), false);
|
||||||
|
CheckEquals(AValue.IsArray, false);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueProcBoolean;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.ABoolean := true;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('aGetBoolean');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals(true,AValue.AsBoolean);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals(True,AValue.AsBoolean);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueProcShortString;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AShortString := 'Hello World';
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('aGetShortString');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropSetValueString;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
AProperty := ARttiType.GetProperty('astring');
|
||||||
|
|
||||||
|
s := 'ipse lorem or something like that';
|
||||||
|
TValue.Make(@s, TypeInfo(s), AValue);
|
||||||
|
AProperty.SetValue(ATestClass, AValue);
|
||||||
|
CheckEquals(ATestClass.AString, s);
|
||||||
|
s := 'Another string';
|
||||||
|
CheckEquals(ATestClass.AString, 'ipse lorem or something like that');
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropSetValueInteger;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
AProperty := ARttiType.GetProperty('aInteger');
|
||||||
|
|
||||||
|
i := -43573;
|
||||||
|
TValue.Make(@i, TypeInfo(i), AValue);
|
||||||
|
AProperty.SetValue(ATestClass, AValue);
|
||||||
|
CheckEquals(ATestClass.AInteger, i);
|
||||||
|
i := 1;
|
||||||
|
CheckEquals(ATestClass.AInteger, -43573);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropSetValueBoolean;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
b: boolean;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
AProperty := ARttiType.GetProperty('aboolean');
|
||||||
|
|
||||||
|
b := true;
|
||||||
|
TValue.Make(@b, TypeInfo(b), AValue);
|
||||||
|
AProperty.SetValue(ATestClass, AValue);
|
||||||
|
CheckEquals(ATestClass.ABoolean, b);
|
||||||
|
b := false;
|
||||||
|
CheckEquals(ATestClass.ABoolean, true);
|
||||||
|
TValue.Make(@b, TypeInfo(b), AValue);
|
||||||
|
AProperty.SetValue(ATestClass, AValue);
|
||||||
|
CheckEquals(ATestClass.ABoolean, false);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropSetValueShortString;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
s: string;
|
||||||
|
ss: ShortString;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
AProperty := ARttiType.GetProperty('aShortString');
|
||||||
|
|
||||||
|
s := 'ipse lorem or something like that';
|
||||||
|
TValue.Make(@s, TypeInfo(s), AValue);
|
||||||
|
AProperty.SetValue(ATestClass, AValue);
|
||||||
|
CheckEquals(ATestClass.AShortString, s);
|
||||||
|
s := 'Another string';
|
||||||
|
CheckEquals(ATestClass.AShortString, 'ipse lorem or something like that');
|
||||||
|
|
||||||
|
ss := 'Hello World';
|
||||||
|
TValue.Make(@ss, TypeInfo(ss), AValue);
|
||||||
|
AProperty.SetValue(ATestClass, AValue);
|
||||||
|
CheckEquals(ATestClass.AShortString, ss);
|
||||||
|
ss := 'Foobar';
|
||||||
|
CheckEquals(ATestClass.AShortString, 'Hello World');
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueProcInteger;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AInteger := 472349;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('agetinteger');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals(472349,AValue.AsInteger);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals(472349,AValue.AsInteger);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.TestPropGetValueProcString;
|
||||||
|
var
|
||||||
|
ATestClass : TTestValueClass;
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
AProperty: TRttiProperty;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ATestClass := TTestValueClass.Create;
|
||||||
|
ATestClass.AString := 'Hello World';
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(ATestClass.ClassInfo);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
AProperty := ARttiType.GetProperty('agetstring');
|
||||||
|
AValue := AProperty.GetValue(ATestClass);
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
finally
|
||||||
|
AtestClass.Free;
|
||||||
|
end;
|
||||||
|
CheckEquals('Hello World',AValue.AsString);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TTestCase1.TestTRttiTypeProperties;
|
||||||
|
var
|
||||||
|
c: TRttiContext;
|
||||||
|
ARttiType: TRttiType;
|
||||||
|
|
||||||
|
begin
|
||||||
|
c := TRttiContext.Create;
|
||||||
|
try
|
||||||
|
ARttiType := c.GetType(TTestValueClass);
|
||||||
|
Check(assigned(ARttiType));
|
||||||
|
CheckEquals(ARttiType.Name,'TTestValueClass');
|
||||||
|
Check(ARttiType.TypeKind=tkClass);
|
||||||
|
// CheckEquals(ARttiType.IsPublicType,false);
|
||||||
|
CheckEquals(ARttiType.TypeSize,SizeOf(TObject));
|
||||||
|
CheckEquals(ARttiType.IsManaged,false);
|
||||||
|
CheckEquals(ARttiType.BaseType.classname,'TRttiInstanceType');
|
||||||
|
CheckEquals(ARttiType.IsInstance,True);
|
||||||
|
CheckEquals(ARttiType.AsInstance.DeclaringUnitName,'tests.rtti');
|
||||||
|
Check(ARttiType.BaseType.Name='TObject');
|
||||||
|
Check(ARttiType.AsInstance.BaseType.Name='TObject');
|
||||||
|
CheckEquals(ARttiType.IsOrdinal,False);
|
||||||
|
CheckEquals(ARttiType.IsRecord,False);
|
||||||
|
CheckEquals(ARttiType.IsSet,False);
|
||||||
|
finally
|
||||||
|
c.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.GetTypeInteger;
|
||||||
|
var
|
||||||
|
LContext: TRttiContext;
|
||||||
|
LType: TRttiType;
|
||||||
|
begin
|
||||||
|
LContext := TRttiContext.Create;
|
||||||
|
|
||||||
|
LType := LContext.GetType(TypeInfo(integer));
|
||||||
|
CheckEquals(LType.Name, 'LongInt');
|
||||||
|
|
||||||
|
LContext.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.GetClassProperties;
|
||||||
|
var
|
||||||
|
LContext: TRttiContext;
|
||||||
|
LType: TRttiType;
|
||||||
|
PropList: {$ifdef fpc}specialize{$endif} TArray<TRttiProperty>;
|
||||||
|
begin
|
||||||
|
LContext := TRttiContext.Create;
|
||||||
|
|
||||||
|
LType := LContext.GetType(TypeInfo(TGetClassProperties));
|
||||||
|
PropList := LType.GetProperties;
|
||||||
|
|
||||||
|
CheckEquals(4, length(PropList));
|
||||||
|
CheckEquals('PubPropRO', PropList[0].Name);
|
||||||
|
CheckEquals('PubPropRW', PropList[1].Name);
|
||||||
|
CheckEquals('PubPropSetRO', PropList[2].Name);
|
||||||
|
CheckEquals('PubPropSetRW', PropList[3].Name);
|
||||||
|
|
||||||
|
LContext.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCase1.GetClassPropertiesValue;
|
||||||
|
var
|
||||||
|
AGetClassProperties: TGetClassProperties;
|
||||||
|
LContext: TRttiContext;
|
||||||
|
LType: TRttiType;
|
||||||
|
AValue: TValue;
|
||||||
|
begin
|
||||||
|
LContext := TRttiContext.Create;
|
||||||
|
|
||||||
|
LType := LContext.GetType(TGetClassProperties);
|
||||||
|
|
||||||
|
AGetClassProperties := TGetClassProperties.Create;
|
||||||
|
try
|
||||||
|
AGetClassProperties.PubPropRW:=12345;
|
||||||
|
|
||||||
|
AValue := LType.GetProperty('PubPropRW').GetValue(AGetClassProperties);
|
||||||
|
CheckEquals(12345, AValue.AsInteger);
|
||||||
|
|
||||||
|
finally
|
||||||
|
AGetClassProperties.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
LContext.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
{$ifdef fpc}
|
||||||
|
RegisterTest(TTestCase1);
|
||||||
|
{$else fpc}
|
||||||
|
RegisterTest(TTestCase1.Suite);
|
||||||
|
{$endif fpc}
|
||||||
|
end.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user