Browse Source

* Patch from Graeme Geldenhuys
* Added support for triggering when a TestSuite starts and ends.
* Modified all the Test Listeners to support the StartTestSuite and
EndTestSuite interface methods, but only the XML Listener actually
uses it at the moment.
* Created a new directory called 'example_xslt' which contains a
sample XSLT and CSS file. This shows how I convert the generated XML
data into a HTML page. (Grouping of the Tests in TestSuites in the
Test Listing section will follow shortly.)

git-svn-id: trunk@5430 -

michael 18 years ago
parent
commit
dee22e8b4a

+ 29 - 30
fcl/fpcunit/DUnitCompatibleInterface.inc

@@ -2,11 +2,6 @@
 
 
 {$IFDEF read_interface}
 {$IFDEF read_interface}
 
 
-{
-    function  GetName: string; virtual;
-    property  Name: string read GetName;
-}
-
     class procedure Check(pValue: boolean; pMessage: string = '');
     class procedure Check(pValue: boolean; pMessage: string = '');
     class procedure CheckEquals(expected, actual: extended; msg: string = ''); overload;
     class procedure CheckEquals(expected, actual: extended; msg: string = ''); overload;
     class procedure CheckEquals(expected, actual: string; msg: string = ''); overload;
     class procedure CheckEquals(expected, actual: string; msg: string = ''); overload;
@@ -15,26 +10,24 @@
     class procedure CheckEquals(expected, actual: boolean; msg: string = ''); overload;
     class procedure CheckEquals(expected, actual: boolean; msg: string = ''); overload;
     class procedure CheckEquals(expected, actual: TClass; msg: string = ''); overload;
     class procedure CheckEquals(expected, actual: TClass; msg: string = ''); overload;
     class procedure CheckNotEquals(expected, actual: string; msg: string = ''); overload;
     class procedure CheckNotEquals(expected, actual: string; msg: string = ''); overload;
+    class procedure CheckNotEquals(expected, actual: integer; msg: string = ''); overload; virtual;
+    class procedure CheckNotEquals(expected, actual: boolean; msg: string = ''); overload; virtual;
+    class procedure CheckNotEquals(expected: extended; actual: extended; delta: extended = 0; msg: string = ''); overload; virtual;
     class procedure CheckNull(obj: IUnknown; msg: string = ''); overload;
     class procedure CheckNull(obj: IUnknown; msg: string = ''); overload;
     class procedure CheckNull(obj: TObject; msg: string = ''); overload;
     class procedure CheckNull(obj: TObject; msg: string = ''); overload;
     class procedure CheckNotNull(obj: TObject; msg: string = ''); overload;
     class procedure CheckNotNull(obj: TObject; msg: string = ''); overload;
     class procedure CheckIs(obj :TObject; pClass: TClass; msg: string = ''); overload;
     class procedure CheckIs(obj :TObject; pClass: TClass; msg: string = ''); overload;
     class procedure CheckSame(expected, actual: TObject; msg: string = ''); overload;
     class procedure CheckSame(expected, actual: TObject; msg: string = ''); overload;
+    class procedure FailNotEquals(expected, actual: string; msg: string = ''; errorAddr: Pointer = nil); virtual;
+
     {
     {
     *** TODO  ***
     *** TODO  ***
     procedure CheckEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
     procedure CheckEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
     procedure CheckEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
     procedure CheckEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
-
-    procedure CheckNotEquals(expected, actual: integer; msg: string = ''); overload; virtual;
-    procedure CheckNotEquals(expected: extended; actual: extended; delta: extended = 0; msg: string = ''); overload; virtual;
-    procedure CheckNotEquals(expected, actual: boolean; msg: string = ''); overload; virtual;
     procedure CheckNotEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
     procedure CheckNotEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
     procedure CheckNotEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
     procedure CheckNotEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
-
     procedure CheckNotNull(obj :IUnknown; msg :string = ''); overload; virtual;
     procedure CheckNotNull(obj :IUnknown; msg :string = ''); overload; virtual;
     procedure CheckSame(expected, actual: IUnknown; msg: string = ''); overload; virtual;
     procedure CheckSame(expected, actual: IUnknown; msg: string = ''); overload; virtual;
-
-
     procedure CheckException(AMethod: TTestMethod; AExceptionClass: TClass; msg :string = '');
     procedure CheckException(AMethod: TTestMethod; AExceptionClass: TClass; msg :string = '');
     procedure CheckInherits(expected, actual: TClass; msg: string = ''); overload; virtual;
     procedure CheckInherits(expected, actual: TClass; msg: string = ''); overload; virtual;
     }
     }
@@ -44,81 +37,82 @@
 
 
 {$IFDEF read_implementation}
 {$IFDEF read_implementation}
 
 
-{
-function TAssert.GetName: string;
-begin
-  Result := TestName;
-end;
-}
-
 class procedure TAssert.Check(pValue: boolean; pMessage: string);
 class procedure TAssert.Check(pValue: boolean; pMessage: string);
 begin
 begin
   AssertTrue(pMessage, pValue);
   AssertTrue(pMessage, pValue);
 end;
 end;
 
 
-
 class procedure TAssert.CheckEquals(expected, actual: extended; msg: string);
 class procedure TAssert.CheckEquals(expected, actual: extended; msg: string);
 begin
 begin
   AssertEquals(msg, expected, actual);
   AssertEquals(msg, expected, actual);
 end;
 end;
 
 
-
 class procedure TAssert.CheckEquals(expected, actual: string; msg: string);
 class procedure TAssert.CheckEquals(expected, actual: string; msg: string);
 begin
 begin
   AssertEquals(msg, expected, actual);
   AssertEquals(msg, expected, actual);
 end;
 end;
 
 
-
 class procedure TAssert.CheckEquals(expected, actual: extended;
 class procedure TAssert.CheckEquals(expected, actual: extended;
   delta: extended; msg: string);
   delta: extended; msg: string);
 begin
 begin
   AssertEquals(msg, expected, actual, delta);
   AssertEquals(msg, expected, actual, delta);
 end;
 end;
 
 
-
 class procedure TAssert.CheckEquals(expected, actual: integer; msg: string);
 class procedure TAssert.CheckEquals(expected, actual: integer; msg: string);
 begin
 begin
   AssertEquals(msg, expected, actual);
   AssertEquals(msg, expected, actual);
 end;
 end;
 
 
-
 class procedure TAssert.CheckEquals(expected, actual: boolean; msg: string);
 class procedure TAssert.CheckEquals(expected, actual: boolean; msg: string);
 begin
 begin
   AssertEquals(msg, expected, actual);
   AssertEquals(msg, expected, actual);
 end;
 end;
 
 
-
 class procedure TAssert.CheckEquals(expected, actual: TClass; msg: string);
 class procedure TAssert.CheckEquals(expected, actual: TClass; msg: string);
 begin
 begin
   AssertEquals(msg, expected, actual);
   AssertEquals(msg, expected, actual);
 end;
 end;
 
 
-
 class procedure TAssert.CheckNotEquals(expected, actual: string; msg: string);
 class procedure TAssert.CheckNotEquals(expected, actual: string; msg: string);
 begin
 begin
   if AnsiCompareStr(Expected, Actual) = 0 then
   if AnsiCompareStr(Expected, Actual) = 0 then
     Fail(msg + ComparisonMsg(Expected, Actual));
     Fail(msg + ComparisonMsg(Expected, Actual));
 end;
 end;
 
 
+class procedure TAssert.CheckNotEquals(expected, actual: integer; msg: string);
+begin
+  if (expected = actual) then
+    Fail(msg + ComparisonMsg(IntToStr(expected), IntToStr(actual)));
+end;
+
+class procedure TAssert.CheckNotEquals(expected, actual: boolean; msg: string);
+begin
+  if (expected = actual) then
+    Fail(msg + ComparisonMsg(BoolToStr(expected), BoolToStr(actual)));
+end;
+
+class procedure TAssert.CheckNotEquals(expected: extended; actual: extended;
+  delta: extended; msg: string);
+begin
+  if (abs(expected-actual) <= delta) then
+      FailNotEquals(FloatToStr(expected), FloatToStr(actual), msg, nil);
+end;
 
 
 class procedure TAssert.CheckNull(obj: IUnknown; msg: string);
 class procedure TAssert.CheckNull(obj: IUnknown; msg: string);
 begin
 begin
   AssertNullIntf(msg, obj);
   AssertNullIntf(msg, obj);
 end;
 end;
 
 
-
 class procedure TAssert.CheckNull(obj: TObject; msg: string);
 class procedure TAssert.CheckNull(obj: TObject; msg: string);
 begin
 begin
   AssertNull(msg, obj);
   AssertNull(msg, obj);
 end;
 end;
 
 
-
 class procedure TAssert.CheckNotNull(obj: TObject; msg: string);
 class procedure TAssert.CheckNotNull(obj: TObject; msg: string);
 begin
 begin
   AssertNotNull(msg, obj);
   AssertNotNull(msg, obj);
 end;
 end;
 
 
-
 class procedure TAssert.CheckIs(obj: TObject; pClass: TClass; msg: string);
 class procedure TAssert.CheckIs(obj: TObject; pClass: TClass; msg: string);
 begin
 begin
   Assert(pClass <> nil);
   Assert(pClass <> nil);
@@ -128,11 +122,16 @@ begin
     Fail(ComparisonMsg(pClass.ClassName, obj.ClassName));
     Fail(ComparisonMsg(pClass.ClassName, obj.ClassName));
 end;
 end;
 
 
-
 class procedure TAssert.CheckSame(expected, actual: TObject; msg: string);
 class procedure TAssert.CheckSame(expected, actual: TObject; msg: string);
 begin
 begin
    AssertSame(msg, expected, actual);
    AssertSame(msg, expected, actual);
 end;
 end;
 
 
+class procedure TAssert.FailNotEquals(expected, actual: string; msg: string;
+  errorAddr: Pointer);
+begin
+  Fail(msg + ComparisonMsg(Expected, Actual));
+end;
+
 {$ENDIF read_implementation}
 {$ENDIF read_implementation}
 
 

+ 29 - 0
fcl/fpcunit/fpcunit.pp

@@ -57,6 +57,7 @@ type
   TRunMethod = procedure of object;
   TRunMethod = procedure of object;
 
 
   TTestResult = class;
   TTestResult = class;
+  TTestSuite = class;
 
 
   {$M+}
   {$M+}
   TTest = class(TObject)
   TTest = class(TObject)
@@ -80,6 +81,8 @@ type
   {$M-}
   {$M-}
 
 
 
 
+  { TAssert }
+
   TAssert = class(TTest)
   TAssert = class(TTest)
   public
   public
     class procedure Fail(const AMessage: string);
     class procedure Fail(const AMessage: string);
@@ -170,6 +173,8 @@ type
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure StartTest(ATest: TTest);
     procedure StartTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
+    procedure StartTestSuite(ATestSuite: TTestSuite);
+    procedure EndTestSuite(ATestSuite: TTestSuite);
   end;
   end;
 
 
   TTestCase = class(TAssert)
   TTestCase = class(TAssert)
@@ -271,6 +276,8 @@ type
     function SkipTest(ATestCase: TTestCase): boolean;
     function SkipTest(ATestCase: TTestCase): boolean;
     procedure AddToSkipList(ATestCase: TTestCase);
     procedure AddToSkipList(ATestCase: TTestCase);
     procedure RemoveFromSkipList(ATestCase: TTestCase);
     procedure RemoveFromSkipList(ATestCase: TTestCase);
+    procedure StartTestSuite(ATestSuite: TTestSuite);
+    procedure EndTestSuite(ATestSuite: TTestSuite);
   published
   published
     property Listeners: TFPList read FListeners;
     property Listeners: TFPList read FListeners;
     property Failures: TFPList read FFailures;
     property Failures: TFPList read FFailures;
@@ -1005,8 +1012,14 @@ procedure TTestSuite.Run(AResult: TTestResult);
 var
 var
   i: integer;
   i: integer;
 begin
 begin
+  if FTests.Count > 0 then
+    AResult.StartTestSuite(self);
+    
   for i := 0 to FTests.Count - 1 do
   for i := 0 to FTests.Count - 1 do
     RunTest(TTest(FTests[i]), AResult);
     RunTest(TTest(FTests[i]), AResult);
+    
+  if FTests.Count > 0 then
+    AResult.EndTestSuite(self);
 end;
 end;
 
 
 
 
@@ -1247,5 +1260,21 @@ begin
   FSkippedTests.Remove(ATestCase);
   FSkippedTests.Remove(ATestCase);
 end;
 end;
 
 
+procedure TTestResult.StartTestSuite(ATestSuite: TTestSuite);
+var
+  i: integer;
+begin
+  for i := 0 to FListeners.Count - 1 do
+    ITestListener(FListeners[i]).StartTestSuite(ATestSuite);
+end;
+
+procedure TTestResult.EndTestSuite(ATestSuite: TTestSuite);
+var
+  i: integer;
+begin
+  for i := 0 to FListeners.Count - 1 do
+    ITestListener(FListeners[i]).EndTestSuite(ATestSuite);
+end;
+
 end.
 end.
 
 

+ 34 - 1
fcl/fpcunit/testreport.pp

@@ -22,6 +22,9 @@ uses
   classes, SysUtils, fpcunit, testutils;
   classes, SysUtils, fpcunit, testutils;
 
 
 type
 type
+
+  { TXMLResultsWriter }
+
   TXMLResultsWriter = class(TNoRefCountObject, ITestListener)
   TXMLResultsWriter = class(TNoRefCountObject, ITestListener)
   public
   public
     procedure WriteHeader;
     procedure WriteHeader;
@@ -31,8 +34,12 @@ type
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure StartTest(ATest: TTest);
     procedure StartTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
+    procedure StartTestSuite(ATestSuite: TTestSuite);
+    procedure EndTestSuite(ATestSuite: TTestSuite);
   end;
   end;
 
 
+  { TPlainResultsWriter }
+
   TPlainResultsWriter = class(TNoRefCountObject, ITestListener)
   TPlainResultsWriter = class(TNoRefCountObject, ITestListener)
   public
   public
     procedure WriteHeader;
     procedure WriteHeader;
@@ -42,6 +49,8 @@ type
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure StartTest(ATest: TTest);
     procedure StartTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
+    procedure StartTestSuite(ATestSuite: TTestSuite);
+    procedure EndTestSuite(ATestSuite: TTestSuite);
   end;
   end;
 
 
  {
  {
@@ -51,6 +60,8 @@ type
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure AddError(ATest: TTest; AError: TTestFailure);
     procedure StartTest(ATest: TTest);
     procedure StartTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
     procedure EndTest(ATest: TTest);
+    procedure StartTestSuite(ATestSuite: TTestSuite);
+    procedure EndTestSuite(ATestSuite: TTestSuite);
   end;}
   end;}
 
 
 function TestSuiteAsXML(aSuite:TTestSuite; Indent : Integer): string;
 function TestSuiteAsXML(aSuite:TTestSuite; Indent : Integer): string;
@@ -106,6 +117,16 @@ begin
   writeln('</test>');
   writeln('</test>');
 end;
 end;
 
 
+procedure TXMLResultsWriter.StartTestSuite(ATestSuite: TTestSuite);
+begin
+
+end;
+
+procedure TXMLResultsWriter.EndTestSuite(ATestSuite: TTestSuite);
+begin
+
+end;
+
 {TPlainResultsWriter}
 {TPlainResultsWriter}
 procedure TPlainResultsWriter.WriteHeader;
 procedure TPlainResultsWriter.WriteHeader;
 begin
 begin
@@ -132,7 +153,7 @@ end;
 
 
 procedure TPlainResultsWriter.StartTest(ATest: TTest);
 procedure TPlainResultsWriter.StartTest(ATest: TTest);
 begin
 begin
-  write('Test: ' , ATest.TestSuiteName + '.' + ATest.TestName);
+  write('Test: ', ATest.TestSuiteName + '.' + ATest.TestName);
 end;
 end;
 
 
 procedure TPlainResultsWriter.EndTest(ATest: TTest);
 procedure TPlainResultsWriter.EndTest(ATest: TTest);
@@ -140,6 +161,18 @@ begin
   writeln;
   writeln;
 end;
 end;
 
 
+procedure TPlainResultsWriter.StartTestSuite(ATestSuite: TTestSuite);
+begin
+  { example output }
+//  Writeln('TestSuite: ' + ATestSuite.TestName);
+end;
+
+procedure TPlainResultsWriter.EndTestSuite(ATestSuite: TTestSuite);
+begin
+  { example output }
+//  Writeln('TestSuite: ' + ATestSuite.TestName + ' - END ');
+end;
+
 function TestSuiteAsXML(aSuite:TTestSuite): string;
 function TestSuiteAsXML(aSuite:TTestSuite): string;
 
 
 begin
 begin

+ 45 - 23
fcl/fpcunit/xmlreporter.pas

@@ -22,7 +22,7 @@
     framework.  It uses the XMLWrite unit, which is part of FPC, to generate
     framework.  It uses the XMLWrite unit, which is part of FPC, to generate
     the XML document. The benefit of using the XMLWrite unit, is that the
     the XML document. The benefit of using the XMLWrite unit, is that the
     data generated is valid XML, with resevered characters correctly escaped.
     data generated is valid XML, with resevered characters correctly escaped.
-    This allows the XML document to be further processed with XSTL etc without
+    This allows the XML document to be further processed with XSLT etc without
     any issues.
     any issues.
 
 
 }
 }
@@ -44,6 +44,9 @@ uses
 
 
 type
 type
   { XML Test Listner }
   { XML Test Listner }
+
+  { TXMLResultsWriter }
+
   TXMLResultsWriter = class(TNoRefCountObject, ITestListener)
   TXMLResultsWriter = class(TNoRefCountObject, ITestListener)
   private
   private
     FDoc: TXMLDocument;
     FDoc: TXMLDocument;
@@ -53,6 +56,7 @@ type
     FFailures: TDOMNode;
     FFailures: TDOMNode;
     FIgnores: TDOMNode;
     FIgnores: TDOMNode;
     FErrors: TDOMNode;
     FErrors: TDOMNode;
+    FLastTestSuite: TDOMNode;
     FStartCrono: TDateTime;
     FStartCrono: TDateTime;
     { Converts the actual test results into XML nodes. This gets called
     { Converts the actual test results into XML nodes. This gets called
       by the public method WriteResult. }
       by the public method WriteResult. }
@@ -69,7 +73,9 @@ type
     procedure   AddError(ATest: TTest; AError: TTestFailure);
     procedure   AddError(ATest: TTest; AError: TTestFailure);
     procedure   StartTest(ATest: TTest);
     procedure   StartTest(ATest: TTest);
     procedure   EndTest(ATest: TTest);
     procedure   EndTest(ATest: TTest);
-    
+    procedure   StartTestSuite(ATestSuite: TTestSuite);
+    procedure   EndTestSuite(ATestSuite: TTestSuite);
+
     { A public property to the internal XML document }
     { A public property to the internal XML document }
     property    Document: TXMLDocument read FDoc;
     property    Document: TXMLDocument read FDoc;
   end;
   end;
@@ -125,18 +131,25 @@ end;
 
 
 constructor TXMLResultsWriter.Create;
 constructor TXMLResultsWriter.Create;
 begin
 begin
-  FDoc        := TXMLDocument.Create;
-  FResults    := nil;
-  FFailures   := nil;
-  FIgnores    := nil;
-  FErrors     := nil;
-  FListing    := nil;
+  FDoc            := TXMLDocument.Create;
+  FResults        := nil;
+  FFailures       := nil;
+  FIgnores        := nil;
+  FErrors         := nil;
+  FListing        := nil;
+  FLastTestSuite  := nil;
   WriteHeader;
   WriteHeader;
 end;
 end;
 
 
 
 
 destructor TXMLResultsWriter.Destroy;
 destructor TXMLResultsWriter.Destroy;
 begin
 begin
+  FResults        := nil;
+  FFailures       := nil;
+  FIgnores        := nil;
+  FErrors         := nil;
+  FListing        := nil;
+  FLastTestSuite  := nil;
   FDoc.Free;
   FDoc.Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
@@ -218,19 +231,9 @@ procedure TXMLResultsWriter.StartTest(ATest: TTest);
 var
 var
   n: TDOMElement;
   n: TDOMElement;
 begin
 begin
-  { Try and find the Listings node first }
-  if not Assigned(FListing) then
-    FListing := FDoc.FindNode('TestListing');
-  { If we couldn't find it, create it }
-  if not Assigned(FListing) then
-  begin
-    FListing := FDoc.CreateElement('TestListing');
-    FResults.AppendChild(FListing);
-  end;
-
   n := FDoc.CreateElement('Test');
   n := FDoc.CreateElement('Test');
   n['Name'] := ATest.TestSuiteName + '.' + ATest.TestName;
   n['Name'] := ATest.TestSuiteName + '.' + ATest.TestName;
-  FListing.AppendChild(n);
+  FLastTestSuite.AppendChild(n);
   FStartCrono := Now;
   FStartCrono := Now;
 end;
 end;
 
 
@@ -239,6 +242,16 @@ procedure TXMLResultsWriter.EndTest(ATest: TTest);
 var
 var
   n: TDOMNode;
   n: TDOMNode;
   lNew: TDOMElement;
   lNew: TDOMElement;
+begin
+  n := FLastTestSuite.LastChild;
+  lNew := FDoc.CreateElement('ElapsedTime');
+  lNew.AppendChild(FDoc.CreateTextNode(FormatDateTime('hh:nn:ss.zzz', Now - FStartCrono)));
+  n.AppendChild(lNew);
+end;
+
+procedure TXMLResultsWriter.StartTestSuite(ATestSuite: TTestSuite);
+var
+  n: TDOMElement;
 begin
 begin
   { Try and find the Listings node first }
   { Try and find the Listings node first }
   if not Assigned(FListing) then
   if not Assigned(FListing) then
@@ -250,10 +263,19 @@ begin
     FResults.AppendChild(FListing);
     FResults.AppendChild(FListing);
   end;
   end;
 
 
-  n := FListing.LastChild;
-  lNew := FDoc.CreateElement('ElapsedTime');
-  lNew.AppendChild(FDoc.CreateTextNode(FormatDateTime('hh:nn:ss.zzz', Now - FStartCrono)));
-  n.AppendChild(lNew);
+  { The first TestSuite always seem to be blank/empty }
+  if ATestSuite.TestName <> '' then
+  begin
+    n := FDoc.CreateElement('TestSuite');
+    n['Name'] := ATestSuite.TestName;
+    FListing.AppendChild(n);
+    FLastTestSuite := n;
+  end;
+end;
+
+procedure TXMLResultsWriter.EndTestSuite(ATestSuite: TTestSuite);
+begin
+  // do nothing
 end;
 end;