tests.rtti.invoke.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. unit tests.rtti.invoke;
  2. {$ifdef fpc}
  3. {$mode objfpc}{$H+}
  4. {$endif}
  5. {.$define debug}
  6. interface
  7. uses
  8. {$IFDEF FPC}
  9. fpcunit,testregistry, testutils,
  10. {$ELSE FPC}
  11. TestFramework,
  12. {$ENDIF FPC}
  13. sysutils, typinfo, Rtti;
  14. type
  15. TTestInvoke = class(TTestCase)
  16. private type
  17. TInvokeFlag = (
  18. ifStatic,
  19. ifConstructor
  20. );
  21. TInvokeFlags = set of TInvokeFlag;
  22. private
  23. function DoInvoke(aCodeAddress: CodePointer; aArgs: TValueArray; aCallConv: TCallConv; aResultType: PTypeInfo; aFlags: TInvokeFlags; out aValid: Boolean): TValue;
  24. procedure DoStaticInvokeTestOrdinalCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; aResult: Int64);
  25. procedure DoStaticInvokeTestAnsiStringCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: AnsiString);
  26. procedure DoStaticInvokeTestUnicodeStringCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: UnicodeString);
  27. {$ifdef fpc}
  28. procedure Status(const aMsg: String);
  29. {$endif}
  30. published
  31. procedure TestShortString;
  32. procedure TestAnsiString;
  33. procedure TestWideString;
  34. procedure TestUnicodeString;
  35. procedure TestLongInt;
  36. procedure TestInt64;
  37. procedure TestTObject;
  38. end;
  39. {$ifndef fpc}
  40. TValueHelper = record helper for TValue
  41. function AsUnicodeString: UnicodeString;
  42. function AsAnsiString: AnsiString;
  43. end;
  44. {$endif}
  45. implementation
  46. {$ifndef fpc}
  47. function TValueHelper.AsUnicodeString: UnicodeString;
  48. begin
  49. Result := UnicodeString(AsString);
  50. end;
  51. function TValueHelper.AsAnsiString: AnsiString;
  52. begin
  53. Result := AnsiString(AsString);
  54. end;
  55. {$endif}
  56. function TTestInvoke.DoInvoke(aCodeAddress: CodePointer; aArgs: TValueArray;
  57. aCallConv: TCallConv; aResultType: PTypeInfo; aFlags: TInvokeFlags; out aValid: Boolean): TValue;
  58. begin
  59. try
  60. Result := Rtti.Invoke(aCodeAddress, aArgs, aCallConv, aResultType, ifStatic in aFlags, ifConstructor in aFlags);
  61. aValid := True;
  62. except
  63. on e: ENotImplemented do begin
  64. Status('Ignoring unimplemented functionality of test');
  65. aValid := False;
  66. end else
  67. raise;
  68. end;
  69. end;
  70. procedure TTestInvoke.DoStaticInvokeTestOrdinalCompare(const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv; aValues: TValueArray; aReturnType: PTypeInfo; aResult: Int64);
  71. var
  72. resval: TValue;
  73. valid: Boolean;
  74. begin
  75. resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
  76. if valid and Assigned(aReturnType) and (resval.AsOrdinal <> aResult) then begin
  77. Fail('Result of test "%s" is unexpected; expected: %s, got: %s', [aTestName, IntToStr(aResult), IntToStr(resval.AsOrdinal)]);
  78. end;
  79. end;
  80. procedure TTestInvoke.DoStaticInvokeTestAnsiStringCompare(
  81. const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv;
  82. aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: AnsiString);
  83. var
  84. resval: TValue;
  85. valid: Boolean;
  86. begin
  87. resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
  88. if valid and Assigned(aReturnType) and (resval.AsAnsiString <> aResult) then begin
  89. Fail('Result of test "%s" is unexpected; expected: "%s", got: "%s"', [aTestName, aResult, resval.AsString]);
  90. end;
  91. end;
  92. procedure TTestInvoke.DoStaticInvokeTestUnicodeStringCompare(
  93. const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv;
  94. aValues: TValueArray; aReturnType: PTypeInfo; constref aResult: UnicodeString
  95. );
  96. var
  97. resval: TValue;
  98. valid: Boolean;
  99. begin
  100. resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
  101. if valid and Assigned(aReturnType) and (resval.AsUnicodeString <> aResult) then begin
  102. Fail('Result of test "%s" is unexpected; expected: "%s", got: "%s"', [aTestName, aResult, resval.AsString]);
  103. end;
  104. end;
  105. {$ifdef fpc}
  106. procedure TTestInvoke.Status(const aMsg: String);
  107. begin
  108. {$ifdef debug}
  109. Writeln(aMsg);
  110. {$endif}
  111. end;
  112. {$endif}
  113. function TestShortStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; register;
  114. begin
  115. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  116. end;
  117. function TestShortStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; cdecl;
  118. begin
  119. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  120. end;
  121. function TestShortStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; stdcall;
  122. begin
  123. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  124. end;
  125. function TestShortStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: ShortString): ShortString; pascal;
  126. begin
  127. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  128. end;
  129. procedure TTestInvoke.TestShortString;
  130. const
  131. strs: array[0..5] of ShortString = (
  132. 'This ',
  133. 'is a ',
  134. 'test ',
  135. 'of ',
  136. 'shortstring ',
  137. 'concatenation'
  138. );
  139. var
  140. values: TValueArray;
  141. resstr: ShortString;
  142. i: LongInt;
  143. begin
  144. SetLength(values, Length(strs));
  145. resstr := '';
  146. for i := Low(values) to High(values) do begin
  147. TValue.Make(@strs[i], TypeInfo(ShortString), values[i]);
  148. resstr := resstr + strs[i];
  149. end;
  150. DoStaticInvokeTestAnsiStringCompare('ShortString Register', @TestShortStringRegister, ccReg, values, TypeInfo(ShortString), resstr);
  151. DoStaticInvokeTestAnsiStringCompare('ShortString Cdecl', @TestShortStringCdecl, ccCdecl, values, TypeInfo(ShortString), resstr);
  152. DoStaticInvokeTestAnsiStringCompare('ShortString StdCall', @TestShortStringStdCall, ccStdCall, values, TypeInfo(ShortString), resstr);
  153. DoStaticInvokeTestAnsiStringCompare('ShortString Pascal', @TestShortStringPascal, ccPascal, values, TypeInfo(ShortString), resstr);
  154. end;
  155. function TestAnsiStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; register;
  156. begin
  157. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  158. end;
  159. function TestAnsiStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; cdecl;
  160. begin
  161. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  162. end;
  163. function TestAnsiStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; stdcall;
  164. begin
  165. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  166. end;
  167. function TestAnsiStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: AnsiString): AnsiString; pascal;
  168. begin
  169. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  170. end;
  171. procedure TTestInvoke.TestAnsiString;
  172. const
  173. strs: array[0..5] of AnsiString = (
  174. 'This ',
  175. 'is a ',
  176. 'test ',
  177. 'of ',
  178. 'AnsiString ',
  179. 'concatenation'
  180. );
  181. var
  182. values: TValueArray;
  183. resstr: AnsiString;
  184. i: LongInt;
  185. begin
  186. SetLength(values, Length(strs));
  187. resstr := '';
  188. for i := Low(values) to High(values) do begin
  189. TValue.Make(@strs[i], TypeInfo(AnsiString), values[i]);
  190. resstr := resstr + strs[i];
  191. end;
  192. DoStaticInvokeTestAnsiStringCompare('AnsiString Register', @TestAnsiStringRegister, ccReg, values, TypeInfo(AnsiString), resstr);
  193. DoStaticInvokeTestAnsiStringCompare('AnsiString Cdecl', @TestAnsiStringCdecl, ccCdecl, values, TypeInfo(AnsiString), resstr);
  194. DoStaticInvokeTestAnsiStringCompare('AnsiString StdCall', @TestAnsiStringStdCall, ccStdCall, values, TypeInfo(AnsiString), resstr);
  195. DoStaticInvokeTestAnsiStringCompare('AnsiString Pascal', @TestAnsiStringPascal, ccPascal, values, TypeInfo(AnsiString), resstr);
  196. end;
  197. function TestWideStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; register;
  198. begin
  199. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  200. end;
  201. function TestWideStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; cdecl;
  202. begin
  203. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  204. end;
  205. function TestWideStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; stdcall;
  206. begin
  207. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  208. end;
  209. function TestWideStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: WideString): WideString; pascal;
  210. begin
  211. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  212. end;
  213. procedure TTestInvoke.TestWideString;
  214. const
  215. strs: array[0..5] of WideString = (
  216. 'This ',
  217. 'is a ',
  218. 'test ',
  219. 'of ',
  220. 'WideString ',
  221. 'concatenation'
  222. );
  223. var
  224. values: TValueArray;
  225. resstr: WideString;
  226. i: LongInt;
  227. begin
  228. SetLength(values, Length(strs));
  229. resstr := '';
  230. for i := Low(values) to High(values) do begin
  231. TValue.Make(@strs[i], TypeInfo(WideString), values[i]);
  232. resstr := resstr + strs[i];
  233. end;
  234. DoStaticInvokeTestUnicodeStringCompare('WideString Register', @TestWideStringRegister, ccReg, values, TypeInfo(WideString), resstr);
  235. DoStaticInvokeTestUnicodeStringCompare('WideString Cdecl', @TestWideStringCdecl, ccCdecl, values, TypeInfo(WideString), resstr);
  236. DoStaticInvokeTestUnicodeStringCompare('WideString StdCall', @TestWideStringStdCall, ccStdCall, values, TypeInfo(WideString), resstr);
  237. DoStaticInvokeTestUnicodeStringCompare('WideString Pascal', @TestWideStringPascal, ccPascal, values, TypeInfo(WideString), resstr);
  238. end;
  239. function TestUnicodeStringRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; register;
  240. begin
  241. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  242. end;
  243. function TestUnicodeStringCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; cdecl;
  244. begin
  245. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  246. end;
  247. function TestUnicodeStringStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; stdcall;
  248. begin
  249. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  250. end;
  251. function TestUnicodeStringPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: UnicodeString): UnicodeString; pascal;
  252. begin
  253. Result := aArg1 + aArg2 + aArg3 + aArg4 + aArg5 + aArg6;
  254. end;
  255. procedure TTestInvoke.TestUnicodeString;
  256. const
  257. strs: array[0..5] of UnicodeString = (
  258. 'This ',
  259. 'is a ',
  260. 'test ',
  261. 'of ',
  262. 'UnicodeString ',
  263. 'concatenation'
  264. );
  265. var
  266. values: TValueArray;
  267. resstr: UnicodeString;
  268. i: LongInt;
  269. begin
  270. SetLength(values, Length(strs));
  271. resstr := '';
  272. for i := Low(values) to High(values) do begin
  273. TValue.Make(@strs[i], TypeInfo(UnicodeString), values[i]);
  274. resstr := resstr + strs[i];
  275. end;
  276. DoStaticInvokeTestUnicodeStringCompare('UnicodeString Register', @TestUnicodeStringRegister, ccReg, values, TypeInfo(UnicodeString), resstr);
  277. DoStaticInvokeTestUnicodeStringCompare('UnicodeString Cdecl', @TestUnicodeStringCdecl, ccCdecl, values, TypeInfo(UnicodeString), resstr);
  278. DoStaticInvokeTestUnicodeStringCompare('UnicodeString StdCall', @TestUnicodeStringStdCall, ccStdCall, values, TypeInfo(UnicodeString), resstr);
  279. DoStaticInvokeTestUnicodeStringCompare('UnicodeString Pascal', @TestUnicodeStringPascal, ccPascal, values, TypeInfo(UnicodeString), resstr);
  280. end;
  281. function TestLongIntRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; register;
  282. begin
  283. Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
  284. end;
  285. function TestLongIntCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; cdecl;
  286. begin
  287. Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
  288. end;
  289. function TestLongIntStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; stdcall;
  290. begin
  291. Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
  292. end;
  293. function TestLongIntPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: LongInt): LongInt; pascal;
  294. begin
  295. Result := aArg1 + aArg2 * 10 + aArg3 * 100 + aArg4 * 1000 + aArg5 * 10000 + aArg6 * 100000;
  296. end;
  297. procedure TTestInvoke.TestLongInt;
  298. const
  299. vals: array[0..5] of LongInt = (
  300. 8,
  301. 4,
  302. 7,
  303. 3,
  304. 6,
  305. 1
  306. );
  307. var
  308. values: TValueArray;
  309. resval, factor: LongInt;
  310. i: LongInt;
  311. begin
  312. SetLength(values, Length(vals));
  313. resval := 0;
  314. factor := 1;
  315. for i := Low(values) to High(values) do begin
  316. TValue.Make(@vals[i], TypeInfo(LongInt), values[i]);
  317. resval := resval + vals[i] * factor;
  318. factor := factor * 10;
  319. end;
  320. DoStaticInvokeTestOrdinalCompare('LongInt Register', @TestLongIntRegister, ccReg, values, TypeInfo(LongInt), resval);
  321. DoStaticInvokeTestOrdinalCompare('LongInt Cdecl', @TestLongIntCdecl, ccCdecl, values, TypeInfo(LongInt), resval);
  322. DoStaticInvokeTestOrdinalCompare('LongInt StdCall', @TestLongIntStdCall, ccStdCall, values, TypeInfo(LongInt), resval);
  323. DoStaticInvokeTestOrdinalCompare('LongInt Pascal', @TestLongIntPascal, ccPascal, values, TypeInfo(LongInt), resval);
  324. end;
  325. function TestInt64Register(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; register;
  326. begin
  327. Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
  328. end;
  329. function TestInt64Cdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; cdecl;
  330. begin
  331. Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
  332. end;
  333. function TestInt64StdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; stdcall;
  334. begin
  335. Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
  336. end;
  337. function TestInt64Pascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: Int64): Int64; pascal;
  338. begin
  339. Result := aArg1 + aArg2 * 100 + aArg3 * 10000 + aArg4 * 1000000 + aArg5 * 100000000 + aArg6 * 10000000000;
  340. end;
  341. procedure TTestInvoke.TestInt64;
  342. const
  343. vals: array[0..5] of Int64 = (
  344. 8,
  345. 4,
  346. 7,
  347. 3,
  348. 6,
  349. 1
  350. );
  351. var
  352. values: TValueArray;
  353. resval, factor: Int64;
  354. i: LongInt;
  355. begin
  356. SetLength(values, Length(vals));
  357. resval := 0;
  358. factor := 1;
  359. for i := Low(values) to High(values) do begin
  360. TValue.Make(@vals[i], TypeInfo(Int64), values[i]);
  361. resval := resval + vals[i] * factor;
  362. factor := factor * 100;
  363. end;
  364. DoStaticInvokeTestOrdinalCompare('Int64 Register', @TestInt64Register, ccReg, values, TypeInfo(Int64), resval);
  365. DoStaticInvokeTestOrdinalCompare('Int64 Cdecl', @TestInt64Cdecl, ccCdecl, values, TypeInfo(Int64), resval);
  366. DoStaticInvokeTestOrdinalCompare('Int64 StdCall', @TestInt64StdCall, ccStdCall, values, TypeInfo(Int64), resval);
  367. DoStaticInvokeTestOrdinalCompare('Int64 Pascal', @TestInt64Pascal, ccPascal, values, TypeInfo(Int64), resval);
  368. end;
  369. type
  370. TTestClass = class
  371. fString: String;
  372. fValue: LongInt;
  373. end;
  374. function TestTTestClassRegister(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; register;
  375. begin
  376. Result := TTestClass.Create;
  377. Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
  378. Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
  379. end;
  380. function TestTTestClassCdecl(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; cdecl;
  381. begin
  382. Result := TTestClass.Create;
  383. Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
  384. Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
  385. end;
  386. function TestTTestClassStdCall(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; stdcall;
  387. begin
  388. Result := TTestClass.Create;
  389. Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
  390. Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
  391. end;
  392. function TestTTestClassPascal(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6: TTestClass): TTestClass; pascal;
  393. begin
  394. Result := TTestClass.Create;
  395. Result.fString := aArg1.fString + aArg2.fString + aArg3.fString + aArg4.fString + aArg5.fString + aArg6.fString;
  396. Result.fValue := aArg1.fValue + aArg2.fValue * 10 + aArg3.fValue * 100 + aArg4.fValue * 1000 + aArg5.fValue * 10000 + aArg6.fValue * 100000;
  397. end;
  398. procedure TTestInvoke.TestTObject;
  399. procedure DoStaticInvokeTestClassCompare(
  400. const aTestName: String; aAddress: CodePointer; aCallConv: TCallConv;
  401. aValues: TValueArray; aReturnType: PTypeInfo; aResult: TTestClass
  402. );
  403. var
  404. resval: TValue;
  405. rescls: TTestClass;
  406. valid: Boolean;
  407. begin
  408. resval := DoInvoke(aAddress, aValues, aCallConv, aReturnType, [ifStatic], valid);
  409. if valid and Assigned(aReturnType) then begin
  410. rescls := TTestClass(PPointer(resval.GetReferenceToRawData)^);
  411. if (rescls.fString <> aResult.fString) or (rescls.fValue <> aResult.fValue) then
  412. Fail('Result of test "%s" is unexpected; expected: "%s"/%s, got: "%s"/%s', [aTestName, aResult.fString, IntToStr(aResult.fValue), rescls.fString, IntToStr(rescls.fValue)]);
  413. end;
  414. end;
  415. const
  416. strs: array[0..5] of AnsiString = (
  417. 'This ',
  418. 'is a ',
  419. 'test ',
  420. 'of ',
  421. 'AnsiString ',
  422. 'concatenation'
  423. );
  424. vals: array[0..5] of Int64 = (
  425. 8,
  426. 4,
  427. 7,
  428. 3,
  429. 6,
  430. 1
  431. );
  432. var
  433. values: TValueArray;
  434. t, rescls: TTestClass;
  435. i, factor: LongInt;
  436. begin
  437. SetLength(values, Length(vals));
  438. factor := 1;
  439. rescls := TTestClass.Create;
  440. for i := Low(values) to High(values) do begin
  441. t := TTestClass.Create;
  442. t.fString := strs[i];
  443. t.fValue := vals[i];
  444. TValue.Make(@t, TypeInfo(TTestClass), values[i]);
  445. rescls.fValue := rescls.fValue + vals[i] * factor;
  446. rescls.fString := rescls.fString + strs[i];
  447. factor := factor * 10;
  448. end;
  449. DoStaticInvokeTestClassCompare('TTestClass Register', @TestTTestClassRegister, ccReg, values, TypeInfo(TTestClass), rescls);
  450. DoStaticInvokeTestClassCompare('TTestClass Cdecl', @TestTTestClassCdecl, ccCdecl, values, TypeInfo(TTestClass), rescls);
  451. DoStaticInvokeTestClassCompare('TTestClass StdCall', @TestTTestClassStdCall, ccStdCall, values, TypeInfo(TTestClass), rescls);
  452. DoStaticInvokeTestClassCompare('TTestClass Pascal', @TestTTestClassPascal, ccPascal, values, TypeInfo(TTestClass), rescls);
  453. end;
  454. begin
  455. {$ifdef fpc}
  456. RegisterTest(TTestInvoke);
  457. {$else fpc}
  458. RegisterTest(TTestInvoke.Suite);
  459. {$endif fpc}
  460. end.