UnitTestLeak.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:13k
源码类别:

Email服务器

开发平台:

Delphi

  1. { $Id: UnitTestLeak.pas,v 1.1 2006/07/19 02:54:52 judc Exp $ }
  2. {: DUnit: An XTreme testing framework for Delphi programs.
  3.    @author  The DUnit Group.
  4.    @version $Revision: 1.1 $
  5. }
  6. (*
  7.  * The contents of this file are subject to the Mozilla Public
  8.  * License Version 1.1 (the "License"); you may not use this file
  9.  * except in compliance with the License. You may obtain a copy of
  10.  * the License at http://www.mozilla.org/MPL/
  11.  *
  12.  * Software distributed under the License is distributed on an "AS
  13.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  14.  * implied. See the License for the specific language governing
  15.  * rights and limitations under the License.
  16.  *
  17.  * The Original Code is DUnit.
  18.  *
  19.  * The Initial Developers of the Original Code are Kent Beck, Erich Gamma,
  20.  * and Juancarlo A馿z.
  21.  * Portions created The Initial Developers are Copyright (C) 1999-2000.
  22.  * Portions created by The DUnit Group are Copyright (C) 2000.
  23.  * All rights reserved.
  24.  *
  25.  * Contributor(s):
  26.  * Kent Beck <kentbeck@csi.com>
  27.  * Erich Gamma <Erich_Gamma@oti.com>
  28.  * Juanco A馿z <juanco@users.sourceforge.net>
  29.  * Chris Morris <chrismo@users.sourceforge.net>
  30.  * Jeff Moore <JeffMoore@users.sourceforge.net>
  31.  * Kris Golko <neuromancer@users.sourceforge.net>
  32.  * The DUnit group at SourceForge <http://dunit.sourceforge.net>
  33.  *
  34.  *)
  35.  
  36. unit UnitTestLeak;
  37. // Sample code to demonstrate testcase by testcase memory leak detection.
  38. // Project must be compiled with "FASTMM" global defines to
  39. // include FastMM4 code.
  40. // See the documentation in FastMMMemLeakMonitor.pas for details on setting
  41. // the FASTMM compile time options.
  42. //
  43. // After compiling the accomanying DUnit source and executing this demo project
  44. // there will be a GUI menu option "Fail TestCase if memory leaked".
  45. //
  46. // The GUI option selection "Fail Test Case if Memory Leaked" is applied to
  47. // every testcase unless overriden. The GUI setting can be overridden on a
  48. // testsuite basis by setting the test property
  49. // FailsOnMemLeakDetection := True/False in the SetUp procedure.
  50. //
  51. // Similarly, individual tests can override the GUI and SetUp setting in the
  52. // Test procedure. The property can be set anywhere in either the SetUp or Test
  53. // procedure as shown below in "procedure TestObjectLeakErrorSurpressed".
  54. // It can even be set after all checks are performed in a Test procedure because
  55. // a test failure would override any leak detection anyway. The property should
  56. // not be set in the TeardDown procedure.
  57. //
  58. // Memory leak errors do not override testcase failures.
  59. //
  60. // In the examples, Non Leaking tests are placed between successive leaks to
  61. // demonstrate that memory leak detection is performed on a case by case basis.
  62. // The non leaky code also acts to clean up lost memory from the previous test.
  63. //
  64. // By default, Memory "recovered" from a preceeding leaky test also flags as an
  65. // error. Setting the Test property IgnoreMemoryRecovery := True in either the
  66. // SetUp or Test procedure prevents an error report.
  67. // The properties FailsOnMemLeakDetection := False and
  68. //                IgnoreMemoryRecovery := True should be used sparingly because
  69. // they are easily burried in code and forgotten.
  70. // It is suggested they should only be used use for deliberate leaks or leaks
  71. // over which the coder has no control.
  72. //
  73. // A better way to handle unavoidable known leaks of a fixed size is as follows.
  74. // In the SetUp or Test procedures call AddKnownMemoryLeak(leaksize, Qty)
  75. // once or multiple times.
  76. // Alternatively simply set the property KnownMemoryLeakSize := value;
  77. // The advantage of setting KnownMemoryLeakSize over completely masking the leak
  78. // is that new leaks wont go undetected.
  79. // So, if a test is known to reclaim previously leaked memory it is preferable
  80. // to set a negative leak value, so future errors are not masked, rather than
  81. // setting IgnoreMemoryRecovery. The dissadvantage is that the previous test
  82. // must also be run else the test will flag an error.
  83. //
  84. // AddKnownMemoryLeak(leaksize, Qty) is probably only ever going to
  85. // have 1 as the qty, and setting KnownMemoryLeakSize has the same effect. The
  86. // call is included in case a substitute for FastMM is used and makes use of
  87. // individual leak tracking. We just use FastMM in a bulk leak detector mode.
  88. //
  89. // Known leaks caused by differing compilers (D5..D2005).
  90. // There are a number of Delphi "components" which are known to leak memory and
  91. // their presence changes between compiler versions. Because DUnit leak
  92. // detection is performed on a differential basis, unless that leaky code is
  93. // invoked and destroyed within the Test procedure then it will have no impact.
  94. // If necessary {$ifdef verXXX} {$endif} type constructs can be used to set
  95. // AllowedLeakSize() sizes according to the compiler in operation.
  96. //
  97. // FastMM was designed as a highly efficient memory manager and the fact we can
  98. // utilise it for "on-the-fly" memory leak detection is a bonus. So the
  99. // following is not a criticism of it's design, just our work-around use of it.
  100. // A limitation imposed by fixed blocks is that it may not be possible to
  101. // pre-calculate the memory allowance required with absolute certainty.
  102. // So the technique for setting the value is to allow the leak size to be
  103. // reported, then register the size with AllowedLeakSize() in the individual
  104. // test code.
  105. //
  106. // Other circumstances where Leaksizes vary if string lengths change naturally.
  107. // For instance if the current date is reported and just a one byte difference
  108. // occurs it may force a string to be allocated to a smaller or larger block.
  109. // It is preferable to write test code so that code under test does't dont leak
  110. // in the first place, which is why this new code exists for DUnit.
  111. // Enjoy. (Peter McNab)
  112. interface
  113. uses
  114.   TestFramework,
  115.   SysUtils;
  116. type
  117.   TTestLeak = class(TTestCase)
  118.   published
  119.     procedure TestCaseFailsNoLeaks;
  120.     procedure TestCaseNoLeaks1;
  121.     procedure TestCaseLeaksObject;
  122.     procedure TestCaseNoLeaks2;
  123.     procedure TestCaseFailsAndLeaks;
  124.     procedure TestCaseNoLeaks3;
  125.     procedure TestCaseLeaksObjectErrorSurpressed;
  126.     procedure TestCaseNoLeaks4;
  127.     procedure TestUnRaisedException;
  128.     procedure TestCaseNoLeaks5;
  129.     procedure TestCaseLeaksArray;
  130.     procedure TestCaseNoLeaks6;
  131.     procedure TestCaseLeaksMemory;
  132.     procedure TestCaseNoLeaks7;
  133.     procedure TestCaseLeaksString0;
  134.     procedure TestCaseNoLeaks8;
  135.     procedure TestCaseLeaksString1;
  136.     procedure TestCaseNoLeaks9;
  137.     procedure TestCaseNoLeaks10;
  138.     procedure TestEmptyReportSuppressed;
  139.     procedure TestEmptyAndReportSo;
  140.   end;
  141.   TTestSetUpLeaks = class(TTestCase)
  142.   public
  143.     procedure SetUp; override;
  144.   published
  145.     procedure TestCaseFreesSetUp1;
  146.     procedure TestCaseLeaksObject;
  147.     procedure TestCaseFreesSetUp2;
  148.   end;
  149.   TTestTearDownLeaks = class(TTestCase)
  150.   public
  151.     procedure SetUp; override;
  152.     procedure TearDown; override;
  153.   published
  154.     procedure TestCaseNoLeaks1;
  155.     procedure TestCaseTearDownLeaks;
  156.     procedure TestCaseNoLeaks2;
  157.   end;
  158.   TTestLeakOfSizeAllowed = class(TTestCase)
  159.   public
  160.     procedure SetUp; override;
  161.     procedure TearDown; override;
  162.   published
  163.     procedure TestCaseNoLeaks1;
  164.     procedure TestCaseLeakOfSizeAllowed;
  165.     procedure TestCaseNoLeaks2;
  166.   end;
  167.   TTestLeakOfDifferentSizeAllowed = class(TTestCase)
  168.   public
  169.     procedure SetUp; override;
  170.     procedure TearDown; override;
  171.   published
  172.     procedure TestCaseNoLeaks1;
  173.     procedure TestCaseLeakOfDifferentSizeAllowed;
  174.     procedure TestCaseNoLeaks2;
  175.   end;
  176. var
  177.   LeakedObject: TObject = nil;
  178.   Excpt: EAbort;
  179.   LeakyArray : array of Byte;
  180.   LeakyString : string;
  181.   LeakyMemory : PChar;
  182.   procedure ClearVars;
  183. implementation
  184. procedure ClearVars;
  185. begin
  186.   SetLength(LeakyArray,0);
  187.   LeakyArray := nil;
  188.   LeakyString := '';
  189.   SetLength(LeakyString, 0);
  190.   FreeAndNil(LeakedObject);
  191.   if (LeakyMemory <> nil) then
  192.   try
  193.     FreeMem(LeakyMemory);
  194.     LeakyMemory := nil;
  195.   except
  196.     LeakyMemory := nil;
  197.   end;
  198.   try
  199.     if Assigned(Excpt) then
  200.       raise excpt;
  201.   except
  202.     Excpt := nil;
  203.   end;
  204. end;
  205. { TTestLeak }
  206. procedure TTestLeak.TestCaseFailsNoLeaks;
  207. begin
  208.   Check(False, 'Deliberate fail no leaks');
  209. end;
  210. procedure TTestLeak.TestCaseFailsAndLeaks;
  211. begin
  212.   LeakedObject := TObject.Create;
  213.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  214.   Check(False, 'Deliberate fail shows failures take precendence over leak report');
  215. end;
  216. procedure TTestLeak.TestCaseNoLeaks1;
  217. begin
  218.   try
  219.     LeakedObject := TObject.Create;
  220.     Check(Assigned(LeakedObject), 'Golly, Failed to Create Object');
  221.   finally
  222.     FreeAndNil(LeakedObject);
  223.   end;
  224. end;
  225. procedure TTestLeak.TestCaseNoLeaks2;
  226. begin
  227.   TestCaseNoLeaks1;
  228. end;
  229. procedure TTestLeak.TestCaseNoLeaks3;
  230. begin
  231.   TestCaseNoLeaks1;
  232. end;
  233. procedure TTestLeak.TestCaseNoLeaks4;
  234. begin
  235.   TestCaseNoLeaks1;
  236. end;
  237. procedure TTestLeak.TestCaseNoLeaks5;
  238. begin
  239.   TestCaseNoLeaks1;
  240. end;
  241. procedure TTestLeak.TestCaseNoLeaks6;
  242. begin
  243.   TestCaseNoLeaks1;
  244. end;
  245. procedure TTestLeak.TestCaseNoLeaks7;
  246. begin
  247.   TestCaseNoLeaks1;
  248. end;
  249. procedure TTestLeak.TestCaseNoLeaks8;
  250. begin
  251.   TestCaseNoLeaks1;
  252. end;
  253. procedure TTestLeak.TestCaseNoLeaks9;
  254. begin
  255.   TestCaseNoLeaks1;
  256. end;
  257. procedure TTestLeak.TestCaseLeaksObjectErrorSurpressed;
  258. begin
  259.   LeakedObject := TObject.Create;
  260.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  261. // Override the GUI setting to prevent Memory leak from failing testcase.
  262.   FailsOnMemoryLeak := False;
  263. end;
  264. procedure TTestLeak.TestCaseLeaksObject;
  265. begin
  266.   LeakedObject := TObject.Create;
  267.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  268. end;
  269. procedure TTestLeak.TestUnRaisedException;
  270. begin
  271.   Excpt := EAbort.Create('Testing');
  272.   Check(Excpt.Message = 'Testing', 'Exception Failed to Create');
  273. end;
  274. procedure TTestLeak.TestCaseLeaksArray;
  275. begin
  276.   SetLength(LeakyArray, 4);
  277.   Check(Sizeof(LeakyArray) = 4,'Leaky Array size error = ' + IntToStr(Sizeof(LeakyArray)));
  278. end;
  279. procedure TTestLeak.TestCaseLeaksMemory;
  280. begin
  281.   GetMem(LeakyMemory, 4);
  282.   Check(Sizeof(LeakyMemory) = 4,'Leaky Memory size error = ' + IntToStr(Sizeof(LeakyMemory)));
  283. end;
  284. procedure TTestLeak.TestCaseLeaksString0;
  285. begin
  286.   SetLength(LeakyString, 0);
  287.   Check(Sizeof(LeakyString) = 4,' 0 Leaky String size error = ' + IntToStr(Sizeof(LeakyString)));
  288. end;
  289. procedure TTestLeak.TestCaseLeaksString1;
  290. begin
  291.   SetLength(LeakyString, 1);
  292.   Check(Sizeof(LeakyString) = 4,' 1 Leaky String size error = ' + IntToStr(Sizeof(LeakyString)));
  293. end;
  294. procedure TTestLeak.TestCaseNoLeaks10;
  295. begin
  296.   TestCaseNoLeaks1;
  297. end;
  298. procedure TTestLeak.TestEmptyReportSuppressed;
  299. begin
  300.   FailsOnNoChecksExecuted := False;
  301. end;
  302. procedure TTestLeak.TestEmptyAndReportSo;
  303. begin
  304.   FailsOnNoChecksExecuted := True;
  305. end;
  306. { TTestSetUpLeaks }
  307. procedure TTestSetUpLeaks.SetUp;
  308. begin
  309.   inherited;
  310.   LeakedObject := TObject.Create;
  311. end;
  312. procedure TTestSetUpLeaks.TestCaseFreesSetUp1;
  313. begin
  314.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  315.   FreeAndNil(LeakedObject);
  316. end;
  317. procedure TTestSetUpLeaks.TestCaseFreesSetUp2;
  318. begin
  319.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  320.   FreeAndNil(LeakedObject);
  321. end;
  322. procedure TTestSetUpLeaks.TestCaseLeaksObject;
  323. begin
  324.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  325. end;
  326. { TTestTearDownLeaks }
  327. procedure TTestTearDownLeaks.SetUp;
  328. begin
  329.   inherited;
  330.   LeakedObject := TObject.Create;
  331. end;
  332. procedure TTestTearDownLeaks.TearDown;
  333. begin
  334.   inherited;
  335. end;
  336. procedure TTestTearDownLeaks.TestCaseNoLeaks1;
  337. begin
  338.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  339.   FreeAndNil(LeakedObject);
  340. end;
  341. procedure TTestTearDownLeaks.TestCaseNoLeaks2;
  342. begin
  343.   TestCaseNoLeaks1;
  344. end;
  345. procedure TTestTearDownLeaks.TestCaseTearDownLeaks;
  346. begin
  347.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  348. end;
  349. { TTestLeakOfSizeAllowed }
  350. procedure TTestLeakOfSizeAllowed.SetUp;
  351. begin
  352.   inherited;
  353.   LeakedObject := TObject.Create;
  354. end;
  355. procedure TTestLeakOfSizeAllowed.TearDown;
  356. begin
  357.   inherited;
  358. end;
  359. procedure TTestLeakOfSizeAllowed.TestCaseLeakOfSizeAllowed;
  360. begin
  361.   AllowedMemoryLeakSize := 16;
  362.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  363. end;
  364. procedure TTestLeakOfSizeAllowed.TestCaseNoLeaks1;
  365. begin
  366.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  367.   FreeAndNil(LeakedObject);
  368. end;
  369. procedure TTestLeakOfSizeAllowed.TestCaseNoLeaks2;
  370. begin
  371.   TestCaseNoLeaks1;
  372. end;
  373. { TTestLeakOfDifferentSizeAllowed }
  374. procedure TTestLeakOfDifferentSizeAllowed.SetUp;
  375. begin
  376.   inherited;
  377.   LeakedObject := TObject.Create;
  378. end;
  379. procedure TTestLeakOfDifferentSizeAllowed.TearDown;
  380. begin
  381.   inherited;
  382. end;
  383. procedure TTestLeakOfDifferentSizeAllowed.TestCaseLeakOfDifferentSizeAllowed;
  384. begin
  385.   AllowedMemoryLeakSize := 1;  // Will always fail because min size is 12 bytes
  386.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  387. end;
  388. procedure TTestLeakOfDifferentSizeAllowed.TestCaseNoLeaks1;
  389. begin
  390.   Check(Assigned(LeakedObject), 'Failed to Create Object');
  391.   FreeAndNil(LeakedObject);
  392. end;
  393. procedure TTestLeakOfDifferentSizeAllowed.TestCaseNoLeaks2;
  394. begin
  395.   TestCaseNoLeaks1;
  396. end;
  397. initialization
  398.   Excpt := nil;
  399.   LeakyMemory := nil;
  400.   SetLength(LeakyString,0);
  401. end.