tests.rtti.invoke.pas 18 KB

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