aboutsummaryrefslogtreecommitdiffstats
path: root/longbow/src/python/site-packages/longbow/GCov.py
diff options
context:
space:
mode:
Diffstat (limited to 'longbow/src/python/site-packages/longbow/GCov.py')
-rwxr-xr-xlongbow/src/python/site-packages/longbow/GCov.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/longbow/src/python/site-packages/longbow/GCov.py b/longbow/src/python/site-packages/longbow/GCov.py
new file mode 100755
index 00000000..c2705fda
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/GCov.py
@@ -0,0 +1,232 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# 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.
+#
+
+#
+import os
+import subprocess
+import re
+import sys
+import pprint
+import FileUtil
+import Language_C
+
+class GCov:
+ def __init__(self):
+ return
+
+def canonicalizeLines(lines):
+ result = []
+ accumulatedLine = ""
+ for line in lines:
+ line = line.strip()
+ if len(line) == 0:
+ if len(accumulatedLine.strip()) > 0:
+ result.append(accumulatedLine.strip())
+ accumulatedLine = ""
+ elif "creating" in line:
+ if len(accumulatedLine.strip()) > 0:
+ result.append(accumulatedLine.strip())
+ accumulatedLine = ""
+ result.append(line)
+ else:
+ accumulatedLine = accumulatedLine + " " + line
+ return result
+
+def executeGCovCommand(testExecutableFileName):
+ currentDirectory = os.getcwd()
+ targetDirectory = os.path.dirname(os.path.abspath(testExecutableFileName))
+ testExecutableBaseName = os.path.basename(testExecutableFileName)
+
+ os.chdir(targetDirectory)
+ objects = Language_C.findFiles("./", testExecutableBaseName+"*.o")
+ if not objects:
+ return
+ objdir = os.path.dirname(objects[0])
+ gcdas = Language_C.findFiles("./", testExecutableBaseName+"*.gcda")
+ if not gcdas:
+ return
+ gcda = gcdas[0]
+ gcnos = Language_C.findFiles("./", testExecutableBaseName+"*.gcno")
+ if not gcnos:
+ return
+ gcno = gcnos[0]
+ proc = subprocess.Popen(['gcov', '-af', '-o='+objdir, '-gcda='+gcda, '-gcno='+gcno, testExecutableBaseName], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ os.chdir(currentDirectory)
+
+ inputLines = map(lambda line: line.strip(), proc.stdout)
+
+ return canonicalizeLines(inputLines)
+
+def parseFunctionLine(line):
+ # Function 'TestFixture_Global_TearDown' Lines executed:71.43% of 7"
+ search = re.search("Function '(.*)' Lines executed:(.*)% of (.*)", line, re.IGNORECASE)
+
+ result = []
+ if search:
+ functionName = search.group(1)
+ percentage = search.group(2)
+ totalLines = search.group(3)
+ result = { functionName : { "coverage" : float(percentage), "numberOfLines" : int(totalLines) } }
+
+ return result
+
+def parseFileLine(testExecutableDirectoryName, line):
+ # File './../parc_Buffer.c' Lines executed:92.69% of 424
+ search = re.search("File '(.*)' Lines executed:(.*)% of (.*)", line, re.IGNORECASE)
+
+ result = { }
+ if search:
+ baseName = os.path.basename(search.group(1));
+ fileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName)
+ percentage = search.group(2)
+ totalLines = search.group(3)
+ result = { fileName : { "coverage" : float(percentage), "totalLines" : int(totalLines) } }
+
+ return result
+
+def parseCreatingLine(testExecutableDirectoryName, line):
+ search = re.search("(.*):creating '(.*)'", line, re.IGNORECASE)
+
+ result = None
+ if search:
+ baseName = os.path.basename(search.group(1));
+ fileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName)
+ baseName = os.path.basename(search.group(2));
+ gcovFileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName)
+
+ result = { "fileName" : fileName, "gcovFileName" : gcovFileName, "gcovLines" : FileUtil.readFileLines(gcovFileName) }
+
+ return result
+
+
+def computeCoverageFromGCovLines(testExecutableDirectoryName, testExecutableFileName, lines):
+ '''
+ This produces a dictionary consisting of:
+
+ 'testedFiles' : dictionary containing as keys 'functions' and the name of a file that was tested
+
+ The value of the key that is the name of a file that was tested is a dictionary containing the keys,
+ 'coverage', 'gcovFileName', and 'gcovLines'
+
+ 'coverage' is the percentage of code executed
+
+ 'testedFunctions' is a list containing lists consisting of the function name, the percent executed, and the number of lines in the function.
+ '''
+ testedFiles = { }
+ testedFunctions = { }
+ gcovFileNames = []
+ for line in lines:
+ if line.startswith("Function"):
+ element = parseFunctionLine(line)
+ testedFunctions.update(element)
+ elif line.startswith("File"):
+ element = parseFileLine(testExecutableDirectoryName, line)
+ testedFiles.update(element)
+ else:
+ element = parseCreatingLine(testExecutableDirectoryName, line)
+ if element != None:
+ fileName = element["fileName"]
+ del element["fileName"]
+ testedFiles[fileName].update(element)
+ pass
+
+ result = { testExecutableFileName : { "testedFunctions" : testedFunctions, "testedFiles" : testedFiles } }
+
+ return result
+
+
+def noCoverage():
+ result = { "testedFiles" : { }, "testedFunctions" : { } }
+ return result
+
+def getCoverage(testExecutableFileName):
+ '''
+ '''
+ if testExecutableFileName == None:
+ return None
+
+ testExecutableFileName = os.path.abspath(testExecutableFileName)
+ testExecutableDirectoryName = os.path.dirname(testExecutableFileName)
+ gcovLines = executeGCovCommand(testExecutableFileName)
+
+ return computeCoverageFromGCovLines(testExecutableDirectoryName, testExecutableFileName, gcovLines)
+
+
+def selectGreaterCoverage(testedFileA, testedFileB):
+ result = testedFileB
+ if testedFileA["coverage"] >= testedFileB["coverage"]:
+ result = testedFileA
+
+ return result
+
+def computeSummary(filesAndTests, newGCovResults):
+ '''
+ First, for each target file named in the gcov results, find the corresponding testedFile and report the maximum coverage.
+
+ If the target file is not in any of the testedFiles
+
+ { targetFileName : { "coverage": percent, "veracity" : "direct" / "indirect" } }
+ '''
+
+ newGCovResults = filter(lambda entry: entry != None, newGCovResults)
+
+ result = dict()
+ for entry in newGCovResults:
+ for testExecutableName in entry:
+ testExecutableCSourceName = Language_C.Module(testExecutableName).getCSourceName()
+
+ for testedFileName in entry[testExecutableName]["testedFiles"]:
+ testedFile = entry[testExecutableName]["testedFiles"][testedFileName]
+
+ if Language_C.Module(testedFileName).getTestExecutableName() == os.path.basename(testExecutableName):
+ result[testedFileName] = testedFile
+ result[testedFileName]["direct"] = "direct"
+ elif testedFileName in result:
+ bestCoverage = selectGreaterCoverage(testedFile, result[testedFileName])
+ if result[testedFileName] != bestCoverage:
+ result[testedFileName] = bestCoverage
+ result[testedFileName]["direct"] = "indirect"
+ else:
+ result[testedFileName] = testedFile
+ result[testedFileName]["direct"] = "indirect"
+
+ return result
+
+def computeAverage(filesAndTests, gcovResults):
+ summary = computeSuperSummary(filesAndTests, gcovResults)
+
+ filesToAverage = removeTestSourceFiles(summary)
+
+ score = 0.0
+
+ if len(filesToAverage) > 0:
+ sum = reduce(lambda x, y: x + y, map(lambda entry: summary[entry]["coverage"], filesToAverage))
+ score = sum / float(len(filesToAverage))
+
+ return score
+
+
+if __name__ == '__main__':
+ pp = pprint.PrettyPrinter(indent=4, width=132)
+ if True:
+ gcovResult = getCoverage("/Users/gscott/Documents/workspace/Distillery/Libparc/parc/algol/test/test_parc_JSON")
+ else:
+ lines = sys.stdin.readlines()
+ lines = canonicalizeLines(lines)
+ pp.pprint(lines)
+
+ gcovResult = computeCoverageFromGCovLines("/Users/gscott/Documents/workspace/Distillery/Libparc/parc/algol/test/", lines)
+
+ pp.pprint(gcovResult)