Since you have direct access to the UEFI builder object, I think you can use "thebuilder.ws" to get the workspace path instead of looking it up in the build vars.

---

I know many of these pre-existing files place parentheses around conditions. This is not really Pythonic and I suggest new code avoid it.

The code additions in this patch have mixed usage.

This has no parentheses:

  if thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "GCC5":

This does:

  if(ret != 0):

So, it would be:

  if ret != 0:

This is probably not worth sending a new patch over alone but something to consider if making other updates.

Reviewed-by: Michael Kubacki <michael.kuba...@microsoft.com>

On 9/29/2022 9:53 PM, Guo, Gua wrote:
From: Gua Guo <gua....@intel.com>

For GCC, use lcov to generate Unit Test code coverage
report

For VS2019, use OpenCppCoverage to generate code
coverage report

Cc: Bob Feng <bob.c.f...@intel.com>
Cc: Bret Barkelew <bret.barke...@microsoft.com>
Cc: Liming Gao <gaolim...@bysoft.com.cn>
Cc: Michael D Kinney <michael.d.kin...@intel.com>
Cc: Sean Brogan <sean.bro...@microsoft.com>
Signed-off-by: Gua Guo <gua....@intel.com>
---
  .../HostBasedUnitTestRunner.py                | 119 ++++++++++++++++++
  1 file changed, 119 insertions(+)

diff --git 
a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py 
b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py
index c1eeaf2625..d92de236dc 100644
--- a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py
+++ b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py
@@ -112,4 +112,123 @@ class HostBasedUnitTestRunner(IUefiBuildPlugin):
                                              "  %s - %s" % 
(case.attrib['name'], result.text))

                                          failure_count += 1

+            if thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "GCC5":

+                self.gen_code_coverage_gcc(thebuilder)

+            elif thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "VS2019":

+                self.gen_code_coverage_msvc(thebuilder)

+            else:

+                logging.info("Skipping code coverage. Only supported on GCC.")

+

          return failure_count

+

+    def gen_code_coverage_gcc(self, thebuilder):

+        logging.info("Generating UnitTest code coverage")

+

+        buildOutputBase = thebuilder.env.GetValue("BUILD_OUTPUT_BASE")

+        workspace = thebuilder.env.GetValue("WORKSPACE")

+

+        # Generate base code coverage for all source files

+        ret = RunCmd("lcov", f"--no-external --capture --initial --directory 
{buildOutputBase} --output-file {buildOutputBase}/cov-base.info --rc lcov_branch_coverage=1")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to build initial coverage 
data.")

+            return 1

+

+        # Coverage data for tested files only

+        ret = RunCmd("lcov", f"--capture --directory {buildOutputBase}/ 
--output-file {buildOutputBase}/coverage-test.info --rc lcov_branch_coverage=1")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to build coverage data for 
tested files.")

+            return 1

+

+        # Aggregate all coverage data

+        ret = RunCmd("lcov", f"--add-tracefile {buildOutputBase}/cov-base.info 
--add-tracefile {buildOutputBase}/coverage-test.info --output-file 
{buildOutputBase}/total-coverage.info --rc lcov_branch_coverage=1")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to aggregate coverage 
data.")

+            return 1

+

+        # Generate coverage XML

+        ret = RunCmd("lcov_cobertura",f"{buildOutputBase}/total-coverage.info -o 
{buildOutputBase}/compare.xml")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to generate coverage 
XML.")

+            return 1

+

+        # Filter out auto-generated and test code

+        ret = RunCmd("lcov_cobertura",f"{buildOutputBase}/total-coverage.info 
--excludes ^.*UnitTest\|^.*MU\|^.*Mock\|^.*DEBUG -o {buildOutputBase}/coverage.xml")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed generate filtered coverage 
XML.")

+            return 1

+

+        # Generate all coverage file

+        testCoverageList = glob.glob 
(f"{workspace}/Build/**/total-coverage.info", recursive=True)

+

+        coverageFile = ""

+        for testCoverage in testCoverageList:

+            coverageFile += " --add-tracefile " + testCoverage

+        ret = RunCmd("lcov", f"{coverageFile} --output-file 
{workspace}/Build/all-coverage.info --rc lcov_branch_coverage=1")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed generate all coverage 
file.")

+            return 1

+

+        # Generate and HTML file if requested.by each package

+        ret = RunCmd("pycobertura", f"show --format html --output 
{buildOutputBase}/coverage.html {buildOutputBase}/coverage.xml --source {workspace}")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to generate HTML in single 
package..")

+

+        # Generate and HTML file if requested.for all package

+        if os.path.isfile(f"{workspace}/Build/coverage.xml"):

+            os.remove(f"{workspace}/Build/coverage.xml")

+        ret = RunCmd("lcov_cobertura",f"{workspace}/Build/all-coverage.info 
--excludes ^.*UnitTest\|^.*MU\|^.*Mock\|^.*DEBUG -o {workspace}/Build/coverage.xml")

+

+        if os.path.isfile(f"{workspace}/Build/coverage.html"):

+            os.remove(f"{workspace}/Build/coverage.html")

+        ret = RunCmd("pycobertura", f"show --format html --output 
{workspace}/Build/coverage.html {workspace}/Build/coverage.xml --source {workspace}")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to generate HTML.")

+

+        return 0

+

+

+    def gen_code_coverage_msvc(self, thebuilder):

+        logging.info("Generating UnitTest code coverage")

+

+

+        buildOutputBase = thebuilder.env.GetValue("BUILD_OUTPUT_BASE")

+        testList = glob.glob(os.path.join(buildOutputBase, "**","*Test*.exe"), 
recursive=True)

+        workspace = thebuilder.env.GetValue("WORKSPACE")

+

+        # Generate coverage file

+        coverageFile = ""

+        for testFile in testList:

+            ret = RunCmd("OpenCppCoverage", f"--source {workspace} --export_type 
binary:{testFile}.cov -- {testFile}")

+            coverageFile += " --input_coverage=" + testFile + ".cov"

+            if(ret != 0):

+                logging.error("UnitTest Coverage: Failed to collect coverage 
data.")

+                return 1

+

+        # Generate and HTML file if requested.by each package

+        ret = RunCmd("OpenCppCoverage", f"--export_type 
cobertura:{buildOutputBase}/coverage.xml --working_dir={workspace}/Build {coverageFile}")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to generate cobertura format 
xml in single package.")

+            return 1

+

+        ret = RunCmd("pycobertura", f"show --format html --output 
{buildOutputBase}/cverage.html {buildOutputBase}/coverage.xml --source {workspace}")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to generate HTML in single 
package.")

+            return 1

+

+        # Generate total report HTML file for all package

+        testCoverageList = glob.glob(os.path.join(workspace, "Build", 
"**","*Test*.exe.cov"), recursive=True)

+        coverageFile = ""

+        for testCoverage in testCoverageList:

+            coverageFile += " --input_coverage=" + testCoverage

+

+        ret = RunCmd("OpenCppCoverage", f"--export_type 
cobertura:{workspace}/Build/coverage.xml --working_dir={workspace}/Build {coverageFile}")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to generate cobertura format 
xml.")

+            return 1

+

+        ret = RunCmd("pycobertura", f"show --format html --output 
{workspace}/Build/coverage.html {workspace}/Build/coverage.xml --source {workspace}")

+        if(ret != 0):

+            logging.error("UnitTest Coverage: Failed to generate HTML.")

+            return 1

+

+        return 0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#97658): https://edk2.groups.io/g/devel/message/97658
Mute This Topic: https://groups.io/mt/94008686/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to