From nobody Mon Feb 9 04:07:49 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+97837+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+97837+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1672658712; cv=none; d=zohomail.com; s=zohoarc; b=gyzUiP1FlIeK2l4scMQTnRjreF1AtH5HvlIwLbGTioN5AXUIF8FHQGVvWewvSecm0KZXQT3BDHlbphdkf2LLQx38VaryBx4dKH9fubRBriWdA6qj/yi99xYEnAEGOI2AtUgBmUytOGtBwu9vlFWOkVdZTtgRlrhq9bJ5pIzg+jc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1672658712; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=S2bqmEVaBe/W/qRUMNV/MfWm2SnChuyloHdDGZCFWD8=; b=bZWIMSa7I12/EjmElr1HvTpm8/SsEFwMrGe3AYKjG/lFz4zFmFC26gCj5c2vjCYbrr+oRgiWvpH4hsWgnu2cOYc4rY1WRHx4qiYYOrFDH01Mb6xL9sG8pVDB6qjfojW/lYkEahMqQmXjMgOdNvgBvi2B9nG/kQs808G/nu6MFRY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+97837+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1672658712379615.5518360651926; Mon, 2 Jan 2023 03:25:12 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id S4IXYY1788612xdivyFFpE4F; Mon, 02 Jan 2023 03:25:11 -0800 X-Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mx.groups.io with SMTP id smtpd.web10.33685.1672658710894079090 for ; Mon, 02 Jan 2023 03:25:11 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10577"; a="385903981" X-IronPort-AV: E=Sophos;i="5.96,293,1665471600"; d="scan'208";a="385903981" X-Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Jan 2023 03:25:10 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10577"; a="656454237" X-IronPort-AV: E=Sophos;i="5.96,293,1665471600"; d="scan'208";a="656454237" X-Received: from gguo-desk.gar.corp.intel.com ([10.5.215.23]) by fmsmga007.fm.intel.com with ESMTP; 02 Jan 2023 03:25:08 -0800 From: "Guo, Gua" To: devel@edk2.groups.io Cc: Gua Guo , Bob Feng , Bret Barkelew , Liming Gao , Michael D Kinney , Sean Brogan Subject: [edk2-devel] [PATCH v8 2/3] BaseTools/Plugin: Add coverage support for Unit Test Date: Mon, 2 Jan 2023 19:25:01 +0800 Message-Id: <8c33c1252be5f9b6b733b47a434a955a68ec9d0f.1672658424.git.gua.guo@intel.com> In-Reply-To: References: MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,gua.guo@intel.com X-Gm-Message-State: Wi88uP0qA8PFgP9wWMZ8fLTax1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1672658711; bh=rjilPCFzValra/R6QvIc4y0AAHCzVYC5xWJyHdFwA8A=; h=Cc:Date:From:Reply-To:Subject:To; b=uqq4OySWveRB25DDzpzK0AuRgV7EZfXp78pxuTnPPBZqpAW3HR3zu2TimLkVcbcrOPA 1aRvYT10ldnAGK4E0/F7G3gdgNE2bLldNqsj+ye8th69QUia8Wfg/vVeGwko8mmKeAP4y U1AjItOa/jW5T+viJHshJtA5DIF2sngh/Jw= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1672658714854100012 Content-Type: text/plain; charset="utf-8" From: Gua Guo For GCC, use lcov to generate Unit Test code coverage report For VS2019, use OpenCppCoverage to generate code coverage report Cc: Bob Feng Cc: Bret Barkelew Cc: Liming Gao Cc: Michael D Kinney Cc: Sean Brogan Signed-off-by: Gua Guo --- .../HostBasedUnitTestRunner.py | 101 +++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunn= er.py b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py index a8220aacd3..0e013c5f1a 100644 --- a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py +++ b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py @@ -94,7 +94,7 @@ class HostBasedUnitTestRunner(IUefiBuildPlugin): =20 # Run the test. ret =3D RunCmd('"' + test + '"', "", workingdir=3Dcp) - if(ret !=3D 0): + if ret !=3D 0: logging.error("UnitTest Execution Error: " + os.path.basename(test)) else: @@ -115,4 +115,103 @@ class HostBasedUnitTestRunner(IUefiBuildPlugin): " %s - %s" % (case.attrib['na= me'], result.text)) failure_count +=3D 1 =20 + if thebuilder.env.GetValue("CODE_COVERAGE") !=3D "FALSE": + if thebuilder.env.GetValue("TOOL_CHAIN_TAG") =3D=3D "GCC5": + self.gen_code_coverage_gcc(thebuilder) + elif thebuilder.env.GetValue("TOOL_CHAIN_TAG").startswith = ("VS"): + self.gen_code_coverage_msvc(thebuilder) + else: + logging.info("Skipping code coverage. Currently, suppo= rt GCC and MSVC compiler.") + return failure_count + + def gen_code_coverage_gcc(self, thebuilder): + logging.info("Generating UnitTest code coverage") + + buildOutputBase =3D thebuilder.env.GetValue("BUILD_OUTPUT_BASE") + workspace =3D thebuilder.env.GetValue("WORKSPACE") + + # Generate base code coverage for all source files + ret =3D RunCmd("lcov", f"--no-external --capture --initial --direc= tory {buildOutputBase} --output-file {buildOutputBase}/cov-base.info --rc l= cov_branch_coverage=3D1") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed to build initial cove= rage data.") + return 1 + + # Coverage data for tested files only + ret =3D RunCmd("lcov", f"--capture --directory {buildOutputBase}/ = --output-file {buildOutputBase}/coverage-test.info --rc lcov_branch_coverag= e=3D1") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed to build coverage dat= a for tested files.") + return 1 + + # Aggregate all coverage data + ret =3D RunCmd("lcov", f"--add-tracefile {buildOutputBase}/cov-bas= e.info --add-tracefile {buildOutputBase}/coverage-test.info --output-file {= buildOutputBase}/total-coverage.info --rc lcov_branch_coverage=3D1") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed to aggregate coverage= data.") + return 1 + + # Generate coverage XML + ret =3D RunCmd("lcov_cobertura",f"{buildOutputBase}/total-coverage= .info -o {buildOutputBase}/compare.xml") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed to generate coverage = XML.") + return 1 + + # Filter out auto-generated and test code + ret =3D RunCmd("lcov_cobertura",f"{buildOutputBase}/total-coverage= .info --excludes ^.*UnitTest\|^.*MU\|^.*Mock\|^.*DEBUG -o {buildOutputBase}= /coverage.xml") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed generate filtered cov= erage XML.") + return 1 + + # Generate all coverage file + testCoverageList =3D glob.glob (f"{workspace}/Build/**/total-cover= age.info", recursive=3DTrue) + + coverageFile =3D "" + for testCoverage in testCoverageList: + coverageFile +=3D " --add-tracefile " + testCoverage + ret =3D RunCmd("lcov", f"{coverageFile} --output-file {workspace}/= Build/all-coverage.info --rc lcov_branch_coverage=3D1") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed generate all coverage= file.") + return 1 + + # Generate and XML file if requested.for all package + if os.path.isfile(f"{workspace}/Build/coverage.xml"): + os.remove(f"{workspace}/Build/coverage.xml") + ret =3D RunCmd("lcov_cobertura",f"{workspace}/Build/all-coverage.i= nfo --excludes ^.*UnitTest\|^.*MU\|^.*Mock\|^.*DEBUG -o {workspace}/Build/c= overage.xml") + + return 0 + + + def gen_code_coverage_msvc(self, thebuilder): + logging.info("Generating UnitTest code coverage") + + + buildOutputBase =3D thebuilder.env.GetValue("BUILD_OUTPUT_BASE") + testList =3D glob.glob(os.path.join(buildOutputBase, "**","*Test*.= exe"), recursive=3DTrue) + workspace =3D thebuilder.env.GetValue("WORKSPACE") + workspace =3D (workspace + os.sep) if workspace[-1] !=3D os.sep el= se workspace + # Generate coverage file + coverageFile =3D "" + for testFile in testList: + ret =3D RunCmd("OpenCppCoverage", f"--source {workspace} --exp= ort_type binary:{testFile}.cov -- {testFile}") + coverageFile +=3D " --input_coverage=3D" + testFile + ".cov" + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed to collect covera= ge data.") + return 1 + + # Generate and XML file if requested.by each package + ret =3D RunCmd("OpenCppCoverage", f"--export_type cobertura:{os.pa= th.join(buildOutputBase, 'coverage.xml')} --working_dir=3D{workspace}Build = {coverageFile}") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed to generate cobertura= format xml in single package.") + return 1 + + # Generate total report XML file for all package + testCoverageList =3D glob.glob(os.path.join(workspace, "Build", "*= *","*Test*.exe.cov"), recursive=3DTrue) + coverageFile =3D "" + for testCoverage in testCoverageList: + coverageFile +=3D " --input_coverage=3D" + testCoverage + + ret =3D RunCmd("OpenCppCoverage", f"--export_type cobertura:{works= pace}Build/coverage.xml --working_dir=3D{workspace}Build {coverageFile}") + if ret !=3D 0: + logging.error("UnitTest Coverage: Failed to generate cobertura= format xml.") + return 1 + + return 0 --=20 2.31.1.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#97837): https://edk2.groups.io/g/devel/message/97837 Mute This Topic: https://groups.io/mt/96004852/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-