diff --git a/example/build.sh b/example/build.sh index 8a8d729..086f739 100755 --- a/example/build.sh +++ b/example/build.sh @@ -18,8 +18,8 @@ ninja # Run unit tests ctest -# Run fastcov with smart branch filtering, as well as system header (/usr/include) and test file filtering -${BASE_DIR}/fastcov.py --gcov gcov-9 --branch-coverage --exclude /usr/include test/ --lcov -o example.info +# Run fastcov with smart branch filtering, as well as system header (/usr/include) and cmake project test file filtering +${BASE_DIR}/fastcov.py -t ExampleTest --gcov gcov-9 --branch-coverage --exclude /usr/include cmake_project/test/ --lcov -o example.info # Generate report with lcov's genhtml genhtml --branch-coverage example.info -o coverage_report diff --git a/fastcov.py b/fastcov.py index 8d1cfba..43c2b77 100755 --- a/fastcov.py +++ b/fastcov.py @@ -173,39 +173,39 @@ def dumpToLcovInfo(fastcov_json, output): with open(output, "w") as f: sources = fastcov_json["sources"] for sf in sorted(sources.keys()): - data = sources[sf] - # NOTE: TN stands for "Test Name" and appears to be unimplemented, but lcov includes it, so we do too... - f.write("TN:\n") - f.write("SF:{}\n".format(sf)) #Source File - - fn_miss = 0 - fn = [] - fnda = [] - for function, fdata in data["functions"].items(): - fn.append((fdata["start_line"], function)) # Function Start Line - fnda.append((fdata["execution_count"], function)) # Function Hits - fn_miss += int(fdata["execution_count"] == 0) - # NOTE: lcov sorts FN, but not FNDA. - for v in sorted(fn): - f.write("FN:{},{}\n".format(*v)) - for v in sorted(fnda): - f.write("FNDA:{},{}\n".format(*v)) - f.write("FNF:{}\n".format(len(data["functions"]))) #Functions Found - f.write("FNH:{}\n".format((len(data["functions"]) - fn_miss))) #Functions Hit - - if data["branches"]: - dumpBranchCoverageToLcovInfo(f, data["branches"]) - - line_miss = 0 - da = [] - for line_num, count in data["lines"].items(): - da.append((line_num, count)) - line_miss += int(count == 0) - for v in sorted(da): - f.write("DA:{},{}\n".format(*v)) # Line - f.write("LF:{}\n".format(len(data["lines"]))) #Lines Found - f.write("LH:{}\n".format((len(data["lines"]) - line_miss))) #Lines Hit - f.write("end_of_record\n") + for tn in sorted(sources[sf].keys()): + data = sources[sf][tn] + f.write("TN:{}\n".format(tn)) #Test Name - used mainly in conjuction with genhtml --show-details + f.write("SF:{}\n".format(sf)) #Source File + + fn_miss = 0 + fn = [] + fnda = [] + for function, fdata in data["functions"].items(): + fn.append((fdata["start_line"], function)) # Function Start Line + fnda.append((fdata["execution_count"], function)) # Function Hits + fn_miss += int(fdata["execution_count"] == 0) + # NOTE: lcov sorts FN, but not FNDA. + for v in sorted(fn): + f.write("FN:{},{}\n".format(*v)) + for v in sorted(fnda): + f.write("FNDA:{},{}\n".format(*v)) + f.write("FNF:{}\n".format(len(data["functions"]))) #Functions Found + f.write("FNH:{}\n".format((len(data["functions"]) - fn_miss))) #Functions Hit + + if data["branches"]: + dumpBranchCoverageToLcovInfo(f, data["branches"]) + + line_miss = 0 + da = [] + for line_num, count in data["lines"].items(): + da.append((line_num, count)) + line_miss += int(count == 0) + for v in sorted(da): + f.write("DA:{},{}\n".format(*v)) # Line + f.write("LF:{}\n".format(len(data["lines"]))) #Lines Found + f.write("LH:{}\n".format((len(data["lines"]) - line_miss))) #Lines Hit + f.write("end_of_record\n") def getSourceLines(source, fallback_encodings=[]): """Return a list of lines from the provided source, trying to decode with fallback encodings if the default fails""" @@ -225,38 +225,43 @@ def exclMarkerWorker(fastcov_sources, chunk, exclude_branches_sw, include_branch for source in chunk: start_line = 0 end_line = 0 - for i, line in enumerate(getSourceLines(source, fallback_encodings), 1): #Start enumeration at line 1 - if i in fastcov_sources[source]["branches"]: - del_exclude_br = exclude_branches_sw and any(line.lstrip().startswith(e) for e in exclude_branches_sw) - del_include_br = include_branches_sw and all(not line.lstrip().startswith(e) for e in include_branches_sw) - if del_exclude_br or del_include_br: - del fastcov_sources[source]["branches"][i] - - if "LCOV_EXCL" not in line: - continue - - if "LCOV_EXCL_LINE" in line: - for key in ["lines", "branches"]: - if i in fastcov_sources[source][key]: - del fastcov_sources[source][key][i] - elif "LCOV_EXCL_START" in line: - start_line = i - elif "LCOV_EXCL_STOP" in line: - end_line = i - - if not start_line: - end_line = 0 + # Start enumeration at line 1 because the first line of the file is line 1 not 0 + for i, line in enumerate(getSourceLines(source, fallback_encodings), 1): + # Cycle through test names (likely only 1) + for test_name in fastcov_sources[source]: + fastcov_data = fastcov_sources[source][test_name] + + if i in fastcov_data["branches"]: + del_exclude_br = exclude_branches_sw and any(line.lstrip().startswith(e) for e in exclude_branches_sw) + del_include_br = include_branches_sw and all(not line.lstrip().startswith(e) for e in include_branches_sw) + if del_exclude_br or del_include_br: + del fastcov_data["branches"][i] + + if "LCOV_EXCL" not in line: continue - for key in ["lines", "branches"]: - for line_num in list(fastcov_sources[source][key].keys()): - if start_line <= line_num <= end_line: - del fastcov_sources[source][key][line_num] - - start_line = end_line = 0 - elif "LCOV_EXCL_BR_LINE" in line: - if i in fastcov_sources[source]["branches"]: - del fastcov_sources[source]["branches"][i] + if "LCOV_EXCL_LINE" in line: + for key in ["lines", "branches"]: + if i in fastcov_data[key]: + del fastcov_data[key][i] + elif "LCOV_EXCL_START" in line: + start_line = i + elif "LCOV_EXCL_STOP" in line: + end_line = i + + if not start_line: + end_line = 0 + continue + + for key in ["lines", "branches"]: + for line_num in list(fastcov_data[key].keys()): + if start_line <= line_num <= end_line: + del fastcov_data[key][line_num] + + start_line = end_line = 0 + elif "LCOV_EXCL_BR_LINE" in line: + if i in fastcov_data["branches"]: + del fastcov_data["branches"][i] def scanExclusionMarkers(fastcov_json, jobs, exclude_branches_sw, include_branches_sw, min_chunk_size, fallback_encodings): chunk_size = max(min_chunk_size, int(len(fastcov_json["sources"]) / jobs) + 1) @@ -335,28 +340,30 @@ def distillLine(line_raw, lines, branches, include_exceptional_branches): branches[line_number] += [0] * (glen - blen) branches[line_number][i] += int(branch["count"]) -def distillSource(source_raw, sources, include_exceptional_branches): +def distillSource(source_raw, sources, test_name, include_exceptional_branches): source_name = source_raw["file_abs"] if source_name not in sources: sources[source_name] = { - "functions": {}, - "branches": {}, - "lines": {}, + test_name: { + "functions": {}, + "branches": {}, + "lines": {} + } } for function in source_raw["functions"]: - distillFunction(function, sources[source_name]["functions"]) + distillFunction(function, sources[source_name][test_name]["functions"]) for line in source_raw["lines"]: - distillLine(line, sources[source_name]["lines"], sources[source_name]["branches"], include_exceptional_branches) + distillLine(line, sources[source_name][test_name]["lines"], sources[source_name][test_name]["branches"], include_exceptional_branches) -def distillReport(report_raw, include_exceptional_branches): +def distillReport(report_raw, args): report_json = { "sources": {} } for source in report_raw: - distillSource(source, report_json["sources"], include_exceptional_branches) + distillSource(source, report_json["sources"], args.test_name, args.xbranchcoverage) return report_json @@ -371,6 +378,144 @@ def getGcovFilterOptions(args): "exclude": args.excludepost, } +def addDicts(dict1, dict2): + """Add dicts together by value. i.e. addDicts({"a":1,"b":0}, {"a":2}) == {"a":3,"b":0}""" + result = {k:v for k,v in dict1.items()} + for k,v in dict2.items(): + if k in result: + result[k] += v + else: + result[k] = v + + return result + +def addLists(list1, list2): + """Add lists together by value. i.e. addLists([1,1], [2,2]) == [3,3]""" + if len(list1) == len(list2): + return [b1 + b2 for b1, b2 in zip(list1, list2)] + else: + # One report had different number branch measurements than the other, print a warning + sys.stderr.write("Warning: possible loss of correctness. Different number of branches for same line when combining reports ({} vs {})\n".format(list1, list2)) + return list1 if len(list1) > len(list2) else list2 + +def combineReports(base, overlay): + for source, scov in overlay["sources"].items(): + # Combine Source Coverage + if source not in base["sources"]: + base["sources"][source] = scov + continue + + for test_name, tcov in scov.items(): + # Combine Source Test Name Coverage + if test_name not in base["sources"][source]: + base["sources"][source][test_name] = tcov + continue + + # Drill down and create convenience variable + base_data = base["sources"][source][test_name] + + # Combine Line Coverage + base_data["lines"] = addDicts(base_data["lines"], tcov["lines"]) + + # Combine Branch Coverage + for branch, cov in tcov["branches"].items(): + if branch not in base_data["branches"]: + base_data["branches"][branch] = cov + else: + base_data["branches"][branch] = addLists(base_data["branches"][branch], cov) + + # Combine Function Coverage + for function, cov in tcov["functions"].items(): + if function not in base_data["functions"]: + base_data["functions"][function] = cov + else: + base_data["functions"][function]["execution_count"] += cov["execution_count"] + +def parseInfo(path): + """Parse an lcov .info file into fastcov json""" + fastcov_json = { + "sources": {} + } + + with open(path) as f: + for line in f: + if line.startswith("TN:"): + current_test_name = line[3:].strip() + elif line.startswith("SF:"): + current_sf = line[3:].strip() + fastcov_json["sources"][current_sf] = { + current_test_name: { + "functions": {}, + "branches": {}, + "lines": {}, + } + } + current_data = fastcov_json["sources"][current_sf][current_test_name] + elif line.startswith("FN:"): + line_num, function_name = line[3:].strip().split(",") + current_data["functions"][function_name] = {} + current_data["functions"][function_name]["start_line"] = int(line_num) + elif line.startswith("FNDA:"): + count, function_name = line[5:].strip().split(",") + current_data["functions"][function_name]["execution_count"] = int(count) + elif line.startswith("DA:"): + line_num, count = line[3:].strip().split(",") + current_data["lines"][line_num] = int(count) + elif line.startswith("BRDA:"): + branch_tokens = line[5:].strip().split(",") + line_num, count = branch_tokens[0], branch_tokens[-1] + if line_num not in current_data["branches"]: + current_data["branches"][line_num] = [] + current_data["branches"][line_num].append(int(count)) + + return fastcov_json + +def convertKeysToInt(report): + for source in report["sources"].keys(): + for test_name in report["sources"][source].keys(): + report_data = report["sources"][source][test_name] + report_data["lines"] = {int(k):v for k,v in report_data["lines"].items()} + report_data["branches"] = {int(k):v for k,v in report_data["branches"].items()} + +def parseAndCombine(paths): + base_report = {} + + for path in paths: + if path.endswith(".json"): + with open(path) as f: + report = json.load(f) + elif path.endswith(".info"): + report = parseInfo(path) + else: + sys.stderr.write("Currently only fastcov .json and lcov .info supported for combine operations, aborting due to {}...\n".format(path)) + sys.exit(3) + + # In order for sorting to work later when we serialize, + # make sure integer keys are int + convertKeysToInt(report) + + if not base_report: + base_report = report + log("Setting {} as base report".format(path)) + else: + combineReports(base_report, report) + log("Adding {} to base report".format(path)) + + return base_report + +def combineCoverageFiles(args): + log("Performing combine operation") + fastcov_json = parseAndCombine(args.combine) + dumpFile(fastcov_json, args) + +def dumpFile(fastcov_json, args): + if args.lcov: + dumpToLcovInfo(fastcov_json, args.output) + log("Created lcov info file '{}'".format(args.output)) + else: + dumpToJson(fastcov_json, args.output) + log("Created fastcov json file '{}'".format(args.output)) + def tupleToDotted(tup): return ".".join(map(str, tup)) @@ -401,15 +546,17 @@ def parseArgs(): This needs to be set if invoking fastcov from somewhere other than the base compiler directory.') parser.add_argument('-j', '--jobs', dest='jobs', type=int, default=multiprocessing.cpu_count(), help='Number of parallel gcov to spawn (default: {}).'.format(multiprocessing.cpu_count())) - parser.add_argument('-m', '--minimum-chunk-size', dest='minimum_chunk', type=int, default=5, help='Minimum number of files a thread should process (default: 5). \ - If you have only 4 gcda files but they are monstrously huge, you could change this value to a 1 so that each thread will only process 1 gcda. Otherwise fastcov will spawn only 1 thread to process all of them.') + parser.add_argument('-m', '--minimum-chunk-size', dest='minimum_chunk', type=int, default=5, help='Minimum number of files a thread should process (default: 5). \ + If you have only 4 gcda files but they are monstrously huge, you could change this value to a 1 so that each thread will only process 1 gcda. Otherwise fastcov will spawn only 1 thread to process all of them.') parser.add_argument('-F', '--fallback-encodings', dest='fallback_encodings', nargs="+", metavar='', default=[], help='List of encodings to try if opening a source file with the default fails (i.e. latin1, etc.). This option is not usually needed.') - parser.add_argument('-l', '--lcov', dest='lcov', action="store_true", help='Output in lcov info format instead of fastcov json') - parser.add_argument('-r', '--gcov-raw', dest='gcov_raw', action="store_true", help='Output in gcov raw json instead of fastcov json') - parser.add_argument('-o', '--output', dest='output', default="coverage.json", help='Name of output file (default: coverage.json)') - parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", help='Suppress output to stdout') + parser.add_argument('-l', '--lcov', dest='lcov', action="store_true", help='Output in lcov info format instead of fastcov json') + parser.add_argument('-o', '--output', dest='output', default="coverage.json", help='Name of output file (default: coverage.json)') + parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", help='Suppress output to stdout') + + parser.add_argument('-t', '--test-name', dest='test_name', default="", help='Specify a test name for the coverage. Equivalent to lcov\'s `-t`.') + parser.add_argument('-C', '--add-tracefile', dest='combine', nargs="+", help='Combine multiple coverage files into one. If this flag is specified, fastcov will do a combine operation instead invoking gcov. Equivalent to lcov\'s `-a`.') parser.add_argument('-v', '--version', action="version", version='%(prog)s {version}'.format(version=__version__), help="Show program's version number and exit") @@ -442,6 +589,11 @@ def main(): # Need at least python 3.5 because of use of recursive glob checkPythonVersion(sys.version_info[0:2]) + # Combine operation? + if args.combine: + combineCoverageFiles(args) + return + # Need at least gcov 9.0.0 because that's when gcov JSON and stdout streaming was introduced checkGcovVersion(getGcovVersion(args.gcov)) @@ -469,7 +621,7 @@ def main(): log("Processed {} .gcov files ({} total, {} skipped)".format(gcov_total - gcov_skipped, gcov_total, gcov_skipped)) # Distill all the extraneous info gcov gives us down to the core report - fastcov_json = distillReport(intermediate_json_files, args.xbranchcoverage) + fastcov_json = distillReport(intermediate_json_files, args) log("Aggregated raw gcov JSON into fastcov JSON report") # Scan for exclusion markers @@ -477,15 +629,7 @@ def main(): log("Scanned {} source files for exclusion markers".format(len(fastcov_json["sources"]))) # Dump to desired file format - if args.lcov: - dumpToLcovInfo(fastcov_json, args.output) - log("Created lcov info file '{}'".format(args.output)) - elif args.gcov_raw: - dumpToJson(intermediate_json_files, args.output) - log("Created gcov raw json file '{}'".format(args.output)) - else: - dumpToJson(fastcov_json, args.output) - log("Created fastcov json file '{}'".format(args.output)) + dumpFile(fastcov_json, args) # Set package version... it's way down here so that we can call tupleToDotted __version__ = tupleToDotted(FASTCOV_VERSION) diff --git a/test/functional/expected_results/combine1.expected.info b/test/functional/expected_results/combine1.expected.info new file mode 100644 index 0000000..c378bc8 --- /dev/null +++ b/test/functional/expected_results/combine1.expected.info @@ -0,0 +1,68 @@ +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:1,_Z3foob +FNF:1 +FNH:1 +BRDA:7,0,0,1000 +BRDA:7,0,1,1 +BRDA:10,0,0,0 +BRDA:10,0,1,1000 +BRF:4 +BRH:3 +DA:3,1 +DA:5,1 +DA:7,1001 +DA:8,1000 +DA:10,1000 +DA:11,0 +DA:14,1 +LF:7 +LH:6 +end_of_record +TN:FunctionalTest1 +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:1,_Z3foob +FNF:1 +FNH:1 +DA:3,1 +DA:5,1 +DA:7,1001 +DA:8,1000 +DA:10,1000 +DA:11,0 +DA:14,1 +LF:7 +LH:6 +end_of_record +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:10,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,10 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,10 +DA:5,10 +DA:6,10 +DA:8,0 +LF:4 +LH:3 +end_of_record +TN:FunctionalTest1 +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:10,_Z3barbii +FNF:1 +FNH:1 +DA:3,10 +DA:5,10 +DA:6,10 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine2.expected.info b/test/functional/expected_results/combine2.expected.info new file mode 100644 index 0000000..b892e2d --- /dev/null +++ b/test/functional/expected_results/combine2.expected.info @@ -0,0 +1,39 @@ +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:1,_Z3foob +FNF:1 +FNH:1 +BRDA:7,0,0,1000 +BRDA:7,0,1,1 +BRDA:10,0,0,0 +BRDA:10,0,1,1000 +BRF:4 +BRH:3 +DA:3,1 +DA:5,1 +DA:7,1001 +DA:8,1000 +DA:10,1000 +DA:11,0 +DA:14,1 +LF:7 +LH:6 +end_of_record +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:10,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,10 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,10 +DA:5,10 +DA:6,10 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine3.expected.info b/test/functional/expected_results/combine3.expected.info new file mode 100644 index 0000000..6db6903 --- /dev/null +++ b/test/functional/expected_results/combine3.expected.info @@ -0,0 +1,44 @@ +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FN:55,_Z3barb +FNDA:1,_Z3barb +FNDA:2,_Z3foob +FNF:2 +FNH:2 +BRDA:7,0,0,2000 +BRDA:7,0,1,2 +BRDA:10,0,0,0 +BRDA:10,0,1,2000 +BRDA:71,0,0,5 +BRDA:71,0,1,5 +BRF:6 +BRH:5 +DA:3,2 +DA:5,2 +DA:7,2002 +DA:8,2000 +DA:10,2000 +DA:11,0 +DA:14,2 +DA:58,10 +LF:8 +LH:7 +end_of_record +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:20,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,20 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,20 +DA:5,20 +DA:6,20 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine3a.info b/test/functional/expected_results/combine3a.info new file mode 100644 index 0000000..aee0081 --- /dev/null +++ b/test/functional/expected_results/combine3a.info @@ -0,0 +1,44 @@ +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FN:55,_Z3barb +FNDA:1,_Z3foob +FNDA:1,_Z3barb +FNF:1 +FNH:1 +BRDA:10,0,0,0 +BRDA:10,0,1,1000 +BRDA:7,0,0,1000 +BRDA:7,0,1,1 +BRDA:71,0,0,5 +BRDA:71,0,1,5 +BRF:4 +BRH:3 +DA:10,1000 +DA:11,0 +DA:14,1 +DA:3,1 +DA:5,1 +DA:7,1001 +DA:8,1000 +DA:58,10 +LF:7 +LH:6 +end_of_record +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:10,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,10 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,10 +DA:5,10 +DA:6,10 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine3b.info b/test/functional/expected_results/combine3b.info new file mode 100644 index 0000000..42eae9e --- /dev/null +++ b/test/functional/expected_results/combine3b.info @@ -0,0 +1,39 @@ +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:1,_Z3foob +FNF:1 +FNH:1 +BRDA:10,0,0,0 +BRDA:10,0,1,1000 +BRDA:7,0,0,1000 +BRDA:7,0,1,1 +BRF:4 +BRH:3 +DA:10,1000 +DA:11,0 +DA:14,1 +DA:3,1 +DA:5,1 +DA:7,1001 +DA:8,1000 +LF:7 +LH:6 +end_of_record +TN: +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:10,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,10 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,10 +DA:5,10 +DA:6,10 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine4.expected.info b/test/functional/expected_results/combine4.expected.info new file mode 100644 index 0000000..6ee7a16 --- /dev/null +++ b/test/functional/expected_results/combine4.expected.info @@ -0,0 +1,256 @@ +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/branches.cpp +FN:11,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNDA:3,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNF:1 +FNH:1 +BRDA:18,0,0,1 +BRDA:18,0,1,2 +BRDA:20,0,0,0 +BRDA:20,0,1,2 +BRDA:26,0,0,7 +BRDA:26,0,1,3 +BRDA:30,0,0,12 +BRDA:30,0,1,3 +BRDA:36,0,0,1 +BRDA:36,0,1,2 +BRDA:36,1,2,1 +BRDA:36,1,3,0 +BRDA:36,2,4,1 +BRDA:36,2,5,2 +BRDA:44,0,0,1 +BRDA:44,0,1,0 +BRDA:44,1,2,2 +BRF:17 +BRH:14 +DA:11,3 +DA:13,6 +DA:14,18 +DA:15,6 +DA:17,3 +DA:18,3 +DA:19,1 +DA:20,2 +DA:21,0 +DA:23,2 +DA:25,3 +DA:26,10 +DA:27,7 +DA:29,3 +DA:30,15 +DA:31,12 +DA:32,12 +DA:36,3 +DA:37,1 +DA:39,1 +DA:40,1 +DA:44,3 +DA:45,1 +DA:46,1 +DA:47,1 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,2 +DA:52,2 +DA:53,2 +DA:56,6 +LF:32 +LH:28 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/branches.cpp +FN:11,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNDA:6,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNF:1 +FNH:1 +BRDA:18,0,0,2 +BRDA:18,0,1,4 +BRDA:20,0,0,0 +BRDA:20,0,1,4 +BRDA:26,0,0,14 +BRDA:26,0,1,6 +BRDA:30,0,0,24 +BRDA:30,0,1,6 +BRDA:36,0,0,2 +BRDA:36,0,1,4 +BRDA:36,1,2,2 +BRDA:36,1,3,0 +BRDA:36,2,4,2 +BRDA:36,2,5,4 +BRDA:44,0,0,2 +BRDA:44,0,1,0 +BRDA:44,1,2,4 +BRF:17 +BRH:14 +DA:11,6 +DA:13,12 +DA:14,36 +DA:15,12 +DA:17,6 +DA:18,6 +DA:19,2 +DA:20,4 +DA:21,0 +DA:23,4 +DA:25,6 +DA:26,20 +DA:27,14 +DA:29,6 +DA:30,30 +DA:31,24 +DA:32,24 +DA:36,6 +DA:37,2 +DA:39,2 +DA:40,2 +DA:44,6 +DA:45,2 +DA:46,2 +DA:47,2 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,4 +DA:52,4 +DA:53,4 +DA:56,12 +LF:32 +LH:28 +end_of_record +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/latin1_enc.cpp +FN:6,_Z8latinfoob +FNDA:1,_Z8latinfoob +FNF:1 +FNH:1 +BRDA:10,0,0,1000 +BRDA:10,0,1,1 +BRDA:26,0,0,1000 +BRDA:26,0,1,1 +BRDA:27,0,0,500 +BRDA:27,0,1,500 +BRDA:29,0,0,1000 +BRDA:29,0,1,0 +BRF:8 +BRH:7 +DA:6,1 +DA:8,1 +DA:10,1001 +DA:13,1000 +DA:14,1000 +DA:26,1001 +DA:27,1000 +DA:29,1000 +DA:30,1000 +DA:33,1 +LF:10 +LH:10 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/latin1_enc.cpp +FN:6,_Z8latinfoob +FNDA:2,_Z8latinfoob +FNF:1 +FNH:1 +BRDA:10,0,0,2000 +BRDA:10,0,1,2 +BRDA:26,0,0,2000 +BRDA:26,0,1,2 +BRDA:27,0,0,1000 +BRDA:27,0,1,1000 +BRDA:29,0,0,2000 +BRDA:29,0,1,0 +BRF:8 +BRH:7 +DA:6,2 +DA:8,2 +DA:10,2002 +DA:13,2000 +DA:14,2000 +DA:26,2002 +DA:27,2000 +DA:29,2000 +DA:30,2000 +DA:33,2 +LF:10 +LH:10 +end_of_record +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:2,_Z3foob +FNF:1 +FNH:1 +BRDA:7,0,0,2000 +BRDA:7,0,1,2 +BRDA:10,0,0,0 +BRDA:10,0,1,2000 +BRF:4 +BRH:3 +DA:3,2 +DA:5,2 +DA:7,2002 +DA:8,2000 +DA:10,2000 +DA:11,0 +DA:14,2 +LF:7 +LH:6 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:4,_Z3foob +FNF:1 +FNH:1 +BRDA:7,0,0,4000 +BRDA:7,0,1,4 +BRDA:10,0,0,0 +BRDA:10,0,1,4000 +BRF:4 +BRH:3 +DA:3,4 +DA:5,4 +DA:7,4004 +DA:8,4000 +DA:10,4000 +DA:11,0 +DA:14,4 +LF:7 +LH:6 +end_of_record +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:20,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,20 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,20 +DA:5,20 +DA:6,20 +DA:8,0 +LF:4 +LH:3 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:40,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,40 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,40 +DA:5,40 +DA:6,40 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine4a.info b/test/functional/expected_results/combine4a.info new file mode 100644 index 0000000..789d4b6 --- /dev/null +++ b/test/functional/expected_results/combine4a.info @@ -0,0 +1,128 @@ +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/branches.cpp +FN:11,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNDA:3,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNF:1 +FNH:1 +BRDA:18,0,0,1 +BRDA:18,0,1,2 +BRDA:20,0,0,0 +BRDA:20,0,1,2 +BRDA:26,0,0,7 +BRDA:26,0,1,3 +BRDA:30,0,0,12 +BRDA:30,0,1,3 +BRDA:36,0,0,1 +BRDA:36,0,1,2 +BRDA:36,1,2,1 +BRDA:36,1,3,0 +BRDA:36,2,4,1 +BRDA:36,2,5,2 +BRDA:44,0,0,1 +BRDA:44,0,1,0 +BRDA:44,1,2,2 +BRF:17 +BRH:14 +DA:11,3 +DA:13,6 +DA:14,18 +DA:15,6 +DA:17,3 +DA:18,3 +DA:19,1 +DA:20,2 +DA:21,0 +DA:23,2 +DA:25,3 +DA:26,10 +DA:27,7 +DA:29,3 +DA:30,15 +DA:31,12 +DA:32,12 +DA:36,3 +DA:37,1 +DA:39,1 +DA:40,1 +DA:44,3 +DA:45,1 +DA:46,1 +DA:47,1 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,2 +DA:52,2 +DA:53,2 +DA:56,6 +LF:32 +LH:28 +end_of_record +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/latin1_enc.cpp +FN:6,_Z8latinfoob +FNDA:1,_Z8latinfoob +FNF:1 +FNH:1 +BRDA:10,0,0,1000 +BRDA:10,0,1,1 +BRDA:26,0,0,1000 +BRDA:26,0,1,1 +BRDA:27,0,0,500 +BRDA:27,0,1,500 +BRDA:29,0,0,1000 +BRDA:29,0,1,0 +BRF:8 +BRH:7 +DA:6,1 +DA:8,1 +DA:10,1001 +DA:13,1000 +DA:14,1000 +DA:26,1001 +DA:27,1000 +DA:29,1000 +DA:30,1000 +DA:33,1 +LF:10 +LH:10 +end_of_record +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:2,_Z3foob +FNF:1 +FNH:1 +BRDA:7,0,0,2000 +BRDA:7,0,1,2 +BRDA:10,0,0,0 +BRDA:10,0,1,2000 +BRF:4 +BRH:3 +DA:3,2 +DA:5,2 +DA:7,2002 +DA:8,2000 +DA:10,2000 +DA:11,0 +DA:14,2 +LF:7 +LH:6 +end_of_record +TN:ExampleTest +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:20,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,20 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,20 +DA:5,20 +DA:6,20 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine4b.info b/test/functional/expected_results/combine4b.info new file mode 100644 index 0000000..5027e95 --- /dev/null +++ b/test/functional/expected_results/combine4b.info @@ -0,0 +1,128 @@ +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/branches.cpp +FN:11,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNDA:3,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNF:1 +FNH:1 +BRDA:18,0,0,1 +BRDA:18,0,1,2 +BRDA:20,0,0,0 +BRDA:20,0,1,2 +BRDA:26,0,0,7 +BRDA:26,0,1,3 +BRDA:30,0,0,12 +BRDA:30,0,1,3 +BRDA:36,0,0,1 +BRDA:36,0,1,2 +BRDA:36,1,2,1 +BRDA:36,1,3,0 +BRDA:36,2,4,1 +BRDA:36,2,5,2 +BRDA:44,0,0,1 +BRDA:44,0,1,0 +BRDA:44,1,2,2 +BRF:17 +BRH:14 +DA:11,3 +DA:13,6 +DA:14,18 +DA:15,6 +DA:17,3 +DA:18,3 +DA:19,1 +DA:20,2 +DA:21,0 +DA:23,2 +DA:25,3 +DA:26,10 +DA:27,7 +DA:29,3 +DA:30,15 +DA:31,12 +DA:32,12 +DA:36,3 +DA:37,1 +DA:39,1 +DA:40,1 +DA:44,3 +DA:45,1 +DA:46,1 +DA:47,1 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,2 +DA:52,2 +DA:53,2 +DA:56,6 +LF:32 +LH:28 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/latin1_enc.cpp +FN:6,_Z8latinfoob +FNDA:1,_Z8latinfoob +FNF:1 +FNH:1 +BRDA:10,0,0,1000 +BRDA:10,0,1,1 +BRDA:26,0,0,1000 +BRDA:26,0,1,1 +BRDA:27,0,0,500 +BRDA:27,0,1,500 +BRDA:29,0,0,1000 +BRDA:29,0,1,0 +BRF:8 +BRH:7 +DA:6,1 +DA:8,1 +DA:10,1001 +DA:13,1000 +DA:14,1000 +DA:26,1001 +DA:27,1000 +DA:29,1000 +DA:30,1000 +DA:33,1 +LF:10 +LH:10 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:2,_Z3foob +FNF:1 +FNH:1 +BRDA:7,0,0,2000 +BRDA:7,0,1,2 +BRDA:10,0,0,0 +BRDA:10,0,1,2000 +BRF:4 +BRH:3 +DA:3,2 +DA:5,2 +DA:7,2002 +DA:8,2000 +DA:10,2000 +DA:11,0 +DA:14,2 +LF:7 +LH:6 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:20,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,20 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,20 +DA:5,20 +DA:6,20 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/combine4c.info b/test/functional/expected_results/combine4c.info new file mode 100644 index 0000000..5027e95 --- /dev/null +++ b/test/functional/expected_results/combine4c.info @@ -0,0 +1,128 @@ +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/branches.cpp +FN:11,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNDA:3,_Z9branchfooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE +FNF:1 +FNH:1 +BRDA:18,0,0,1 +BRDA:18,0,1,2 +BRDA:20,0,0,0 +BRDA:20,0,1,2 +BRDA:26,0,0,7 +BRDA:26,0,1,3 +BRDA:30,0,0,12 +BRDA:30,0,1,3 +BRDA:36,0,0,1 +BRDA:36,0,1,2 +BRDA:36,1,2,1 +BRDA:36,1,3,0 +BRDA:36,2,4,1 +BRDA:36,2,5,2 +BRDA:44,0,0,1 +BRDA:44,0,1,0 +BRDA:44,1,2,2 +BRF:17 +BRH:14 +DA:11,3 +DA:13,6 +DA:14,18 +DA:15,6 +DA:17,3 +DA:18,3 +DA:19,1 +DA:20,2 +DA:21,0 +DA:23,2 +DA:25,3 +DA:26,10 +DA:27,7 +DA:29,3 +DA:30,15 +DA:31,12 +DA:32,12 +DA:36,3 +DA:37,1 +DA:39,1 +DA:40,1 +DA:44,3 +DA:45,1 +DA:46,1 +DA:47,1 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,2 +DA:52,2 +DA:53,2 +DA:56,6 +LF:32 +LH:28 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/latin1_enc.cpp +FN:6,_Z8latinfoob +FNDA:1,_Z8latinfoob +FNF:1 +FNH:1 +BRDA:10,0,0,1000 +BRDA:10,0,1,1 +BRDA:26,0,0,1000 +BRDA:26,0,1,1 +BRDA:27,0,0,500 +BRDA:27,0,1,500 +BRDA:29,0,0,1000 +BRDA:29,0,1,0 +BRF:8 +BRH:7 +DA:6,1 +DA:8,1 +DA:10,1001 +DA:13,1000 +DA:14,1000 +DA:26,1001 +DA:27,1000 +DA:29,1000 +DA:30,1000 +DA:33,1 +LF:10 +LH:10 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:2,_Z3foob +FNF:1 +FNH:1 +BRDA:7,0,0,2000 +BRDA:7,0,1,2 +BRDA:10,0,0,0 +BRDA:10,0,1,2000 +BRF:4 +BRH:3 +DA:3,2 +DA:5,2 +DA:7,2002 +DA:8,2000 +DA:10,2000 +DA:11,0 +DA:14,2 +LF:7 +LH:6 +end_of_record +TN:ExampleTest22 +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:20,_Z3barbii +FNF:1 +FNH:1 +BRDA:5,0,0,20 +BRDA:5,0,1,0 +BRF:2 +BRH:1 +DA:3,20 +DA:5,20 +DA:6,20 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/test1.expected.fastcov.json b/test/functional/expected_results/test1.expected.fastcov.json index 01a0381..aaeea78 100644 --- a/test/functional/expected_results/test1.expected.fastcov.json +++ b/test/functional/expected_results/test1.expected.fastcov.json @@ -1 +1,41 @@ -{"sources": {"/mnt/workspace/test/functional/cmake_project/src/source2.cpp": {"functions": {"_Z3barbii": {"start_line": 3, "execution_count": 10}}, "branches": {}, "lines": {"3": 10, "5": 10, "6": 10, "8": 0}}, "/mnt/workspace/test/functional/cmake_project/src/source1.cpp": {"functions": {"_Z3foob": {"start_line": 3, "execution_count": 1}}, "branches": {}, "lines": {"3": 1, "5": 1, "7": 1001, "8": 1000, "10": 1000, "11": 0, "14": 1}}}} \ No newline at end of file +{ + "sources": { + "/mnt/workspace/test/functional/cmake_project/src/source2.cpp": { + "": { + "functions": { + "_Z3barbii": { + "start_line": 3, + "execution_count": 10 + } + }, + "branches": {}, + "lines": { + "3": 10, + "5": 10, + "6": 10, + "8": 0 + } + } + }, + "/mnt/workspace/test/functional/cmake_project/src/source1.cpp": { + "": { + "functions": { + "_Z3foob": { + "start_line": 3, + "execution_count": 1 + } + }, + "branches": {}, + "lines": { + "3": 1, + "5": 1, + "7": 1001, + "8": 1000, + "10": 1000, + "11": 0, + "14": 1 + } + } + } + } +} \ No newline at end of file diff --git a/test/functional/expected_results/test1.tn.expected.info b/test/functional/expected_results/test1.tn.expected.info new file mode 100644 index 0000000..9262e25 --- /dev/null +++ b/test/functional/expected_results/test1.tn.expected.info @@ -0,0 +1,29 @@ +TN:FunctionalTest1 +SF:/mnt/workspace/test/functional/cmake_project/src/source1.cpp +FN:3,_Z3foob +FNDA:1,_Z3foob +FNF:1 +FNH:1 +DA:3,1 +DA:5,1 +DA:7,1001 +DA:8,1000 +DA:10,1000 +DA:11,0 +DA:14,1 +LF:7 +LH:6 +end_of_record +TN:FunctionalTest1 +SF:/mnt/workspace/test/functional/cmake_project/src/source2.cpp +FN:3,_Z3barbii +FNDA:10,_Z3barbii +FNF:1 +FNH:1 +DA:3,10 +DA:5,10 +DA:6,10 +DA:8,0 +LF:4 +LH:3 +end_of_record diff --git a/test/functional/expected_results/test2.expected.fastcov.json b/test/functional/expected_results/test2.expected.fastcov.json index 386bcad..02be2de 100644 --- a/test/functional/expected_results/test2.expected.fastcov.json +++ b/test/functional/expected_results/test2.expected.fastcov.json @@ -1 +1,55 @@ -{"sources": {"/mnt/workspace/test/functional/cmake_project/src/source2.cpp": {"functions": {"_Z3barbii": {"start_line": 3, "execution_count": 10}}, "branches": {"5": [10, 0]}, "lines": {"3": 10, "5": 10, "6": 10, "8": 0}}, "/mnt/workspace/test/functional/cmake_project/src/source1.cpp": {"functions": {"_Z3foob": {"start_line": 3, "execution_count": 1}}, "branches": {"7": [1000, 1], "10": [0, 1000]}, "lines": {"3": 1, "5": 1, "7": 1001, "8": 1000, "10": 1000, "11": 0, "14": 1}}}} \ No newline at end of file +{ + "sources": { + "/mnt/workspace/test/functional/cmake_project/src/source2.cpp": { + "": { + "functions": { + "_Z3barbii": { + "start_line": 3, + "execution_count": 10 + } + }, + "branches": { + "5": [ + 10, + 0 + ] + }, + "lines": { + "3": 10, + "5": 10, + "6": 10, + "8": 0 + } + } + }, + "/mnt/workspace/test/functional/cmake_project/src/source1.cpp": { + "": { + "functions": { + "_Z3foob": { + "start_line": 3, + "execution_count": 1 + } + }, + "branches": { + "7": [ + 1000, + 1 + ], + "10": [ + 0, + 1000 + ] + }, + "lines": { + "3": 1, + "5": 1, + "7": 1001, + "8": 1000, + "10": 1000, + "11": 0, + "14": 1 + } + } + } + } +} \ No newline at end of file diff --git a/test/functional/run_all.sh b/test/functional/run_all.sh index 1dee365..39f23af 100755 --- a/test/functional/run_all.sh +++ b/test/functional/run_all.sh @@ -37,19 +37,17 @@ ctest -R ctest_1 coverage run --append ${TEST_DIR}/fastcov.py --gcov gcov-9 --exclude cmake_project/test/ --lcov -o test1.actual.info cmp test1.actual.info ${TEST_DIR}/expected_results/test1.expected.info -coverage run --append ${TEST_DIR}/fastcov.py --gcov gcov-9 --exclude cmake_project/test/ --gcov-raw -o test1.actual.gcov.json -${TEST_DIR}/json_cmp.py test1.actual.gcov.json test1.actual.gcov.json #Just check we can parse it for now... gcov race conditions make it hard to compare against expected - coverage run --append ${TEST_DIR}/fastcov.py --gcov gcov-9 --exclude cmake_project/test/ -o test1.actual.fastcov.json ${TEST_DIR}/json_cmp.py test1.actual.fastcov.json ${TEST_DIR}/expected_results/test1.expected.fastcov.json +# Test the setting of the "testname" field +coverage run --append ${TEST_DIR}/fastcov.py -t FunctionalTest1 --gcov gcov-9 --exclude cmake_project/test/ --lcov -o test1.tn.actual.info +cmp test1.tn.actual.info ${TEST_DIR}/expected_results/test1.tn.expected.info + # Test (basic report info - with branches) coverage run --append ${TEST_DIR}/fastcov.py --exceptional-branch-coverage --gcov gcov-9 --exclude cmake_project/test/ --lcov -o test2.actual.info cmp test2.actual.info ${TEST_DIR}/expected_results/test2.expected.info -coverage run --append ${TEST_DIR}/fastcov.py --exceptional-branch-coverage --gcov gcov-9 --exclude cmake_project/test/ --gcov-raw -o test2.actual.gcov.json -${TEST_DIR}/json_cmp.py test2.actual.gcov.json test2.actual.gcov.json #Just check we can parse it for now... gcov race conditions make it hard to compare against expected - coverage run --append ${TEST_DIR}/fastcov.py --exceptional-branch-coverage --gcov gcov-9 --exclude cmake_project/test/ -o test2.actual.fastcov.json ${TEST_DIR}/json_cmp.py test2.actual.fastcov.json ${TEST_DIR}/expected_results/test2.expected.fastcov.json @@ -79,6 +77,30 @@ if coverage run --append ${TEST_DIR}/fastcov.py --gcov ${TEST_DIR}/fake-gcov.sh exit 1 fi +# Combine operation +coverage run --append ${TEST_DIR}/fastcov.py -C ${TEST_DIR}/expected_results/test2.expected.info ${TEST_DIR}/expected_results/test1.tn.expected.info --lcov -o combine1.actual.info +cmp combine1.actual.info ${TEST_DIR}/expected_results/combine1.expected.info + +# Combine operation - Mix and Match json/info +coverage run --append ${TEST_DIR}/fastcov.py -C ${TEST_DIR}/expected_results/test2.expected.fastcov.json ${TEST_DIR}/expected_results/test1.tn.expected.info --lcov -o combine1.actual.info +cmp combine1.actual.info ${TEST_DIR}/expected_results/combine1.expected.info + +# Combine operation- source files across coverage reports +${TEST_DIR}/fastcov.py --exceptional-branch-coverage --gcov gcov-9 --process-gcno --source-files ../src/source1.cpp --lcov -o combine.source1.actual.info +${TEST_DIR}/fastcov.py --exceptional-branch-coverage --gcov gcov-9 --process-gcno --source-files ../src/source2.cpp --lcov -o combine.source2.actual.info +coverage run --append ${TEST_DIR}/fastcov.py -C combine.source1.actual.info combine.source2.actual.info --lcov -o combine2.actual.info +cmp combine2.actual.info ${TEST_DIR}/expected_results/combine2.expected.info + +# Combine files with different function inclusion +coverage run --append ${TEST_DIR}/fastcov.py -C ${TEST_DIR}/expected_results/combine3b.info ${TEST_DIR}/expected_results/combine3a.info --lcov -o combine3.actual.info +cmp combine3.actual.info ${TEST_DIR}/expected_results/combine3.expected.info + +# Combine files with different test names +# Expected result generated with: +# lcov -a combine4a.info -a combine4b.info -a combine4c.info --rc lcov_branch_coverage=1 -o combine4.expected.info +coverage run --append ${TEST_DIR}/fastcov.py -C ${TEST_DIR}/expected_results/combine4a.info ${TEST_DIR}/expected_results/combine4b.info ${TEST_DIR}/expected_results/combine4c.info --lcov -o combine4.actual.info +cmp combine4.actual.info ${TEST_DIR}/expected_results/combine4.expected.info + # Run ctest_2 ${TEST_DIR}/fastcov.py --gcov gcov-9 --zerocounters # Clear previous test coverage ctest -R ctest_2 @@ -123,4 +145,5 @@ coverage run --append ${TEST_DIR}/fastcov.py --exceptional-branch-coverage --gco cmp multitest.actual.info ${TEST_DIR}/expected_results/multitest.expected.info # Write out coverage as xml -coverage xml -o coverage.xml \ No newline at end of file +coverage xml -o coverage.xml +# coverage html # Generate HTML report \ No newline at end of file diff --git a/test/run_tests.sh b/test/run_tests.sh index 0c12ea1..a6c240e 100755 --- a/test/run_tests.sh +++ b/test/run_tests.sh @@ -6,8 +6,12 @@ set -x # Fail on first error set -e +# Check that example project builds +cd ../example +./build.sh + # Run all unit tests -cd unit +cd ../test/unit ./run_all.sh # Run all functional Tests diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index da60c0c..5de9afa 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -32,3 +32,27 @@ def test_chunk(): assert len(list(fastcov.chunks(chunk_me, 4))) == len(expected) for i, chunk in enumerate(fastcov.chunks(chunk_me, 4)): assert chunk == expected[i] + +def test_addDicts(): + dict1 = {"a": 1} + dict2 = {"a": 0, "b": 1, "c": 200} + + # Should return a new dict + result = fastcov.addDicts(dict1, dict2) + assert(result == {"a": 1, "b": 1, "c": 200}) + + result2 = fastcov.addDicts(result, dict2) + assert(result2 == {"a": 1, "b": 2, "c": 400}) + +def test_addLists(): + list1 = [1,2,3,4] + list2 = [1,0,0,4] + list3 = [1,0] + + # Should return a new list + result = fastcov.addLists(list1, list2) + assert(result == [2,2,3,8]) + + # if lens are mismatched, make sure it chooses the bigger one + result = fastcov.addLists(list1, list3) + assert(result == list1) \ No newline at end of file diff --git a/test/unit/test_version_match.py b/test/unit/test_version_match.py index 374a43c..153ba23 100644 --- a/test/unit/test_version_match.py +++ b/test/unit/test_version_match.py @@ -34,4 +34,10 @@ def test_gcov_version_match(): with pytest.raises(SystemExit) as e: fastcov.checkGcovVersion((8,1,0)) assert e.type == SystemExit - assert e.value.code == 2 \ No newline at end of file + assert e.value.code == 2 + +def test_bad_combine_extension(): + with pytest.raises(SystemExit) as e: + fastcov.parseAndCombine(["badfile.bad"]) + assert e.type == SystemExit + assert e.value.code == 3 \ No newline at end of file