From 5c31c3e4eb36cccaaf72d0f0582beed98f6665e0 Mon Sep 17 00:00:00 2001
From: Joseph Snyder <joe.snyder@kitware.com>
Date: Mon, 29 Sep 2014 14:52:10 -0400
Subject: CTest: Add code coverage parser for Pascal/Delphi

Add a class to parse the HTML output of the Delphi-code-coverage tool

 http://code.google.com/p/delphi-code-coverage/

Add a test for the new parser.
---
 Source/CMakeLists.txt                              |   1 +
 Source/CTest/cmCTestCoverageHandler.cxx            |  36 +++
 Source/CTest/cmCTestCoverageHandler.h              |   3 +
 Source/CTest/cmParseDelphiCoverage.cxx             | 253 +++++++++++++++++++++
 Source/CTest/cmParseDelphiCoverage.h               |  46 ++++
 Tests/CMakeLists.txt                               |  17 ++
 Tests/DelphiCoverage/DartConfiguration.tcl.in      |   8 +
 Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html | 117 ++++++++++
 Tests/DelphiCoverage/src/UTCovTest.pas             |  75 ++++++
 9 files changed, 556 insertions(+)
 create mode 100644 Source/CTest/cmParseDelphiCoverage.cxx
 create mode 100644 Source/CTest/cmParseDelphiCoverage.h
 create mode 100644 Tests/DelphiCoverage/DartConfiguration.tcl.in
 create mode 100644 Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html
 create mode 100644 Tests/DelphiCoverage/src/UTCovTest.pas

diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index c3f77f4..1472264 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -524,6 +524,7 @@ set(CTEST_SRCS cmCTest.cxx
   CTest/cmParseJacocoCoverage.cxx
   CTest/cmParsePHPCoverage.cxx
   CTest/cmParseCoberturaCoverage.cxx
+  CTest/cmParseDelphiCoverage.cxx
   CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
   CTest/cmCTestGenericHandler.cxx
   CTest/cmCTestHandlerCommand.cxx
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 76f6584..d921705 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -15,6 +15,7 @@
 #include "cmParseGTMCoverage.h"
 #include "cmParseCacheCoverage.h"
 #include "cmParseJacocoCoverage.h"
+#include "cmParseDelphiCoverage.h"
 #include "cmCTest.h"
 #include "cmake.h"
 #include "cmMakefile.h"
@@ -423,6 +424,12 @@ int cmCTestCoverageHandler::ProcessHandler()
     return error;
     }
 
+    file_count += this->HandleDelphiCoverage(&cont);
+  error = cont.Error;
+  if ( file_count < 0 )
+    {
+    return error;
+    }
   std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
 
   if ( file_count == 0 )
@@ -910,7 +917,36 @@ int cmCTestCoverageHandler::HandleJacocoCoverage(
   return static_cast<int>(cont->TotalCoverage.size());
 }
 
+//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandleDelphiCoverage(
+  cmCTestCoverageHandlerContainer* cont)
+{
+  cmParseDelphiCoverage cov =
+   cmParseDelphiCoverage(*cont, this->CTest);
+  cmsys::Glob g;
+  std::vector<std::string> files;
+  g.SetRecurse(true);
+
+  std::string BinDir
+    = this->CTest->GetBinaryDir();
+  std::string coverageFile = BinDir+ "/*.html";
 
+  g.FindFiles(coverageFile);
+  files=g.GetFiles();
+  if (files.size() > 0)
+    {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+      "Found Delphi HTML Files, Performing Coverage" << std::endl);
+    cov.LoadCoverageData(files);
+    }
+  else
+    {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+      " Cannot find Delphi coverage files: " << coverageFile
+      << std::endl);
+    }
+  return static_cast<int>(cont->TotalCoverage.size());
+}
 //----------------------------------------------------------------------
 int cmCTestCoverageHandler::HandleGCovCoverage(
   cmCTestCoverageHandlerContainer* cont)
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
index d0f274c..01c5d7f 100644
--- a/Source/CTest/cmCTestCoverageHandler.h
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -84,6 +84,9 @@ private:
   //! Handle coverage for Jacoco
   int HandleJacocoCoverage(cmCTestCoverageHandlerContainer* cont);
 
+  //! Handle coverage for Delphi (Pascal)
+  int HandleDelphiCoverage(cmCTestCoverageHandlerContainer* cont);
+
 //! Handle coverage using Bullseye
   int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
   int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx
new file mode 100644
index 0000000..ad71c85
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.cxx
@@ -0,0 +1,253 @@
+#include "cmStandardIncludes.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmParseDelphiCoverage.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/FStream.hxx>
+
+
+class cmParseDelphiCoverage::HTMLParser
+{
+public:
+  typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+  FileLinesType;
+  HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+     : CTest(ctest), Coverage(cont)
+    {
+    }
+
+  virtual ~HTMLParser()
+    {
+    }
+
+  bool initializeDelphiFile(const std::string filename,
+     cmParseDelphiCoverage::HTMLParser::FileLinesType &coverageVector)
+    {
+    std::string line;
+    size_t comPos;
+    size_t semiPos;
+    bool blockComFlag= false;
+    bool lineComFlag= false;
+    std::vector<std::string> beginSet;
+    cmsys::ifstream in(filename.c_str());
+    if(!in)
+      {
+      return false;
+      }
+    while(cmSystemTools::GetLineFromStream(in, line))
+      {
+      lineComFlag=false;
+      // Unique cases found in lines.
+      size_t beginPos = line.find("begin");
+
+      //Check that the begin is the first non-space string on the line
+      if( (beginPos == line.find_first_not_of(' ')) && beginPos != line.npos )
+        {
+        beginSet.push_back("begin");
+        coverageVector.push_back(-1);
+        continue;
+        }
+      else if(line.find('{') != line.npos)
+        {
+        blockComFlag=true;
+        }
+      else if(line.find('}') != line.npos)
+        {
+        blockComFlag=false;
+        coverageVector.push_back(-1);
+        continue;
+        }
+      else if((line.find("end;") != line.npos)
+         && (beginSet.size() > 0))
+        {
+        beginSet.pop_back();
+        coverageVector.push_back(-1);
+        continue;
+        }
+
+      //  This checks for comments after lines of code, finding the
+      //  comment symbol after the ending semicolon.
+      comPos = line.find("//");
+      if(comPos != line.npos)
+        {
+        semiPos= line.find(';');
+        if(comPos < semiPos)
+          {
+          lineComFlag=true;
+          }
+        }
+      //Based up what was found, add a line to the coverageVector
+      if((beginSet.size() > 0) && line != ""  && !blockComFlag
+         && !lineComFlag)
+        {
+        coverageVector.push_back(0);
+        }
+      else
+        {
+        coverageVector.push_back(-1);
+        }
+      }
+      return true;
+    }
+  bool ParseFile(const char* file)
+    {
+    std::string line=file;
+    std::string lineresult;
+    std::string lastroutine;
+    std::string filename;
+    std::string filelineoffset;
+    size_t afterLineNum = 0;
+    size_t lastoffset = 0;
+    size_t endcovpos = 0;
+    size_t endnamepos = 0;
+    size_t pos = 0;
+
+    /*
+    *  This first 'while' section goes through the found HTML
+    *  file name and attempts to capture the source file name
+    *   which is set as part of the HTML file name: the name of
+    *   the file is found in parenthesis '()'
+    *
+    *   See test HTML file name: UTCovTest(UTCovTest.pas).html.
+    *
+    *   Find the text inside each pair of parenthesis and check
+    *   to see if it ends in '.pas'.  If it can't be found,
+    *   exit the function.
+    */
+    while(true)
+      {
+      lastoffset = line.find('(',pos);
+      if(lastoffset==line.npos)
+        {
+        cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
+           endnamepos << "File not found  " << lastoffset  << std::endl);
+        return false;
+        }
+      endnamepos = line.find(')',lastoffset);
+      filename = line.substr(lastoffset+1,
+         (endnamepos-1)-lastoffset);
+      if(filename.find(".pas") != filename.npos)
+        {
+        cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
+           "Coverage found for file:  " << filename  << std::endl);
+        break;
+        }
+      pos = lastoffset+1;
+      endnamepos = 0;
+      lastoffset =0;
+      }
+    /*
+    *  Glob through the source directory for the
+    *  file found above
+    */
+    cmsys::Glob gl;
+    gl.RecurseOn();
+    gl.RecurseThroughSymlinksOff();
+    std::string glob = Coverage.SourceDir + "*/" + filename;
+    gl.FindFiles(glob);
+    std::vector<std::string> const& files = gl.GetFiles();
+    if(files.size() == 0)
+      {
+      /*
+      *  If that doesn't find any matching files
+      *  return a failure.
+      */
+      cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
+         "Unable to find file matching" << glob << std::endl);
+      return false;
+      }
+    FileLinesType&  coverageVector =
+       this->Coverage.TotalCoverage[files[0]];
+
+    /*
+    *  Initialize the file to have all code between 'begin' and
+    *  'end' tags marked as executable
+    */
+
+    this->initializeDelphiFile(files[0],coverageVector);
+
+    cmsys::ifstream in(file);
+    if(!in)
+      {
+      return false;
+      }
+
+    /*
+    *  Now read the HTML file, looking for the lines that have an
+    *  "inline" in it. Then parse out the "class" value of that
+    *  line to determine if the line is executed or not.
+    *
+    *  Sample HTML line:
+    *
+    *  <tr class="covered"><td>47</td><td><pre style="display:inline;">
+    *    &nbsp;CheckEquals(1,2-1);</pre></td></tr>
+    *
+    */
+
+    while(  cmSystemTools::GetLineFromStream(in, line))
+      {
+      if(line.find("inline") == line.npos)
+        {
+        continue;
+        }
+
+      lastoffset = line.find("class=");
+      endcovpos = line.find(">",lastoffset);
+      lineresult = line.substr(lastoffset+7,(endcovpos-8)-lastoffset);
+
+      if(lineresult == "covered")
+        {
+        afterLineNum = line.find('<',endcovpos+5);
+        filelineoffset= line.substr(endcovpos+5,
+        afterLineNum-(endcovpos+5));
+        coverageVector[atoi(filelineoffset.c_str())-1] = 1;
+        }
+      }
+      return true;
+    }
+
+
+  private:
+    cmCTest* CTest;
+    cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseDelphiCoverage::cmParseDelphiCoverage(
+   cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
+   :Coverage(cont), CTest(ctest)
+  {
+  }
+
+bool cmParseDelphiCoverage::LoadCoverageData(
+  const std::vector<std::string> files)
+  {
+  size_t i;
+  std::string path;
+  size_t numf = files.size();
+  for (i = 0; i < numf; i++)
+    {
+    path = files[i];
+
+    cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
+       "Reading HTML File " << path  << std::endl);
+    if(cmSystemTools::GetFilenameLastExtension(path) == ".html")
+      {
+      if(!this->ReadDelphiHTML(path.c_str()))
+        {
+        return false;
+        }
+      }
+    }
+  return true;
+  };
+
+bool cmParseDelphiCoverage::ReadDelphiHTML(const char* file)
+  {
+  cmParseDelphiCoverage::HTMLParser
+     parser(this->CTest, this->Coverage);
+  parser.ParseFile(file);
+  return true;
+  };
diff --git a/Source/CTest/cmParseDelphiCoverage.h b/Source/CTest/cmParseDelphiCoverage.h
new file mode 100644
index 0000000..018340b
--- /dev/null
+++ b/Source/CTest/cmParseDelphiCoverage.h
@@ -0,0 +1,46 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc.
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+
+#ifndef cmParseDelphiCoverage_h
+#define cmParseDelphiCoverage_h
+
+#include "cmStandardIncludes.h"
+#include "cmCTestCoverageHandler.h"
+
+
+/** \class cmParseDelphiCoverage
+ * \brief Parse Delphi coverage information
+ *
+ * This class is used to parse Delphi(Pascal) coverage information
+ * generated by the Delphi-Code-Coverage tool
+ *
+ * https://code.google.com/p/delphi-code-coverage/
+ */
+
+class cmParseDelphiCoverage
+  {
+  public:
+    cmParseDelphiCoverage(cmCTestCoverageHandlerContainer& cont,
+        cmCTest* ctest);
+    bool LoadCoverageData(const std::vector<std::string> files);
+    bool ReadDelphiHTML(const char* file);
+    // Read a single HTML file from output
+    bool ReadHTMLFile(const char* f);
+
+
+  protected:
+
+    class HTMLParser;
+    cmCTestCoverageHandlerContainer& Coverage;
+    cmCTest* CTest;
+  };
+#endif
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 0b4aef7..ab56130 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -2310,6 +2310,23 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
       "Process file.*CoverageTest.java.*Total LOC:.*17.*Percentage Coverage: 76.47*"
       ENVIRONMENT COVFILE=)
 
+  # test coverage for Delphi-code-Coverage
+  configure_file(
+     "${CMake_SOURCE_DIR}/Tests/DelphiCoverage/DartConfiguration.tcl.in"
+     "${CMake_BINARY_DIR}/Testing/DelphiCoverage/DartConfiguration.tcl")
+  file(COPY "${CMake_SOURCE_DIR}/Tests/DelphiCoverage/src"
+    DESTINATION "${CMake_BINARY_DIR}/Testing/DelphiCoverage")
+  file(COPY "${CMake_SOURCE_DIR}/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html"
+    DESTINATION "${CMake_BINARY_DIR}/Testing/DelphiCoverage")
+  add_test(NAME CTestDelphiCoverage
+    COMMAND cmake -E chdir
+    ${CMake_BINARY_DIR}/Testing/DelphiCoverage
+    $<TARGET_FILE:ctest> -T Coverage --debug)
+  set_tests_properties(CTestDelphiCoverage PROPERTIES
+      PASS_REGULAR_EXPRESSION
+      "Process file.*UTCovTest.pas.*Total LOC:.*20.*Percentage Coverage: 95.*"
+      ENVIRONMENT COVFILE=)
+
   function(add_config_tests cfg)
     set(base "${CMake_BINARY_DIR}/Tests/CTestConfig")
 
diff --git a/Tests/DelphiCoverage/DartConfiguration.tcl.in b/Tests/DelphiCoverage/DartConfiguration.tcl.in
new file mode 100644
index 0000000..4edcea6
--- /dev/null
+++ b/Tests/DelphiCoverage/DartConfiguration.tcl.in
@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_BINARY_DIR}/Testing/DelphiCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/DelphiCoverage
diff --git a/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html b/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html
new file mode 100644
index 0000000..9caaea3
--- /dev/null
+++ b/Tests/DelphiCoverage/UTCovTest(UTCovTest.pas).html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+    <title>Delphi CodeCoverage Coverage Report</title>
+<style type="text/css">
+table {border-spacing:0; border-collapse:collapse;}
+table, td, th {border: 1px solid black;}
+td, th {background: white; margin: 0; padding: 2px 0.5em 2px 0.5em}
+td {border-width: 0 1px 0 0;}
+th {border-width: 1px 1px 1px 0;}
+p, h1, h2, h3, th {font-family: verdana,arial,sans-serif; font-size: 10pt;}
+td {font-family: courier,monospace; font-size: 10pt;}
+th {background: #CCCCCC;}
+table.o tr td:nth-child(1) {font-weight: bold;}
+table.o tr td:nth-child(2) {text-align: right;}
+table.o tr td {border-width: 1px;}
+table.s {width: 100%;}
+table.s tr td {padding: 0 0.25em 0 0.25em;}
+table.s tr td:first-child {text-align: right; font-weight: bold;}
+table.s tr.notcovered td {background: #DDDDFF;}
+table.s tr.nocodegen td {background: #FFFFEE;}
+table.s tr.covered td {background: #CCFFCC;}
+table.s tr.covered td:first-child {color: green;}
+table.s {border-width: 1px 0 1px 1px;}
+table.sum tr td {border-width: 1px;}
+table.sum tr th {text-align:right;}
+table.sum tr th:first-child {text-align:center;}
+table.sum tr td {text-align:right;}
+table.sum tr td:first-child {text-align:left;}
+</style>
+</head>
+<body>
+<p>Coverage report for <strong>UTCovTest (C:\Users\joe.snyder\Work\OSEHRA\VistA\Packages\Order Entry Results Reporting\CPRS\Testing\Tests\UTCovTest.pas)</strong>.</p>
+<p> Generated at 10/3/2014 12:24:11 PM by <a href="http://code.google.com/p/delphi-code-coverage/" title="Code Coverage for Delphi 5+">DelphiCodeCoverage</a> - an open source tool for Delphi Code Coverage.</p>
+<p> Statistics for C:\Users\joe.snyder\Work\OSEHRA\VistA\Packages\Order Entry Results Reporting\CPRS\Testing\Tests\UTCovTest.pas </p>
+<table  class="o"><tr><td>Number of lines covered</td><td>19</td></tr><tr><td>Number of lines with code gen</td><td>19</td></tr><tr><td>Line coverage</td><td>100%</td></tr></table>
+<br /><br />
+<table  class="s">
+<tr class="nocodegen"><td>1</td><td><pre style="display:inline;">//---------------------------------------------------------------------------</pre></td></tr>
+<tr class="nocodegen"><td>2</td><td><pre style="display:inline;">// Copyright 2012 The Open Source Electronic Health Record Agent</pre></td></tr>
+<tr class="nocodegen"><td>3</td><td><pre style="display:inline;">//</pre></td></tr>
+<tr class="nocodegen"><td>4</td><td><pre style="display:inline;">// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</pre></td></tr>
+<tr class="nocodegen"><td>5</td><td><pre style="display:inline;">// you may not use this file except in compliance with the License.</pre></td></tr>
+<tr class="nocodegen"><td>6</td><td><pre style="display:inline;">// You may obtain a copy of the License at</pre></td></tr>
+<tr class="nocodegen"><td>7</td><td><pre style="display:inline;">//</pre></td></tr>
+<tr class="nocodegen"><td>8</td><td><pre style="display:inline;">// &nbsp; &nbsp; http://www.apache.org/licenses/LICENSE-2.0</pre></td></tr>
+<tr class="nocodegen"><td>9</td><td><pre style="display:inline;">//</pre></td></tr>
+<tr class="nocodegen"><td>10</td><td><pre style="display:inline;">// Unless required by applicable law or agreed to in writing, software</pre></td></tr>
+<tr class="nocodegen"><td>11</td><td><pre style="display:inline;">// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</pre></td></tr>
+<tr class="nocodegen"><td>12</td><td><pre style="display:inline;">// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</pre></td></tr>
+<tr class="nocodegen"><td>13</td><td><pre style="display:inline;">// See the License for the specific language governing permissions and</pre></td></tr>
+<tr class="nocodegen"><td>14</td><td><pre style="display:inline;">// limitations under the License.</pre></td></tr>
+<tr class="nocodegen"><td>15</td><td><pre style="display:inline;">//---------------------------------------------------------------------------</pre></td></tr>
+<tr class="nocodegen"><td>16</td><td><pre style="display:inline;">unit UTCovTest;</pre></td></tr>
+<tr class="nocodegen"><td>17</td><td><pre style="display:inline;">interface</pre></td></tr>
+<tr class="nocodegen"><td>18</td><td><pre style="display:inline;">uses UnitTest, TestFrameWork,SysUtils,Windows;</pre></td></tr>
+<tr class="nocodegen"><td>19</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>20</td><td><pre style="display:inline;">implementation</pre></td></tr>
+<tr class="nocodegen"><td>21</td><td><pre style="display:inline;">type</pre></td></tr>
+<tr class="nocodegen"><td>22</td><td><pre style="display:inline;">UTCovTestTests=class(TTestCase)</pre></td></tr>
+<tr class="nocodegen"><td>23</td><td><pre style="display:inline;"> &nbsp;public</pre></td></tr>
+<tr class="nocodegen"><td>24</td><td><pre style="display:inline;"> &nbsp;procedure SetUp; override;</pre></td></tr>
+<tr class="nocodegen"><td>25</td><td><pre style="display:inline;"> &nbsp;procedure TearDown; override;</pre></td></tr>
+<tr class="nocodegen"><td>26</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>27</td><td><pre style="display:inline;"> &nbsp;published</pre></td></tr>
+<tr class="nocodegen"><td>28</td><td><pre style="display:inline;"> &nbsp; &nbsp;procedure TestCov1;</pre></td></tr>
+<tr class="nocodegen"><td>29</td><td><pre style="display:inline;"> &nbsp; &nbsp;procedure TestCov2;</pre></td></tr>
+<tr class="nocodegen"><td>30</td><td><pre style="display:inline;"> &nbsp; &nbsp;procedure TestCov3;</pre></td></tr>
+<tr class="nocodegen"><td>31</td><td><pre style="display:inline;"> &nbsp;end;</pre></td></tr>
+<tr class="nocodegen"><td>32</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>33</td><td><pre style="display:inline;">procedure NotRun;</pre></td></tr>
+<tr class="nocodegen"><td>34</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="nocodegen"><td>35</td><td><pre style="display:inline;"> &nbsp; &nbsp;WriteLn(&apos;This line will never run&apos;);</pre></td></tr>
+<tr class="nocodegen"><td>36</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>37</td><td><pre style="display:inline;">procedure UTCovTestTests.SetUp;</pre></td></tr>
+<tr class="nocodegen"><td>38</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>39</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>40</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>41</td><td><pre style="display:inline;">procedure UTCovTestTests.TearDown;</pre></td></tr>
+<tr class="nocodegen"><td>42</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>43</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>44</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>45</td><td><pre style="display:inline;">procedure UTCovTestTests.TestCov1;</pre></td></tr>
+<tr class="covered"><td>46</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="nocodegen"><td>47</td><td><pre style="display:inline;"> &nbsp;{</pre></td></tr>
+<tr class="nocodegen"><td>48</td><td><pre style="display:inline;"> &nbsp;Block comment lines</pre></td></tr>
+<tr class="nocodegen"><td>49</td><td><pre style="display:inline;"> &nbsp;}</pre></td></tr>
+<tr class="covered"><td>50</td><td><pre style="display:inline;"> &nbsp;CheckEquals(1,2-1);</pre></td></tr>
+<tr class="covered"><td>51</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>52</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>53</td><td><pre style="display:inline;">procedure UTCovTestTests.TestCov2;</pre></td></tr>
+<tr class="nocodegen"><td>54</td><td><pre style="display:inline;">var</pre></td></tr>
+<tr class="nocodegen"><td>55</td><td><pre style="display:inline;"> &nbsp;i:DWORD;</pre></td></tr>
+<tr class="covered"><td>56</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>57</td><td><pre style="display:inline;"> &nbsp;for i := 0 to 1 do</pre></td></tr>
+<tr class="covered"><td>58</td><td><pre style="display:inline;"> &nbsp; &nbsp;WriteLn( IntToStr(i));</pre></td></tr>
+<tr class="nocodegen"><td>59</td><td><pre style="display:inline;"> &nbsp;// Comment</pre></td></tr>
+<tr class="covered"><td>60</td><td><pre style="display:inline;"> &nbsp;CheckEquals(i,2);</pre></td></tr>
+<tr class="covered"><td>61</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>62</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="nocodegen"><td>63</td><td><pre style="display:inline;">procedure UTCovTestTests.TestCov3;</pre></td></tr>
+<tr class="nocodegen"><td>64</td><td><pre style="display:inline;">var</pre></td></tr>
+<tr class="nocodegen"><td>65</td><td><pre style="display:inline;"> i : DWORD;</pre></td></tr>
+<tr class="covered"><td>66</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>67</td><td><pre style="display:inline;"> &nbsp;i := 0;</pre></td></tr>
+<tr class="covered"><td>68</td><td><pre style="display:inline;"> &nbsp;while i &lt; 5 do</pre></td></tr>
+<tr class="covered"><td>69</td><td><pre style="display:inline;"> &nbsp; i := i+1;</pre></td></tr>
+<tr class="covered"><td>70</td><td><pre style="display:inline;"> &nbsp;CheckEquals(i,5);</pre></td></tr>
+<tr class="covered"><td>71</td><td><pre style="display:inline;">end;</pre></td></tr>
+<tr class="nocodegen"><td>72</td><td><pre style="display:inline;"></pre></td></tr>
+<tr class="covered"><td>73</td><td><pre style="display:inline;">begin</pre></td></tr>
+<tr class="covered"><td>74</td><td><pre style="display:inline;"> &nbsp;UnitTest.addSuite(UTCovTestTests.Suite);</pre></td></tr>
+<tr class="covered"><td>75</td><td><pre style="display:inline;">end.</pre></td></tr>
+</table>
+</body>
+</html>
diff --git a/Tests/DelphiCoverage/src/UTCovTest.pas b/Tests/DelphiCoverage/src/UTCovTest.pas
new file mode 100644
index 0000000..66db3c0
--- /dev/null
+++ b/Tests/DelphiCoverage/src/UTCovTest.pas
@@ -0,0 +1,75 @@
+//---------------------------------------------------------------------------
+// Copyright 2012 The Open Source Electronic Health Record Agent
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//---------------------------------------------------------------------------
+unit UTCovTest;
+interface
+uses UnitTest, TestFrameWork,SysUtils,Windows;
+
+implementation
+type
+UTCovTestTests=class(TTestCase)
+  public
+  procedure SetUp; override;
+  procedure TearDown; override;
+
+  published
+    procedure TestCov1;
+    procedure TestCov2;
+    procedure TestCov3;
+  end;
+
+procedure NotRun;
+begin
+    WriteLn('This line will never run');
+end;
+procedure UTCovTestTests.SetUp;
+begin
+end;
+
+procedure UTCovTestTests.TearDown;
+begin
+end;
+
+procedure UTCovTestTests.TestCov1;
+begin
+  {
+  Block comment lines
+  }
+  CheckEquals(1,2-1);
+end;
+
+procedure UTCovTestTests.TestCov2;
+var
+  i:DWORD;
+begin
+  for i := 0 to 1 do
+    WriteLn( IntToStr(i));
+  // Comment
+  CheckEquals(i,2);
+end;
+
+procedure UTCovTestTests.TestCov3;
+var
+ i : DWORD;
+begin
+  i := 0;
+  while i < 5 do
+   i := i+1;
+  CheckEquals(i,5);
+end;
+
+begin
+  UnitTest.addSuite(UTCovTestTests.Suite);
+end.
\ No newline at end of file
-- 
cgit v0.12