Преглед изворни кода

added a simple optional utility to convert FP Testsuite results to JUnit.XML format

git-svn-id: trunk@25915 -
Károly Balogh пре 11 година
родитељ
комит
eb8858933d
2 измењених фајлова са 198 додато и 0 уклоњено
  1. 1 0
      .gitattributes
  2. 197 0
      tests/utils/fpts2junit.pp

+ 1 - 0
.gitattributes

@@ -12263,6 +12263,7 @@ tests/utils/dosbox/exitcode.pas svneol=native#text/plain
 tests/utils/dotest.pp svneol=native#text/plain
 tests/utils/fail.pp svneol=native#text/plain
 tests/utils/fptime.pp svneol=native#text/plain
+tests/utils/fpts2junit.pp svneol=native#text/plain
 tests/utils/gparmake.pp svneol=native#text/plain
 tests/utils/libtar.pas svneol=native#text/plain
 tests/utils/macos/LinkRunDir -text

+ 197 - 0
tests/utils/fpts2junit.pp

@@ -0,0 +1,197 @@
+{
+    This file is part of the Free Pascal test suite.
+    Copyright (c) 2013 by Karoly Balogh <[email protected]>
+    Copyright (c) 2013 by Viprinet Europe GmbH
+
+    This program can convert Free Pascal Testsute results to JUnit
+    results to be used (for example) with Jenkins CI suite.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{$MODE DELPHI}
+{$I+}
+program fpts2junit;
+
+uses
+  classes, sysutils, strutils,
+  DOM, XMLWrite;
+
+const
+  LOG_SHORT = 'log';
+  LOG_LONG  = 'longlog';
+
+  DEFAULT_JUNIT_XML = 'fpc_testsuite.xml';
+
+  PATTERN_SUCCESS = 'Success';
+  PATTERN_FAILED  = 'Fail';
+  PATTERN_SKIPPED = 'Skip';
+
+  IE_FUBAR = 'internalerror generated';
+
+function getIndexInList(l: TStringList; className: String; caseName: String): LongInt;
+var
+  line: String;
+  filename: String;
+begin
+  result:=-1;
+  filename:=className+'/'+caseName;
+  for line in l do
+    if (Pos(filename, line) > 0) then
+      begin
+        result:=l.IndexOf(line);
+        break;
+      end;
+end;
+
+procedure convertLogFiles(testOutputPath: String; junitXMLName: String);
+var
+  logShort: TStringList;
+  logLong: TStringList;
+
+  junitXML: TXMLDocument;
+
+  rootNode: TDOMNode;
+  caseNode: TDOMNode;
+  tmpNode: TDOMNode;
+
+  failed: LongInt;
+  error: LongInt;
+  skipped: LongInt;
+  success: LongInt;
+  tmpLine: String;
+
+  startIdx: LongInt;
+  tmpString: String;
+  className: String;
+  caseName: String;
+begin
+  logShort:=TStringList.Create;
+  logLong:=TStringList.Create;
+
+  // sanity check arguments
+  testOutputPath:=IncludeTrailingPathDelimiter(ExpandFileName(testOutputPath));
+  if not DirectoryExists(testOutputPath) then
+    begin
+      writeln('Path: ',testOutputPath,' is not valid.');
+      halt(1);
+    end;
+
+  if not AnsiEndsText('.xml', junitXMLName) then
+    junitXMLName:=DEFAULT_JUNIT_XML;
+
+  // read *ALL* the logs! (ok, some of them)
+  writeln('Reading logs from directory: ',testOutputPath);
+  logShort.LoadFromFile(testOutputPath+LOG_SHORT);
+  logLong.LoadFromFile(testOutputPath+LOG_LONG);
+
+  junitXML:=TXMLDocument.Create;
+
+  // convert
+  failed:=0;
+  error:=0;
+  skipped:=0;
+  success:=0;
+
+  rootNode:=junitXML.CreateElement('testsuite');
+  junitXML.AppendChild(rootNode);
+
+  for tmpLine in logShort do
+    begin
+      // this is pretty fubar in the logfile, to break the format
+      // lets fix it up...
+      if AnsiEndsText(IE_FUBAR, tmpLine) then
+        begin
+          tmpLine:=AnsiReplaceText(tmpLine, IE_FUBAR, '');
+        end;
+
+      // extract useful stuff
+      tmpString:=ExtractWord(WordCount(tmpLine,[' '])-2,tmpLine,[' ']);
+      className:=AnsiLeftStr(tmpString,RPos(DirectorySeparator,tmpString)-1);
+      caseName:=ExtractWord(WordCount(tmpString,[DirectorySeparator]),tmpString,[DirectorySeparator]);
+
+      // create testcase node
+      caseNode:=junitXML.CreateElement('testcase');
+      TDOMElement(caseNode).SetAttribute('classname',className);
+      TDOMElement(caseNode).SetAttribute('name',caseName);
+      rootNode.AppendChild(caseNode);
+
+      if AnsiStartsText(PATTERN_FAILED, tmpLine) then
+        begin
+          tmpString:=TrimSet(AnsiLeftStr(tmpLine, AnsiPos(className, tmpLine)-1),[' ']);
+
+          // handle compiler errors as errors, otherwise failures
+          if AnsiPos('compile',tmpString) <> 0 then
+            begin
+              Inc(error);
+              tmpNode:=junitXML.CreateElement('error');
+            end
+          else
+            begin
+              Inc(failed);
+              tmpNode:=junitXML.CreateElement('failure');
+            end;
+
+          TDOMElement(tmpNode).SetAttribute('message',tmpString);
+          startIdx:=getIndexInList(logLong, className, caseName);
+          tmpString:='';
+          while startIdx > 0 do
+            begin
+              tmpString:=tmpString + #10 + logLong[startIdx];
+              Inc(startIdx);
+              if (startIdx >= logLong.Count) or
+                 AnsiStartsText('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', logLong[startIdx]) then break;
+            end;
+          if tmpString <> '' then
+            tmpNode.AppendChild(junitXML.CreateTextNode(tmpString+#10));
+          caseNode.AppendChild(tmpNode);
+          continue;
+        end;
+      if AnsiStartsText(PATTERN_SKIPPED, tmpLine) then 
+        begin
+          Inc(skipped);
+          caseNode.AppendChild(junitXML.CreateElement('skipped'));
+          continue; 
+        end;
+      if AnsiStartsText(PATTERN_SUCCESS, tmpLine) then 
+        begin
+          Inc(success); 
+          continue;
+        end;
+      writeln('Unparseable line: [',tmpLine,']');
+      Halt(1);
+    end;
+
+  // set required elements in the root node
+  TDOMElement(rootNode).SetAttribute('errors',IntToStr(error));
+  TDOMElement(rootNode).SetAttribute('failures',IntToStr(failed));
+  TDOMElement(rootNode).SetAttribute('tests',IntToStr(logShort.Count));
+  TDOMElement(rootNode).SetAttribute('name','Compiler.Testsuite');
+  TDOMElement(rootNode).SetAttribute('package','FPC');
+
+  writeln('Writing results to file: ',junitXMLName);
+  writeXMLFile(junitXML, junitXMLName);
+end;
+
+procedure printusage;
+begin
+  writeln('Usage:');
+  writeln('  ',ExtractFileName(ParamStr(0)),' <path_to_test_output_dir> [output.xml]');
+  writeln('    * if no output filename is specified, "',DEFAULT_JUNIT_XML,'" will be used.');
+  writeln('    * if specified, output filename must end with ".xml", otherwise default ');
+  writeln('      name will be used.');
+  halt(1);
+end;
+
+begin
+  if (ParamCount < 1) or (ParamCount > 2) then
+    printusage;
+
+  convertLogFiles(ParamStr(1),ParamStr(2));
+end.