mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-07-27 00:06:11 +02:00
532 lines
18 KiB
ObjectPascal
532 lines
18 KiB
ObjectPascal
unit tests.rtti.invoke;
|
|
|
|
{$ifdef fpc}
|
|
{$mode objfpc}{$H+}
|
|
{$endif}
|
|
|
|
{.$define debug}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF FPC}
|
|
fpcunit,testregistry, testutils,
|
|
{$ELSE FPC}
|
|
TestFramework,
|
|
{$ENDIF FPC}
|
|
sysutils, typinfo, Rtti;
|
|
|
|
type
|
|
TTestInvoke = class(TTestCase)
|
|
private type
|
|
TInvokeFlag = (
|
|
ifStatic,
|
|
ifConstructor
|
|
);
|
|
TInvokeFlags = set of TInvokeFlag;
|
|
private
|
|
function DoInvoke(aCodeAddress: CodePointer; aArgs: TValueArray; aCallConv: TCallConv; aResultType: PTypeInfo; aFlags: TInvokeFlags; out aValid: Boolean): TValue;
|
|
procedure DoStaticInvokeTestOrdinalCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; aResult: Int64);
|
|
procedure DoStaticInvokeTestAnsiStringCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: AnsiString);
|
|
procedure DoStaticInvokeTestUnicodeStringCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: UnicodeString);
|
|
{$ifdef fpc}
|
|
procedure Status(const aMsg: String);
|
|
{$endif}
|
|
published
|
|
procedure TestShortString;
|
|
procedure TestAnsiString;
|
|
procedure TestWideString;
|
|
procedure TestUnicodeString;
|
|
|
|
procedure TestLongInt;
|
|
procedure TestInt64;
|
|
|
|
procedure TestTObject;
|
|
end;
|
|
|
|
{$ifndef fpc}
|
|
TValueHelper = record helper for TValue
|
|
function AsUnicodeString: UnicodeString;
|
|
function AsAnsiString: AnsiString;
|
|
end;
|
|
{$endif}
|
|
|
|
implementation
|
|
|
|
{$ifndef fpc}
|
|
function TValueHelper.AsUnicodeString: UnicodeString;
|
|
begin
|
|
Result := UnicodeString(AsString);
|
|
end;
|
|
|
|
function TValueHelper.AsAnsiString: AnsiString;
|
|
begin
|
|
Result := AnsiString(AsString);
|
|
end;
|
|
{$endif}
|
|
|
|
function TTestInvoke.DoInvoke(aCodeAddress: CodePointer; aArgs: TValueArray;
|
|
aCallConv: TCallConv; aResultType: PTypeInfo; aFlags: TInvokeFlags; out aValid: Boolean): TValue;
|
|
begin
|
|
try
|
|
Result := Rtti.Invoke(aCodeAddress, aArgs, aCallConv, aResultType, ifStatic in aFlags, ifConstructor in aFlags);
|
|
aValid := True;
|
|
except
|
|
on e: ENotImplemented do begin
|
|
Status('Ignoring unimplemented functionality of test');
|
|
aValid := False;
|
|
end else
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
procedure TTestInvoke.DoStaticInvokeTestOrdinalCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; aResult: Int64);
|
|
var
|
|
resval: TValue;
|
|
valid: Boolean;
|
|
begin
|
|
resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
|
|
if valid and Assigned(aReturnType) and (resval.AsOrdinal <> aResult) then begin
|
|
Fail('Result of test "%s" is unexpected; expected: %s, got: %s', [aTestName, IntToStr(aResult), IntToStr(resval.AsOrdinal)]);
|
|
end;
|
|
end;
|
|
|
|
procedure TTestInvoke.DoStaticInvokeTestAnsiStringCompare(
|
|
const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv;
|
|
aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: AnsiString);
|
|
var
|
|
resval: TValue;
|
|
valid: Boolean;
|
|
begin
|
|
resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
|
|
if valid and Assigned(aReturnType) and (resval.AsAnsiString <> aResult) then begin
|
|
Fail('Result of test "%s" is unexpected; expected: "%s", got: "%s"', [aTestName, aResult, resval.AsString]);
|
|
end;
|
|
end;
|
|
|
|
procedure TTestInvoke.DoStaticInvokeTestUnicodeStringCompare(
|
|
const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv;
|
|
aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: UnicodeString
|
|
);
|
|
var
|
|
resval: TValue;
|
|
valid: Boolean;
|
|
begin
|
|
resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
|
|
if valid and Assigned(aReturnType) and (resval.AsUnicodeString <> aResult) then begin
|
|
Fail('Result of test "%s" is unexpected; expected: "%s", got: "%s"', [aTestName, aResult, resval.AsString]);
|
|
end;
|
|
end;
|
|
|
|
{$ifdef fpc}
|
|
procedure TTestInvoke.Status(const aMsg: String);
|
|
begin
|
|
{$ifdef debug}
|
|
Writeln(aMsg);
|
|
{$endif}
|
|
end;
|
|
{$endif}
|
|
|
|
function TestShortStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; register;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestShortStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; cdecl;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestShortStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; stdcall;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestShortStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; pascal;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
procedure TTestInvoke.TestShortString;
|
|
const
|
|
strs: array[0..5] of ShortString = (
|
|
'This ',
|
|
'is a ',
|
|
'test ',
|
|
'of ',
|
|
'shortstring ',
|
|
'concatenation'
|
|
);
|
|
|
|
var
|
|
values: TValueArray;
|
|
resstr: ShortString;
|
|
i: LongInt;
|
|
begin
|
|
SetLength(values, Length(strs));
|
|
resstr := '';
|
|
for i := Low(values) to High(values) do begin
|
|
TValue.Make(@strs[i], TypeInfo(ShortString), values[i]);
|
|
resstr := resstr + strs[i];
|
|
end;
|
|
|
|
DoStaticInvokeTestAnsiStringCompare('ShortString Register', @TestShortStringRegister, ccReg, values, TypeInfo(ShortString), resstr);
|
|
DoStaticInvokeTestAnsiStringCompare('ShortString Cdecl', @TestShortStringCdecl, ccCdecl, values, TypeInfo(ShortString), resstr);
|
|
DoStaticInvokeTestAnsiStringCompare('ShortString StdCall', @TestShortStringStdCall, ccStdCall, values, TypeInfo(ShortString), resstr);
|
|
DoStaticInvokeTestAnsiStringCompare('ShortString Pascal', @TestShortStringPascal, ccPascal, values, TypeInfo(ShortString), resstr);
|
|
end;
|
|
|
|
function TestAnsiStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; register;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestAnsiStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; cdecl;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestAnsiStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; stdcall;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestAnsiStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; pascal;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
procedure TTestInvoke.TestAnsiString;
|
|
const
|
|
strs: array[0..5] of AnsiString = (
|
|
'This ',
|
|
'is a ',
|
|
'test ',
|
|
'of ',
|
|
'AnsiString ',
|
|
'concatenation'
|
|
);
|
|
|
|
var
|
|
values: TValueArray;
|
|
resstr: AnsiString;
|
|
i: LongInt;
|
|
begin
|
|
SetLength(values, Length(strs));
|
|
resstr := '';
|
|
for i := Low(values) to High(values) do begin
|
|
TValue.Make(@strs[i], TypeInfo(AnsiString), values[i]);
|
|
resstr := resstr + strs[i];
|
|
end;
|
|
|
|
DoStaticInvokeTestAnsiStringCompare('AnsiString Register', @TestAnsiStringRegister, ccReg, values, TypeInfo(AnsiString), resstr);
|
|
DoStaticInvokeTestAnsiStringCompare('AnsiString Cdecl', @TestAnsiStringCdecl, ccCdecl, values, TypeInfo(AnsiString), resstr);
|
|
DoStaticInvokeTestAnsiStringCompare('AnsiString StdCall', @TestAnsiStringStdCall, ccStdCall, values, TypeInfo(AnsiString), resstr);
|
|
DoStaticInvokeTestAnsiStringCompare('AnsiString Pascal', @TestAnsiStringPascal, ccPascal, values, TypeInfo(AnsiString), resstr);
|
|
end;
|
|
|
|
function TestWideStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; register;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestWideStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; cdecl;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestWideStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; stdcall;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestWideStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; pascal;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
procedure TTestInvoke.TestWideString;
|
|
const
|
|
strs: array[0..5] of WideString = (
|
|
'This ',
|
|
'is a ',
|
|
'test ',
|
|
'of ',
|
|
'WideString ',
|
|
'concatenation'
|
|
);
|
|
|
|
var
|
|
values: TValueArray;
|
|
resstr: WideString;
|
|
i: LongInt;
|
|
begin
|
|
SetLength(values, Length(strs));
|
|
resstr := '';
|
|
for i := Low(values) to High(values) do begin
|
|
TValue.Make(@strs[i], TypeInfo(WideString), values[i]);
|
|
resstr := resstr + strs[i];
|
|
end;
|
|
|
|
DoStaticInvokeTestUnicodeStringCompare('WideString Register', @TestWideStringRegister, ccReg, values, TypeInfo(WideString), resstr);
|
|
DoStaticInvokeTestUnicodeStringCompare('WideString Cdecl', @TestWideStringCdecl, ccCdecl, values, TypeInfo(WideString), resstr);
|
|
DoStaticInvokeTestUnicodeStringCompare('WideString StdCall', @TestWideStringStdCall, ccStdCall, values, TypeInfo(WideString), resstr);
|
|
DoStaticInvokeTestUnicodeStringCompare('WideString Pascal', @TestWideStringPascal, ccPascal, values, TypeInfo(WideString), resstr);
|
|
end;
|
|
|
|
function TestUnicodeStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; register;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestUnicodeStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; cdecl;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestUnicodeStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; stdcall;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
function TestUnicodeStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; pascal;
|
|
begin
|
|
Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
|
|
end;
|
|
|
|
procedure TTestInvoke.TestUnicodeString;
|
|
const
|
|
strs: array[0..5] of UnicodeString = (
|
|
'This ',
|
|
'is a ',
|
|
'test ',
|
|
'of ',
|
|
'UnicodeString ',
|
|
'concatenation'
|
|
);
|
|
|
|
var
|
|
values: TValueArray;
|
|
resstr: UnicodeString;
|
|
i: LongInt;
|
|
begin
|
|
SetLength(values, Length(strs));
|
|
resstr := '';
|
|
for i := Low(values) to High(values) do begin
|
|
TValue.Make(@strs[i], TypeInfo(UnicodeString), values[i]);
|
|
resstr := resstr + strs[i];
|
|
end;
|
|
|
|
DoStaticInvokeTestUnicodeStringCompare('UnicodeString Register', @TestUnicodeStringRegister, ccReg, values, TypeInfo(UnicodeString), resstr);
|
|
DoStaticInvokeTestUnicodeStringCompare('UnicodeString Cdecl', @TestUnicodeStringCdecl, ccCdecl, values, TypeInfo(UnicodeString), resstr);
|
|
DoStaticInvokeTestUnicodeStringCompare('UnicodeString StdCall', @TestUnicodeStringStdCall, ccStdCall, values, TypeInfo(UnicodeString), resstr);
|
|
DoStaticInvokeTestUnicodeStringCompare('UnicodeString Pascal', @TestUnicodeStringPascal, ccPascal, values, TypeInfo(UnicodeString), resstr);
|
|
end;
|
|
|
|
function TestLongIntRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; register;
|
|
begin
|
|
Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
|
|
end;
|
|
|
|
function TestLongIntCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; cdecl;
|
|
begin
|
|
Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
|
|
end;
|
|
|
|
function TestLongIntStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; stdcall;
|
|
begin
|
|
Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
|
|
end;
|
|
|
|
function TestLongIntPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; pascal;
|
|
begin
|
|
Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
|
|
end;
|
|
|
|
procedure TTestInvoke.TestLongInt;
|
|
const
|
|
vals: array[0..5] of LongInt = (
|
|
8,
|
|
4,
|
|
7,
|
|
3,
|
|
6,
|
|
1
|
|
);
|
|
|
|
var
|
|
values: TValueArray;
|
|
resval, factor: LongInt;
|
|
i: LongInt;
|
|
begin
|
|
SetLength(values, Length(vals));
|
|
resval := 0;
|
|
factor := 1;
|
|
for i := Low(values) to High(values) do begin
|
|
TValue.Make(@vals[i], TypeInfo(LongInt), values[i]);
|
|
resval := resval + vals[i] * factor;
|
|
factor := factor * 10;
|
|
end;
|
|
|
|
DoStaticInvokeTestOrdinalCompare('LongInt Register', @TestLongIntRegister, ccReg, values, TypeInfo(LongInt), resval);
|
|
DoStaticInvokeTestOrdinalCompare('LongInt Cdecl', @TestLongIntCdecl, ccCdecl, values, TypeInfo(LongInt), resval);
|
|
DoStaticInvokeTestOrdinalCompare('LongInt StdCall', @TestLongIntStdCall, ccStdCall, values, TypeInfo(LongInt), resval);
|
|
DoStaticInvokeTestOrdinalCompare('LongInt Pascal', @TestLongIntPascal, ccPascal, values, TypeInfo(LongInt), resval);
|
|
end;
|
|
|
|
function TestInt64Register(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; register;
|
|
begin
|
|
Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
|
|
end;
|
|
|
|
function TestInt64Cdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; cdecl;
|
|
begin
|
|
Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
|
|
end;
|
|
|
|
function TestInt64StdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; stdcall;
|
|
begin
|
|
Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
|
|
end;
|
|
|
|
function TestInt64Pascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; pascal;
|
|
begin
|
|
Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
|
|
end;
|
|
|
|
procedure TTestInvoke.TestInt64;
|
|
const
|
|
vals: array[0..5] of Int64 = (
|
|
8,
|
|
4,
|
|
7,
|
|
3,
|
|
6,
|
|
1
|
|
);
|
|
|
|
var
|
|
values: TValueArray;
|
|
resval, factor: Int64;
|
|
i: LongInt;
|
|
begin
|
|
SetLength(values, Length(vals));
|
|
resval := 0;
|
|
factor := 1;
|
|
for i := Low(values) to High(values) do begin
|
|
TValue.Make(@vals[i], TypeInfo(Int64), values[i]);
|
|
resval := resval + vals[i] * factor;
|
|
factor := factor * 100;
|
|
end;
|
|
|
|
DoStaticInvokeTestOrdinalCompare('Int64 Register', @TestInt64Register, ccReg, values, TypeInfo(Int64), resval);
|
|
DoStaticInvokeTestOrdinalCompare('Int64 Cdecl', @TestInt64Cdecl, ccCdecl, values, TypeInfo(Int64), resval);
|
|
DoStaticInvokeTestOrdinalCompare('Int64 StdCall', @TestInt64StdCall, ccStdCall, values, TypeInfo(Int64), resval);
|
|
DoStaticInvokeTestOrdinalCompare('Int64 Pascal', @TestInt64Pascal, ccPascal, values, TypeInfo(Int64), resval);
|
|
end;
|
|
|
|
type
|
|
TTestClass = class
|
|
fString: String;
|
|
fValue: LongInt;
|
|
end;
|
|
|
|
function TestTTestClassRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; register;
|
|
begin
|
|
Result := TTestClass.Create;
|
|
Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
|
|
Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
|
|
end;
|
|
|
|
function TestTTestClassCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; cdecl;
|
|
begin
|
|
Result := TTestClass.Create;
|
|
Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
|
|
Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
|
|
end;
|
|
|
|
function TestTTestClassStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; stdcall;
|
|
begin
|
|
Result := TTestClass.Create;
|
|
Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
|
|
Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
|
|
end;
|
|
|
|
function TestTTestClassPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; pascal;
|
|
begin
|
|
Result := TTestClass.Create;
|
|
Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
|
|
Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
|
|
end;
|
|
|
|
procedure TTestInvoke.TestTObject;
|
|
|
|
procedure DoStaticInvokeTestClassCompare(
|
|
const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv;
|
|
aValues: TValueArray; aReturnType: PTypeInfo; aResult: TTestClass
|
|
);
|
|
var
|
|
resval: TValue;
|
|
rescls: TTestClass;
|
|
valid: Boolean;
|
|
begin
|
|
resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
|
|
if valid and Assigned(aReturnType) then begin
|
|
rescls := TTestClass(PPointer(resval.GetReferenceToRawData)^);
|
|
if (rescls.fString <> aResult.fString) or (rescls.fValue <> aResult.fValue) then
|
|
Fail('Result of test "%s" is unexpected; expected: "%s"/%s, got: "%s"/%s', [aTestName, aResult.fString, IntToStr(aResult.fValue), rescls.fString, IntToStr(rescls.fValue)]);
|
|
end;
|
|
end;
|
|
|
|
const
|
|
strs: array[0..5] of AnsiString = (
|
|
'This ',
|
|
'is a ',
|
|
'test ',
|
|
'of ',
|
|
'AnsiString ',
|
|
'concatenation'
|
|
);
|
|
|
|
vals: array[0..5] of Int64 = (
|
|
8,
|
|
4,
|
|
7,
|
|
3,
|
|
6,
|
|
1
|
|
);
|
|
|
|
var
|
|
values: TValueArray;
|
|
t, rescls: TTestClass;
|
|
i, factor: LongInt;
|
|
begin
|
|
SetLength(values, Length(vals));
|
|
factor := 1;
|
|
rescls := TTestClass.Create;
|
|
for i := Low(values) to High(values) do begin
|
|
t := TTestClass.Create;
|
|
t.fString := strs[i];
|
|
t.fValue := vals[i];
|
|
TValue.Make(@t, TypeInfo(TTestClass), values[i]);
|
|
rescls.fValue := rescls.fValue + vals[i] * factor;
|
|
rescls.fString := rescls.fString + strs[i];
|
|
factor := factor * 10;
|
|
end;
|
|
|
|
DoStaticInvokeTestClassCompare('TTestClass Register', @TestTTestClassRegister, ccReg, values, TypeInfo(TTestClass), rescls);
|
|
DoStaticInvokeTestClassCompare('TTestClass Cdecl', @TestTTestClassCdecl, ccCdecl, values, TypeInfo(TTestClass), rescls);
|
|
DoStaticInvokeTestClassCompare('TTestClass StdCall', @TestTTestClassStdCall, ccStdCall, values, TypeInfo(TTestClass), rescls);
|
|
DoStaticInvokeTestClassCompare('TTestClass Pascal', @TestTTestClassPascal, ccPascal, values, TypeInfo(TTestClass), rescls);
|
|
end;
|
|
|
|
begin
|
|
{$ifdef fpc}
|
|
RegisterTest(TTestInvoke);
|
|
{$else fpc}
|
|
RegisterTest(TTestInvoke.Suite);
|
|
{$endif fpc}
|
|
end.
|
|
|