Commit 220e8134 authored by Joe Snyder's avatar Joe Snyder Committed by Brad King

CTest: Add Javascript coverage parser

Add a coverage parser for the Blanket.js library using the JSON output of
the mocha.js test runner.

Add a test for the new parser.
parent a2456e15
......@@ -522,6 +522,7 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmParseCacheCoverage.cxx
CTest/cmParseGTMCoverage.cxx
CTest/cmParseJacocoCoverage.cxx
CTest/cmParseBlanketJSCoverage.cxx
CTest/cmParsePHPCoverage.cxx
CTest/cmParseCoberturaCoverage.cxx
CTest/cmParseDelphiCoverage.cxx
......
......@@ -16,6 +16,7 @@
#include "cmParseCacheCoverage.h"
#include "cmParseJacocoCoverage.h"
#include "cmParseDelphiCoverage.h"
#include "cmParseBlanketJSCoverage.h"
#include "cmCTest.h"
#include "cmake.h"
#include "cmMakefile.h"
......@@ -419,6 +420,13 @@ int cmCTestCoverageHandler::ProcessHandler()
file_count += this->HandleJacocoCoverage(&cont);
error = cont.Error;
if ( file_count < 0 )
{
return error;
}
file_count += this->HandleBlanketJSCoverage(&cont);
error = cont.Error;
if ( file_count < 0 )
{
return error;
......@@ -927,10 +935,12 @@ int cmCTestCoverageHandler::HandleDelphiCoverage(
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)
......@@ -947,6 +957,36 @@ int cmCTestCoverageHandler::HandleDelphiCoverage(
}
return static_cast<int>(cont->TotalCoverage.size());
}
//----------------------------------------------------------------------
int cmCTestCoverageHandler::HandleBlanketJSCoverage(
cmCTestCoverageHandlerContainer* cont)
{
cmParseBlanketJSCoverage cov =
cmParseBlanketJSCoverage(*cont, this->CTest);
std::string SourceDir
= this->CTest->GetCTestConfiguration("SourceDirectory");
//Look for something other than output.json, still JSON extension.
std::string coverageFile = SourceDir+ "/*.json";
cmsys::Glob g;
std::vector<std::string> files;
g.FindFiles(coverageFile);
files=g.GetFiles();
if (files.size() > 0)
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Found BlanketJS output JSON, Performing Coverage" << std::endl);
cov.LoadCoverageData(files);
}
else
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" Cannot find BlanketJS coverage files: " << coverageFile
<< std::endl);
}
return static_cast<int>(cont->TotalCoverage.size());
}
//----------------------------------------------------------------------
int cmCTestCoverageHandler::HandleGCovCoverage(
cmCTestCoverageHandlerContainer* cont)
......
......@@ -87,6 +87,9 @@ private:
//! Handle coverage for Delphi (Pascal)
int HandleDelphiCoverage(cmCTestCoverageHandlerContainer* cont);
//! Handle coverage for Jacoco
int HandleBlanketJSCoverage(cmCTestCoverageHandlerContainer* cont);
//! Handle coverage using Bullseye
int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
......
/*============================================================================
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.
============================================================================*/
#include "cmStandardIncludes.h"
#include <stdio.h>
#include <stdlib.h>
#include "cmSystemTools.h"
#include "cmParseBlanketJSCoverage.h"
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
#include <cmsys/FStream.hxx>
class cmParseBlanketJSCoverage::JSONParser
{
public:
typedef cmCTestCoverageHandlerContainer::
SingleFileCoverageVector FileLinesType;
JSONParser(cmCTestCoverageHandlerContainer& cont)
: Coverage(cont)
{
}
virtual ~JSONParser()
{
}
std::string getValue(std::string line, int type)
{
size_t begIndex;
size_t endIndex;
endIndex = line.rfind(',');
begIndex = line.find_first_of(':');
if(type == 0)
{
// A unique substring to remove the extra characters
// around the files name in the JSON (extra " and ,)
std::string foundFileName =
line.substr(begIndex+3,endIndex-(begIndex+4));
return foundFileName;
}
else
{
return line.substr(begIndex,line.npos);
}
}
bool ParseFile(std::string file)
{
FileLinesType localCoverageVector;
std::string filename;
bool foundFile = false;
bool inSource = false;
std::string covResult;
std::string line;
cmsys::ifstream in(file.c_str());
if(!in)
{
return false;
}
while( cmSystemTools::GetLineFromStream(in, line))
{
if(line.find("filename") != line.npos)
{
if(foundFile)
{
/*
* Upon finding a second file name, generate a
* vector within the total coverage to capture the
* information in the local vector
*/
FileLinesType& CoverageVector =
this->Coverage.TotalCoverage[filename.c_str()];
CoverageVector = localCoverageVector;
localCoverageVector.clear();
foundFile=false;
}
foundFile= true;
inSource = false;
filename = getValue(line,0).c_str();
}
else if((line.find("coverage") != line.npos) && foundFile && inSource )
{
/*
* two types of "coverage" in the JSON structure
*
* The coverage result over the file or set of files
* and the coverage for each individual line
*
* FoundFile and foundSource ensure that
* only the value of the line coverage is captured
*/
std::string result = getValue(line,1).c_str();
result = result.substr(2,result.npos);
if(result == "\"\"")
{
// Empty quotation marks indicate that the
// line is not executable
localCoverageVector.push_back(-1);
}
else
{
// Else, it contains the number of time executed
localCoverageVector.push_back(atoi(result.c_str()));
}
}
else if(line.find("source") != line.npos)
{
inSource=true;
}
}
// On exit, capture end of last file covered.
FileLinesType& CoverageVector =
this->Coverage.TotalCoverage[filename.c_str()];
CoverageVector = localCoverageVector;
foundFile=false;
localCoverageVector.clear();
return true;
}
private:
cmCTestCoverageHandlerContainer& Coverage;
};
cmParseBlanketJSCoverage::cmParseBlanketJSCoverage(
cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
:Coverage(cont), CTest(ctest)
{
}
bool cmParseBlanketJSCoverage::LoadCoverageData(std::vector<std::string> files)
{
size_t i=0;
std::string path;
cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
"Found " << files.size() <<" Files" << std::endl);
for(i=0;i<files.size();i++)
{
cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
"Reading JSON File " << files[i] << std::endl);
if(!this->ReadJSONFile(files[i]))
{
return false;
}
}
return true;
}
bool cmParseBlanketJSCoverage::ReadJSONFile(std::string file)
{
cmParseBlanketJSCoverage::JSONParser parser
(this->Coverage);
cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
"Parsing " << file << std::endl);
parser.ParseFile(file);
return true;
}
/*============================================================================
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 cmParseBlanketJSCoverage_h
#define cmParseBlanketJSCoverage_h
#include "cmStandardIncludes.h"
#include "cmCTestCoverageHandler.h"
/** \class cmParseBlanketJSCoverage
* \brief Parse BlanketJS coverage information
*
* This class is used to parse BlanketJS(Pascal) coverage information
* generated by the Blanket.js library when used in conjunction with the
* test runner mocha.js, which is used to write out the JSON format.
*
* Blanket.js:
* http://blanketjs.org/
*
* Mocha.js
* http://visionmedia.github.io/mocha/
*/
class cmParseBlanketJSCoverage
{
public:
cmParseBlanketJSCoverage(cmCTestCoverageHandlerContainer& cont,
cmCTest* ctest);
bool LoadCoverageData(std::vector<std::string> files);
// Read the JSON output
bool ReadJSONFile(std::string file);
protected:
class JSONParser;
cmCTestCoverageHandlerContainer& Coverage;
cmCTest* CTest;
};
#endif
......@@ -2339,6 +2339,25 @@ ${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=)
# Adding a test case for Javascript Coverage
configure_file(
"${CMake_SOURCE_DIR}/Tests/JavascriptCoverage/DartConfiguration.tcl.in"
"${CMake_BINARY_DIR}/Testing/JavascriptCoverage/DartConfiguration.tcl")
configure_file(
"${CMake_SOURCE_DIR}/Tests/JavascriptCoverage/output.json.in"
"${CMake_BINARY_DIR}/Testing/JavascriptCoverage/output.json")
file(COPY "${CMake_SOURCE_DIR}/Tests/JavascriptCoverage/"
DESTINATION "${CMake_BINARY_DIR}/Testing/JavascriptCoverage"
FILES_MATCHING PATTERN "*.js")
add_test(NAME CTestJavascriptCoverage
COMMAND cmake -E chdir
${CMake_BINARY_DIR}/Testing/JavascriptCoverage
$<TARGET_FILE:ctest> -T Coverage --debug)
set_tests_properties(CTestJavascriptCoverage PROPERTIES
PASS_REGULAR_EXPRESSION
"Process file.*test3.js.*Total LOC:.*49.*Percentage Coverage: 79.59*"
ENVIRONMENT COVFILE=)
# test coverage for Delphi-code-Coverage
configure_file(
"${CMake_SOURCE_DIR}/Tests/DelphiCoverage/DartConfiguration.tcl.in"
......
# 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/JavascriptCoverage
BuildDirectory: ${CMake_BINARY_DIR}/Testing/JavascriptCoverage
This diff is collapsed.
var assert = require("assert")
var test = {
version: "1.0.0"
}
function covTest(p1,p2) {
if (p1 > 3) {
return 1;
}
else {
return p1 + p2;
}
}
function covTest2(p1,p2) {
return 0;
}
function covTest3(p1) {
for(i=0;i < p1;i++){
}
return i;
}
function covTest4(p1) {
i=0;
while(i < p1){
i++;
}
return i;
}
describe('Array', function(){
describe('CovTest', function(){
it('should return when the value is not present', function(){
assert.equal(4,covTest(2,2));
})
})
describe('CovTest>3', function(){
it('should return when the value is not present', function(){
assert.equal(1,covTest(4,2));
})
})
describe('covTest4', function(){
it('should return when the value is not present', function(){
assert.equal(5,covTest4(5));
})
})
describe('covTest3', function(){
it('should return when the value is not present', function(){
assert.equal(5,covTest3(5));
})
})
})
var assert = require("assert")
var test = {
version: "1.0.0"
}
function covTest(p1,p2) {
if (p1 > 3) {
return 1;
}
else {
return p1 + p2;
}
}
function covTest2(p1,p2) {
return 0;
}
function covTest3(p1) {
for(i=0;i < p1;i++){
}
return i;
}
function covTest4(p1) {
i=0;
while(i < p1){
i++;
}
return i;
}
describe('Array', function(){
describe('CovTest2', function(){
it('should return when the value is not present', function(){
assert.equal(0,covTest2(2,2));
})
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment