diff options
author | Brad King <brad.king@kitware.com> | 2013-10-08 13:53:25 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2013-10-08 13:53:25 (GMT) |
commit | 2ba45f52857dc0a98edb4e392b27276ea927e92c (patch) | |
tree | c9fd8c01cf93a3a72ea474429b601c630bb8f455 | |
parent | 5bf71025056465ebacf49b9da6446b8ed7833a95 (diff) | |
parent | d0ec3a01a61f259768d31fc20791780807e1788e (diff) | |
download | CMake-2ba45f52857dc0a98edb4e392b27276ea927e92c.zip CMake-2ba45f52857dc0a98edb4e392b27276ea927e92c.tar.gz CMake-2ba45f52857dc0a98edb4e392b27276ea927e92c.tar.bz2 |
Merge topic 'Add-coverage.py-Coverage'
d0ec3a0 Adding support for the Python coverage.py tool.
-rw-r--r-- | Source/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Source/CTest/cmCTestCoverageHandler.cxx | 34 | ||||
-rw-r--r-- | Source/CTest/cmCTestCoverageHandler.h | 4 | ||||
-rw-r--r-- | Source/CTest/cmParsePythonCoverage.cxx | 113 | ||||
-rw-r--r-- | Source/CTest/cmParsePythonCoverage.h | 48 | ||||
-rw-r--r-- | Tests/CMakeLists.txt | 19 | ||||
-rw-r--r-- | Tests/PythonCoverage/DartConfiguration.tcl.in | 8 | ||||
-rw-r--r-- | Tests/PythonCoverage/coverage.xml.in | 35 | ||||
-rw-r--r-- | Tests/PythonCoverage/coveragetest/foo.py | 8 | ||||
-rw-r--r-- | Tests/PythonCoverage/coveragetest/test_foo.py | 11 |
10 files changed, 281 insertions, 0 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 4144bea..9b81e8b 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -439,6 +439,7 @@ set(CTEST_SRCS cmCTest.cxx CTest/cmParseCacheCoverage.cxx CTest/cmParseGTMCoverage.cxx CTest/cmParsePHPCoverage.cxx + CTest/cmParsePythonCoverage.cxx CTest/cmCTestEmptyBinaryDirectoryCommand.cxx CTest/cmCTestGenericHandler.cxx CTest/cmCTestHandlerCommand.cxx diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 20aded2..ef071b9 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -11,6 +11,7 @@ ============================================================================*/ #include "cmCTestCoverageHandler.h" #include "cmParsePHPCoverage.h" +#include "cmParsePythonCoverage.h" #include "cmParseGTMCoverage.h" #include "cmParseCacheCoverage.h" #include "cmCTest.h" @@ -392,6 +393,13 @@ int cmCTestCoverageHandler::ProcessHandler() { return error; } + file_count += this->HandlePythonCoverage(&cont); + error = cont.Error; + if ( file_count < 0 ) + { + return error; + } + file_count += this->HandleMumpsCoverage(&cont); error = cont.Error; if ( file_count < 0 ) @@ -761,6 +769,32 @@ int cmCTestCoverageHandler::HandlePHPCoverage( } return static_cast<int>(cont->TotalCoverage.size()); } + +//---------------------------------------------------------------------- +int cmCTestCoverageHandler::HandlePythonCoverage( + cmCTestCoverageHandlerContainer* cont) +{ + cmParsePythonCoverage cov(*cont, this->CTest); + + // Assume the coverage.xml is in the source directory + std::string coverageXMLFile = this->CTest->GetBinaryDir() + "/coverage.xml"; + + if(cmSystemTools::FileExists(coverageXMLFile.c_str())) + { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Parsing coverage.py XML file: " << coverageXMLFile + << std::endl); + cov.ReadCoverageXML(coverageXMLFile.c_str()); + } + else + { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Cannot find coverage.py XML file: " << coverageXMLFile + << std::endl); + } + return static_cast<int>(cont->TotalCoverage.size()); +} + //---------------------------------------------------------------------- int cmCTestCoverageHandler::HandleMumpsCoverage( cmCTestCoverageHandlerContainer* cont) diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h index 92b0b22..3506928 100644 --- a/Source/CTest/cmCTestCoverageHandler.h +++ b/Source/CTest/cmCTestCoverageHandler.h @@ -70,6 +70,10 @@ private: //! Handle coverage using xdebug php coverage int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont); + + //! Handle coverage for Python with coverage.py + int HandlePythonCoverage(cmCTestCoverageHandlerContainer* cont); + //! Handle coverage for mumps int HandleMumpsCoverage(cmCTestCoverageHandlerContainer* cont); diff --git a/Source/CTest/cmParsePythonCoverage.cxx b/Source/CTest/cmParsePythonCoverage.cxx new file mode 100644 index 0000000..a086f13 --- /dev/null +++ b/Source/CTest/cmParsePythonCoverage.cxx @@ -0,0 +1,113 @@ +#include "cmStandardIncludes.h" +#include "cmSystemTools.h" +#include "cmXMLParser.h" +#include "cmParsePythonCoverage.h" +#include <cmsys/Directory.hxx> + + +//---------------------------------------------------------------------------- +class cmParsePythonCoverage::XMLParser: public cmXMLParser +{ +public: + XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont) + : CTest(ctest), Coverage(cont) + { + } + + virtual ~XMLParser() + { + } + +protected: + + virtual void StartElement(const char* name, const char** atts) + { + if(strcmp(name, "class") == 0) + { + int tagCount = 0; + while(true) + { + if(strcmp(atts[tagCount], "filename") == 0) + { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Reading file: " + << atts[tagCount+1] << std::endl); + this->CurFileName = this->Coverage.SourceDir + "/" + + atts[tagCount+1]; + FileLinesType& curFileLines = + this->Coverage.TotalCoverage[this->CurFileName]; + std::ifstream fin(this->CurFileName.c_str()); + if(!fin) + { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Python Coverage: Error opening " << this->CurFileName + << std::endl); + this->Coverage.Error++; + break; + } + + std::string line; + curFileLines.push_back(-1); + while(cmSystemTools::GetLineFromStream(fin, line)) + { + curFileLines.push_back(-1); + } + + break; + } + ++tagCount; + } + } + else if(strcmp(name, "line") == 0) + { + int tagCount = 0; + int curNumber = -1; + int curHits = -1; + while(true) + { + if(strcmp(atts[tagCount], "hits") == 0) + { + curHits = atoi(atts[tagCount+1]); + } + else if(strcmp(atts[tagCount], "number") == 0) + { + curNumber = atoi(atts[tagCount+1]); + } + + if(curHits > -1 && curNumber > -1) + { + FileLinesType& curFileLines = + this->Coverage.TotalCoverage[this->CurFileName]; + curFileLines[curNumber] = curHits; + break; + } + ++tagCount; + } + } + } + + virtual void EndElement(const char*) {} + +private: + + typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector + FileLinesType; + cmCTest* CTest; + cmCTestCoverageHandlerContainer& Coverage; + std::string CurFileName; + +}; + + +cmParsePythonCoverage::cmParsePythonCoverage( + cmCTestCoverageHandlerContainer& cont, + cmCTest* ctest) + :Coverage(cont), CTest(ctest) +{ +} + +bool cmParsePythonCoverage::ReadCoverageXML(const char* xmlFile) +{ + cmParsePythonCoverage::XMLParser parser(this->CTest, this->Coverage); + parser.ParseFile(xmlFile); + return true; +} diff --git a/Source/CTest/cmParsePythonCoverage.h b/Source/CTest/cmParsePythonCoverage.h new file mode 100644 index 0000000..668c7f9 --- /dev/null +++ b/Source/CTest/cmParsePythonCoverage.h @@ -0,0 +1,48 @@ +/*============================================================================ + 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 cmParsePythonCoverage_h +#define cmParsePythonCoverage_h + +#include "cmStandardIncludes.h" +#include "cmCTestCoverageHandler.h" + +/** \class cmParsePythonCoverage + * \brief Parse coverage.py Python coverage information + * + * This class is used to parse the output of the coverage.py tool that + * is currently maintained by Ned Batchelder. That tool has a command + * that produces xml output in the format typically output by the common + * Java-based Cobertura coverage application. This helper class parses + * that XML file to fill the coverage-handler container. + */ +class cmParsePythonCoverage +{ +public: + + //! Create the coverage parser by passing in the coverage handler + //! container and the cmCTest object + cmParsePythonCoverage(cmCTestCoverageHandlerContainer& cont, + cmCTest* ctest); + + //! Read the XML produced by running `coverage xml` + bool ReadCoverageXML(const char* xmlFile); + +private: + + class XMLParser; + cmCTestCoverageHandlerContainer& Coverage; + cmCTest* CTest; + std::string CurFileName; +}; + +#endif diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 2d35b5a..504f4bb 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1960,6 +1960,25 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ PASS_REGULAR_EXPRESSION "Process file.*XINDEX.m.*Total LOC:.*125.*Percentage Coverage: 85.60.*" ENVIRONMENT COVFILE=) + + # Adding a test case for Python Coverage + configure_file( + "${CMake_SOURCE_DIR}/Tests/PythonCoverage/coverage.xml.in" + "${CMake_BINARY_DIR}/Testing/PythonCoverage/coverage.xml") + configure_file( + "${CMake_SOURCE_DIR}/Tests/PythonCoverage/DartConfiguration.tcl.in" + "${CMake_BINARY_DIR}/Testing/PythonCoverage/DartConfiguration.tcl") + file(COPY "${CMake_SOURCE_DIR}/Tests/PythonCoverage/coveragetest" + DESTINATION "${CMake_BINARY_DIR}/Testing/PythonCoverage") + add_test(NAME CTestPythonCoverage + COMMAND cmake -E chdir + ${CMake_BINARY_DIR}/Testing/PythonCoverage + $<TARGET_FILE:ctest> -T Coverage --debug) + set_tests_properties(CTestPythonCoverage PROPERTIES + PASS_REGULAR_EXPRESSION + "Process file.*foo.py.*Total LOC:.*13.*Percentage Coverage: 84.62.*" + ENVIRONMENT COVFILE=) + # Use macro, not function so that build can still be driven by CMake 2.4. # After 2.6 is required, this could be a function without the extra 'set' # calls. diff --git a/Tests/PythonCoverage/DartConfiguration.tcl.in b/Tests/PythonCoverage/DartConfiguration.tcl.in new file mode 100644 index 0000000..e29cffe --- /dev/null +++ b/Tests/PythonCoverage/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/PythonCoverage/coveragetest +BuildDirectory: ${CMake_BINARY_DIR}/Testing/PythonCoverage diff --git a/Tests/PythonCoverage/coverage.xml.in b/Tests/PythonCoverage/coverage.xml.in new file mode 100644 index 0000000..fcc1b1c --- /dev/null +++ b/Tests/PythonCoverage/coverage.xml.in @@ -0,0 +1,35 @@ +<?xml version="1.0" ?> +<!DOCTYPE coverage + SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'> +<coverage branch-rate="0" line-rate="0.8462" timestamp="1380469411433" version="3.6"> + <!-- Generated by coverage.py: http://nedbatchelder.com/code/coverage --> + <packages> + <package branch-rate="0" complexity="0" line-rate="0.8462" name=""> + <classes> + <class branch-rate="0" complexity="0" filename="foo.py" line-rate="0.6667" name="foo"> + <methods/> + <lines> + <line hits="1" number="2"/> + <line hits="1" number="3"/> + <line hits="1" number="4"/> + <line hits="1" number="6"/> + <line hits="0" number="7"/> + <line hits="0" number="8"/> + </lines> + </class> + <class branch-rate="0" complexity="0" filename="test_foo.py" line-rate="1" name="test_foo"> + <methods/> + <lines> + <line hits="1" number="2"/> + <line hits="1" number="3"/> + <line hits="1" number="5"/> + <line hits="1" number="7"/> + <line hits="1" number="8"/> + <line hits="1" number="10"/> + <line hits="1" number="11"/> + </lines> + </class> + </classes> + </package> + </packages> +</coverage> diff --git a/Tests/PythonCoverage/coveragetest/foo.py b/Tests/PythonCoverage/coveragetest/foo.py new file mode 100644 index 0000000..97b5a41 --- /dev/null +++ b/Tests/PythonCoverage/coveragetest/foo.py @@ -0,0 +1,8 @@ + +def foo(): + x = 3 + 3 + return x + +def bar(): + y = 2 + 2 + return y diff --git a/Tests/PythonCoverage/coveragetest/test_foo.py b/Tests/PythonCoverage/coveragetest/test_foo.py new file mode 100644 index 0000000..51a69d8 --- /dev/null +++ b/Tests/PythonCoverage/coveragetest/test_foo.py @@ -0,0 +1,11 @@ + +import foo +import unittest + +class TestFoo(unittest.TestCase): + + def testFoo(self): + self.assertEquals(foo.foo(), 6, 'foo() == 6') + +if __name__ == '__main__': + unittest.main() |