diff options
Diffstat (limited to 'longbow/src/python/site-packages/longbow/CoverageReport.py')
-rwxr-xr-x | longbow/src/python/site-packages/longbow/CoverageReport.py | 262 |
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 |