aboutsummaryrefslogtreecommitdiffstats
path: root/longbow/src/python/site-packages/longbow/CoverageReport.py
diff options
context:
space:
mode:
Diffstat (limited to 'longbow/src/python/site-packages/longbow/CoverageReport.py')
-rwxr-xr-xlongbow/src/python/site-packages/longbow/CoverageReport.py262
1 files changed, 262 insertions, 0 deletions
diff --git a/longbow/src/python/site-packages/longbow/CoverageReport.py b/longbow/src/python/site-packages/longbow/CoverageReport.py
new file mode 100755
index 00000000..c18ae056
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/CoverageReport.py
@@ -0,0 +1,262 @@
+#! /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 sys
+import os
+import re
+import subprocess
+import difflib
+import csv
+# import argparse
+import pprint
+# sys.path.append("${INSTALL_PYTHON_DIR}")
+# sys.path.append("${DEPENDENCY_PYTHON_DIR}")
+# sys.path.append("../site-packages/longbow/")
+import LongBow
+import GCov
+import GCovSummary
+import FileUtil
+import ANSITerm
+import Language_C
+
+def checkTestExecutable(executableFileName):
+ result = False
+
+ if not os.path.exists(executableFileName):
+ return result
+
+ path = os.path.dirname(executableFileName)
+ pattern = os.path.basename(executableFileName)+'*.gcda'
+ if not Language_C.findFiles(path, pattern):
+ return result
+
+ pattern = os.path.basename(executableFileName)+'*.gcno'
+ if not Language_C.findFiles(path, pattern):
+ return result
+
+ result = True
+ return result
+
+def findTestExecutable(fileName, hints=[]):
+ '''
+Given a file name, look in the canonical places for a corresponding LongBow test file.
+ '''
+ directoryName = os.path.dirname(fileName)
+ if len(directoryName) == 0:
+ directoryName = "."
+
+ file = Language_C.Module(fileName)
+
+ possibleTestFiles = list()
+ for hint in hints:
+ possibleTestFiles.append(hint + "/" + file.getExecutableName())
+ possibleTestFiles.append(hint + "/" + file.getTestExecutableName())
+ possibleTestFiles.append(directoryName + "/" + file.getExecutableName())
+ possibleTestFiles.append(directoryName + "/" + file.getTestExecutableName())
+ possibleTestFiles.append(directoryName + "/test/" + file.getTestExecutableName())
+
+ result = None
+ for possibleTestFile in possibleTestFiles:
+ if checkTestExecutable(possibleTestFile) == True:
+ result = os.path.abspath(possibleTestFile)
+ break
+
+ return result
+
+
+def textSummary(args, filesAndTests, gCovResults, prefix=""):
+
+ summary = GCov.computeSummary(filesAndTests, gCovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ if len(summary) == 0:
+ return
+
+ if args.explain:
+ pp = pprint.PrettyPrinter(indent=2, width=150)
+ pp.pprint(summary)
+
+ maximumFileLength = max(map(lambda entry: len(entry), summary))
+
+ format = "%s%-" + str(maximumFileLength) + "s %6s"
+ print format % (prefix, "File Path", "Score")
+
+ format = "%s%-" + str(maximumFileLength) + "s %6.2f"
+ for testedFile in sorted(summary.keys()):
+ string = format % (prefix, testedFile, summary[testedFile]["coverage"])
+ if summary[testedFile]["direct"] == "indirect":
+ ANSITerm.printColorized("magenta", string)
+ else:
+ LongBow.scorePrinter(eval(args.distribution), summary[testedFile]["coverage"], string)
+
+ return
+
+
+def textAverage(args, filesAndTests, gcovResults):
+ summary = GCov.computeSummary(filesAndTests, gcovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ score = GCovSummary.averageCoverage(summary)
+
+ LongBow.scorePrinter(eval(args.distribution), score, "%.2f" % (score))
+ return score
+
+
+def csvSummary(args, filesAndTests, gCovResults):
+ summary = GCov.computeSummary(filesAndTests, gCovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ if len(summary) > 0:
+ for testedFile in sorted(summary.keys()):
+ outputString = "%s,%.2f" % (testedFile, summary[testedFile]["coverage"])
+ LongBow.scorePrinter(eval(args.distribution), summary[testedFile]["coverage"], outputString)
+
+ return
+
+
+def csvAverage(args, filesAndTests, gcovResults):
+ summary = GCov.computeSummary(filesAndTests, gcovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ score = GCovSummary.averageCoverage(summary)
+
+ LongBow.scorePrinter(eval(args.distribution), score, "%.2f" % (score))
+ return
+
+
+def textVisualDisplayGcovLine(line):
+ token = line.split(":", 2)
+ if len(token) == 3:
+ if token[0] == "#####":
+ print ANSITerm.colorize("red", token[1] + " " + token[2])
+ elif token[0] == "$$$$$":
+ print ANSITerm.colorize("yellow", token[1] + " " + token[2])
+ else:
+ print ANSITerm.colorize("green", token[1] + " " + token[2])
+
+ return
+
+
+def textVisual(args, filesAndTests, gcovResults):
+
+ summary = GCov.computeSummary(filesAndTests, gcovResults)
+ if args.explain:
+ pp = pprint.PrettyPrinter(indent=2, width=150)
+ pp.pprint(summary)
+ pp.pprint(filesAndTests)
+
+ for entry in filesAndTests:
+ print entry[0]
+ try:
+ gcovLines = summary[entry[0]]["gcovLines"]
+ map(lambda line: textVisualDisplayGcovLine(line.strip()), gcovLines)
+ except KeyError:
+ print >> sys.stderr, "No coverage information for", entry[0]
+
+ return
+
+
+def displaySummary(args, filesAndTests, newGCovResults):
+ if args.output == "text":
+ textSummary(args, filesAndTests, newGCovResults)
+ elif args.output == "csv":
+ csvSummary(args, filesAndTests, newGCovResults)
+ else:
+ print >> sys.stderr, "Unsupported output type"
+ return
+
+
+def displayAverage(args, filesAndTests, gcovResults):
+ if args.output == "text":
+ textAverage(args, filesAndTests, gcovResults)
+ elif args.output == "csv":
+ csvAverage(args, filesAndTests, gcovResults)
+ else:
+ print >> sys.stderr, "Unsupported output type"
+ return
+
+
+def explain(args, filesAndTests, gcovResults):
+
+ pp = pprint.PrettyPrinter(indent=2, width=150)
+ pp.pprint(gcovResults)
+
+ return
+
+def getFilesAndTests(fileNames, testDirs=[]):
+ namesAndPaths = map(lambda fileName: [fileName, os.path.abspath(fileName)], fileNames)
+ filesAndTests = map(lambda nameAndPath: [ nameAndPath[0], findTestExecutable(nameAndPath[1], testDirs) ], namesAndPaths)
+ return filesAndTests
+
+
+def gradeAndPrint(targets, testDirs=[], problemsOnly=False, prefix=""):
+ filesAndTests = getFilesAndTests(targets, testDirs)
+ newGCovResults = map(lambda fileAndTestFile: GCov.getCoverage(fileAndTestFile[1]), filesAndTests)
+
+ summarys = GCov.computeSummary(filesAndTests, newGCovResults)
+ if len(summarys) < 1:
+ print "%sNo GCov Results - Please be sure to run 'make check' first" % prefix
+ return False
+ summarys = GCovSummary.removeTestSourceFiles(summarys)
+
+ paths = summarys.keys()
+ if problemsOnly:
+ paths = filter(lambda key: summarys[key]["coverage"] < 100, paths)
+
+ distribution=[99,90]
+ maximumFileLength = max(map(lambda entry: len(os.path.relpath(entry)), paths))
+ format = "%s%-" + str(maximumFileLength) + "s %6s"
+ print format % (prefix, "File Path", "Score")
+ format = "%s%-" + str(maximumFileLength) + "s %6.2f"
+ for path in sorted(paths):
+ string = format % (prefix, os.path.relpath(path), summarys[path]["coverage"])
+ LongBow.scorePrinter(distribution, summarys[path]["coverage"], string)
+
+ return True
+
+def commandLineMain(args, fileNames, testDir=""):
+
+ testDirs = []
+ if testDir:
+ testDirs.append(testDir)
+ fileNames = map(lambda fileName: os.path.abspath(fileName), fileNames)
+ filesAndTests = map(lambda fileName: [fileName, findTestExecutable(fileName, testDirs)], fileNames)
+
+ filesWithNoTest = filter(lambda fileAndTest: fileAndTest[1] == None, filesAndTests)
+ if len(filesWithNoTest) != 0:
+ outputFormat = "%s has no corresponding test executable or coverage data.\n"
+ map(lambda filesAndTests: sys.stderr.write(outputFormat % (filesAndTests[0])), filesWithNoTest)
+
+ gCovResults = map(lambda fileAndTestFile: GCov.getCoverage(fileAndTestFile[1]), filesAndTests)
+
+ if args.summary is True:
+ displaySummary(args, filesAndTests, gCovResults)
+ elif args.average is True:
+ displayAverage(args, filesAndTests, gCovResults)
+ elif args.visual is True:
+ textVisual(args, filesAndTests, gCovResults)
+ elif args.explain is True:
+ explain(args, filesAndTests, gCovResults)
+
+ return True