From f8afad6f22786ba646cbd10a73e5738884cc84b8 Mon Sep 17 00:00:00 2001 From: Irina Iancu Date: Wed, 1 Aug 2018 09:29:01 -0700 Subject: Add a parser for gcov intermediate file format. This change comes as a preparation for using gcov for Bazel C++ coverage instead of lcov. See documentation of gcov intermediate format at https://gcc.gnu.org/onlinedocs/gcc/Invoking-Gcov.html#Invoking-Gcov under --intermediate-format. Change-Id: I6cd2df8b3a6611b187a2b0c161b14388413bc670 PiperOrigin-RevId: 206940660 --- .../java/com/google/devtools/lcovmerger/BUILD | 30 +++- .../google/devtools/lcovmerger/BranchCoverage.java | 23 +-- .../com/google/devtools/lcovmerger/Constants.java | 50 ++++++ .../com/google/devtools/lcovmerger/Coverage.java | 15 ++ .../com/google/devtools/lcovmerger/GcovParser.java | 196 +++++++++++++++++++++ .../google/devtools/lcovmerger/LcovConstants.java | 38 ---- .../com/google/devtools/lcovmerger/LcovParser.java | 66 +++---- .../google/devtools/lcovmerger/LcovPrinter.java | 44 ++--- .../java/com/google/devtools/lcovmerger/Main.java | 112 ++++++++---- .../com/google/devtools/lcovmerger/Parser.java | 23 +++ .../devtools/lcovmerger/SourceFileCoverage.java | 8 + .../javatests/com/google/devtools/lcovmerger/BUILD | 25 ++- .../devtools/lcovmerger/BranchCoverageTest.java | 68 +------ .../google/devtools/lcovmerger/GcovParserTest.java | 129 ++++++++++++++ .../com/google/devtools/lcovmerger/MainTest.java | 6 +- 15 files changed, 622 insertions(+), 211 deletions(-) create mode 100644 tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Constants.java create mode 100644 tools/test/LcovMerger/java/com/google/devtools/lcovmerger/GcovParser.java delete mode 100644 tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovConstants.java create mode 100644 tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Parser.java create mode 100644 tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/GcovParserTest.java (limited to 'tools') diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BUILD b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BUILD index 38e0816a95..7af7779a78 100644 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BUILD +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BUILD @@ -56,8 +56,8 @@ java_library( srcs = ["LcovPrinter.java"], deps = [ ":BranchCoverage", + ":Constants", ":Coverage", - ":LcovConstants", ":LineCoverage", ":SourceFileCoverage", "//third_party:guava", @@ -65,16 +65,33 @@ java_library( ) java_library( - name = "LcovConstants", - srcs = ["LcovConstants.java"], + name = "Constants", + srcs = ["Constants.java"], +) + +java_library( + name = "GcovParser", + srcs = [ + "GcovParser.java", + "Parser.java", + ], + deps = [ + ":BranchCoverage", + ":Constants", + ":LineCoverage", + ":SourceFileCoverage", + ], ) java_library( name = "LcovParser", - srcs = ["LcovParser.java"], + srcs = [ + "LcovParser.java", + "Parser.java", + ], deps = [ ":BranchCoverage", - ":LcovConstants", + ":Constants", ":LineCoverage", ":SourceFileCoverage", ], @@ -90,8 +107,9 @@ java_library( name = "MainLibrary", srcs = ["Main.java"], deps = [ + ":Constants", ":Coverage", - ":LcovConstants", + ":GcovParser", ":LcovParser", ":LcovPrinter", ":SourceFileCoverage", diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BranchCoverage.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BranchCoverage.java index 0fbe78311a..bc12dc6098 100644 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BranchCoverage.java +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/BranchCoverage.java @@ -22,15 +22,14 @@ import com.google.auto.value.AutoValue; @AutoValue abstract class BranchCoverage { - static BranchCoverage create( - int lineNumber, - String blockNumber, - String branchNumber, - boolean wasExecuted, - int nrOfExecutions) { - assert (wasExecuted && nrOfExecutions > 0) || (!wasExecuted && nrOfExecutions == 0); + static BranchCoverage create(int lineNumber, int nrOfExecutions) { return new AutoValue_BranchCoverage( - lineNumber, blockNumber, branchNumber, wasExecuted, nrOfExecutions); + lineNumber, /*blockNumber=*/ "", /*branchNumber=*/ "", nrOfExecutions); + } + + static BranchCoverage createWithBlockAndBranch( + int lineNumber, String blockNumber, String branchNumber, int nrOfExecutions) { + return new AutoValue_BranchCoverage(lineNumber, blockNumber, branchNumber, nrOfExecutions); } /** @@ -44,11 +43,10 @@ abstract class BranchCoverage { assert first.blockNumber().equals(second.blockNumber()); assert first.branchNumber().equals(second.branchNumber()); - return create( + return createWithBlockAndBranch( first.lineNumber(), first.blockNumber(), first.branchNumber(), - first.wasExecuted() || second.wasExecuted(), first.nrOfExecutions() + second.nrOfExecutions()); } @@ -56,6 +54,9 @@ abstract class BranchCoverage { // The two numbers below should be -1 for non-gcc emitted coverage (e.g. Java). abstract String blockNumber(); // internal gcc internal ID for the branch abstract String branchNumber(); // internal gcc internal ID for the branch - abstract boolean wasExecuted(); abstract int nrOfExecutions(); + + boolean wasExecuted() { + return nrOfExecutions() > 0; + } } diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Constants.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Constants.java new file mode 100644 index 0000000000..9a8fe88850 --- /dev/null +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Constants.java @@ -0,0 +1,50 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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. + +package com.google.devtools.lcovmerger; + +/** + * Stores markers used by the lcov tracefile and gcov intermediate format file. See lcov documentation and the flag + * {@code --intermediate-format} in + * gcov documentation. + */ +class Constants { + static final String SF_MARKER = "SF:"; + static final String FN_MARKER = "FN:"; + static final String FNDA_MARKER = "FNDA:"; + static final String FNF_MARKER = "FNF:"; + static final String FNH_MARKER = "FNH:"; + static final String BRDA_MARKER = "BRDA:"; + static final String BA_MARKER = "BA:"; + static final String BRF_MARKER = "BRF:"; + static final String BRH_MARKER = "BRH:"; + static final String DA_MARKER = "DA:"; + static final String LH_MARKER = "LH:"; + static final String LF_MARKER = "LF:"; + static final String END_OF_RECORD_MARKER = "end_of_record"; + static final String TAKEN = "-"; + static final String TRACEFILE_EXTENSION = ".dat"; + static final String DELIMITER = ","; + static final String GCOV_EXTENSION = ".gcov"; + static final String GCOV_VERSION_MARKER = "version:"; + static final String GCOV_CWD_MARKER = "cwd:"; + static final String GCOV_FILE_MARKER = "file:"; + static final String GCOV_FUNCTION_MARKER = "function:"; + static final String GCOV_LINE_MARKER = "lcount:"; + static final String GCOV_BRANCH_MARKER = "branch:"; + static final String GCOV_BRANCH_NOTEXEC = "notexec"; + static final String GCOV_BRANCH_NOTTAKEN = "taken"; + static final String GCOV_BRANCH_TAKEN = "nottaken"; +} diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Coverage.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Coverage.java index 82733aa84a..75eaa420cc 100644 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Coverage.java +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Coverage.java @@ -34,6 +34,21 @@ class Coverage { } } + static Coverage merge(Coverage c1, Coverage c2) { + Coverage merged = new Coverage(); + for (SourceFileCoverage sourceFile : c1.getAllSourceFiles()) { + merged.add(sourceFile); + } + for (SourceFileCoverage sourceFile : c2.getAllSourceFiles()) { + merged.add(sourceFile); + } + return merged; + } + + boolean isEmpty() { + return sourceFiles.isEmpty(); + } + Collection getAllSourceFiles() { return sourceFiles.values(); } diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/GcovParser.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/GcovParser.java new file mode 100644 index 0000000000..25592192b2 --- /dev/null +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/GcovParser.java @@ -0,0 +1,196 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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. + +package com.google.devtools.lcovmerger; + +import static com.google.devtools.lcovmerger.Constants.DELIMITER; +import static com.google.devtools.lcovmerger.Constants.GCOV_BRANCH_MARKER; +import static com.google.devtools.lcovmerger.Constants.GCOV_BRANCH_NOTEXEC; +import static com.google.devtools.lcovmerger.Constants.GCOV_BRANCH_NOTTAKEN; +import static com.google.devtools.lcovmerger.Constants.GCOV_BRANCH_TAKEN; +import static com.google.devtools.lcovmerger.Constants.GCOV_CWD_MARKER; +import static com.google.devtools.lcovmerger.Constants.GCOV_FILE_MARKER; +import static com.google.devtools.lcovmerger.Constants.GCOV_FUNCTION_MARKER; +import static com.google.devtools.lcovmerger.Constants.GCOV_LINE_MARKER; +import static com.google.devtools.lcovmerger.Constants.GCOV_VERSION_MARKER; +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A {@link Parser} for gcov intermediate format. See the flag {@code --intermediate-format} in gcov documentation. + */ +public class GcovParser { + + private static final Logger logger = Logger.getLogger(GcovParser.class.getName()); + private List allSourceFiles; + private final InputStream inputStream; + private SourceFileCoverage currentSourceFileCoverage; + + private GcovParser(InputStream inputStream) { + this.inputStream = inputStream; + } + + public static List parse(InputStream inputStream) throws IOException { + return new GcovParser(inputStream).parse(); + } + + private List parse() throws IOException { + allSourceFiles = new ArrayList<>(); + boolean malformedInput = false; + try (BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(inputStream, UTF_8))) { + String line; + // TODO(bazel-team): This is susceptible to OOM if the input file is too large and doesn't + // contain any newlines. + while ((line = bufferedReader.readLine()) != null) { + if (!parseLine(line)) { + malformedInput = true; + } + } + bufferedReader.close(); + } + endSourceFile(); + if (malformedInput) { + throw new IOException("gcov intermediate input is malformed."); + } + return allSourceFiles; + } + + /** + * Merges {@code currentSourceFileCoverage} into {@code allSourceFilesCoverageData} and resets + * {@code currentSourceFileCoverage} to null. + */ + private void endSourceFile() { + if (currentSourceFileCoverage == null) { + return; + } + allSourceFiles.add(currentSourceFileCoverage); + currentSourceFileCoverage = null; + } + + private boolean parseLine(String line) { + if (line.startsWith(GCOV_FILE_MARKER)) { + endSourceFile(); + return parseSource(line); + } + if (line.startsWith(GCOV_FUNCTION_MARKER)) { + return parseFunction(line); + } + if (line.startsWith(GCOV_LINE_MARKER)) { + return parseLCount(line); + } + if (line.startsWith(GCOV_BRANCH_MARKER)) { + return parseBranch(line); + } + if (line.startsWith(GCOV_VERSION_MARKER) || line.startsWith(GCOV_CWD_MARKER)) { + // Ignore these fields for now as they are not necessary. + return true; + } + return false; + } + + private boolean parseSource(String line) { + String sourcefile = line.substring(GCOV_FILE_MARKER.length()); + if (sourcefile.isEmpty()) { + logger.log(Level.WARNING, "gcov info doesn't contain source file name on line: " + line); + return false; + } + currentSourceFileCoverage = new SourceFileCoverage(sourcefile); + return true; + } + + // function:start_line_number,end_line_number,execution_count,function_name + private boolean parseFunction(String line) { + String lineContent = line.substring(GCOV_FUNCTION_MARKER.length()); + String[] items = lineContent.split(DELIMITER, -1); + if (items.length != 4) { + logger.log(Level.WARNING, "gcov info contains invalid line " + line); + return false; + } + try { + // Ignore end_line_number since it's redundant information. + int startLine = Integer.parseInt(items[0]); + int execCount = Integer.parseInt(items[2]); + String functionName = items[3]; + currentSourceFileCoverage.addLineNumber(functionName, startLine); + currentSourceFileCoverage.addFunctionExecution(functionName, execCount); + } catch (NumberFormatException e) { + logger.log(Level.WARNING, "gcov info contains invalid line " + line); + return false; + } + return true; + } + + // lcount:line number,execution_count,has_unexecuted_block + private boolean parseLCount(String line) { + String lineContent = line.substring(GCOV_LINE_MARKER.length()); + String[] items = lineContent.split(DELIMITER, -1); + if (items.length != 3) { + logger.log(Level.WARNING, "gcov info contains invalid line " + line); + return false; + } + try { + // Ignore has_unexecuted_block since it's not used. + int lineNr = Integer.parseInt(items[0]); + int execCount = Integer.parseInt(items[1]); + currentSourceFileCoverage.addLine(lineNr, LineCoverage.create(lineNr, execCount, null)); + } catch (NumberFormatException e) { + logger.log(Level.WARNING, "gcov info contains invalid line " + line); + return false; + } + return true; + } + + // branch:line_number,branch_coverage_type + private boolean parseBranch(String line) { + String lineContent = line.substring(GCOV_BRANCH_MARKER.length()); + String[] items = lineContent.split(DELIMITER, -1); + if (items.length != 2) { + logger.log(Level.WARNING, "gcov info contains invalid line " + line); + return false; + } + try { + // Ignore has_unexecuted_block since it's not used. + int lineNr = Integer.parseInt(items[0]); + String type = items[1]; + int execCount; + switch (type) { + case GCOV_BRANCH_NOTEXEC: + execCount = 0; + break; + case GCOV_BRANCH_NOTTAKEN: + case GCOV_BRANCH_TAKEN: + execCount = 1; + break; + default: + logger.log(Level.WARNING, "gcov info contains invalid line " + line); + return false; + } + currentSourceFileCoverage.addBranch(lineNr, BranchCoverage.create(lineNr, execCount)); + } catch (NumberFormatException e) { + logger.log(Level.WARNING, "gcov info contains invalid line " + line); + return false; + } + return true; + } +} diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovConstants.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovConstants.java deleted file mode 100644 index 83c6ce5f85..0000000000 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovConstants.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 The Bazel Authors. All rights reserved. -// -// 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. - -package com.google.devtools.lcovmerger; - -/** - * Stores markers used by the lcov tracefile. See - * lcov documentation - */ -class LcovConstants { - static final String SF_MARKER = "SF:"; - static final String FN_MARKER = "FN:"; - static final String FNDA_MARKER = "FNDA:"; - static final String FNF_MARKER = "FNF:"; - static final String FNH_MARKER = "FNH:"; - static final String BRDA_MARKER = "BRDA:"; - static final String BA_MARKER = "BA:"; - static final String BRF_MARKER = "BRF:"; - static final String BRH_MARKER = "BRH:"; - static final String DA_MARKER = "DA:"; - static final String LH_MARKER = "LH:"; - static final String LF_MARKER = "LF:"; - static final String END_OF_RECORD_MARKER = "end_of_record"; - static final String LCOV_DELIMITER = ","; - static final String TAKEN = "-"; - static final String TRACEFILE_EXTENSION = ".dat"; -} diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovParser.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovParser.java index b441b8761e..64062db60b 100644 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovParser.java +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovParser.java @@ -14,21 +14,21 @@ package com.google.devtools.lcovmerger; -import static com.google.devtools.lcovmerger.LcovConstants.BA_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.BRDA_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.BRF_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.BRH_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.DA_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.END_OF_RECORD_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.FNDA_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.FNF_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.FNH_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.FN_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.LCOV_DELIMITER; -import static com.google.devtools.lcovmerger.LcovConstants.LF_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.LH_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.SF_MARKER; -import static com.google.devtools.lcovmerger.LcovConstants.TAKEN; +import static com.google.devtools.lcovmerger.Constants.BA_MARKER; +import static com.google.devtools.lcovmerger.Constants.BRDA_MARKER; +import static com.google.devtools.lcovmerger.Constants.BRF_MARKER; +import static com.google.devtools.lcovmerger.Constants.BRH_MARKER; +import static com.google.devtools.lcovmerger.Constants.DA_MARKER; +import static com.google.devtools.lcovmerger.Constants.DELIMITER; +import static com.google.devtools.lcovmerger.Constants.END_OF_RECORD_MARKER; +import static com.google.devtools.lcovmerger.Constants.FNDA_MARKER; +import static com.google.devtools.lcovmerger.Constants.FNF_MARKER; +import static com.google.devtools.lcovmerger.Constants.FNH_MARKER; +import static com.google.devtools.lcovmerger.Constants.FN_MARKER; +import static com.google.devtools.lcovmerger.Constants.LF_MARKER; +import static com.google.devtools.lcovmerger.Constants.LH_MARKER; +import static com.google.devtools.lcovmerger.Constants.SF_MARKER; +import static com.google.devtools.lcovmerger.Constants.TAKEN; import static java.nio.charset.StandardCharsets.UTF_8; import java.io.BufferedReader; @@ -47,19 +47,15 @@ import java.util.logging.Logger; class LcovParser { private static final Logger logger = Logger.getLogger(LcovParser.class.getName()); + private final InputStream inputStream; private SourceFileCoverage currentSourceFileCoverage; - private final InputStream tracefileStream; - private LcovParser(InputStream tracefileStream) { - this.tracefileStream = tracefileStream; + private LcovParser(InputStream inputStream) { + this.inputStream = inputStream; } - /** - * Returns a list of the source files found in the given tracefile. - */ - public static List parse(InputStream tracefileStream) throws IOException { - LcovParser lcovParser = new LcovParser(tracefileStream); - return lcovParser.parse(); + public static List parse(InputStream inputStream) throws IOException { + return new LcovParser(inputStream).parse(); } /** @@ -72,7 +68,7 @@ class LcovParser { private List parse() throws IOException { List allSourceFiles = new ArrayList<>(); try (BufferedReader bufferedReader = - new BufferedReader(new InputStreamReader(tracefileStream, UTF_8))) { + new BufferedReader(new InputStreamReader(inputStream, UTF_8))) { String line; while ((line = bufferedReader.readLine()) != null) { parseLine(line, allSourceFiles); @@ -164,7 +160,7 @@ class LcovParser { // FN:, private boolean parseFNLine(String line) { String lineContent = line.substring(FN_MARKER.length()); - String[] funcData = lineContent.split(LCOV_DELIMITER, -1); + String[] funcData = lineContent.split(DELIMITER, -1); if (funcData.length != 2 || funcData[0].isEmpty() || funcData[1].isEmpty()) { logger.log(Level.WARNING, "Tracefile contains invalid FN line " + line); return false; @@ -183,7 +179,7 @@ class LcovParser { // FNDA:, private boolean parseFNDALine(String line) { String lineContent = line.substring(FNDA_MARKER.length()); - String[] funcData = lineContent.split(LCOV_DELIMITER, -1); + String[] funcData = lineContent.split(DELIMITER, -1); if (funcData.length != 2 || funcData[0].isEmpty() || funcData[1].isEmpty()) { logger.log(Level.WARNING, "Tracefile contains invalid FNDA line " + line); return false; @@ -238,7 +234,7 @@ class LcovParser { // BA:, private boolean parseBALine(String line) { String lineContent = line.substring(BA_MARKER.length()); - String[] lineData = lineContent.split(LCOV_DELIMITER, -1); + String[] lineData = lineContent.split(DELIMITER, -1); if (lineData.length != 2) { logger.log(Level.WARNING, "Tracefile contains invalid BRDA line " + line); return false; @@ -253,12 +249,7 @@ class LcovParser { int lineNumber = Integer.parseInt(lineData[0]); int taken = Integer.parseInt(lineData[1]); - boolean wasExecuted = false; - if (taken == 1 || taken == 2) { - wasExecuted = true; - } - BranchCoverage branchCoverage = - BranchCoverage.create(lineNumber, "", "", wasExecuted, taken); + BranchCoverage branchCoverage = BranchCoverage.create(lineNumber, taken); currentSourceFileCoverage.addBranch(lineNumber, branchCoverage); } catch (NumberFormatException e) { @@ -271,7 +262,7 @@ class LcovParser { // BRDA:,,, private boolean parseBRDALine(String line) { String lineContent = line.substring(BRDA_MARKER.length()); - String[] lineData = lineContent.split(LCOV_DELIMITER, -1); + String[] lineData = lineContent.split(DELIMITER, -1); if (lineData.length != 4) { logger.log(Level.WARNING, "Tracefile contains invalid BRDA line " + line); return false; @@ -295,7 +286,8 @@ class LcovParser { wasExecuted = true; } BranchCoverage branchCoverage = - BranchCoverage.create(lineNumber, blockNumber, branchNumber, wasExecuted, executionCount); + BranchCoverage.createWithBlockAndBranch( + lineNumber, blockNumber, branchNumber, executionCount); currentSourceFileCoverage.addBranch(lineNumber, branchCoverage); } catch (NumberFormatException e) { @@ -344,7 +336,7 @@ class LcovParser { // DA:,,[,] private boolean parseDALine(String line) { String lineContent = line.substring(DA_MARKER.length()); - String[] lineData = lineContent.split(LCOV_DELIMITER, -1); + String[] lineData = lineContent.split(DELIMITER, -1); if (lineData.length != 2 && lineData.length != 3) { logger.log(Level.WARNING, "Tracefile contains invalid DA line " + line); return false; diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovPrinter.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovPrinter.java index ef5f9e16ad..7fa6ccc38b 100644 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovPrinter.java +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/LcovPrinter.java @@ -88,7 +88,7 @@ class LcovPrinter { // SF: private void printSFLine(SourceFileCoverage sourceFile) throws IOException { - bufferedWriter.write(LcovConstants.SF_MARKER); + bufferedWriter.write(Constants.SF_MARKER); bufferedWriter.write(sourceFile.sourceFileName()); bufferedWriter.newLine(); } @@ -97,9 +97,9 @@ class LcovPrinter { private void printFNLines(SourceFileCoverage sourceFile) throws IOException { for (Entry entry : sourceFile.getAllLineNumbers()) { - bufferedWriter.write(LcovConstants.FN_MARKER); + bufferedWriter.write(Constants.FN_MARKER); bufferedWriter.write(Integer.toString(entry.getValue())); // line number of function start - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); bufferedWriter.write(entry.getKey()); // function name bufferedWriter.newLine(); } @@ -109,9 +109,9 @@ class LcovPrinter { private void printFNDALines(SourceFileCoverage sourceFile) throws IOException { for (Entry entry : sourceFile.getAllExecutionCount()) { - bufferedWriter.write(LcovConstants.FNDA_MARKER); + bufferedWriter.write(Constants.FNDA_MARKER); bufferedWriter.write(Integer.toString(entry.getValue())); // execution count - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); bufferedWriter.write(entry.getKey()); // function name bufferedWriter.newLine(); } @@ -119,14 +119,14 @@ class LcovPrinter { // FNF: private void printFNFLine(SourceFileCoverage sourceFile) throws IOException { - bufferedWriter.write(LcovConstants.FNF_MARKER); + bufferedWriter.write(Constants.FNF_MARKER); bufferedWriter.write(Integer.toString(sourceFile.nrFunctionsFound())); bufferedWriter.newLine(); } // FNH: private void printFNHLine(SourceFileCoverage sourceFile) throws IOException { - bufferedWriter.write(LcovConstants.FNH_MARKER); + bufferedWriter.write(Constants.FNH_MARKER); bufferedWriter.write(Integer.toString(sourceFile.nrFunctionsHit())); bufferedWriter.newLine(); } @@ -138,17 +138,17 @@ class LcovPrinter { // We skip printing this as a BRDA line and print it later as a BA line. continue; } - bufferedWriter.write(LcovConstants.BRDA_MARKER); + bufferedWriter.write(Constants.BRDA_MARKER); bufferedWriter.write(Integer.toString(branch.lineNumber())); - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); bufferedWriter.write(branch.blockNumber()); - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); bufferedWriter.write(branch.branchNumber()); - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); if (branch.wasExecuted()) { bufferedWriter.write(Integer.toString(branch.nrOfExecutions())); } else { - bufferedWriter.write(LcovConstants.TAKEN); + bufferedWriter.write(Constants.TAKEN); } bufferedWriter.newLine(); } @@ -161,9 +161,9 @@ class LcovPrinter { // This branch was already printed with more information as a BRDA line. continue; } - bufferedWriter.write(LcovConstants.BA_MARKER); + bufferedWriter.write(Constants.BA_MARKER); bufferedWriter.write(Integer.toString(branch.lineNumber())); - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); // 0 = branch was not executed // 1 = branch was executed but not taken // 2 = branch was executed and taken @@ -175,7 +175,7 @@ class LcovPrinter { // BRF: private void printBRFLine(SourceFileCoverage sourceFile) throws IOException { if (sourceFile.nrBranchesFound() > 0) { - bufferedWriter.write(LcovConstants.BRF_MARKER); + bufferedWriter.write(Constants.BRF_MARKER); bufferedWriter.write(Integer.toString(sourceFile.nrBranchesFound())); bufferedWriter.newLine(); } @@ -185,7 +185,7 @@ class LcovPrinter { private void printBRHLine(SourceFileCoverage sourceFile) throws IOException { // Only print if there were any branches found. if (sourceFile.nrBranchesFound() > 0) { - bufferedWriter.write(LcovConstants.BRH_MARKER); + bufferedWriter.write(Constants.BRH_MARKER); bufferedWriter.write(Integer.toString(sourceFile.nrBranchesHit())); bufferedWriter.newLine(); } @@ -195,12 +195,12 @@ class LcovPrinter { private void printDALines(SourceFileCoverage sourceFile) throws IOException { for (LineCoverage lineExecution : sourceFile.getAllLineExecution()) { - bufferedWriter.write(LcovConstants.DA_MARKER); + bufferedWriter.write(Constants.DA_MARKER); bufferedWriter.write(Integer.toString(lineExecution.lineNumber())); - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); bufferedWriter.write(Integer.toString(lineExecution.executionCount())); if (lineExecution.checksum() != null) { - bufferedWriter.write(LcovConstants.LCOV_DELIMITER); + bufferedWriter.write(Constants.DELIMITER); bufferedWriter.write(lineExecution.checksum()); } bufferedWriter.newLine(); @@ -209,21 +209,21 @@ class LcovPrinter { // LH: private void printLHLine(SourceFileCoverage sourceFile) throws IOException { - bufferedWriter.write(LcovConstants.LH_MARKER); + bufferedWriter.write(Constants.LH_MARKER); bufferedWriter.write(Integer.toString(sourceFile.nrOfLinesWithNonZeroExecution())); bufferedWriter.newLine(); } // LF: private void printLFLine(SourceFileCoverage sourceFile) throws IOException { - bufferedWriter.write(LcovConstants.LF_MARKER); + bufferedWriter.write(Constants.LF_MARKER); bufferedWriter.write(Integer.toString(sourceFile.nrOfInstrumentedLines())); bufferedWriter.newLine(); } // end_of_record private void printEndOfRecordLine() throws IOException { - bufferedWriter.write(LcovConstants.END_OF_RECORD_MARKER); + bufferedWriter.write(Constants.END_OF_RECORD_MARKER); bufferedWriter.newLine(); } } diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Main.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Main.java index 2984d7b274..b490765383 100644 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Main.java +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Main.java @@ -14,7 +14,8 @@ package com.google.devtools.lcovmerger; -import static com.google.devtools.lcovmerger.LcovConstants.TRACEFILE_EXTENSION; +import static com.google.devtools.lcovmerger.Constants.GCOV_EXTENSION; +import static com.google.devtools.lcovmerger.Constants.TRACEFILE_EXTENSION; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.common.annotations.VisibleForTesting; @@ -28,6 +29,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,65 +53,107 @@ public class Main { System.exit(1); } + List filesInCoverageDir = + flags.containsKey("coverage_dir") + ? getCoverageFilesInDir(flags.get("coverage_dir")) + : Collections.emptyList(); + Coverage coverage = + Coverage.merge( + parseFiles(getTracefiles(flags, filesInCoverageDir), LcovParser::parse), + parseFiles(getGcovInfoFiles(filesInCoverageDir), GcovParser::parse)); + + if (coverage.isEmpty()) { + logger.log(Level.SEVERE, "There was no coverage found."); + System.exit(1); + } + + int exitStatus = 0; + String outputFile = flags.get("output_file"); + try { + LcovPrinter.print(new FileOutputStream(new File(outputFile)), coverage); + } catch (IOException e) { + logger.log( + Level.SEVERE, + "Could not write to output file " + outputFile + " due to " + e.getMessage()); + exitStatus = 1; + } + System.exit(exitStatus); + } + + private static List getGcovInfoFiles(List filesInCoverageDir) { + List gcovFiles = getFilesWithExtension(filesInCoverageDir, GCOV_EXTENSION); + if (gcovFiles.isEmpty()) { + logger.log(Level.SEVERE, "No gcov info file found."); + } else { + logger.log(Level.INFO, "Found " + gcovFiles.size() + " gcov info files."); + } + return gcovFiles; + } + + private static List getTracefiles( + Map flags, List filesInCoverageDir) { List lcovTracefiles = new ArrayList<>(); if (flags.containsKey("coverage_dir")) { - logger.log(Level.SEVERE, "Retrieving tracefiles from coverage_dir."); - lcovTracefiles = getLcovTracefilesFromDir(flags.get("coverage_dir")); + lcovTracefiles = getFilesWithExtension(filesInCoverageDir, TRACEFILE_EXTENSION); } else if (flags.containsKey("reports_file")) { - logger.log(Level.SEVERE, "Retrieving tracefiles from reports_file."); - lcovTracefiles = getLcovTracefilesFromFile(flags.get("reports_file")); + lcovTracefiles = getTracefilesFromFile(flags.get("reports_file")); } if (lcovTracefiles.isEmpty()) { logger.log(Level.SEVERE, "No lcov file found."); - System.exit(1); + } else { + logger.log(Level.INFO, "Found " + lcovTracefiles.size() + " tracefiles."); } - logger.log(Level.SEVERE, "Found " + lcovTracefiles.size() + " tracefiles."); + return lcovTracefiles; + } + + private static Coverage parseFiles(List files, Parser parser) { Coverage coverage = new Coverage(); - for (File tracefile : lcovTracefiles) { + for (File file : files) { try { - logger.log(Level.SEVERE, "Parsing tracefile " + tracefile.toString()); - List sourceFilesCoverage = - LcovParser.parse(new FileInputStream(tracefile)); + logger.log(Level.SEVERE, "Parsing file " + file.toString()); + List sourceFilesCoverage = parser.parse(new FileInputStream(file)); for (SourceFileCoverage sourceFileCoverage : sourceFilesCoverage) { coverage.add(sourceFileCoverage); } } catch (IOException e) { - logger.log(Level.SEVERE, "Tracefile " + tracefile.getAbsolutePath() + " was deleted"); + logger.log( + Level.SEVERE, + "File " + file.getAbsolutePath() + " could not be parsed due to: " + e.getMessage()); System.exit(1); } } - int exitStatus = 0; - String outputFile = flags.get("output_file"); - try { - File coverageFile = new File(outputFile); - LcovPrinter.print(new FileOutputStream(coverageFile), coverage); - } catch (IOException e) { - logger.log(Level.SEVERE, - "Could not write to output file " + outputFile + " due to " + e.getMessage()); - exitStatus = 1; - } - System.exit(exitStatus); + return coverage; } /** - * Returns a list of all the files with a “.dat” extension found recursively under the given - * directory. + * Returns a list of all the files with the given extension found recursively under the given dir. */ @VisibleForTesting - static List getLcovTracefilesFromDir(String coverageDir) { - List datFiles = new ArrayList<>(); - try (Stream stream = Files.walk(Paths.get(coverageDir))) { - datFiles = stream.filter(p -> p.toString().endsWith(TRACEFILE_EXTENSION)) - .map(path -> path.toFile()) - .collect(Collectors.toList()); + static List getCoverageFilesInDir(String dir) { + List files = new ArrayList<>(); + try (Stream stream = Files.walk(Paths.get(dir))) { + files = + stream + .filter( + p -> + p.toString().endsWith(TRACEFILE_EXTENSION) + || p.toString().endsWith(GCOV_EXTENSION)) + .map(path -> path.toFile()) + .collect(Collectors.toList()); } catch (IOException ex) { - logger.log(Level.SEVERE, "Error reading folder " + coverageDir + ": " + ex.getMessage()); + logger.log(Level.SEVERE, "Error reading folder " + dir + ": " + ex.getMessage()); } + return files; + } - return datFiles; + static List getFilesWithExtension(List files, String extension) { + return files + .stream() + .filter(file -> file.toString().endsWith(extension)) + .collect(Collectors.toList()); } - static List getLcovTracefilesFromFile(String reportsFile) { + static List getTracefilesFromFile(String reportsFile) { List datFiles = new ArrayList<>(); try (FileInputStream inputStream = new FileInputStream(reportsFile)) { InputStreamReader inputStreamReader = new InputStreamReader(inputStream, UTF_8); diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Parser.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Parser.java new file mode 100644 index 0000000000..4cfafdce07 --- /dev/null +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/Parser.java @@ -0,0 +1,23 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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. + +package com.google.devtools.lcovmerger; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +interface Parser { + List parse(InputStream inputStream) throws IOException; +} diff --git a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/SourceFileCoverage.java b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/SourceFileCoverage.java index 0cdb1a6f85..b98a873a8c 100644 --- a/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/SourceFileCoverage.java +++ b/tools/test/LcovMerger/java/com/google/devtools/lcovmerger/SourceFileCoverage.java @@ -237,6 +237,10 @@ class SourceFileCoverage { } void addBranch(Integer lineNumber, BranchCoverage branch) { + if (this.branches.get(lineNumber) != null) { + this.branches.put(lineNumber, BranchCoverage.merge(this.branches.get(lineNumber), branch)); + return; + } this.branches.put(lineNumber, branch); } @@ -245,6 +249,10 @@ class SourceFileCoverage { } void addLine(Integer lineNumber, LineCoverage line) { + if (this.lines.get(lineNumber) != null) { + this.lines.put(lineNumber, LineCoverage.merge(line, this.lines.get(lineNumber))); + return; + } this.lines.put(lineNumber, line); } diff --git a/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BUILD b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BUILD index daf81b51d3..51a6e0bcf8 100644 --- a/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BUILD +++ b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BUILD @@ -6,6 +6,7 @@ java_test( name = "BranchCoverageTest", srcs = ["BranchCoverageTest.java"], deps = [ + "//third_party:guava", "//third_party:junit4", "//third_party:truth", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:BranchCoverage", @@ -16,6 +17,7 @@ java_test( name = "LineCoverageTest", srcs = ["LineCoverageTest.java"], deps = [ + "//third_party:guava", "//third_party:junit4", "//third_party:truth", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:LineCoverage", @@ -28,6 +30,7 @@ java_test( deps = [ ":LcovMergerTestUtils", ":LineCoverageTest", + "//third_party:guava", "//third_party:junit4", "//third_party:truth", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:LineCoverage", @@ -43,8 +46,8 @@ java_test( "//third_party:guava", "//third_party:junit4", "//third_party:truth", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:Constants", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:Coverage", - "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:LcovConstants", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:LcovPrinter", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:SourceFileCoverage", ], @@ -58,13 +61,30 @@ java_test( "//third_party:guava", "//third_party:junit4", "//third_party:truth", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:Constants", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:Coverage", - "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:LcovConstants", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:LcovParser", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:SourceFileCoverage", ], ) +java_test( + name = "GcovParserTest", + srcs = ["GcovParserTest.java"], + deps = [ + ":LcovMergerTestUtils", + "//third_party:guava", + "//third_party:junit4", + "//third_party:truth", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:BranchCoverage", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:Constants", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:Coverage", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:GcovParser", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:LineCoverage", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:SourceFileCoverage", + ], +) + java_test( name = "CoverageTest", srcs = ["CoverageTest.java"], @@ -85,6 +105,7 @@ java_test( ":LcovMergerTestUtils", "//third_party:junit4", "//third_party:truth", + "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:Constants", "//tools/test/LcovMerger/java/com/google/devtools/lcovmerger:MainLibrary", ], ) diff --git a/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BranchCoverageTest.java b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BranchCoverageTest.java index 2e0056e700..85003ef1d7 100644 --- a/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BranchCoverageTest.java +++ b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/BranchCoverageTest.java @@ -30,59 +30,41 @@ public class BranchCoverageTest { private static final int BRANCH1_LINE_NR = 10; private static final String BRANCH1_BLOCK_NR = "3"; private static final String BRANCH1_BRANCH_NR = "2"; - private static final boolean BRANCH1_WAS_EXECUTED = false; private static final int BRANCH1_NR_EXECUTIONS = 0; - private static final boolean BRANCH1_OTHER_TRACEFILE_WAS_EXECUTED = true; private static final int BRANCH1_OTHER_TRACEFILE_NR_EXECUTIONS = 5; private static final int BRANCH2_LINE_NR = 20; private static final String BRANCH2_BLOCK_NR = "7"; private static final String BRANCH2_BRANCH_NR = "2"; - private static final boolean BRANCH2_WAS_EXECUTED = false; private static final int BRANCH2_NR_EXECUTIONS = 0; - private static final boolean BRANCH2_OTHER_TRACEFILE_WAS_EXECUTED = false; private static final int BRANCH2_OTHER_TRACEFILE_NR_EXECUTIONS = 0; static final BranchCoverage getBranch1CoverageData() { - return BranchCoverage.create( - BRANCH1_LINE_NR, - BRANCH1_BLOCK_NR, - BRANCH1_BRANCH_NR, - BRANCH1_WAS_EXECUTED, - BRANCH1_NR_EXECUTIONS - ); + return BranchCoverage.createWithBlockAndBranch( + BRANCH1_LINE_NR, BRANCH1_BLOCK_NR, BRANCH1_BRANCH_NR, BRANCH1_NR_EXECUTIONS); } static final BranchCoverage getBranch2CoverageData() { - return BranchCoverage.create( - BRANCH2_LINE_NR, - BRANCH2_BLOCK_NR, - BRANCH2_BRANCH_NR, - BRANCH2_WAS_EXECUTED, - BRANCH2_NR_EXECUTIONS - ); + return BranchCoverage.createWithBlockAndBranch( + BRANCH2_LINE_NR, BRANCH2_BLOCK_NR, BRANCH2_BRANCH_NR, BRANCH2_NR_EXECUTIONS); } static final BranchCoverage getBranch1OtherTracefileCoverageData() { - return BranchCoverage.create( + return BranchCoverage.createWithBlockAndBranch( BRANCH1_LINE_NR, BRANCH1_BLOCK_NR, BRANCH1_BRANCH_NR, - BRANCH1_OTHER_TRACEFILE_WAS_EXECUTED, - BRANCH1_OTHER_TRACEFILE_NR_EXECUTIONS - ); + BRANCH1_OTHER_TRACEFILE_NR_EXECUTIONS); } static final BranchCoverage getBranch2OtherTracefileCoverageData() { - return BranchCoverage.create( + return BranchCoverage.createWithBlockAndBranch( BRANCH2_LINE_NR, BRANCH2_BLOCK_NR, BRANCH2_BRANCH_NR, - BRANCH2_OTHER_TRACEFILE_WAS_EXECUTED, - BRANCH2_OTHER_TRACEFILE_NR_EXECUTIONS - ); + BRANCH2_OTHER_TRACEFILE_NR_EXECUTIONS); } @Test @@ -109,7 +91,7 @@ public class BranchCoverageTest { assertThat(merged.wasExecuted()).isFalse(); assertThat(merged.nrOfExecutions()).isEqualTo(0); } - + @Test public void testMergeBranch1Branch2AssertationError() { BranchCoverage branch1 = getBranch1CoverageData(); @@ -121,36 +103,4 @@ public class BranchCoverageTest { } fail(); } - - @Test - public void testcreateBranchCoverageDataInvalidWasExecutedTrue() { - try { - BranchCoverage.create( - BRANCH1_LINE_NR, - BRANCH1_BLOCK_NR, - BRANCH1_BRANCH_NR, - true, - 0 - ); - } catch (AssertionError er) { - return; - } - fail(); - } - - @Test - public void testcreateBranchCoverageDataInvalidWasExecutedFalse() { - try { - BranchCoverage.create( - BRANCH1_LINE_NR, - BRANCH1_BLOCK_NR, - BRANCH1_BRANCH_NR, - false, - 10 - ); - } catch (AssertionError er) { - return; - } - fail(); - } } diff --git a/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/GcovParserTest.java b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/GcovParserTest.java new file mode 100644 index 0000000000..85b069ef0e --- /dev/null +++ b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/GcovParserTest.java @@ -0,0 +1,129 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// 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. + +package com.google.devtools.lcovmerger; + +import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@GcovParser}. */ +@RunWith(JUnit4.class) +public class GcovParserTest { + + private static final ImmutableList GCOV_INFO_FILE = + ImmutableList.of( + "version: 8.1.0 20180103", + "cwd:/home/gcc/testcase", + "file:tmp.cpp", + "function:7,7,0,_ZN3FooIcEC2Ev", + "function:7,7,1,_ZN3FooIiEC2Ev", + "function:8,8,0,_ZN3FooIcE3incEv", + "function:8,8,2,_ZN3FooIiE3incEv", + "function:18,37,1,main", + "lcount:7,0,1", + "lcount:7,1,0", + "lcount:8,0,1", + "lcount:8,2,0", + "lcount:18,1,0", + "lcount:21,1,0", + "branch:21,taken", + "branch:21,nottaken", + "lcount:23,1,0", + "branch:23,taken", + "branch:23,nottaken", + "lcount:24,1,0", + "branch:24,taken", + "branch:24,nottaken", + "lcount:25,1,0", + "lcount:27,11,0", + "branch:27,taken", + "branch:27,taken", + "lcount:28,10,0", + "lcount:30,1,1", + "branch:30,nottaken", + "branch:30,taken", + "lcount:32,1,0", + "branch:32,nottaken", + "branch:32,taken", + "lcount:33,0,1", + "branch:33,notexec", + "branch:33,notexec", + "lcount:35,1,0", + "branch:35,taken", + "branch:35,nottaken", + "lcount:36,1,0"); + + @Test(expected = IOException.class) + public void testParseInvalidFile() throws IOException { + GcovParser.parse(new ByteArrayInputStream("Invalid gcov file".getBytes(UTF_8))); + } + + @Test + public void testParseTracefileWithOneSourcefile() throws IOException { + + List sourceFiles = + GcovParser.parse( + new ByteArrayInputStream(Joiner.on("\n").join(GCOV_INFO_FILE).getBytes(UTF_8))); + assertThat(sourceFiles).hasSize(1); + assertGcovInfoFile(sourceFiles.get(0)); + } + + private void assertGcovInfoFile(SourceFileCoverage sourceFileCoverage) { + assertThat(sourceFileCoverage.sourceFileName()).isEqualTo("tmp.cpp"); + + assertThat(sourceFileCoverage.nrFunctionsFound()).isEqualTo(5); + assertThat(sourceFileCoverage.nrFunctionsHit()).isEqualTo(3); + assertThat(sourceFileCoverage.nrOfInstrumentedLines()).isEqualTo(14); + assertThat(sourceFileCoverage.nrOfLinesWithNonZeroExecution()).isEqualTo(13); + assertThat(sourceFileCoverage.nrBranchesFound()).isEqualTo(8); + assertThat(sourceFileCoverage.nrBranchesHit()).isEqualTo(7); + + assertThat(sourceFileCoverage.getAllLineExecution()) + .containsExactly( + LineCoverage.create(7, 1, null), + LineCoverage.create(8, 2, null), + LineCoverage.create(18, 1, null), + LineCoverage.create(21, 1, null), + LineCoverage.create(23, 1, null), + LineCoverage.create(24, 1, null), + LineCoverage.create(25, 1, null), + LineCoverage.create(27, 11, null), + LineCoverage.create(28, 10, null), + LineCoverage.create(30, 1, null), + LineCoverage.create(32, 1, null), + LineCoverage.create(33, 0, null), + LineCoverage.create(35, 1, null), + LineCoverage.create(36, 1, null)); + + assertThat(sourceFileCoverage.getAllBranches()) + .containsExactly( + BranchCoverage.create(21, 2), + BranchCoverage.create(23, 2), + BranchCoverage.create(24, 2), + BranchCoverage.create(27, 2), + BranchCoverage.create(30, 2), + BranchCoverage.create(32, 2), + BranchCoverage.create(33, 0), + BranchCoverage.create(35, 2)); + } +} diff --git a/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/MainTest.java b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/MainTest.java index a6b99fb12e..e8a6c754bf 100644 --- a/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/MainTest.java +++ b/tools/test/LcovMerger/javatests/com/google/devtools/lcovmerger/MainTest.java @@ -15,6 +15,7 @@ package com.google.devtools.lcovmerger; import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.lcovmerger.Constants.TRACEFILE_EXTENSION; import java.io.File; import java.io.IOException; @@ -41,7 +42,7 @@ public class MainTest { @Test public void testMainEmptyCoverageDir() { - assertThat(Main.getLcovTracefilesFromDir(coverageDir.toAbsolutePath().toString())).isEmpty(); + assertThat(Main.getCoverageFilesInDir(coverageDir.toAbsolutePath().toString())).isEmpty(); } @Test @@ -52,7 +53,8 @@ public class MainTest { Files.createTempFile(ccCoverageDir, "tracefile1", ".dat"); Files.createTempFile(javaCoverageDir, "tracefile2", ".dat"); - List tracefiles = Main.getLcovTracefilesFromDir(coverageDir.toAbsolutePath().toString()); + List coverageFiles = Main.getCoverageFilesInDir(coverageDir.toAbsolutePath().toString()); + List tracefiles = Main.getFilesWithExtension(coverageFiles, TRACEFILE_EXTENSION); assertThat(tracefiles).hasSize(2); } } -- cgit v1.2.3