From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54051+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54051+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099240073201.02929660355858; Fri, 7 Feb 2020 10:14:00 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id jNR0YY1788612xKJerfruxr5; Fri, 07 Feb 2020 10:13:59 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web10.8964.1581099238804041597 for ; Fri, 07 Feb 2020 10:13:59 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:13:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500536" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:13:58 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew , Liming Gao Subject: [edk2-devel] [Patch v2 01/11] .pytool: Add CI support for host based unit tests with results Date: Fri, 7 Feb 2020 10:13:44 -0800 Message-Id: <20200207181354.31632-2-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: tdiEhvo6snfavFZINXnNQuOgx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099239; bh=V0bgRFNib7yaGcKfU/K8wDofgwA4qBhGWdPao1y/WkM=; h=Cc:Date:From:Reply-To:Subject:To; b=Y2pFa3I21iS0PTDo7ZTQEt6YDOGLEP/nASTcE+/IXYDsgM7wUO3yolTMNPmGhfdWSjh ISNWrPZGkKU+M3T3Uf+Nx5s9XeEyuMC6CBh/Tb8C4IMBsjKO78eFDBkhectOFLsp/3T38 4HEv98xay6WLaroQ+s3bwuNN5UT/T4NxYDw= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 * Add plugin to build and run host based unit tests * Add plugin that performs a DSC complete check DSC files used to build host based tests * Update DscCompleteCheck plugin to ignore module INFs with a MODULE_TYPE of HOST_APPLICATION and library INFs that only support a module type of HOST_APPLICATION. * Fix issues in XML reports from checkers. Cc: Sean Brogan Cc: Bret Barkelew Cc: Liming Gao Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew --- .pytool/CISettings.py | 22 ++++-- .../CharEncodingCheck/CharEncodingCheck.py | 2 +- .../Plugin/CompilerPlugin/CompilerPlugin.py | 4 +- .../Plugin/DependencyCheck/DependencyCheck.py | 2 +- .../DscCompleteCheck/DscCompleteCheck.py | 35 ++++++--- .pytool/Plugin/DscCompleteCheck/Readme.md | 7 +- .pytool/Plugin/GuidCheck/GuidCheck.py | 2 +- .../HostUnitTestCompilerPlugin.py} | 71 +++++++++++++++---- .../HostUnitTestCompiler_plug_in.yaml | 12 ++++ .../HostUnitTestCompilerPlugin/Readme.md | 24 +++++++ .../HostUnitTestDscCompleteCheck.py} | 58 ++++++++++----- .../HostUnitTestDscCompleteCheck_plug_in.yaml | 12 ++++ .../HostUnitTestDscCompleteCheck/Readme.md | 32 +++++++++ .../LibraryClassCheck/LibraryClassCheck.py | 2 +- 14 files changed, 231 insertions(+), 54 deletions(-) copy .pytool/Plugin/{CompilerPlugin/CompilerPlugin.py =3D> HostUnitTestCom= pilerPlugin/HostUnitTestCompilerPlugin.py} (54%) create mode 100644 .pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestC= ompiler_plug_in.yaml create mode 100644 .pytool/Plugin/HostUnitTestCompilerPlugin/Readme.md copy .pytool/Plugin/{DscCompleteCheck/DscCompleteCheck.py =3D> HostUnitTes= tDscCompleteCheck/HostUnitTestDscCompleteCheck.py} (62%) create mode 100644 .pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTes= tDscCompleteCheck_plug_in.yaml create mode 100644 .pytool/Plugin/HostUnitTestDscCompleteCheck/Readme.md diff --git a/.pytool/CISettings.py b/.pytool/CISettings.py index ce177937e1..79593d9dc5 100644 --- a/.pytool/CISettings.py +++ b/.pytool/CISettings.py @@ -48,7 +48,8 @@ class Settings(CiBuildSettingsManager, UpdateSettingsMana= ger, SetupSettingsManag "FmpDevicePkg", "ShellPkg", "FatPkg", - "CryptoPkg" + "CryptoPkg", + "UnitTestFrameworkPkg" ) =20 def GetArchitecturesSupported(self): @@ -117,10 +118,13 @@ class Settings(CiBuildSettingsManager, UpdateSettings= Manager, SetupSettingsManag =20 def GetActiveScopes(self): ''' return tuple containing scopes that should be active for this = process ''' - scopes =3D ("cibuild","edk2-build") + scopes =3D ("cibuild", "edk2-build", "host-based-test") =20 self.ActualToolChainTag =3D shell_environment.GetBuildVars().GetVa= lue("TOOL_CHAIN_TAG", "") =20 + if GetHostInfo().os.upper() =3D=3D "WINDOWS": + scopes +=3D ('host-test-win',) + if GetHostInfo().os.upper() =3D=3D "LINUX" and self.ActualToolChai= nTag.upper().startswith("GCC"): if "AARCH64" in self.ActualArchitectures: scopes +=3D ("gcc_aarch64_linux",) @@ -133,18 +137,21 @@ class Settings(CiBuildSettingsManager, UpdateSettings= Manager, SetupSettingsManag ''' return iterable containing RequiredSubmodule objects. If no RequiredSubmodules return an empty iterable ''' - rs=3D[] + rs =3D [] rs.append(RequiredSubmodule( "ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3", False)) rs.append(RequiredSubmodule( "CryptoPkg/Library/OpensslLib/openssl", False)) + rs.append(RequiredSubmodule( + "UnitTestFrameworkPkg/Library/CmockaLib/cmocka", False)) return rs =20 def GetName(self): return "Edk2" =20 def GetDependencies(self): - return [] + return [ + ] =20 def GetPackagesPath(self): return () @@ -155,10 +162,11 @@ class Settings(CiBuildSettingsManager, UpdateSettings= Manager, SetupSettingsManag =20 def FilterPackagesToTest(self, changedFilesList: list, potentialPackag= esList: list) -> list: ''' Filter potential packages to test based on changed files. ''' - build_these_packages=3D[] - possible_packages=3DpotentialPackagesList.copy() + build_these_packages =3D [] + possible_packages =3D potentialPackagesList.copy() for f in changedFilesList: - nodes=3Df.split("/") # split each part of path for comparison= later + # split each part of path for comparison later + nodes =3D f.split("/") =20 # python file change in .pytool folder causes building all if f.endswith(".py") and ".pytool" in nodes: diff --git a/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py b/.pytoo= l/Plugin/CharEncodingCheck/CharEncodingCheck.py index 02f25ab19f..1496e1f249 100644 --- a/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py +++ b/.pytool/Plugin/CharEncodingCheck/CharEncodingCheck.py @@ -100,7 +100,7 @@ class CharEncodingCheck(ICiBuildPlugin): overall_status +=3D 1 =20 tc.LogStdOut("Tested Encoding on {0} files".format(files_tested)) - if overall_status is not 0: + if overall_status !=3D 0: tc.SetFailed("CharEncoding {0} Failed. Errors {1}".format(pac= kagename, overall_status), "CHAR_ENCODING_CHECK_FAILED") else: tc.SetSuccess() diff --git a/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py b/.pytool/Plug= in/CompilerPlugin/CompilerPlugin.py index 3b6f7c7698..e8657940d7 100644 --- a/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py +++ b/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py @@ -1,4 +1,4 @@ -# @file HostUnitTestCompiler_plugin.py +# @file CompilerPlugin.py ## # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -42,7 +42,7 @@ class CompilerPlugin(ICiBuildPlugin): return ["DEBUG", "RELEASE"] =20 ## - # External function of plugin. This function is used to perform the t= ask of the MuBuild Plugin + # External function of plugin. This function is used to perform the t= ask of the ICiBuildPlugin Plugin # # - package is the edk2 path to package. This means workspace/packa= gepath relative. # - edk2path object configured with workspace and packages path diff --git a/.pytool/Plugin/DependencyCheck/DependencyCheck.py b/.pytool/Pl= ugin/DependencyCheck/DependencyCheck.py index 2c3d8baf69..db154d769a 100644 --- a/.pytool/Plugin/DependencyCheck/DependencyCheck.py +++ b/.pytool/Plugin/DependencyCheck/DependencyCheck.py @@ -113,7 +113,7 @@ class DependencyCheck(ICiBuildPlugin): overall_status +=3D 1 =20 # If XML object exists, add results - if overall_status is not 0: + if overall_status !=3D 0: tc.SetFailed("Failed with {0} errors".format(overall_status), = "DEPENDENCYCHECK_FAILED") else: tc.SetSuccess() diff --git a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py b/.pytool/= Plugin/DscCompleteCheck/DscCompleteCheck.py index 9af4f72c8d..c613cd5233 100644 --- a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py +++ b/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py @@ -54,12 +54,15 @@ class DscCompleteCheck(ICiBuildPlugin): # Parse the config for required DscPath element if "DscPath" not in pkgconfig: tc.SetSkipped() - tc.LogStdError("DscPath not found in config file. Nothing to = check.") + tc.LogStdError( + "DscPath not found in config file. Nothing to check.") return -1 =20 - abs_pkg_path =3D Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2Rel= ativePath(packagename) + abs_pkg_path =3D Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2Rel= ativePath( + packagename) abs_dsc_path =3D os.path.join(abs_pkg_path, pkgconfig["DscPath"].s= trip()) - wsr_dsc_path =3D Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(a= bs_dsc_path) + wsr_dsc_path =3D Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + abs_dsc_path) =20 if abs_dsc_path is None or wsr_dsc_path =3D=3D "" or not os.path.i= sfile(abs_dsc_path): tc.SetSkipped() @@ -68,7 +71,8 @@ class DscCompleteCheck(ICiBuildPlugin): =20 # Get INF Files INFFiles =3D self.WalkDirectoryForExtension([".inf"], abs_pkg_path) - INFFiles =3D [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) f= or x in INFFiles] # make edk2relative path so can compare with DSC + INFFiles =3D [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + x) for x in INFFiles] # make edk2relative path so can compare= with DSC =20 # remove ignores =20 @@ -79,8 +83,10 @@ class DscCompleteCheck(ICiBuildPlugin): tc.LogStdOut("Ignoring INF {0}".format(a)) INFFiles.remove(a) except: - tc.LogStdError("DscCompleteCheck.IgnoreInf -> {0} not = found in filesystem. Invalid ignore file".format(a)) - logging.info("DscCompleteCheck.IgnoreInf -> {0} not fo= und in filesystem. Invalid ignore file".format(a)) + tc.LogStdError( + "DscCompleteCheck.IgnoreInf -> {0} not found in fi= lesystem. Invalid ignore file".format(a)) + logging.info( + "DscCompleteCheck.IgnoreInf -> {0} not found in fi= lesystem. Invalid ignore file".format(a)) =20 # DSC Parser dp =3D DscParser() @@ -99,11 +105,19 @@ class DscCompleteCheck(ICiBuildPlugin): infp.SetPackagePaths(Edk2pathObj.PackagePathList) infp.ParseFile(INF) if("MODULE_TYPE" not in infp.Dict): - tc.LogStdOut("Ignoring INF. Missing key for MODULE_TYP= E {0}".format(INF)) + tc.LogStdOut( + "Ignoring INF. Missing key for MODULE_TYPE {0}".fo= rmat(INF)) continue =20 if(infp.Dict["MODULE_TYPE"] =3D=3D "HOST_APPLICATION"): - tc.LogStdOut("Ignoring INF. Module type is HOST_APPLI= CATION {0}".format(INF)) + tc.LogStdOut( + "Ignoring INF. Module type is HOST_APPLICATION {0= }".format(INF)) + continue + + if len(infp.SupportedPhases) =3D=3D 1 and \ + "HOST_APPLICATION" in infp.SupportedPhases: + tc.LogStdOut( + "Ignoring Library INF due to only supporting type = HOST_APPLICATION {0}".format(INF)) continue =20 logging.critical(INF + " not in " + wsr_dsc_path) @@ -111,8 +125,9 @@ class DscCompleteCheck(ICiBuildPlugin): overall_status =3D overall_status + 1 =20 # If XML object exists, add result - if overall_status is not 0: - tc.SetFailed("DscCompleteCheck {0} Failed. Errors {1}".format= (wsr_dsc_path, overall_status), "CHECK_FAILED") + if overall_status !=3D 0: + tc.SetFailed("DscCompleteCheck {0} Failed. Errors {1}".format( + wsr_dsc_path, overall_status), "CHECK_FAILED") else: tc.SetSuccess() return overall_status diff --git a/.pytool/Plugin/DscCompleteCheck/Readme.md b/.pytool/Plugin/Dsc= CompleteCheck/Readme.md index eefbb9894d..8aaa4f76ee 100644 --- a/.pytool/Plugin/DscCompleteCheck/Readme.md +++ b/.pytool/Plugin/DscCompleteCheck/Readme.md @@ -7,6 +7,11 @@ that it would not be built if the package were built). Thi= s is critical because much of the CI infrastructure assumes that all modules will be listed in t= he DSC and compiled. =20 +This test will ignore INFs in the following cases: + +1. When MODULE_TYPE =3D HOST_APPLICATION +2. When a Library instance **only** supports the HOST_APPLICATION environm= ent + ## Configuration =20 The plugin has a few configuration options to support the UEFI codebase. @@ -14,7 +19,7 @@ The plugin has a few configuration options to support the= UEFI codebase. ``` yaml "DscCompleteCheck": { "DscPath": "", # Path to dsc from root of package - "IgnoreInf": [] # Ignore INF if found in filesystem by not dsc + "IgnoreInf": [] # Ignore INF if found in filesystem but not dsc } ``` =20 diff --git a/.pytool/Plugin/GuidCheck/GuidCheck.py b/.pytool/Plugin/GuidChe= ck/GuidCheck.py index f0b10beb1e..61fdc77911 100644 --- a/.pytool/Plugin/GuidCheck/GuidCheck.py +++ b/.pytool/Plugin/GuidCheck/GuidCheck.py @@ -221,7 +221,7 @@ class GuidCheck(ICiBuildPlugin): =20 # add result to test case overall_status =3D len(Errors) - if overall_status is not 0: + if overall_status !=3D 0: tc.SetFailed("GuidCheck {0} Failed. Errors {1}".format( packagename, overall_status), "CHECK_FAILED") else: diff --git a/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py b/.pytool/Plug= in/HostUnitTestCompilerPlugin/HostUnitTestCompilerPlugin.py similarity index 54% copy from .pytool/Plugin/CompilerPlugin/CompilerPlugin.py copy to .pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompilerPlugi= n.py index 3b6f7c7698..f21b40caf2 100644 --- a/.pytool/Plugin/CompilerPlugin/CompilerPlugin.py +++ b/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompilerPlugin.= py @@ -1,4 +1,4 @@ -# @file HostUnitTestCompiler_plugin.py +# @file HostUnitTestCompilerPlugin.py ## # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -12,21 +12,25 @@ from edk2toolext.environment.plugintypes.ci_build_plugi= n import ICiBuildPlugin from edk2toolext.environment.uefi_build import UefiBuilder from edk2toolext import edk2_logging from edk2toolext.environment.var_dict import VarDict +from edk2toollib.utility_functions import GetHostInfo =20 =20 -class CompilerPlugin(ICiBuildPlugin): +class HostUnitTestCompilerPlugin(ICiBuildPlugin): """ - A CiBuildPlugin that compiles the package dsc - from the package being tested. + A CiBuildPlugin that compiles the dsc for host based unit test apps. + An IUefiBuildPlugin may be attached to this plugin that will run the + unit tests and collect the results after successful compilation. =20 Configuration options: - "CompilerPlugin": { + "HostUnitTestCompilerPlugin": { "DscPath": "" } """ =20 def GetTestName(self, packagename: str, environment: VarDict) -> tuple: """ Provide the testcase name and classname for use in reporting + testclassname: a descriptive string for the testcase can inclu= de whitespace + classname: should be patterned .. =20 Args: packagename: string containing name of package to build @@ -35,14 +39,41 @@ class CompilerPlugin(ICiBuildPlugin): a tuple containing the testcase name and the classname (testcasename, classname) """ - target =3D environment.GetValue("TARGET") - return ("Compile " + packagename + " " + target, packagename + ".C= ompiler." + target) + num,types =3D self.__GetHostUnitTestArch(environment) + types =3D types.replace(" ", "_") + + return ("Compile and Run Host-Based UnitTests for " + packagename = + " on arch " + types, + packagename + ".HostUnitTestCompiler." + types) =20 def RunsOnTargetList(self): - return ["DEBUG", "RELEASE"] + return ["NOOPT"] + + # + # Find the intersection of application types that can run on this host + # and the TARGET_ARCH being build in this request. + # + # return tuple with (number of UEFI arch types, space separated string) + def __GetHostUnitTestArch(self, environment): + requested =3D environment.GetValue("TARGET_ARCH").split(' ') + host =3D [] + if GetHostInfo().arch =3D=3D 'x86': + #assume 64bit can handle 64 and 32 + #assume 32bit can only handle 32 + ## change once IA32 issues resolved host.append("IA32") + if GetHostInfo().bit =3D=3D '64': + host.append("X64") + elif GetHostInfo().arch =3D=3D 'ARM': + if GetHostInfo().bit =3D=3D '64': + host.append("AARCH64") + elif GetHostInfo().bit =3D=3D '32': + host.append("ARM") + + willrun =3D set(requested) & set(host) + return (len(willrun), " ".join(willrun)) + =20 ## - # External function of plugin. This function is used to perform the t= ask of the MuBuild Plugin + # External function of plugin. This function is used to perform the t= ask of the ICiBuildPlugin Plugin # # - package is the edk2 path to package. This means workspace/packa= gepath relative. # - edk2path object configured with workspace and packages path @@ -54,11 +85,12 @@ class CompilerPlugin(ICiBuildPlugin): # - output_stream the StringIO output stream from this plugin via lo= gging def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environm= ent, PLM, PLMHelper, tc, output_stream=3DNone): self._env =3D environment + environment.SetValue("CI_BUILD_TYPE", "host_unit_test", "Set in Ho= stUnitTestCompilerPlugin") =20 # Parse the config for required DscPath element if "DscPath" not in pkgconfig: tc.SetSkipped() - tc.LogStdError("DscPath not found in config file. Nothing to = compile.") + tc.LogStdError("DscPath not found in config file. Nothing to = compile for HostBasedUnitTests.") return -1 =20 AP =3D Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(= packagename) @@ -67,11 +99,26 @@ class CompilerPlugin(ICiBuildPlugin): AP_Path =3D Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC) if AP is None or AP_Path is None or not os.path.isfile(APDSC): tc.SetSkipped() - tc.LogStdError("Package Dsc not found.") + tc.LogStdError("Package HostBasedUnitTest Dsc not found.") return -1 =20 logging.info("Building {0}".format(AP_Path)) self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler Pl= ugin") + num, RUNNABLE_ARCHITECTURES =3D self.__GetHostUnitTestArch(environ= ment) + if(num =3D=3D 0): + tc.SetSkipped() + tc.LogStdError("No host architecture compatibility") + return -1 + + if not environment.SetValue("TARGET_ARCH", + RUNNABLE_ARCHITECTURES, + "Update Target Arch based on Host Supp= ort"): + #use AllowOverride function since this is a controlled attempt= to change + environment.AllowOverride("TARGET_ARCH") + if not environment.SetValue("TARGET_ARCH", + RUNNABLE_ARCHITECTURES, + "Update Target Arch based on Host = Support"): + raise RuntimeError("Can't Change TARGET_ARCH as required") =20 # Parse DSC to check for SUPPORTED_ARCHITECTURES dp =3D DscParser() @@ -85,7 +132,7 @@ class CompilerPlugin(ICiBuildPlugin): # Skip if there is no intersection between SUPPORTED_ARCHITECT= URES and TARGET_ARCHITECTURES if len(set(SUPPORTED_ARCHITECTURES) & set(TARGET_ARCHITECTURES= )) =3D=3D 0: tc.SetSkipped() - tc.LogStdError("No supported architecutres to build") + tc.LogStdError("No supported architecutres to build for ho= st unit tests") return -1 =20 uefiBuilder =3D UefiBuilder() diff --git a/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompiler= _plug_in.yaml b/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompi= ler_plug_in.yaml new file mode 100644 index 0000000000..3cecf0af9a --- /dev/null +++ b/.pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompiler_plug_i= n.yaml @@ -0,0 +1,12 @@ +## +# CiBuildPlugin used to build anything that identifies +# as a unit test. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "host-based-test", + "name": "Host Unit Test Compiler Plugin", + "module": "HostUnitTestCompilerPlugin" +} diff --git a/.pytool/Plugin/HostUnitTestCompilerPlugin/Readme.md b/.pytool/= Plugin/HostUnitTestCompilerPlugin/Readme.md new file mode 100644 index 0000000000..3eeebb4b16 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestCompilerPlugin/Readme.md @@ -0,0 +1,24 @@ +# Host UnitTest Compiler Plugin + +A CiBuildPlugin that compiles the dsc for host based unit test apps. +An IUefiBuildPlugin may be attached to this plugin that will run the unit = tests and collect the results after successful compilation. + +## Configuration + +The package relative path of the DSC file to build. + +``` yaml +"HostUnitTestCompilerPlugin": { + "DscPath": "" +} +``` + +### DscPath + +Package relative path to the DSC file to build. + +## Copyright + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + diff --git a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py b/.pytool/= Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCheck.py similarity index 62% copy from .pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py copy to .pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscComplete= Check.py index 9af4f72c8d..66bdecacfb 100644 --- a/.pytool/Plugin/DscCompleteCheck/DscCompleteCheck.py +++ b/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCh= eck.py @@ -1,4 +1,7 @@ -# @file DscCompleteCheck.py +# @file HostUnitTestDscCompleteCheck.py +# +# This is a copy of DscCompleteCheck with different filtering logic. +# It should be discussed if this should be one plugin # # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -11,15 +14,15 @@ from edk2toollib.uefi.edk2.parsers.inf_parser import In= fParser from edk2toolext.environment.var_dict import VarDict =20 =20 -class DscCompleteCheck(ICiBuildPlugin): +class HostUnitTestDscCompleteCheck(ICiBuildPlugin): """ - A CiBuildPlugin that scans the package dsc file and confirms all modul= es (inf files) are + A CiBuildPlugin that scans the package Host Unit Test dsc file and con= firms all Host application modules (inf files) are listed in the components sections. =20 Configuration options: - "DscCompleteCheck": { - "DscPath": "" - "IgnoreInf": [] # Ignore INF if found in filesystem by not dsc + "HostUnitTestDscCompleteCheck": { + "DscPath": "", # Path to Host based unit test DSC file + "IgnoreInf": [] # Ignore INF if found in filesystem but not dsc } """ =20 @@ -35,7 +38,7 @@ class DscCompleteCheck(ICiBuildPlugin): testclassname: a descriptive string for the testcase can i= nclude whitespace classname: should be patterned .. """ - return ("Check the " + packagename + " DSC for a being complete", = packagename + ".DscCompleteCheck") + return ("Check the " + packagename + " Host Unit Test DSC for a be= ing complete", packagename + ".HostUnitTestDscCompleteCheck") =20 ## # External function of plugin. This function is used to perform the t= ask of the MuBuild Plugin @@ -54,21 +57,25 @@ class DscCompleteCheck(ICiBuildPlugin): # Parse the config for required DscPath element if "DscPath" not in pkgconfig: tc.SetSkipped() - tc.LogStdError("DscPath not found in config file. Nothing to = check.") + tc.LogStdError( + "DscPath not found in config file. Nothing to check.") return -1 =20 - abs_pkg_path =3D Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2Rel= ativePath(packagename) + abs_pkg_path =3D Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2Rel= ativePath( + packagename) abs_dsc_path =3D os.path.join(abs_pkg_path, pkgconfig["DscPath"].s= trip()) - wsr_dsc_path =3D Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(a= bs_dsc_path) + wsr_dsc_path =3D Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + abs_dsc_path) =20 if abs_dsc_path is None or wsr_dsc_path =3D=3D "" or not os.path.i= sfile(abs_dsc_path): tc.SetSkipped() - tc.LogStdError("Package Dsc not found") + tc.LogStdError("Package Host Unit Test Dsc not found") return 0 =20 # Get INF Files INFFiles =3D self.WalkDirectoryForExtension([".inf"], abs_pkg_path) - INFFiles =3D [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) f= or x in INFFiles] # make edk2relative path so can compare with DSC + INFFiles =3D [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath( + x) for x in INFFiles] # make edk2relative path so can compare= with DSC =20 # remove ignores =20 @@ -79,8 +86,10 @@ class DscCompleteCheck(ICiBuildPlugin): tc.LogStdOut("Ignoring INF {0}".format(a)) INFFiles.remove(a) except: - tc.LogStdError("DscCompleteCheck.IgnoreInf -> {0} not = found in filesystem. Invalid ignore file".format(a)) - logging.info("DscCompleteCheck.IgnoreInf -> {0} not fo= und in filesystem. Invalid ignore file".format(a)) + tc.LogStdError( + "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not= found in filesystem. Invalid ignore file".format(a)) + logging.info( + "HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not= found in filesystem. Invalid ignore file".format(a)) =20 # DSC Parser dp =3D DscParser() @@ -99,11 +108,23 @@ class DscCompleteCheck(ICiBuildPlugin): infp.SetPackagePaths(Edk2pathObj.PackagePathList) infp.ParseFile(INF) if("MODULE_TYPE" not in infp.Dict): - tc.LogStdOut("Ignoring INF. Missing key for MODULE_TYP= E {0}".format(INF)) + tc.LogStdOut( + "Ignoring INF. Missing key for MODULE_TYPE {0}".fo= rmat(INF)) continue =20 if(infp.Dict["MODULE_TYPE"] =3D=3D "HOST_APPLICATION"): - tc.LogStdOut("Ignoring INF. Module type is HOST_APPLI= CATION {0}".format(INF)) + # should compile test a library that is declared type = HOST_APPLICATION + pass + + elif len(infp.SupportedPhases) > 0 and \ + "HOST_APPLICATION" in infp.SupportedPhases: + # should compile test a library that supports HOST_APP= LICATION but + # require it to be an explicit opt-in + pass + + else: + tc.LogStdOut( + "Ignoring INF. MODULE_TYPE or suppored phases not = HOST_APPLICATION {0}".format(INF)) continue =20 logging.critical(INF + " not in " + wsr_dsc_path) @@ -111,8 +132,9 @@ class DscCompleteCheck(ICiBuildPlugin): overall_status =3D overall_status + 1 =20 # If XML object exists, add result - if overall_status is not 0: - tc.SetFailed("DscCompleteCheck {0} Failed. Errors {1}".format= (wsr_dsc_path, overall_status), "CHECK_FAILED") + if overall_status !=3D 0: + tc.SetFailed("HostUnitTestDscCompleteCheck {0} Failed. Errors= {1}".format( + wsr_dsc_path, overall_status), "CHECK_FAILED") else: tc.SetSuccess() return overall_status diff --git a/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCom= pleteCheck_plug_in.yaml b/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostU= nitTestDscCompleteCheck_plug_in.yaml new file mode 100644 index 0000000000..82cebd7667 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestDscCompleteCheck/HostUnitTestDscCompleteCh= eck_plug_in.yaml @@ -0,0 +1,12 @@ +## +# CiBuildPlugin used to confirm all INFs are listed in +# the components section of package dsc +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "host-based-test", + "name": "Host Unit Test Dsc Complete Check Test", + "module": "HostUnitTestDscCompleteCheck" + } diff --git a/.pytool/Plugin/HostUnitTestDscCompleteCheck/Readme.md b/.pytoo= l/Plugin/HostUnitTestDscCompleteCheck/Readme.md new file mode 100644 index 0000000000..d77a1f2af1 --- /dev/null +++ b/.pytool/Plugin/HostUnitTestDscCompleteCheck/Readme.md @@ -0,0 +1,32 @@ +# Host Unit Test Dsc Complete Check Plugin + +This CiBuildPlugin scans all INF files from a package for those related to= host +based unit tests confirms they are listed in the unit test DSC file for th= e package. +The test considers it an error if any INF meeting the requirements does no= t appear +in the `Components` section of the unit test DSC. This is critical because +much of the CI infrastructure assumes that modules will be listed in the = DSC +and compiled. + +This test will only require INFs in the following cases: + +1. When MODULE_TYPE =3D HOST_APPLICATION +2. When a Library instance supports the HOST_APPLICATION environment + +## Configuration + +The plugin has a few configuration options to support the UEFI codebase. + +``` yaml +"HostUnitTestDscCompleteCheck": { + "DscPath": "", # Path to Host based unit test DSC file + "IgnoreInf": [] # Ignore INF if found in filesystem but not dsc +} +``` + +### DscPath + +Path to DSC to consider platform dsc + +### IgnoreInf + +Ignore error if Inf file is not listed in DSC file diff --git a/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py b/.pytoo= l/Plugin/LibraryClassCheck/LibraryClassCheck.py index a62a7e912b..20d87f13f5 100644 --- a/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py +++ b/.pytool/Plugin/LibraryClassCheck/LibraryClassCheck.py @@ -146,7 +146,7 @@ class LibraryClassCheck(ICiBuildPlugin): =20 =20 # If XML object exists, add result - if overall_status is not 0: + if overall_status !=3D 0: tc.SetFailed("LibraryClassCheck {0} Failed. Errors {1}".forma= t(wsr_dec_path, overall_status), "CHECK_FAILED") else: tc.SetSuccess() --=20 2.21.0.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 (#54051): https://edk2.groups.io/g/devel/message/54051 Mute This Topic: https://groups.io/mt/71060079/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54052+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54052+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099240622133.37398047311865; Fri, 7 Feb 2020 10:14:00 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id wj3QYY1788612xd7EQxrLagS; Fri, 07 Feb 2020 10:14:00 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web10.8964.1581099238804041597 for ; Fri, 07 Feb 2020 10:13:59 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:13:58 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500539" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:13:58 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew , Bob Feng , Liming Gao Subject: [edk2-devel] [Patch v2 02/11] BaseTools/Plugin: Add HostBasedUnitTestRunner plugin Date: Fri, 7 Feb 2020 10:13:45 -0800 Message-Id: <20200207181354.31632-3-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: hJxM7agIHrHMFyN83CBWpllXx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099240; bh=Xltwht8iZ+evINFR9bgpSeZGp929jGBMqVVILY67DFo=; h=Cc:Date:From:Reply-To:Subject:To; b=Qru/iUPBYtFGhuqdWPJvKx/jSrXRchOFcGW6aCjEBtlOpLn3yXib3WHRDHye6mgmE1o 4Nks2GJ8AT8C/8ER2xMI3SGDjAekOznhJaVhoV01acK2eS+eDCZFVNIMTtH9tt2pJgSGb p6F+mwYDmTzsgCyPnrARZWa7/q12LI0AQJA= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 Add plugin to BaseTools to run host based unit tests. Cc: Sean Brogan Cc: Bret Barkelew Cc: Bob Feng Cc: Liming Gao Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew Acked-by: Bob Feng --- .../HostBasedUnitTestRunner.py | 115 ++++++++++++++++++ .../HostBasedUnitTestRunner_plug_in.yaml | 12 ++ 2 files changed, 127 insertions(+) create mode 100644 BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitT= estRunner.py create mode 100644 BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitT= estRunner_plug_in.yaml diff --git a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunn= er.py b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py new file mode 100644 index 0000000000..92426760ae --- /dev/null +++ b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner.py @@ -0,0 +1,115 @@ +# @file HostBasedUnitTestRunner.py +# Plugin to located any host-based unit tests in the output directory and = execute them. +## +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +import os +import logging +import glob +import xml.etree.ElementTree +from edk2toolext.environment.plugintypes.uefi_build_plugin import IUefiBui= ldPlugin +from edk2toolext import edk2_logging +import edk2toollib.windows.locate_tools as locate_tools +from edk2toolext.environment import shell_environment +from edk2toollib.utility_functions import RunCmd + + +class HostBasedUnitTestRunner(IUefiBuildPlugin): + + def do_pre_build(self, thebuilder): + ''' + Works with the compiler (either the HostBasedCompilerPlugin or an = other Builder) to set + up the environment that will be needed to build host-based unit te= sts. + + EXPECTS: + - Build Var 'CI_BUILD_TYPE' - If not set to 'host_unit_test', will= not do anything. + + UPDATES: + - Shell Var (Several) - Updates the shell with all vars listed in = interesting_keys. + - Shell Path - Updated from QueryVcVariables() + - Shell Var 'CMOCKA_MESSAGE_OUTPUT' + ''' + ci_type =3D thebuilder.env.GetValue('CI_BUILD_TYPE') + if ci_type !=3D 'host_unit_test': + return 0 + + shell_env =3D shell_environment.GetEnvironment() + # Use the tools lib to determine the correct values for the vars t= hat interest us. + interesting_keys =3D ["ExtensionSdkDir", "INCLUDE", "LIB", "LIBPAT= H", "UniversalCRTSdkDir", + "UCRTVersion", "WindowsLibPath", "WindowsSdkBi= nPath", "WindowsSdkDir", "WindowsSdkVerBinPath", + "WindowsSDKVersion", "VCToolsInstallDir"] + vs_vars =3D locate_tools.QueryVcVariables(interesting_keys, "amd64= ") + for (k, v) in vs_vars.items(): + if k.upper() =3D=3D "PATH": + shell_env.append_path(v) + else: + shell_env.set_shell_var(k, v) + + # Set up the reporting type for Cmocka. + shell_env.set_shell_var('CMOCKA_MESSAGE_OUTPUT', 'xml') + return 0 + + def do_post_build(self, thebuilder): + ''' + After a build, will automatically locate and run all host-based un= it tests. Logs any + failures with Warning severity and will return a count of the fail= ures as the return code. + + EXPECTS: + - Build Var 'CI_BUILD_TYPE' - If not set to 'host_unit_test', will= not do anything. + + UPDATES: + - Shell Var 'CMOCKA_XML_FILE' + ''' + ci_type =3D thebuilder.env.GetValue('CI_BUILD_TYPE') + if ci_type !=3D 'host_unit_test': + return 0 + + shell_env =3D shell_environment.GetEnvironment() + logging.log(edk2_logging.get_section_level(), + "Run Host based Unit Tests") + path =3D thebuilder.env.GetValue("BUILD_OUTPUT_BASE") + + failure_count =3D 0 + + for arch in thebuilder.env.GetValue("TARGET_ARCH").split(): + logging.log(edk2_logging.get_subsection_level(), + "Testing for architecture: " + arch) + cp =3D os.path.join(path, arch) + + # If any old results XML files exist, clean them up. + for old_result in glob.iglob(os.path.join(cp, "*.result.xml")): + os.remove(old_result) + + # Determine whether any tests exist. + testList =3D glob.glob(os.path.join(cp, "*Test*.exe")) + for test in testList: + # Configure output name. + shell_env.set_shell_var( + 'CMOCKA_XML_FILE', test + ".%g." + arch + ".result.xml= ") + + # Run the test. + ret =3D RunCmd('"' + test + '"', "", workingdir=3Dcp) + if(ret !=3D 0): + logging.error("UnitTest Execution Error: " + + os.path.basename(test)) + else: + logging.info("UnitTest Completed: " + + os.path.basename(test)) + file_match_pattern =3D test + ".*." + arch + ".result.= xml" + xml_results_list =3D glob.glob(file_match_pattern) + for xml_result_file in xml_results_list: + root =3D xml.etree.ElementTree.parse( + xml_result_file).getroot() + for suite in root: + for case in suite: + for result in case: + if result.tag =3D=3D 'failure': + logging.warning( + "%s Test Failed" % os.path.bas= ename(test)) + logging.warning( + " %s - %s" % (case.attrib['na= me'], result.text)) + failure_count +=3D 1 + + return failure_count diff --git a/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunn= er_plug_in.yaml b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTes= tRunner_plug_in.yaml new file mode 100644 index 0000000000..d9eb852e97 --- /dev/null +++ b/BaseTools/Plugin/HostBasedUnitTestRunner/HostBasedUnitTestRunner_plug= _in.yaml @@ -0,0 +1,12 @@ +## +# IUefiBuildPlugin used to run any unittests that +# were built on this build. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + "scope": "host-test-win", + "name": "Windows Host-Based Unit Test Runner", + "module": "HostBasedUnitTestRunner" +} --=20 2.21.0.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 (#54052): https://edk2.groups.io/g/devel/message/54052 Mute This Topic: https://groups.io/mt/71060080/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54053+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54053+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099240844551.9575590394336; Fri, 7 Feb 2020 10:14:00 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id pV86YY1788612xbFIo2CaJf3; Fri, 07 Feb 2020 10:14:00 -0800 X-Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by mx.groups.io with SMTP id smtpd.web09.9012.1581099239712058624 for ; Fri, 07 Feb 2020 10:13:59 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:13:59 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500542" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:13:59 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Bret Barkelew , Sean Brogan , Bret Barkelew , Liming Gao , Hao A Wu Subject: [edk2-devel] [Patch v2 03/11] MdePkg/Include/Library: Add UnitTestLib class Date: Fri, 7 Feb 2020 10:13:46 -0800 Message-Id: <20200207181354.31632-4-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: kdScn0MqcgBQMNdXda21HfSJx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099240; bh=HrO7R9kCPbU4yQjAnDHw8toDq5R2zX9UOHzY6m8TlYs=; h=Cc:Date:From:Reply-To:Subject:To; b=xT6kG3YUG7a/yrsHv6AIIJSOAmsW+sjalj173qw8sxZbD/puebw1FEoSLxKiB8EjYga kN7UvM8Q+wk2MagZIGVJ158kGwAXNMtdOs4nu1+vsjbd+UkGk5/kRV28/yDqrJS7l1BN6 Ae4mPOegbWW1Ui/Pf644Ht8uQvSOv78YFpo= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" From: Bret Barkelew https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 Add UnitTestLib class to MdePkg that provides services and macros to implement unit tests. These services and macros support the following features: * Create a Unit Test Framework * Add a Unit Test Suite to a Unit Test Framework + Support optional step that executes before a Unit Test Suite is started. + Support optional step that executes after a Unit Test Suite is finished. * Add a Unit Test to a Unit Test Suite + Support optional step that executes before a Unit Test is started. + Support optional step that executes after a Unit Test is finished. * Run all unit tests added to a Unit Test Framework * Save Unit Test Framework state to persistent storage * Support assertion checks in a unit test for TRUE, FALSE, EQUAL, MEM_EQUAL, NOT_EFI_ERROR, STATUS_EQUAL, and NOT_NULL. * Support generation of log messages at ERROR, WARN, INFO, and VERBOSE levels. Cc: Sean Brogan Cc: Bret Barkelew Cc: Liming Gao Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew Reviewed-by: Michael D Kinney Reviewed-by: Hao A Wu --- MdePkg/Include/Library/UnitTestLib.h | 757 +++++++++++++++++++++++++++ MdePkg/MdePkg.dec | 4 + 2 files changed, 761 insertions(+) create mode 100644 MdePkg/Include/Library/UnitTestLib.h diff --git a/MdePkg/Include/Library/UnitTestLib.h b/MdePkg/Include/Library/= UnitTestLib.h new file mode 100644 index 0000000000..c06c36bea5 --- /dev/null +++ b/MdePkg/Include/Library/UnitTestLib.h @@ -0,0 +1,757 @@ +/** @file + Provides a unit test framework. This allows tests to focus on testing l= ogic + and the framework to focus on runnings, reporting, statistics, etc. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __UNIT_TEST_LIB_H__ +#define __UNIT_TEST_LIB_H__ + +/// +/// Unit Test Status +/// +typedef UINT32 UNIT_TEST_STATUS; +#define UNIT_TEST_PASSED (0) +#define UNIT_TEST_ERROR_PREREQUISITE_NOT_MET (1) +#define UNIT_TEST_ERROR_TEST_FAILED (2) +#define UNIT_TEST_ERROR_CLEANUP_FAILED (3) +#define UNIT_TEST_SKIPPED (0xFFFFFFFD) +#define UNIT_TEST_RUNNING (0xFFFFFFFE) +#define UNIT_TEST_PENDING (0xFFFFFFFF) + +/// +/// Declare PcdUnitTestLogLevel bits and UnitTestLog() ErrorLevel paramete= r. +/// +#define UNIT_TEST_LOG_LEVEL_ERROR BIT0 +#define UNIT_TEST_LOG_LEVEL_WARN BIT1 +#define UNIT_TEST_LOG_LEVEL_INFO BIT2 +#define UNIT_TEST_LOG_LEVEL_VERBOSE BIT3 + +/// +/// Unit Test Framework Handle +/// +struct UNIT_TEST_FRAMEWORK_OBJECT; +typedef struct UNIT_TEST_FRAMEWORK_OBJECT *UNIT_TEST_FRAMEWORK_HANDLE; + +/// +/// Unit Test Suite Handle +/// +struct UNIT_TEST_SUITE_OBJECT; +typedef struct UNIT_TEST_SUITE_OBJECT *UNIT_TEST_SUITE_HANDLE; + +/// +/// Unit Test Handle +/// +struct UNIT_TEST_OBJECT; +typedef struct UNIT_TEST_OBJECT *UNIT_TEST_HANDLE; + +/// +/// Unit Test Context +/// +typedef VOID* UNIT_TEST_CONTEXT; + +/** + The prototype for a single UnitTest case function. + + Functions with this prototype are registered to be dispatched by the + UnitTest framework, and results are recorded as test Pass or Fail. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. + +**/ +typedef +UNIT_TEST_STATUS +(EFIAPI *UNIT_TEST_FUNCTION)( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit-Test Prerequisite Function pointer type. + + Functions with this prototype are registered to be dispatched by the uni= t test + framework prior to a given test case. If this prereq function returns + UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, the test case will be skipped. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED Unit test case prerequisi= tes + are met. + @retval UNIT_TEST_ERROR_PREREQUISITE_NOT_MET Test case should be skipp= ed. + +**/ +typedef +UNIT_TEST_STATUS +(EFIAPI *UNIT_TEST_PREREQUISITE)( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit-Test Cleanup (after) function pointer type. + + Functions with this prototype are registered to be dispatched by the + unit test framework after a given test case. This will be called even if= the + test case returns an error, but not if the prerequisite fails and the te= st is + skipped. The purpose of this function is to clean up any global state or + test data. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED Test case cleanup succeeded. + @retval UNIT_TEST_ERROR_CLEANUP_FAILED Test case cleanup failed. + +**/ +typedef +VOID +(EFIAPI *UNIT_TEST_CLEANUP)( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit-Test Test Suite Setup (before) function pointer type. Functions wit= h this + prototype are registered to be dispatched by the UnitTest framework prio= r to + running any of the test cases in a test suite. It will only be run once= at + the beginning of the suite (not prior to each case). + + The purpose of this function is to set up any global state or test data. +**/ +typedef +VOID +(EFIAPI *UNIT_TEST_SUITE_SETUP)( + VOID + ); + +/** + Unit-Test Test Suite Teardown (after) function pointer type. Functions = with + this prototype are registered to be dispatched by the UnitTest framework= after + running all of the test cases in a test suite. It will only be run once= at + the end of the suite. + + The purpose of this function is to clean up any global state or test dat= a. +**/ +typedef +VOID +(EFIAPI *UNIT_TEST_SUITE_TEARDOWN)( + VOID + ); + +/** + Method to Initialize the Unit Test framework. This function registers t= he + test name and also initializes the internal state of the test framework = to + receive any new suites and tests. + + @param[out] FrameworkHandle Unit test framework to be created. + @param[in] Title Null-terminated ASCII string that is the u= ser + friendly name of the framework. String is + copied. + @param[in] ShortTitle Null-terminated ASCII short string that is= the + short name of the framework with no spaces. + String is copied. + @param[in] VersionString Null-terminated ASCII version string for t= he + framework. String is copied. + + @retval EFI_SUCCESS The unit test framework was initialized. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is NULL. + @retval EFI_INVALID_PARAMETER VersionString is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is invalid. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + initialize the unit test framework. +**/ +EFI_STATUS +EFIAPI +InitUnitTestFramework ( + OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *ShortTitle, + IN CHAR8 *VersionString + ); + +/** + Registers a Unit Test Suite in the Unit Test Framework. + At least one test suite must be registered, because all test cases must = be + within a unit test suite. + + @param[out] SuiteHandle Unit test suite to create + @param[in] FrameworkHandle Unit test framework to add unit test suite= to + @param[in] Title Null-terminated ASCII string that is the u= ser + friendly name of the test suite. String is + copied. + @param[in] Name Null-terminated ASCII string that is the s= hort + name of the test suite with no spaces. St= ring + is copied. + @param[in] Setup Setup function, runs before suite. This i= s an + optional parameter that may be NULL. + @param[in] Teardown Teardown function, runs after suite. This= is an + optional parameter that may be NULL. + + @retval EFI_SUCCESS The unit test suite was created. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + initialize the unit test suite. +**/ +EFI_STATUS +EFIAPI +CreateUnitTestSuite ( + OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle, + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *Name, + IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL, + IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL + ); + +/** + Adds test case to Suite + + @param[in] SuiteHandle Unit test suite to add test to. + @param[in] Description Null-terminated ASCII string that is the user + friendly description of a test. String is cop= ied. + @param[in] Name Null-terminated ASCII string that is the short= name + of the test with no spaces. String is copied. + @param[in] Function Unit test function. + @param[in] Prerequisite Prerequisite function, runs before test. This= is + an optional parameter that may be NULL. + @param[in] CleanUp Clean up function, runs after test. This is an + optional parameter that may be NULL. + @param[in] Context Pointer to context. This is an optional par= ameter + that may be NULL. + + @retval EFI_SUCCESS The unit test case was added to Suite. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER Description is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_INVALID_PARAMETER Function is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + add the unit test case to Suite. +**/ +EFI_STATUS +EFIAPI +AddTestCase ( + IN UNIT_TEST_SUITE_HANDLE SuiteHandle, + IN CHAR8 *Description, + IN CHAR8 *Name, + IN UNIT_TEST_FUNCTION Function, + IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL, + IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, + IN UNIT_TEST_CONTEXT Context OPTIONAL + ); + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and u= nit + test cases are registered, this function will cause the unit test framew= ork to + dispatch all unit test cases in sequence and record the results for repo= rting. + + @param[in] FrameworkHandle A handle to the current running framework t= hat + dispatched the test. Necessary for recordi= ng + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +/** + Cleanup a test framework. + + After tests are run, this will teardown the entire framework and free all + allocated data within. + + @param[in] FrameworkHandle A handle to the current running framework t= hat + dispatched the test. Necessary for recordi= ng + certain test events with the framework. + + @retval EFI_SUCCESS All resources associated with framework = were + freed. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +FreeUnitTestFramework ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +/** + Leverages a framework-specific mechanism (see UnitTestPersistenceLib if = you're + a framework author) to save the state of the executing framework along w= ith + any allocated data so that the test may be resumed upon reentry. A test = case + should pass any needed context (which, to prevent an infinite loop, shou= ld be + at least the current execution count) which will be saved by the framewo= rk and + passed to the test case upon resume. + + Generally called from within a test case prior to quitting or rebooting. + + @param[in] FrameworkHandle A handle to the current running framework= that + dispatched the test. Necessary for recor= ding + certain test events with the framework. + @param[in] ContextToSave A buffer of test case-specific data to be= saved + along with framework state. Will be pass= ed as + "Context" to the test case upon resume. = This + is an optional parameter that may be NULL. + @param[in] ContextToSaveSize Size of the ContextToSave buffer. + + @retval EFI_SUCCESS The framework state and context were sav= ed. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and + ContextToSaveSize is 0. + @retval EFI_INVALID_PARAMETER ContextToSave is >=3D 4GB. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + save the framework and context state. + @retval EFI_DEVICE_ERROR The framework and context state could no= t be + saved to a persistent storage device due= to a + device error. +**/ +EFI_STATUS +EFIAPI +SaveFrameworkState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ); + +/** + This macro uses the framework assertion logic to check an expression for + "TRUE". If the expression evaluates to TRUE, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Expression Expression to be evaluated for TRUE. +**/ +#define UT_ASSERT_TRUE(Expression) = \ + if(!UnitTestAssertTrue ((Expression), __FUNCTION__, __LINE__, __FILE__, = #Expression)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + This macro uses the framework assertion logic to check an expression for + "FALSE". If the expression evaluates to FALSE, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Expression Expression to be evaluated for FALSE. +**/ +#define UT_ASSERT_FALSE(Expression) = \ + if(!UnitTestAssertFalse ((Expression), __FUNCTION__, __LINE__, __FILE__,= #Expression)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + This macro uses the framework assertion logic to check whether two simple + values are equal. If the values are equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] ValueA Value to be compared for equality (64-bit comparison= ). + @param[in] ValueB Value to be compared for equality (64-bit comparison= ). +**/ +#define UT_ASSERT_EQUAL(ValueA, ValueB) = \ + if(!UnitTestAssertEqual ((UINT64)(ValueA), (UINT64)(ValueB), __FUNCTION_= _, __LINE__, __FILE__, #ValueA, #ValueB)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + This macro uses the framework assertion logic to check whether two memory + buffers are equal. If the buffers are equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and BufferB. +**/ +#define UT_ASSERT_MEM_EQUAL(BufferA, BufferB, Length) = \ + if(!UnitTestAssertMemEqual ((VOID *)(UINTN)(BufferA), (VOID *)(UINTN)(Bu= fferB), (UINTN)Length, __FUNCTION__, __LINE__, __FILE__, #BufferA, #BufferB= )) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + This macro uses the framework assertion logic to check whether two simple + values are non-equal. If the values are non-equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] ValueA Value to be compared for inequality (64-bit comparis= on). + @param[in] ValueB Value to be compared for inequality (64-bit comparis= on). +**/ +#define UT_ASSERT_NOT_EQUAL(ValueA, ValueB) = \ + if(!UnitTestAssertNotEqual ((UINT64)(ValueA), (UINT64)(ValueB), __FUNCTI= ON__, __LINE__, __FILE__, #ValueA, #ValueB)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + This macro uses the framework assertion logic to check whether an EFI_ST= ATUS + value is !EFI_ERROR(). If the status is !EFI_ERROR(), execution continu= es. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Status EFI_STATUS value to check. +**/ +#define UT_ASSERT_NOT_EFI_ERROR(Status) = \ + if(!UnitTestAssertNotEfiError ((Status), __FUNCTION__, __LINE__, __FILE_= _, #Status)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + This macro uses the framework assertion logic to check whether two EFI_S= TATUS + values are equal. If the values are equal, execution continues. + Otherwise, the test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Status EFI_STATUS values to compare for equality. + @param[in] Expected EFI_STATUS values to compare for equality. +**/ +#define UT_ASSERT_STATUS_EQUAL(Status, Expected) = \ + if(!UnitTestAssertStatusEqual ((Status), (Expected), __FUNCTION__, __LIN= E__, __FILE__, #Status)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + This macro uses the framework assertion logic to check whether a pointer= is + not NULL. If the pointer is not NULL, execution continues. Otherwise, t= he + test case immediately returns UNIT_TEST_ERROR_TEST_FAILED. + + @param[in] Pointer Pointer to be checked against NULL. +**/ +#define UT_ASSERT_NOT_NULL(Pointer) = \ + if(!UnitTestAssertNotNull ((Pointer), __FUNCTION__, __LINE__, __FILE__, = #Pointer)) { \ + return UNIT_TEST_ERROR_TEST_FAILED; = \ + } + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of = the + assert provided by FunctionName, LineNumber, FileName, and Description a= re + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluatio= n. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression= being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of t= he + assert provided by FunctionName, LineNumber, FileName, and Description a= re + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluatio= n. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression= being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the locatio= n of + the assert provided by FunctionName, LineNumber, FileName, and Descripti= on are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the lo= cation + of the assert provided by FunctionName, LineNumber, FileName, Descriptio= nA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +/** + If the contents of BufferA are identical to the contents of BufferB, the= n TRUE + is returned. If the contents of BufferA are not identical to the conten= ts of + BufferB, then an assert is triggered and the location of the assert prov= ided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and Buff= erB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the content= s of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the locati= on + of the assert provided by FunctionName, LineNumber, FileName, Descriptio= nA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, a= nd + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under te= st. + @param[in] Expected The expected EFI_STATUS return value from an A= PI + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a descrip= tion + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ); + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the locatio= n of + the assert provided by FunctionName, LineNumber, FileName, and PointerNa= me + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a fu= nction + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a descrip= tion + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ); + +/** + Test logging macro that records an ERROR message in the test framework l= og. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_ERROR(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_ERROR, Format, ##__VA_ARGS__) + +/** + Test logging macro that records a WARNING message in the test framework = log. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_WARNING(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_WARN, Format, ##__VA_ARGS__) + +/** + Test logging macro that records an INFO message in the test framework lo= g. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_INFO(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_INFO, Format, ##__VA_ARGS__) + +/** + Test logging macro that records a VERBOSE message in the test framework = log. + Record is associated with the currently executing test case. + + @param[in] Format Formatting string following the format defined in + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +#define UT_LOG_VERBOSE(Format, ...) \ + UnitTestLog (UNIT_TEST_LOG_LEVEL_VERBOSE, Format, ##__VA_ARGS__) + +/** + Test logging function that records a messages in the test framework log. + Record is associated with the currently executing test case. + + @param[in] ErrorLevel The error level of the unit test log message. + @param[in] Format Formatting string following the format defined i= n the + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +VOID +EFIAPI +UnitTestLog ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ); + +#endif diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index d022cc5e3e..ac1f5339af 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -244,6 +244,10 @@ [LibraryClasses] ## @libraryclass Module entry point library for standalone MM drivers. StandaloneMmDriverEntryPoint|Include/Library/StandaloneMmDriverEntryPoin= t.h =20 + ## @libraryclass Provides a unit test framework + # + UnitTestLib|Include/Library/UnitTestLib.h + [LibraryClasses.IA32, LibraryClasses.X64] ## @libraryclass Abstracts both S/W SMI generation and detection. ## --=20 2.21.0.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 (#54053): https://edk2.groups.io/g/devel/message/54053 Mute This Topic: https://groups.io/mt/71060081/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54054+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54054+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099241496363.5597379610325; Fri, 7 Feb 2020 10:14:01 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id JAusYY1788612x2Kln3r2Hbd; Fri, 07 Feb 2020 10:14:01 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web10.8964.1581099238804041597 for ; Fri, 07 Feb 2020 10:14:00 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:13:59 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500543" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:13:59 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew Subject: [edk2-devel] [Patch v2 04/11] UnitTestFrameworkPkg: Add public and private interfaces Date: Fri, 7 Feb 2020 10:13:47 -0800 Message-Id: <20200207181354.31632-5-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: RibPkv3lairjPzfttYb2Q22Rx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099241; bh=odh3PzQBgVjxap+MRjcsv8LhgVqc76e4z8UxoBrN7XE=; h=Cc:Date:From:Reply-To:Subject:To; b=dRHuP9YVD+ksGUXE9C/R+KwUEWeNxALlzSmgdQwmaOIsbfckN8mKTE9lxYC9uHCdfCh U0vETLVLZRi0xctA4y24M1wrcDYsQQtHAq4AFlj+incnRWTe8zvSVVoPZkMQzYbPN5bOw T0qe4zEgTEhxYRLlFqHmhy2KWhh/ded/jpw= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 Add public interfaces for use by unit test implementations. * Include path to cmocka library interfaces. * PcdUnitTestLogLevel to set the unit test logging message level to filter log messages. Add private interfaces that are used by UnitTestLib implementations. * [Private] UnitTestBootLib - Set boot next to continue unit tests across a reboot. * [Private] UnitTestPersistenceLib - Save unit test framework state to a persistent storage device. * [Private] UnitTestResultLib - Output unit test results to a console device. * [Private] UnitTestFrameworkTypes.h - Internal structures used by UnitTestLib implementations to keep track if unit test frameworks, unit test suites, and unit tests along with the serialized storage format to save a unit test framework state to persistent storage. Cc: Sean Brogan Cc: Bret Barkelew Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew --- .../PrivateInclude/Library/UnitTestBootLib.h | 31 +++ .../Library/UnitTestPersistenceLib.h | 76 ++++++ .../Library/UnitTestResultReportLib.h | 27 ++ .../PrivateInclude/UnitTestFrameworkTypes.h | 183 +++++++++++++ UnitTestFrameworkPkg/ReadMe.md | 257 ++++++++++++++++++ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec | 50 ++++ UnitTestFrameworkPkg/UnitTestFrameworkPkg.uni | 21 ++ 7 files changed, 645 insertions(+) create mode 100644 UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestBoo= tLib.h create mode 100644 UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestPer= sistenceLib.h create mode 100644 UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestRes= ultReportLib.h create mode 100644 UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTy= pes.h create mode 100644 UnitTestFrameworkPkg/ReadMe.md create mode 100644 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec create mode 100644 UnitTestFrameworkPkg/UnitTestFrameworkPkg.uni diff --git a/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestBootLib.h = b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestBootLib.h new file mode 100644 index 0000000000..d90bff0e4c --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestBootLib.h @@ -0,0 +1,31 @@ +/** @file + Provides a library function that can be customized to set the platform t= o boot + from USB on the next boot. This allows the test framework to reboot bac= k to + USB. Since boot managers are not all the same creating a lib to support + platform customization will make porting to new code base/platform easie= r. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UNIT_TEST_BOOT_LIB_H__ +#define __UNIT_TEST_BOOT_LIB_H__ + +/** + Set the boot manager to boot from a specific device on the next boot. Th= is + should be set only for the next boot and shouldn't require any manual cl= ean up + + @retval EFI_SUCCESS Boot device for next boot was set. + @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not + supportted. + @retval Other Boot device for next boot can not be set. +**/ +EFI_STATUS +EFIAPI +SetBootNextDevice ( + VOID + ); + +#endif diff --git a/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestPersistenc= eLib.h b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestPersistenceLib= .h new file mode 100644 index 0000000000..af19ba8f53 --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestPersistenceLib.h @@ -0,0 +1,76 @@ +/** @file + This header file describes a library that contains functions to save and + restore unit test internal state, in case the test needs to pause and re= sume + (eg. a reboot-based test). + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UNIT_TEST_PERSISTENCE_LIB_H_ +#define _UNIT_TEST_PERSISTENCE_LIB_H_ + +#include + +#define UNIT_TEST_PERSISTENCE_LIB_VERSION 1 + +/** + Determines whether a persistence cache already exists for + the given framework. + + @param[in] FrameworkHandle A pointer to the framework that is being p= ersisted. + + @retval TRUE + @retval FALSE Cache doesn't exist or an error occurred. + +**/ +BOOLEAN +EFIAPI +DoesCacheExist ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +/** + Will save the data associated with an internal Unit Test Framework + state in a manner that can persist a Unit Test Application quit or + even a system reboot. + + @param[in] FrameworkHandle A pointer to the framework that is being p= ersisted. + @param[in] SaveData A pointer to the buffer containing the ser= ialized + framework internal state. + + @retval EFI_SUCCESS Data is persisted and the test can be safely q= uit. + @retval Others Data is not persisted and test cannot be resum= ed upon exit. + +**/ +EFI_STATUS +EFIAPI +SaveUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_SAVE_HEADER *SaveData + ); + +/** + Will retrieve any cached state associated with the given framework. + Will allocate a buffer to hold the loaded data. + + @param[in] FrameworkHandle A pointer to the framework that is being p= ersisted. + @param[in] SaveData A pointer pointer that will be updated wit= h the address + of the loaded data buffer. + + @retval EFI_SUCCESS Data has been loaded successfully and Save= Data is updated + with a pointer to the buffer. + @retval Others An error has occurred and no data has been= loaded. SaveData + is set to NULL. + +**/ +EFI_STATUS +EFIAPI +LoadUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + OUT UNIT_TEST_SAVE_HEADER **SaveData + ); + +#endif diff --git a/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestResultRepo= rtLib.h b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestResultReportL= ib.h new file mode 100644 index 0000000000..a417f490dc --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/Library/UnitTestResultReportLib.h @@ -0,0 +1,27 @@ +/** @file + Provides a unit test result report. This allows new result output forma= ts to + be easily customized. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UNIT_TEST_RESULT_REPORT_LIB_H__ +#define __UNIT_TEST_RESULT_REPORT_LIB_H__ + +#include + +/** +Method to produce the Unit Test run results + +@retval Success +**/ +EFI_STATUS +EFIAPI +OutputUnitTestFrameworkReport ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ); + +#endif diff --git a/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h b= /UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h new file mode 100644 index 0000000000..e58b30093e --- /dev/null +++ b/UnitTestFrameworkPkg/PrivateInclude/UnitTestFrameworkTypes.h @@ -0,0 +1,183 @@ +/** @file + Provides the basic types and common elements of the unit test framework + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UNIT_TEST_TYPES_H__ +#define __UNIT_TEST_TYPES_H__ + +#include + +/// +/// The maximum length of a string stored in the unit test framework +/// +#define UNIT_TEST_MAX_STRING_LENGTH (120) + +/// +/// The size of a firngerprint used to save/resume execution of a unit test +/// framework. This is the size of a CRC32 value which is 32-bit value. +/// +/// +#define UNIT_TEST_FINGERPRINT_SIZE (sizeof (UINT32)) + +/// +/// The maximum length of a test failure message stored in the unit test +/// framework +/// +#define UNIT_TEST_TESTFAILUREMSG_LENGTH (120) + +/// +/// FAILURE_TYPE used to record the type of assert that was triggered by a= unit +/// test. +/// +typedef UINT32 FAILURE_TYPE; +#define FAILURETYPE_NOFAILURE (0) +#define FAILURETYPE_OTHER (1) +#define FAILURETYPE_ASSERTTRUE (2) +#define FAILURETYPE_ASSERTFALSE (3) +#define FAILURETYPE_ASSERTEQUAL (4) +#define FAILURETYPE_ASSERTNOTEQUAL (5) +#define FAILURETYPE_ASSERTNOTEFIERROR (6) +#define FAILURETYPE_ASSERTSTATUSEQUAL (7) +#define FAILURETYPE_ASSERTNOTNULL (8) + +/// +/// Unit Test context structure tracked by the unit test framework. +/// +typedef struct { + CHAR8 *Description; + CHAR8 *Name; //can't have spaces and should be short + CHAR8 *Log; + FAILURE_TYPE FailureType; + CHAR8 FailureMessage[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; + UNIT_TEST_STATUS Result; + UNIT_TEST_FUNCTION RunTest; + UNIT_TEST_PREREQUISITE Prerequisite; + UNIT_TEST_CLEANUP CleanUp; + UNIT_TEST_CONTEXT Context; + UNIT_TEST_SUITE_HANDLE ParentSuite; +} UNIT_TEST; + +/// +/// Structure used to store the set of unit tests in a unit test suite as = a list. +/// +typedef struct { + LIST_ENTRY Entry; + UNIT_TEST UT; +} UNIT_TEST_LIST_ENTRY; + +/// +/// Unit Test Suite context structure tracked by the unit test framework. +/// +typedef struct { + UINTN NumTests; + CHAR8 *Title; + CHAR8 *Name; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; + UNIT_TEST_SUITE_SETUP Setup; + UNIT_TEST_SUITE_TEARDOWN Teardown; + LIST_ENTRY TestCaseList; // UNIT_TEST_LIST_ENTRY + UNIT_TEST_FRAMEWORK_HANDLE ParentFramework; +} UNIT_TEST_SUITE; + +/// +/// Structure used to store the set of unit test suites in a unit test fra= mework +/// as a list. +/// +typedef struct { + LIST_ENTRY Entry; + UNIT_TEST_SUITE UTS; +} UNIT_TEST_SUITE_LIST_ENTRY; + +/// +/// Unit Test Framework context structure tracked by the unit test framewo= rk. +/// +typedef struct { + CHAR8 *Title; + CHAR8 *ShortTitle; // This title should contain NO spaces or = non-filename characters. Is used in reporting and serialization. + CHAR8 *VersionString; + CHAR8 *Log; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; + LIST_ENTRY TestSuiteList; // UNIT_TEST_SUITE_LIST_ENTRY + EFI_TIME StartTime; + EFI_TIME EndTime; + UNIT_TEST *CurrentTest; + VOID *SavedState; // This is an instance of UNIT_TEST_SAVE_H= EADER*, if present. +} UNIT_TEST_FRAMEWORK; + +/// +/// Serialized version of a unit test +/// +typedef struct { + UINT32 Size; // Size = of the UNIT_TEST_SAVE_TEST including Log[] + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Finge= rprint of the test itself. + CHAR8 FailureMessage[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + FAILURE_TYPE FailureType; + UNIT_TEST_STATUS Result; + CHAR8 Log[]; +} UNIT_TEST_SAVE_TEST; + +/// +/// Serialized version of a unit test context +/// +typedef struct { + UINT32 Size; // Size of the UNIT_TE= ST_SAVE_CONTEXT including Data[] + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Fingerprint of the = corresponding test. + UINT8 Data[]; // Actual data of the = context. +} UNIT_TEST_SAVE_CONTEXT; + +/// +/// Serialized version of unit test framework +/// +typedef struct { + UINT8 Version; + UINT32 SaveStateSize; // Size of the entir= e serialized buffer. + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Fingerprint of th= e framework that has been saved. + EFI_TIME StartTime; + UINT32 TestCount; + BOOLEAN HasSavedContext; + // UNIT_TEST_SAVE_TEST Tests[]; // Array of structures starts= here. + // UNIT_TEST_SAVE_CONTEXT SavedContext[]; // Saved context for the curr= ently running test. + // CHAR8 Log[]; // NOTE: Not yet implemented!! +} UNIT_TEST_SAVE_HEADER; + +/** + This function is responsible for initializing the log buffer for a singl= e test. It can + be used internally, but may also be consumed by the test framework to ad= d pre-existing + data to a log before it's used. + + @param[in,out] TestHandle A handle to the test being initialized. + @param[in] Buffer [Optional] A pointer to pre-existing log d= ata that should + be used to initialize the log. Should incl= ude a NULL terminator. + @param[in] BufferSize [Optional] The size of the pre-existing lo= g data. + +**/ +VOID +EFIAPI +UnitTestLogInit ( + IN OUT UNIT_TEST *Test, + IN UINT8 *Buffer OPTIONAL, + IN UINTN BufferSize OPTIONAL + ); + +/** + Internal helper function to return a handle to the currently executing f= ramework. + This function is generally used for communication within the UnitTest fr= amework, but is + defined here so that it can be consumed by the Assertion and Logging mac= ros. + + There should be no need to consume as a test writer, but it's there if y= ou need it. + + @retval Handle to the currently executing test framework. + +**/ +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ); + +#endif diff --git a/UnitTestFrameworkPkg/ReadMe.md b/UnitTestFrameworkPkg/ReadMe.md new file mode 100644 index 0000000000..7296f0a45c --- /dev/null +++ b/UnitTestFrameworkPkg/ReadMe.md @@ -0,0 +1,257 @@ +# Unit Test Framework Package + +## About + +This package adds a unit test framework capable of building tests for mult= iple contexts including +the UEFI shell environment and host-based environments. It allows for unit= test development to focus +on the tests and leave error logging, result formatting, context persistan= ce, and test running to the framework. +The unit test framework works well for low level unit tests as well as sys= tem level tests and +fits easily in automation frameworks. + +### UnitTestLib + +The main "framework" library. The core of the framework is the Framework o= bject, which can have any number +of test cases and test suites registered with it. The Framework object is = also what drives test execution. + +The Framework also provides helper macros and functions for checking test = conditions and +reporting errors. Status and error info will be logged into the test conte= xt. There are a number +of Assert macros that make the unit test code friendly to view and easy to= understand. + +Finally, the Framework also supports logging strings during the test execu= tion. This data is logged +to the test context and will be available in the test reporting phase. Thi= s should be used for +logging test details and helpful messages to resolve test failures. + +### UnitTestPersistenceLib + +Persistence lib has the main job of saving and restoring test context to a= storage medium so that for tests +that require exiting the active process and then resuming state can be mai= ntained. This is critical +in supporting a system reboot in the middle of a test run. + +### UnitTestResultReportLib + +Library provides function to run at the end of a framework test run and ha= ndles formatting the report. +This is a common customization point and allows the unit test framework to= fit its output reports into +other test infrastructure. In this package a simple library instances has = been supplied to output test +results to the console as plain text. + +## Samples + +There is a sample unit test provided as both an example of how to write a = unit test and leverage +many of the features of the framework. This sample can be found in the `Te= st/UnitTest/Sample/SampleUnitTest` +directory. + +The sample is provided in PEI, SMM, DXE, and UEFI App flavors. It also has= a flavor for the HOST_APPLICATION +build type, which can be run on a host system without needing a target. + +## Usage + +This section is built a lot like a "Getting Started". We'll go through som= e of the components that are needed +when constructing a unit test and some of the decisions that are made by t= he test writer. We'll also describe +how to check for expected conditions in test cases and a bit of the loggin= g characteristics. + +Most of these examples will refer to the SampleUnitTestUefiShell app found= in this package. + +### Requirements - INF + +In our INF file, we'll need to bring in the `UnitTestLib` library. Conveni= ently, the interface +header for the `UnitTestLib` is located in `MdePkg`, so you shouldn't need= to depend on any other +packages. As long as your DSC file knows where to find the lib implementat= ion that you want to use, +you should be good to go. + +See this example in 'SampleUnitTestApp.inf'... + +``` +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib +``` + +### Requirements - Code + +Not to state the obvious, but let's make sure we have the following includ= e before getting too far along... + +```c +#include +``` + +Now that we've got that squared away, let's look at our 'Main()'' routine = (or DriverEntryPoint() or whatever). + +### Configuring the Framework + +Everything in the UnitTestPkg framework is built around an object called -= - conveniently -- the Framework. +This Framework object will contain all the information about our test, the= test suites and test cases associated +with it, the current location within the test pass, and any results that h= ave been recorded so far. + +To get started with a test, we must first create a Framework instance. The= function for this is +`InitUnitTestFramework`. It takes in `CHAR8` strings for the long name, sh= ort name, and test version. +The long name and version strings are just for user presentation and relat= ively flexible. The short name +will be used to name any cache files and/or test results, so should be a n= ame that makes sense in that context. +These strings are copied internally to the Framework, so using stack-alloc= ated or literal strings is fine. + +In the 'SampleUnitTestUefiShell' app, the module name is used as the short= name, so the init looks like this. + +```c +DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION = )); + +// +// Start setting up the test framework for running the tests. +// +Status =3D InitUnitTestFramework( &Framework, UNIT_TEST_APP_NAME, gEfiCall= erBaseName, UNIT_TEST_APP_VERSION ); +``` + +The `&Framework` returned here is the handle to the Framework. If it's suc= cessfully returned, we can start adding +test suites and test cases. + +Test suites exist purely to help organize test cases and to differentiate = the results in reports. If you're writing +a small unit test, you can conceivably put all test cases into a single su= ite. However, if you end up with 20+ test +cases, it may be beneficial to organize them according to purpose. You _mu= st_ have at least one test suite, even if +it's just a catch-all. The function to create a test suite is `CreateUnitT= estSuite`. It takes in a handle to +the Framework object, a `CHAR8` string for the suite title and package nam= e, and optional function pointers for +a setup function and a teardown function. + +The suite title is for user presentation. The package name is for xUnit ty= pe reporting and uses a '.'-separated +hierarchical format (see 'SampleUnitTestApp' for example). If provided, th= e setup and teardown functions will be +called once at the start of the suite (before _any_ tests have run) and on= ce at the end of the suite (after _all_ +tests have run), respectively. If either or both of these are unneeded, pa= ss `NULL`. The function prototypes are +`UNIT_TEST_SUITE_SETUP` and `UNIT_TEST_SUITE_TEARDOWN`. + +Looking at 'SampleUnitTestUefiShell' app, you can see that the first test = suite is created as below... + +```c +// +// Populate the SimpleMathTests Unit Test Suite. +// +Status =3D CreateUnitTestSuite( &SimpleMathTests, Fw, "Simple Math Tests",= "Sample.Math", NULL, NULL ); +``` + +This test suite has no setup or teardown functions. The `&SimpleMathTests`= returned here is a handle to the suite and +will be used when adding test cases. + +Great! Now we've finished some of the cruft, red tape, and busy work. We'r= e ready to add some tests. Adding a test +to a test suite is accomplished with the -- you guessed it -- `AddTestCase= ` function. It takes in the suite handle; +a `CHAR8` string for the description and class name; a function pointer fo= r the test case itself; additional, optional +function pointers for prerequisite check and cleanup routines; and and opt= ional pointer to a context structure. + +Okay, that's a lot. Let's take it one piece at a time. The description and= class name strings are very similar in +usage to the suite title and package name strings in the test suites. The = former is for user presentation and the +latter is for xUnit parsing. The test case function pointer is what is act= ually executed as the "test" and the +prototype should be `UNIT_TEST_FUNCTION`. The last three parameters requir= e a little bit more explaining. + +The prerequisite check function has a prototype of `UNIT_TEST_PREREQUISITE= ` and -- if provided -- will be called +immediately before the test case. If this function returns any error, the = test case will not be run and will be +recorded as `UNIT_TEST_ERROR_PREREQUISITE_NOT_MET`. The cleanup function (= prototype `UNIT_TEST_CLEANUP`) will be called +immediately after the test case to provide an opportunity to reset any glo= bal state that may have been changed in the +test case. In the event of a prerequisite failure, the cleanup function wi= ll also be skipped. If either of these +functions is not needed, pass `NULL`. + +The context pointer is entirely case-specific. It will be passed to the te= st case upon execution. One of the purposes +of the context pointer is to allow test case reuse with different input da= ta. (Another use is for testing that wraps +around a system reboot, but that's beyond the scope of this guide.) The te= st case must know how to interpret the context +pointer, so it could be a simple value, or it could be a complex structure= . If unneeded, pass `NULL`. + +In 'SampleUnitTestUefiShell' app, the first test case is added using the c= ode below... + +```c +AddTestCase( SimpleMathTests, "Adding 1 to 1 should produce 2", "Addition"= , OnePlusOneShouldEqualTwo, NULL, NULL, NULL ); +``` + +This test case calls the function `OnePlusOneShouldEqualTwo` and has no pr= erequisite, cleanup, or context. + +Once all the suites and cases are added, it's time to run the Framework. + +```c +// +// Execute the tests. +// +Status =3D RunAllTestSuites( Framework ); +``` + +### A Simple Test Case + +We'll take a look at the below test case from 'SampleUnitTestApp'... + +```c +UNIT_TEST_STATUS +EFIAPI +OnePlusOneShouldEqualTwo ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UNIT_TEST_CONTEXT Context + ) +{ + UINTN A, B, C; + + A =3D 1; + B =3D 1; + C =3D A + B; + + UT_ASSERT_EQUAL(C, 2); + return UNIT_TEST_PASSED; +} // OnePlusOneShouldEqualTwo() +``` + +The prototype for this function matches the `UNIT_TEST_FUNCTION` prototype= . It takes in a handle to the Framework +itself and the context pointer. The context pointer could be cast and inte= rpreted as anything within this test case, +which is why it's important to configure contexts carefully. The test case= returns a value of `UNIT_TEST_STATUS`, which +will be recorded in the Framework and reported at the end of all suites. + +In this test case, the `UT_ASSERT_EQUAL` assertion is being used to establ= ish that the business logic has functioned +correctly. There are several assertion macros, and you are encouraged to u= se one that matches as closely to your +intended test criterium as possible, because the logging is specific to th= e macro and more specific macros have more +detailed logs. When in doubt, there are always `UT_ASSERT_TRUE` and `UT_AS= SERT_FALSE`. Assertion macros that fail their +test criterium will immediately return from the test case with `UNIT_TEST_= ERROR_TEST_FAILED` and log an error string. +_Note_ that this early return can have implications for memory leakage. + +At the end, if all test criteria pass, you should return `UNIT_TEST_PASSED= `. + +### More Complex Cases + +To write more advanced tests, first take a look at all the Assertion and L= ogging macros provided in the framework. + +Beyond that, if you're writing host-based tests and want to take a depende= ncy on the UnitTestFrameworkPkg, you can +leverage the `cmocka.h` interface and write tests with all the features of= the Cmocka framework. + +Documentation for Cmocka can be found here: +https://api.cmocka.org/ + +## Development + +When using the EDK2 Pytools for CI testing, the host-based unit tests will= be built and run on any build that includes the `NOOPT` build target. + +If you are trying to iterate on a single test, a convenient pattern is to = build only that test module. For example, the following command will build = only the SafeIntLib host-based test from the MdePkg... + +```bash +stuart_ci_build -c .pytool/CISettings.py TOOL_CHAIN_TAG=3DVS2017 -p MdePkg= -t NOOPT BUILDMODULE=3DMdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBas= eSafeIntLib.inf +``` + +## Known Limitations + +### PEI, DXE, SMM + +While sample tests have been provided for these execution environments, on= ly cursory build validation +has been performed. Care has been taken while designing the frameworks to = allow for execution during +boot phases, but only UEFI Shell and host-based tests have been thoroughly= evaluated. Full support for +PEI, DXE, and SMM is forthcoming, but should be considered beta/staging fo= r now. + +### Host-Based Support vs Other Tests + +The host-based test framework is powered internally by the Cmocka framewor= k. As such, it has abilities +that the target-based tests don't (yet). It would be awesome if this meant= that it was a super set of +the target-based tests, and it worked just like the target-based tests but= with more features. Unfortunately, +this is not the case. While care has been taken to keep them as close a po= ssible, there are a few known +inconsistencies that we're still ironing out. For example, the logging mes= sages in the target-based tests +are cached internally and associated with the running test case. They can = be saved later as part of the +reporting lib. This isn't currently possible with host-based. Only the ass= ertion failures are logged. + +We will continue trying to make these as similar as possible. + +## Copyright + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec b/UnitTestFramew= orkPkg/UnitTestFrameworkPkg.dec new file mode 100644 index 0000000000..069289f009 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec @@ -0,0 +1,50 @@ +## @file +# This Package provides all definitions (including functions, MACROs, +# structures library classes, and PCDs) and libraries instances, which are= used +# to support unit testing and interface testing. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION =3D 0x00010005 + PACKAGE_NAME =3D UnitTestFrameworkPkg + PACKAGE_UNI_FILE =3D UnitTestFrameworkPkg.uni + PACKAGE_GUID =3D 4A70C4A0-D72C-4D3F-9943-BE7C41C50BA3 + PACKAGE_VERSION =3D 1.00 + +[Includes] + Library/CmockaLib/cmocka/include + +[Includes.Common.Private] + PrivateInclude + Library/CmockaLib/cmocka/include/cmockery + +[LibraryClasses.Common.Private] + ## @libraryclass Allows save and restore unit test internal state + # + UnitTestPersistenceLib|PrivateInclude/Library/UnitTestPersistenceLib.h + + ## @libraryclass Provides a unit test result report + # + UnitTestResultReportLib|PrivateInclude/Library/UnitTestResultReportLib.h + + ## @libraryclass Provides boot-option routines useful in shell-based tes= ts. + # + UnitTestBootLib|PrivateInclude/Library/UnitTestBootLib.h + +[Guids] + gUnitTestFrameworkPkgTokenSpaceGuid =3D { 0x833d3aba, 0x39b4, 0x43a2, { = 0xb9, 0x30, 0x7a, 0x34, 0x53, 0x39, 0x31, 0xb3 } } + +[PcdsFixedAtBuild] + ## This flag is used to control build time optimization based on unit te= st + # log level. The default value is 0xFFFFFFFF to enable all unit test l= og + # messages. + # BIT0 - Error unit test log messages.
+ # BIT1 - Warning unit test log messages.
+ # BIT2 - Informational unit test log messages.
+ # BIT3 - Verbose unit test log messages.
+ # @Prompt Unit Test Log Message Level + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel|0xFFFFFFFF|UINT3= 2|0x00000001 diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.uni b/UnitTestFramew= orkPkg/UnitTestFrameworkPkg.uni new file mode 100644 index 0000000000..180675ae1a --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.uni @@ -0,0 +1,21 @@ +// /** @file +// This Package provides all definitions (including functions, MACROs, +// structures library classes, and PCDs) and libraries instances, which ar= e used +// to support unit testing and interface testing. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PACKAGE_ABSTRACT #language en-US "This Package provides al= l definitions (including functions, MACROs, structures library classes, and= PCDs) and libraries instances, which are used to support unit testing and = interface testing." + +#string STR_PACKAGE_DESCRIPTION #language en-US "This Package provides al= l definitions (including functions, MACROs, structures library classes, and= PCDs) and libraries instances, which are used to support unit testing and = interface testing." + +#string STR_gUnitTestFrameworkPkgTokenSpaceGuid_PcdUnitTestLogLevel_PROMPT= #language en-US "Unit Test Log Message Level" + +#string STR_gUnitTestFrameworkPkgTokenSpaceGuid_PcdUnitTestLogLevel_HELP = #language en-US "This flag is used to control build time optimization bas= ed on unit test log level. The default value is 0xFFFFFFFF to enable all u= nit test log messages.

\n" + = "BIT0 - Error unit test log messages.
\n" + = "BIT1 - Warning unit test log messages.
\n" + = "BIT2 - Informational unit test log messages.
\n" + = "BIT3 - Verbose unit test log messages.
\n" --=20 2.21.0.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 (#54054): https://edk2.groups.io/g/devel/message/54054 Mute This Topic: https://groups.io/mt/71060082/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54055+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54055+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099242193517.725907820461; Fri, 7 Feb 2020 10:14:02 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id etazYY1788612xSEvM0rFoZw; Fri, 07 Feb 2020 10:14:01 -0800 X-Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by mx.groups.io with SMTP id smtpd.web12.9025.1581099240821545376 for ; Fri, 07 Feb 2020 10:14:01 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:14:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500544" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:13:59 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew Subject: [edk2-devel] [Patch v2 05/11] UnitTestFrameworkPkg/Library: Add library instances Date: Fri, 7 Feb 2020 10:13:48 -0800 Message-Id: <20200207181354.31632-6-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: TXX2TsmJRxmCjVTryfmcsOFox1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099241; bh=ZRlcqtRKPekSkdPSZ3zpm3R2gNa3iurb1W0Y2AQil7o=; h=Cc:Date:From:Reply-To:Subject:To; b=wcOCHAYYxpnlN7Lu6qaZFAAS5HqEZqLIKghpO1a6l4vfGCsdZtDYvj8bACyBDhEcK/p s1eGaBTsJ4XbbtAwep45yIt/WqUJ/NRSUArXgLiB3St153cEoD9kYRW11Qou2dRId4K0u GsH74DLkjwMe6srmodmurmV+rmfx3r3JoNI= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 Add the following library instances that are used to build unit tests for host and target environments. * CmockaLib with cmocka submodule to: https://git.cryptomilk.org/projects/cmocka.git * DebugLibPosix - Instance of DebugLib based on POSIX APIs (e.g. printf). * MemoryAllocationLibPosix - Instance of MemoryAllocationLib based on POSIX APIs (e.g. malloc/free). * UnitTestBootLibNull - Null instance of the UnitTestBootLib * UnitTestBootLibUsbClass - UnitTestBootLib instances that supports setting boot next to a USB device. * UnitTestLib - UnitTestLib instance that is designed to work with PEI, DXE, SMM, and UEFI Shell target environments. * UnitTestLibCmocka - UintTestLib instance that uses cmocka APIs and can only be use in a host environment. * UnitTestPersistenceLibNull - Null instance of the UnitTestPersistenceLib * UnitTestPersistenceLibSimpleFileSystem - UnitTestPersistenceLib instance that can safe the unit test framework state to a media device that supports the UEFI Simple File System Protocol. * UnitTestResultReportLibConOut - UnitTestResultReportLib instance that sends report results to the UEFI standard output console. * UnitTestResultReportLibDebugLib - UnitTestResultReportLib instance that sends report results to a DebugLib using DEBUG() macros. Cc: Sean Brogan Cc: Bret Barkelew Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew --- .gitmodules | 3 + .../Library/CmockaLib/CmockaLib.inf | 35 + .../Library/CmockaLib/CmockaLib.uni | 14 + UnitTestFrameworkPkg/Library/CmockaLib/cmocka | 1 + .../Posix/DebugLibPosix/DebugLibPosix.c | 279 ++++++ .../Posix/DebugLibPosix/DebugLibPosix.inf | 35 + .../Posix/DebugLibPosix/DebugLibPosix.uni | 14 + .../MemoryAllocationLibPosix.c | 631 +++++++++++++ .../MemoryAllocationLibPosix.inf | 27 + .../MemoryAllocationLibPosix.uni | 14 + .../UnitTestBootLibNull/UnitTestBootLibNull.c | 26 + .../UnitTestBootLibNull.inf | 23 + .../UnitTestBootLibNull.uni | 11 + .../UnitTestBootLibUsbClass.c | 127 +++ .../UnitTestBootLibUsbClass.inf | 34 + .../UnitTestBootLibUsbClass.uni | 12 + .../Library/UnitTestLib/Assert.c | 491 ++++++++++ .../Library/UnitTestLib/AssertCmocka.c | 335 +++++++ .../Library/UnitTestLib/Log.c | 200 ++++ .../Library/UnitTestLib/RunTests.c | 171 ++++ .../Library/UnitTestLib/RunTestsCmocka.c | 278 ++++++ .../Library/UnitTestLib/UnitTestLib.c | 853 ++++++++++++++++++ .../Library/UnitTestLib/UnitTestLib.inf | 37 + .../Library/UnitTestLib/UnitTestLib.uni | 11 + .../Library/UnitTestLib/UnitTestLibCmocka.inf | 38 + .../Library/UnitTestLib/UnitTestLibCmocka.uni | 11 + .../UnitTestPersistenceLibNull.c | 75 ++ .../UnitTestPersistenceLibNull.inf | 28 + .../UnitTestPersistenceLibNull.uni | 11 + .../UnitTestPersistenceLibSimpleFileSystem.c | 416 +++++++++ ...UnitTestPersistenceLibSimpleFileSystem.inf | 47 + ...UnitTestPersistenceLibSimpleFileSystem.uni | 15 + .../UnitTestResultReportLib.c | 216 +++++ .../UnitTestResultReportLibConOut.c | 48 + .../UnitTestResultReportLibConOut.inf | 29 + .../UnitTestResultReportLibConOut.uni | 11 + .../UnitTestResultReportLibDebugLib.c | 47 + .../UnitTestResultReportLibDebugLib.inf | 28 + .../UnitTestResultReportLibDebugLib.uni | 11 + 39 files changed, 4693 insertions(+) create mode 100644 UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf create mode 100644 UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni create mode 160000 UnitTestFrameworkPkg/Library/CmockaLib/cmocka create mode 100644 UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugL= ibPosix.c create mode 100644 UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugL= ibPosix.inf create mode 100644 UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugL= ibPosix.uni create mode 100644 UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibP= osix/MemoryAllocationLibPosix.c create mode 100644 UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibP= osix/MemoryAllocationLibPosix.inf create mode 100644 UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibP= osix/MemoryAllocationLibPosix.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTe= stBootLibNull.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTe= stBootLibNull.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTe= stBootLibNull.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/Un= itTestBootLibUsbClass.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/Un= itTestBootLibUsbClass.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/Un= itTestBootLibUsbClass.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/Log.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka= .c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmo= cka.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmo= cka.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull= /UnitTestPersistenceLibNull.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull= /UnitTestPersistenceLibNull.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull= /UnitTestPersistenceLibNull.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimp= leFileSystem/UnitTestPersistenceLibSimpleFileSystem.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimp= leFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimp= leFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Un= itTestResultReportLib.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Un= itTestResultReportLibConOut.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Un= itTestResultReportLibConOut.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Un= itTestResultReportLibConOut.uni create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Un= itTestResultReportLibDebugLib.c create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Un= itTestResultReportLibDebugLib.inf create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Un= itTestResultReportLibDebugLib.uni diff --git a/.gitmodules b/.gitmodules index 508f0c1828..b30f5bf136 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "SoftFloat"] path =3D ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3 url =3D https://github.com/ucb-bar/berkeley-softfloat-3.git +[submodule "UnitTestFrameworkPkg/Library/CmockaLib/cmocka"] + path =3D UnitTestFrameworkPkg/Library/CmockaLib/cmocka + url =3D https://git.cryptomilk.org/projects/cmocka.git diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf b/UnitTes= tFrameworkPkg/Library/CmockaLib/CmockaLib.inf new file mode 100644 index 0000000000..07da7a88e9 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf @@ -0,0 +1,35 @@ +## @file +# This module provides Cmocka Library implementation. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D CmockaLib + MODULE_UNI_FILE =3D CmockaLib.uni + FILE_GUID =3D F1662152-3399-49AC-BE44-CAA97575FACE + MODULE_TYPE =3D BASE + VERSION_STRING =3D 0.1 + LIBRARY_CLASS =3D CmockaLib|HOST_APPLICATION + +# +# VALID_ARCHITECTURES =3D IA32 X64 ARM AARCH64 +# + +[Sources] + cmocka/src/cmocka.c + +[Packages] + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS =3D=3D /c -DHAVE_VSNPRINTF -DHAVE_SNPRINTF + MSFT:NOOPT_*_*_CC_FLAGS =3D /Od + + GCC:*_*_*_CC_FLAGS =3D=3D -g -DHAVE_SIGNAL_H + GCC:NOOPT_*_*_CC_FLAGS =3D -O0 + GCC:*_*_IA32_CC_FLAGS =3D -m32 + GCC:*_*_X64_CC_FLAGS =3D -m64 diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni b/UnitTes= tFrameworkPkg/Library/CmockaLib/CmockaLib.uni new file mode 100644 index 0000000000..acdb72d075 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni @@ -0,0 +1,14 @@ +// /** @file +// This module provides Cmocka Library implementation. +// +// This module provides Cmocka Library implementation. +// +// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Cmocka Library im= plementation" + +#string STR_MODULE_DESCRIPTION #language en-US "This module provi= des Cmocka Library implementation." diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/cmocka b/UnitTestFramew= orkPkg/Library/CmockaLib/cmocka new file mode 160000 index 0000000000..1cc9cde344 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/CmockaLib/cmocka @@ -0,0 +1 @@ +Subproject commit 1cc9cde3448cdd2e000886a26acf1caac2db7cf1 diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix= .c b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c new file mode 100644 index 0000000000..0daea00728 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c @@ -0,0 +1,279 @@ +/** @file + Instance of Debug Library based on POSIX APIs + + Uses Print Library to produce formatted output strings sent to printf(). + + Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include +#include +#include +#include + +/// +/// Define the maximum debug and assert message length that this library s= upports +/// +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +/** + Prints a debug message to the debug output device if the specified error= level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format a= nd the + associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format The format string for the debug message to print. + @param ... The variable argument list whose contents are access= ed + based on the format string specified by Format. + +**/ +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + VA_LIST Marker; + + VA_START (Marker, Format); + DebugVPrint (ErrorLevel, Format, Marker); + VA_END (Marker); +} + +/** + Prints a debug message to the debug output device if the specified + error level is enabled. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format a= nd + the associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format Format string for the debug message to print. + @param VaListMarker VA_LIST marker for the variable argument list. + +**/ +VOID +EFIAPI +DebugVPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + IN VA_LIST VaListMarker + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + + AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker); + printf ("%s", Buffer); +} + +/** + Prints a debug message to the debug output device if the specified + error level is enabled. + This function use BASE_LIST which would provide a more compatible + service than VA_LIST. + + If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function + GetDebugPrintErrorLevel (), then print the message specified by Format a= nd + the associated variable argument list to the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format Format string for the debug message to print. + @param BaseListMarker BASE_LIST marker for the variable argument list. + +**/ +VOID +EFIAPI +DebugBPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + IN BASE_LIST BaseListMarker + ) +{ + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH]; + + AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker); + printf ("%s", Buffer); +} + +/** + Prints an assert message containing a filename, line number, and descrip= tion. + This may be followed by a breakpoint or a dead loop. + + Print a message of the form "ASSERT (): \n" + to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED= bit of + PcdDebugPropertyMask is set then CpuBreakpoint() is called. Otherwise, if + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugPropertyMask is se= t then + CpuDeadLoop() is called. If neither of these bits are set, then this fu= nction + returns immediately after the message is printed to the debug output dev= ice. + DebugAssert() must actively prevent recursion. If DebugAssert() is call= ed while + processing another DebugAssert(), then DebugAssert() must return immedia= tely. + + If FileName is NULL, then a string of "(NULL) Filename" is pr= inted. + If Description is NULL, then a string of "(NULL) Descripti= on" is printed. + + @param FileName The pointer to the name of the source file that gen= erated the assert condition. + @param LineNumber The line number in the source file that generated t= he assert condition + @param Description The pointer to the description of the assert condit= ion. + +**/ +VOID +EFIAPI +DebugAssert ( + IN CONST CHAR8 *FileName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + printf ("ASSERT: %s(%d): %s\n", FileName, (INT32)(UINT32)LineNumber, Des= cription); + + // + // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings + // + if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_EN= ABLED) !=3D 0) { + CpuBreakpoint (); + } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLO= OP_ENABLED) !=3D 0) { + CpuDeadLoop (); + } +} + +/** + Fills a target buffer with PcdDebugClearMemoryValue, and returns the tar= get buffer. + + This function fills Length bytes of Buffer with the value specified by + PcdDebugClearMemoryValue, and returns Buffer. + + If Buffer is NULL, then ASSERT(). + If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param Buffer The pointer to the target buffer to be filled with PcdD= ebugClearMemoryValue. + @param Length The number of bytes in Buffer to fill with zeros PcdDeb= ugClearMemoryValue. + + @return Buffer The pointer to the target buffer filled with PcdDebugCl= earMemoryValue. + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ + // + // If Buffer is NULL, then ASSERT(). + // + ASSERT (Buffer !=3D NULL); + + // + // SetMem() checks for the the ASSERT() condition on Length and returns = Buffer + // + return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue)); +} + +/** + Returns TRUE if ASSERT() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bi= t of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebug= PropertyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebug= PropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_= ASSERT_ENABLED) !=3D 0); +} + +/** + Returns TRUE if DEBUG() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit= of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugP= ropertyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugP= ropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_= PRINT_ENABLED) !=3D 0); +} + +/** + Returns TRUE if DEBUG_CODE() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit = of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPr= opertyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPr= opertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_= CODE_ENABLED) !=3D 0); +} + +/** + Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled. + + This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bi= t of + PcdDebugPropertyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebug= PropertyMask is set. + @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebug= PropertyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_= MEMORY_ENABLED) !=3D 0); +} + +/** + Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixe= dDebugPrintErrorLevel. + + This function compares the bit mask of ErrorLevel and PcdFixedDebugPrint= ErrorLevel. + + @retval TRUE Current ErrorLevel is supported. + @retval FALSE Current ErrorLevel is not supported. + +**/ +BOOLEAN +EFIAPI +DebugPrintLevelEnabled ( + IN CONST UINTN ErrorLevel + ) +{ + return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) = !=3D 0); +} diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix= .inf b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf new file mode 100644 index 0000000000..5babbca3b0 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf @@ -0,0 +1,35 @@ +## @file +# Instance of Debug Library based on POSIX APIs +# +# Uses Print Library to produce formatted output strings sent to printf(). +# +# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D DebugLibPosix + MODULE_UNI_FILE =3D DebugLibPosix.uni + FILE_GUID =3D 6A77CE89-C1B6-4A6B-9561-07D7127514A7 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D DebugLib|HOST_APPLICATION + +[Sources] + DebugLibPosix.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + PcdLib + PrintLib + BaseLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSU= MES + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix= .uni b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni new file mode 100644 index 0000000000..d34f1a05be --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni @@ -0,0 +1,14 @@ +// /** @file +// Instance of Debug Library based on POSIX APIs +// +// Uses Print Library to produce formatted output strings sent to printf(). +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Instance of Debug= Library based on POSIX APIs" + +#string STR_MODULE_DESCRIPTION #language en-US "Uses Print Librar= y to produce formatted output strings sent to printf()." diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/Me= moryAllocationLibPosix.c b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocat= ionLibPosix/MemoryAllocationLibPosix.c new file mode 100644 index 0000000000..1f590524d8 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAll= ocationLibPosix.c @@ -0,0 +1,631 @@ +/** @file + Instance of Memory Allocation Library based on POSIX APIs + + Uses POSIX APIs malloc() and free() to allocate and free memory. + + Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +#include +#include +#include + +/// +/// Signature for PAGE_HEAD structure +/// Used to verify that buffer being freed was allocated by this library. +/// +#define PAGE_HEAD_PRIVATE_SIGNATURE SIGNATURE_32 ('P', 'H', 'D', 'R') + +/// +/// Structure placed immediately before an aligned allocation to store the +/// information required to free the entire buffer allocated to support th= en +/// aligned allocation. +/// +typedef struct { + UINT32 Signature; + VOID *AllocatedBufffer; + UINTN TotalPages; + VOID *AlignedBuffer; + UINTN AlignedPages; +} PAGE_HEAD; + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of type EfiBootServicesData and return= s a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If= Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the req= uest, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ) +{ + return AllocateAlignedPages (Pages, SIZE_4KB); +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData. + + Allocates the number of 4KB pages of type EfiRuntimeServicesData and ret= urns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If= Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the req= uest, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePages ( + IN UINTN Pages + ) +{ + return AllocatePages (Pages); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType. + + Allocates the number of 4KB pages of type EfiReservedMemoryType and retu= rns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If= Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the req= uest, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPages ( + IN UINTN Pages + ) +{ + return AllocatePages (Pages); +} + +/** + Frees one or more 4KB pages that were previously allocated with one of t= he page allocation + functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specifi= ed by Buffer. Buffer + must have been allocated on a previous call to the page allocation servi= ces of the Memory + Allocation Library. If it is not possible to free allocated pages, then= this function will + perform no actions. + + If Buffer was not allocated with a page allocation function in the Memor= y Allocation Library, + then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer The pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreePages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + FreeAlignedPages (Buffer, Pages); +} + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specifi= ed alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServ= icesData with an + alignment specified by Alignment. The allocated buffer is returned. If= Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment rema= ining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSER= T(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a= power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + PAGE_HEAD PageHead; + PAGE_HEAD *PageHeadPtr; + UINTN AlignmentMask; + + ASSERT ((Alignment & (Alignment - 1)) =3D=3D 0); + + if (Alignment < SIZE_4KB) { + Alignment =3D SIZE_4KB; + } + AlignmentMask =3D Alignment - 1; + + // + // We need reserve Alignment pages for PAGE_HEAD, as meta data. + // + PageHead.Signature =3D PAGE_HEAD_PRIVATE_SIGNATURE; + PageHead.TotalPages =3D Pages + EFI_SIZE_TO_PAGES (Alignment) * 2; + PageHead.AlignedPages =3D Pages; + PageHead.AllocatedBufffer =3D malloc (EFI_PAGES_TO_SIZE (PageHead.TotalP= ages)); + if (PageHead.AllocatedBufffer =3D=3D NULL) { + return NULL; + } + PageHead.AlignedBuffer =3D (VOID *)(((UINTN) PageHead.AllocatedBufffer += AlignmentMask) & ~AlignmentMask); + if ((UINTN)PageHead.AlignedBuffer - (UINTN)PageHead.AllocatedBufffer < s= izeof(PAGE_HEAD)) { + PageHead.AlignedBuffer =3D (VOID *)((UINTN)PageHead.AlignedBuffer + Al= ignment); + } + + PageHeadPtr =3D (VOID *)((UINTN)PageHead.AlignedBuffer - sizeof(PAGE_HEA= D)); + memcpy (PageHeadPtr, &PageHead, sizeof(PAGE_HEAD)); + + return PageHead.AlignedBuffer; +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData at a spec= ified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiRuntimeS= ervicesData with an + alignment specified by Alignment. The allocated buffer is returned. If= Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment rema= ining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSER= T(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a= power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedRuntimePages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return AllocateAlignedPages (Pages, Alignment); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType at a speci= fied alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiReserved= MemoryType with an + alignment specified by Alignment. The allocated buffer is returned. If= Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment rema= ining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSER= T(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a= power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedReservedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return AllocateAlignedPages (Pages, Alignment); +} + +/** + Frees one or more 4KB pages that were previously allocated with one of t= he aligned page + allocation functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specifi= ed by Buffer. Buffer + must have been allocated on a previous call to the aligned page allocati= on services of the Memory + Allocation Library. If it is not possible to free allocated pages, then= this function will + perform no actions. + + If Buffer was not allocated with an aligned page allocation function in = the Memory Allocation + Library, then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer The pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreeAlignedPages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + PAGE_HEAD *PageHeadPtr; + + // + // NOTE: Partial free is not supported. Just keep it. + // + PageHeadPtr =3D (VOID *)((UINTN)Buffer - sizeof(PAGE_HEAD)); + if (PageHeadPtr->Signature !=3D PAGE_HEAD_PRIVATE_SIGNATURE) { + return; + } + if (PageHeadPtr->AlignedPages !=3D Pages) { + return; + } + + PageHeadPtr->Signature =3D 0; + free (PageHeadPtr->AllocatedBufffer); +} + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootSe= rvicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid b= uffer of 0 size is + returned. If there is not enough memory remaining to satisfy the reques= t, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ) +{ + return malloc (AllocationSize); +} + +/** + Allocates a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntim= eServicesData and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid= buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the reques= t, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePool ( + IN UINTN AllocationSize + ) +{ + return AllocatePool (AllocationSize); +} + +/** + Allocates a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReserv= edMemoryType and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid= buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the reques= t, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPool ( + IN UINTN AllocationSize + ) +{ + return AllocatePool (AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootSe= rvicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If Al= locationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remai= ning to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateZeroPool ( + IN UINTN AllocationSize + ) +{ + VOID *Buffer; + + Buffer =3D malloc (AllocationSize); + if (Buffer =3D=3D NULL) { + return NULL; + } + memset (Buffer, 0, AllocationSize); + return Buffer; +} + +/** + Allocates and zeros a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntim= eServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If Al= locationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remai= ning to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeZeroPool ( + IN UINTN AllocationSize + ) +{ + return AllocateZeroPool (AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReserv= edMemoryType, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If Al= locationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remai= ning to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedZeroPool ( + IN UINTN AllocationSize + ) +{ + return AllocateZeroPool (AllocationSize); +} + +/** + Copies a buffer to an allocated buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootSe= rvicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and retu= rns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size= is returned. If there + is not enough memory remaining to satisfy the request, then NULL is retu= rned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSER= T(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + VOID *Memory; + + Memory =3D malloc (AllocationSize); + if (Memory =3D=3D NULL) { + return NULL; + } + memcpy (Memory, Buffer, AllocationSize); + return Memory; +} + +/** + Copies a buffer to an allocated buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntim= eServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and retu= rns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size= is returned. If there + is not enough memory remaining to satisfy the request, then NULL is retu= rned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSER= T(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return AllocateCopyPool (AllocationSize, Buffer); +} + +/** + Copies a buffer to an allocated buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReserv= edMemoryType, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and retu= rns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size= is returned. If there + is not enough memory remaining to satisfy the request, then NULL is retu= rned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSER= T(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return AllocateCopyPool (AllocationSize, Buffer); +} + +/** + Reallocates a buffer of type EfiBootServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of= type + EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldS= ize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, a= nd + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there i= s not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of New= Size and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is = an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocatePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + VOID *NewBuffer; + + NewBuffer =3D malloc (NewSize); + if (NewBuffer !=3D NULL && OldBuffer !=3D NULL) { + memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize)); + } + if (OldBuffer !=3D NULL) { + FreePool(OldBuffer); + } + return NewBuffer; +} + +/** + Reallocates a buffer of type EfiRuntimeServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of= type + EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of O= ldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, a= nd + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there i= s not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of New= Size and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is = an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateRuntimePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return ReallocatePool (OldSize, NewSize, OldBuffer); +} + +/** + Reallocates a buffer of type EfiReservedMemoryType. + + Allocates and zeros the number bytes specified by NewSize from memory of= type + EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of Ol= dSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, a= nd + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there i= s not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of New= Size and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is = an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateReservedPool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return ReallocatePool (OldSize, NewSize, OldBuffer); +} + +/** + Frees a buffer that was previously allocated with one of the pool alloca= tion functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated o= n a previous call to the + pool allocation services of the Memory Allocation Library. If it is not= possible to free pool + resources, then this function will perform no actions. + + If Buffer was not allocated with a pool allocation function in the Memor= y Allocation Library, + then ASSERT(). + + @param Buffer The pointer to the buffer to free. + +**/ +VOID +EFIAPI +FreePool ( + IN VOID *Buffer + ) +{ + free (Buffer); +} diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/Me= moryAllocationLibPosix.inf b/UnitTestFrameworkPkg/Library/Posix/MemoryAlloc= ationLibPosix/MemoryAllocationLibPosix.inf new file mode 100644 index 0000000000..44ec3fd517 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAll= ocationLibPosix.inf @@ -0,0 +1,27 @@ +## @file +# Instance of Memory Allocation Library based on POSIX APIs +# +# Uses POSIX APIs malloc() and free() to allocate and free memory. +# +# Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D MemoryAllocationLibPosix + MODULE_UNI_FILE =3D MemoryAllocationLibPosix.uni + FILE_GUID =3D A1672454-A3D3-4AAC-A86B-8D63132BBB91 + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D MemoryAllocationLib|HOST_APPLICATION + +[Sources] + MemoryAllocationLibPosix.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/Me= moryAllocationLibPosix.uni b/UnitTestFrameworkPkg/Library/Posix/MemoryAlloc= ationLibPosix/MemoryAllocationLibPosix.uni new file mode 100644 index 0000000000..854b427976 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAll= ocationLibPosix.uni @@ -0,0 +1,14 @@ +// /** @file +// Instance of Memory Allocation Library based on POSIX APIs +// +// Uses POSIX APIs malloc() and free() to allocate and free memory. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Instance of Memor= y Allocation Library based on POSIX APIs" + +#string STR_MODULE_DESCRIPTION #language en-US "Uses POSIX APIs m= alloc() and free() to allocate and free memory." diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootL= ibNull.c b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLib= Null.c new file mode 100644 index 0000000000..c5a5162c58 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c @@ -0,0 +1,26 @@ +/** + NULL implementation for UnitTestBootLib to allow simple compilation + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +/** + Set the boot manager to boot from a specific device on the next boot. Th= is + should be set only for the next boot and shouldn't require any manual cl= ean up + + @retval EFI_SUCCESS Boot device for next boot was set. + @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not + supportted. + @retval Other Boot device for next boot can not be set. +**/ +EFI_STATUS +EFIAPI +SetBootNextDevice( + VOID + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootL= ibNull.inf b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootL= ibNull.inf new file mode 100644 index 0000000000..a4a907b65b --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.= inf @@ -0,0 +1,23 @@ +## @file +# NULL library for UnitTestBootUsb +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestBootLibNull + MODULE_UNI_FILE =3D UnitTestBootLibNull.uni + FILE_GUID =3D f143e75d-76e1-4040-b134-8f4f0bd5e3bd + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D DXE_DRIVER + LIBRARY_CLASS =3D UnitTestBootLib + +[Sources] + UnitTestBootLibNull.c + +[Packages] + MdePkg/MdePkg.dec + diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootL= ibNull.uni b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootL= ibNull.uni new file mode 100644 index 0000000000..1ed3b20544 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.= uni @@ -0,0 +1,11 @@ +// /** @file +// NULL library for UnitTestBootUsb +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "NULL library for = UnitTestBootUsb" + +#string STR_MODULE_DESCRIPTION #language en-US "NULL library for = UnitTestBootUsb." diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestB= ootLibUsbClass.c b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/Uni= tTestBootLibUsbClass.c new file mode 100644 index 0000000000..4ce48bd233 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibU= sbClass.c @@ -0,0 +1,127 @@ +/** + Implement UnitTestBootLib using USB Class Boot option. This should be + industry standard and should work on all platforms + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** + Set the boot manager to boot from a specific device on the next boot. Th= is + should be set only for the next boot and shouldn't require any manual cl= ean up + + @retval EFI_SUCCESS Boot device for next boot was set. + @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not + supportted. + @retval Other Boot device for next boot can not be set. +**/ +EFI_STATUS +EFIAPI +SetBootNextDevice ( + VOID + ) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION NewOption; + UINT32 Attributes; + UINT8 *OptionalData; + UINT32 OptionalDataSize; + UINT16 BootNextValue; + USB_CLASS_DEVICE_PATH UsbDp; + EFI_DEVICE_PATH_PROTOCOL *DpEnd; + EFI_DEVICE_PATH_PROTOCOL *Dp; + BOOLEAN NewOptionValid; + + OptionalData =3D NULL; + OptionalDataSize =3D 0; + BootNextValue =3D 0xABCD; // this should be a safe number... + DpEnd =3D NULL; + Dp =3D NULL; + NewOptionValid =3D FALSE; + + UsbDp.Header.Length[0] =3D (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) & 0xff); + UsbDp.Header.Length[1] =3D (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) >> 8); + UsbDp.Header.Type =3D MESSAGING_DEVICE_PATH; + UsbDp.Header.SubType =3D MSG_USB_CLASS_DP; + UsbDp.VendorId =3D 0xFFFF; + UsbDp.ProductId =3D 0xFFFF; + UsbDp.DeviceClass =3D 0xFF; + UsbDp.DeviceSubClass =3D 0xFF; + UsbDp.DeviceProtocol =3D 0xFF; + + Attributes =3D LOAD_OPTION_ACTIVE; + + DpEnd =3D AppendDevicePathNode (NULL, NULL); + if (DpEnd =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Unable to create device path. DpEnd is NULL= .\n", __FUNCTION__)); + Status =3D EFI_OUT_OF_RESOURCES; + goto CLEANUP; + } + + //@MRT --- Is this memory leak because we lose the old Dp memory + Dp =3D AppendDevicePathNode ( + DpEnd, + (EFI_DEVICE_PATH_PROTOCOL *)&UsbDp + ); + if (Dp =3D=3D NULL) { + DEBUG((DEBUG_ERROR, "%a: Unable to create device path. Dp is NULL.\n"= , __FUNCTION__)); + Status =3D EFI_OUT_OF_RESOURCES; + goto CLEANUP; + } + + Status =3D EfiBootManagerInitializeLoadOption ( + &NewOption, + (UINTN) BootNextValue, + LoadOptionTypeBoot, + Attributes, + L"Generic USB Class Device", + Dp, + OptionalData, + OptionalDataSize + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Error creating load option. Status =3D %r\n= ", __FUNCTION__, Status)); + goto CLEANUP; + } + + NewOptionValid =3D TRUE; + DEBUG ((DEBUG_VERBOSE, "%a: Generic USB Class Device boot option created= .\n", __FUNCTION__)); + Status =3D EfiBootManagerLoadOptionToVariable (&NewOption); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Error Saving boot option NV variable. Status= =3D %r\n", __FUNCTION__, Status)); + goto CLEANUP; + } + + // + // Set Boot Next + // + Status =3D gRT->SetVariable ( + L"BootNext", + &gEfiGlobalVariableGuid, + (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_= ACCESS | EFI_VARIABLE_NON_VOLATILE), + sizeof(BootNextValue), + &(BootNextValue) + ); + + DEBUG((DEBUG_VERBOSE, "%a - Set BootNext Status (%r)\n", __FUNCTION__, S= tatus)); + +CLEANUP: + if (Dp !=3D NULL) { + FreePool (Dp); + } + if (DpEnd !=3D NULL) { + FreePool (DpEnd); + } + if (NewOptionValid) { + EfiBootManagerFreeLoadOption (&NewOption); + } + return Status; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestB= ootLibUsbClass.inf b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/U= nitTestBootLibUsbClass.inf new file mode 100644 index 0000000000..80c4e4f111 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibU= sbClass.inf @@ -0,0 +1,34 @@ +## @file +# Library to support booting to USB on the next boot +# This instance uses the industry standard usb class boot option. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestBootLibUsbClass + MODULE_UNI_FILE =3D UnitTestBootLibUsbClass.uni + FILE_GUID =3D DFADE2A2-DB69-47DE-A37A-40FB6D52E844 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_APPLICATION + LIBRARY_CLASS =3D UnitTestBootLib + +[Sources] + UnitTestBootLibUsbClass.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + DebugLib + UefiRuntimeServicesTableLib + MemoryAllocationLib + DevicePathLib + UefiBootManagerLib + +[Guids] + gEfiGlobalVariableGuid ## CONSUMES ## Used to probe boot options and se= t BootNext. diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestB= ootLibUsbClass.uni b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/U= nitTestBootLibUsbClass.uni new file mode 100644 index 0000000000..8468b3537c --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibU= sbClass.uni @@ -0,0 +1,12 @@ +// /** @file +// Library to support booting to USB on the next boot +// This instance uses the industry standard usb class boot option. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to suppor= t booting to USB on the next boot" + +#string STR_MODULE_DESCRIPTION #language en-US "This instance use= s the industry standard usb class boot option.." diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c b/UnitTestFr= ameworkPkg/Library/UnitTestLib/Assert.c new file mode 100644 index 0000000000..dd85b84b08 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c @@ -0,0 +1,491 @@ +/** + Implement UnitTestLib assert services + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +STATIC +EFI_STATUS +AddUnitTestFailure ( + IN OUT UNIT_TEST *UnitTest, + IN CONST CHAR8 *FailureMessage, + IN FAILURE_TYPE FailureType + ) +{ + // + // Make sure that you're cooking with gas. + // + if (UnitTest =3D=3D NULL || FailureMessage =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + UnitTest->FailureType =3D FailureType; + AsciiStrCpyS ( + &UnitTest->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH, + FailureMessage + ); + + return EFI_SUCCESS; +} + +STATIC +VOID +UnitTestLogFailure ( + IN FAILURE_TYPE FailureType, + IN CONST CHAR8 *Format, + ... + ) +{ + UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle; + CHAR8 LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + VA_LIST Marker; + + // + // Get active Framework handle + // + FrameworkHandle =3D GetActiveFrameworkHandle (); + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (LogString, sizeof (LogString), Format, Marker); + VA_END (Marker); + + // + // Finally, add the string to the log. + // + AddUnitTestFailure ( + ((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, + LogString, + FailureType + ); + + return; +} + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of = the + assert provided by FunctionName, LineNumber, FileName, and Description a= re + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluatio= n. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression= being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (!Expression) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTTRUE, + "%a::%d Expression (%a) is not TRUE!\n", + FunctionName, + LineNumber, + Description + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Expression (%a) is not TRUE!\n", + FunctionName, + LineNumber, + Description + ); + } + return Expression; +} + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of t= he + assert provided by FunctionName, LineNumber, FileName, and Description a= re + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluatio= n. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression= being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (Expression) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTFALSE, + "%a::%d Expression(%a) is not FALSE!\n", + FunctionName, + LineNumber, + Description + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Expression (%a) is not FALSE!\n", + FunctionName, + LineNumber, + Description + ); + } + return !Expression; +} + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the locatio= n of + the assert provided by FunctionName, LineNumber, FileName, and Descripti= on are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if (EFI_ERROR (Status)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTEFIERROR, + "%a::%d Status '%a' is EFI_ERROR (%r)!\n", + FunctionName, + LineNumber, + Description, + Status + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Status '%a' is EFI_ERROR (%r)!\n", + FunctionName, + LineNumber, + Description, + Status + ); + } + return !EFI_ERROR( Status ); +} + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the lo= cation + of the assert provided by FunctionName, LineNumber, FileName, Descriptio= nA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if ((ValueA !=3D ValueB)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTEQUAL, + "%a::%d Value %a !=3D %a (%d !=3D %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Value %a !=3D %a (%d !=3D %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + } + return (ValueA =3D=3D ValueB); +} + +/** + If the contents of BufferA are identical to the contents of BufferB, the= n TRUE + is returned. If the contents of BufferA are not identical to the conten= ts of + BufferB, then an assert is triggered and the location of the assert prov= ided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and Buff= erB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the content= s of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if (CompareMem(BufferA, BufferB, Length) !=3D 0) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTEQUAL, + "%a::%d Memory at %a !=3D %a for length %d bytes!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + Length + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Value %a !=3D %a for length %d bytes!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + Length + ); + return FALSE; + } + return TRUE; +} + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the locati= on + of the assert provided by FunctionName, LineNumber, FileName, Descriptio= nA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if ((ValueA =3D=3D ValueB)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTEQUAL, + "%a::%d Value %a =3D=3D %a (%d =3D=3D %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Value %a =3D=3D %a (%d =3D=3D %d)!\n", + FunctionName, + LineNumber, + DescriptionA, + DescriptionB, + ValueA, + ValueB + ); + } + return (ValueA !=3D ValueB); +} + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, a= nd + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under te= st. + @param[in] Expected The expected EFI_STATUS return value from an A= PI + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a descrip= tion + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + if ((Status !=3D Expected)) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTSTATUSEQUAL, + "%a::%d Status '%a' is %r, should be %r!\n", + FunctionName, + LineNumber, + Description, + Status, + Expected + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Status '%a' is %r, should be %r!\n", + FunctionName, + LineNumber, + Description, + Status, + Expected + ); + } + return (Status =3D=3D Expected); +} + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the locatio= n of + the assert provided by FunctionName, LineNumber, FileName, and PointerNa= me + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a fu= nction + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a descrip= tion + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ) +{ + if (Pointer =3D=3D NULL) { + UnitTestLogFailure ( + FAILURETYPE_ASSERTNOTNULL, + "%a::%d Pointer (%a) is NULL!\n", + FunctionName, + LineNumber, + PointerName + ); + UT_LOG_ERROR ( + "[ASSERT FAIL] %a::%d Pointer (%a) is NULL!\n", + FunctionName, + LineNumber, + PointerName + ); + } + return (Pointer !=3D NULL); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c b/Unit= TestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c new file mode 100644 index 0000000000..e48d614976 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c @@ -0,0 +1,335 @@ +/** @file + Implement UnitTestLib assert services using cmocka services + + Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_STRING_SIZE 1025 + +/** + If Expression is TRUE, then TRUE is returned. + If Expression is FALSE, then an assert is triggered and the location of = the + assert provided by FunctionName, LineNumber, FileName, and Description a= re + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluatio= n. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression= being + evaluated. + + @retval TRUE Expression is TRUE. + @retval FALSE Expression is FALSE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_TRUE(%s:%x)", Description= , Expression); + _assert_true (Expression, TempStr, FileName, (INT32)LineNumber); + + return Expression; +} + +/** + If Expression is FALSE, then TRUE is returned. + If Expression is TRUE, then an assert is triggered and the location of t= he + assert provided by FunctionName, LineNumber, FileName, and Description a= re + recorded and FALSE is returned. + + @param[in] Expression The BOOLEAN result of the expression evaluatio= n. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the expression= being + evaluated. + + @retval TRUE Expression is FALSE. + @retval FALSE Expression is TRUE. +**/ +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_FALSE(%s:%x)", Descriptio= n, Expression); + _assert_true (!Expression, TempStr, FileName, (INT32)LineNumber); + + return !Expression; +} + +/** + If Status is not an EFI_ERROR(), then TRUE is returned. + If Status is an EFI_ERROR(), then an assert is triggered and the locatio= n of + the assert provided by FunctionName, LineNumber, FileName, and Descripti= on are + recorded and FALSE is returned. + + @param[in] Status The EFI_STATUS value to evaluate. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string of the status + expression being evaluated. + + @retval TRUE Status is not an EFI_ERROR(). + @retval FALSE Status is an EFI_ERROR(). +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EFI_ERROR(%s:%p)", De= scription, (void *)Status); + _assert_true (!EFI_ERROR (Status), TempStr, FileName, (INT32)LineNumber); + + return !EFI_ERROR (Status); +} + +/** + If ValueA is equal ValueB, then TRUE is returned. + If ValueA is not equal to ValueB, then an assert is triggered and the lo= cation + of the assert provided by FunctionName, LineNumber, FileName, Descriptio= nA, + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of ValueB. + + @retval TRUE ValueA is equal to ValueB. + @retval FALSE ValueA is not equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_EQUAL(%s:%llx, %s:%llx)",= DescriptionA, ValueA, DescriptionB, ValueB); + _assert_true ((ValueA =3D=3D ValueB), TempStr, FileName, (INT32)LineNumb= er); + + return (ValueA =3D=3D ValueB); +} + +/** + If the contents of BufferA are identical to the contents of BufferB, the= n TRUE + is returned. If the contents of BufferA are not identical to the conten= ts of + BufferB, then an assert is triggered and the location of the assert prov= ided + by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are + recorded and FALSE is returned. + + @param[in] BufferA Pointer to a buffer for comparison. + @param[in] BufferB Pointer to a buffer for comparison. + @param[in] Length Number of bytes to compare in BufferA and Buff= erB. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of BufferA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of BufferB. + + @retval TRUE The contents of BufferA are identical to the contents of + BufferB. + @retval FALSE The contents of BufferA are not identical to the content= s of + BufferB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertMemEqual ( + IN VOID *BufferA, + IN VOID *BufferB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + BOOLEAN Result; + + Result =3D (CompareMem(BufferA, BufferB, Length) =3D=3D 0); + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_MEM_EQUAL(%s:%p, %s:%p)",= DescriptionA, BufferA, DescriptionB, BufferB); + _assert_true (Result, TempStr, FileName, (INT32)LineNumber); + + return Result; +} + +/** + If ValueA is not equal ValueB, then TRUE is returned. + If ValueA is equal to ValueB, then an assert is triggered and the locati= on + of the assert provided by FunctionName, LineNumber, FileName, Descriptio= nA + and DescriptionB are recorded and FALSE is returned. + + @param[in] ValueA 64-bit value. + @param[in] ValueB 64-bit value. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] DescriptionA Null-terminated ASCII string that is a descrip= tion + of ValueA. + @param[in] DescriptionB Null-terminated ASCII string that is a descrip= tion + of ValueB. + + @retval TRUE ValueA is not equal to ValueB. + @retval FALSE ValueA is equal to ValueB. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UINT64 ValueA, + IN UINT64 ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EQUAL(%s:%llx, %s:%ll= x)", DescriptionA, ValueA, DescriptionB, ValueB); + _assert_true ((ValueA !=3D ValueB), TempStr, FileName, (INT32)LineNumber= ); + + return (ValueA !=3D ValueB); +} + +/** + If Status is equal to Expected, then TRUE is returned. + If Status is not equal to Expected, then an assert is triggered and the + location of the assert provided by FunctionName, LineNumber, FileName, a= nd + Description are recorded and FALSE is returned. + + @param[in] Status EFI_STATUS value returned from an API under te= st. + @param[in] Expected The expected EFI_STATUS return value from an A= PI + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] Description Null-terminated ASCII string that is a descrip= tion + of Status. + + @retval TRUE Status is equal to Expected. + @retval FALSE Status is not equal to Expected. +**/ +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *Description + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_STATUS_EQUAL(%s:%p)", Des= cription, (VOID *)Status); + _assert_true ((Status =3D=3D Expected), TempStr, FileName, (INT32)LineNu= mber); + + return (Status =3D=3D Expected); +} + +/** + If Pointer is not equal to NULL, then TRUE is returned. + If Pointer is equal to NULL, then an assert is triggered and the locatio= n of + the assert provided by FunctionName, LineNumber, FileName, and PointerNa= me + are recorded and FALSE is returned. + + @param[in] Pointer Pointer value to be checked against NULL. + @param[in] Expected The expected EFI_STATUS return value from a fu= nction + under test. + @param[in] FunctionName Null-terminated ASCII string of the function + executing the assert macro. + @param[in] LineNumber The source file line number of the assert macr= o. + @param[in] FileName Null-terminated ASCII string of the filename + executing the assert macro. + @param[in] PointerName Null-terminated ASCII string that is a descrip= tion + of Pointer. + + @retval TRUE Pointer is not equal to NULL. + @retval FALSE Pointer is equal to NULL. +**/ +BOOLEAN +EFIAPI +UnitTestAssertNotNull ( + IN VOID *Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *FileName, + IN CONST CHAR8 *PointerName + ) +{ + CHAR8 TempStr[MAX_STRING_SIZE]; + + snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_NULL(%s:%p)", Pointer= Name, Pointer); + _assert_true ((Pointer !=3D NULL), TempStr, FileName, (INT32)LineNumber); + + return (Pointer !=3D NULL); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c b/UnitTestFrame= workPkg/Library/UnitTestLib/Log.c new file mode 100644 index 0000000000..78df086a28 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c @@ -0,0 +1,200 @@ +/** + Implemnet UnitTestLib log services + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH (512) +#define UNIT_TEST_MAX_LOG_BUFFER SIZE_16KB + +struct _UNIT_TEST_LOG_PREFIX_STRING { + UNIT_TEST_STATUS LogLevel; + CHAR8 *String; +}; + +struct _UNIT_TEST_LOG_PREFIX_STRING mLogPrefixStrings[] =3D { + { UNIT_TEST_LOG_LEVEL_ERROR, "[ERROR] " }, + { UNIT_TEST_LOG_LEVEL_WARN, "[WARNING] " }, + { UNIT_TEST_LOG_LEVEL_INFO, "[INFO] " }, + { UNIT_TEST_LOG_LEVEL_VERBOSE, "[VERBOSE] " } +}; + +// +// Unit-Test Log helper functions +// + +STATIC +CONST CHAR8* +GetStringForStatusLogPrefix ( + IN UINTN LogLevel + ) +{ + UINTN Index; + CHAR8 *Result; + + Result =3D NULL; + for (Index =3D 0; Index < ARRAY_SIZE (mLogPrefixStrings); Index++) { + if (mLogPrefixStrings[Index].LogLevel =3D=3D LogLevel) { + Result =3D mLogPrefixStrings[Index].String; + break; + } + } + return Result; +} + +STATIC +EFI_STATUS +AddStringToUnitTestLog ( + IN OUT UNIT_TEST *UnitTest, + IN CONST CHAR8 *String + ) +{ + EFI_STATUS Status; + + // + // Make sure that you're cooking with gas. + // + if (UnitTest =3D=3D NULL || String =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // If this is the first log for the test allocate log space + if (UnitTest->Log =3D=3D NULL) { + UnitTestLogInit (UnitTest, NULL, 0); + } + + if (UnitTest->Log =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "Failed to allocate space for unit test log\n")); + ASSERT (UnitTest->Log !=3D NULL); + return EFI_OUT_OF_RESOURCES; + } + + Status =3D AsciiStrnCatS ( + UnitTest->Log, + UNIT_TEST_MAX_LOG_BUFFER / sizeof (CHAR8), + String, + UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH + ); + if(EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to add unit test log string. Status =3D = %r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} + +/** + This function is responsible for initializing the log buffer for a singl= e test. It can + be used internally, but may also be consumed by the test framework to ad= d pre-existing + data to a log before it's used. + + @param[in,out] TestHandle A handle to the test being initialized. + @param[in] Buffer [Optional] A pointer to pre-existing log d= ata that should + be used to initialize the log. Should incl= ude a NULL terminator. + @param[in] BufferSize [Optional] The size of the pre-existing lo= g data. + +**/ +VOID +EFIAPI +UnitTestLogInit ( + IN OUT UNIT_TEST *Test, + IN UINT8 *Buffer, OPTIONAL + IN UINTN BufferSize OPTIONAL + ) +{ + // + // Make sure that you're cooking with gas. + // + if (Test =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a called with invalid Test parameter\n", __FUNC= TION__)); + return; + } + + // + // If this is the first log for the test allocate log space + // + if (Test->Log =3D=3D NULL) { + Test->Log =3D AllocateZeroPool (UNIT_TEST_MAX_LOG_BUFFER); + } + + // + //check again to make sure allocate worked + // + if(Test->Log =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for the log\n")); + return; + } + + if((Buffer !=3D NULL) && (BufferSize > 0) && ((BufferSize <=3D UNIT_TEST= _MAX_LOG_BUFFER))) { + CopyMem (Test->Log, Buffer, BufferSize); + } +} + +/** + Test logging function that records a messages in the test framework log. + Record is associated with the currently executing test case. + + @param[in] ErrorLevel The error level of the unit test log message. + @param[in] Format Formatting string following the format defined i= n the + MdePkg/Include/Library/PrintLib.h. + @param[in] ... Print args. +**/ +VOID +EFIAPI +UnitTestLog ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle; + CHAR8 NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STR= ING_LENGTH]; + CHAR8 LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LE= NGTH]; + CONST CHAR8 *LogTypePrefix; + VA_LIST Marker; + + FrameworkHandle =3D GetActiveFrameworkHandle (); + + LogTypePrefix =3D NULL; + + // + // Make sure that this unit test log level is enabled. + // + if ((ErrorLevel & (UINTN)PcdGet32 (PcdUnitTestLogLevel)) =3D=3D 0) { + return; + } + + // + // If we need to define a new format string... + // well... get to it. + // + LogTypePrefix =3D GetStringForStatusLogPrefix (ErrorLevel); + if (LogTypePrefix !=3D NULL) { + AsciiSPrint (NewFormatString, sizeof (NewFormatString), "%a%a", LogTyp= ePrefix, Format); + } else { + AsciiStrCpyS (NewFormatString, sizeof (NewFormatString), Format); + } + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + AsciiVSPrint (LogString, sizeof (LogString), NewFormatString, Marker); + VA_END (Marker); + + // + // Finally, add the string to the log. + // + AddStringToUnitTestLog (((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->Curren= tTest, LogString); +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c b/UnitTest= FrameworkPkg/Library/UnitTestLib/RunTests.c new file mode 100644 index 0000000000..fb247c59e7 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c @@ -0,0 +1,171 @@ +/** + UnitTestLib APIs to run unit tests + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle =3D NULL; + +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ) +{ + ASSERT (mFrameworkHandle !=3D NULL); + return mFrameworkHandle; +} + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry; + UNIT_TEST *Test; + UNIT_TEST_FRAMEWORK *ParentFramework; + + TestEntry =3D NULL; + ParentFramework =3D (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework; + + if (Suite =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "------------------------------------------------= ---------\n")); + DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title)); + DEBUG ((DEBUG_VERBOSE, "------------------------------------------------= ---------\n")); + + if (Suite->Setup !=3D NULL) { + Suite->Setup (); + } + + // + // Iterate all tests within the suite + // + for (TestEntry =3D (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCa= seList)); + (LIST_ENTRY*)TestEntry !=3D &(Suite->TestCaseList); + TestEntry =3D (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCas= eList), (LIST_ENTRY *)TestEntry)) { + Test =3D &TestEntry->UT; + ParentFramework->CurrentTest =3D Test; + + DEBUG ((DEBUG_VERBOSE, "**********************************************= ***********\n")); + DEBUG ((DEBUG_VERBOSE, " RUNNING TEST: %a:\n", Test->Description)); + DEBUG ((DEBUG_VERBOSE, "**********************************************= ************\n")); + + // + // First, check to see whether the test has already been run. + // NOTE: This would generally only be the case if a saved state was de= tected and loaded. + // + if (Test->Result !=3D UNIT_TEST_PENDING && Test->Result !=3D UNIT_TEST= _RUNNING) { + DEBUG ((DEBUG_VERBOSE, "Test was run on a previous pass. Skipping.\n= ")); + ParentFramework->CurrentTest =3D NULL; + continue; + } + + // + // Next, if we're still running, make sure that our test prerequisites= are in place. + if (Test->Result =3D=3D UNIT_TEST_PENDING && Test->Prerequisite !=3D N= ULL) { + DEBUG ((DEBUG_VERBOSE, "PREREQ\n")); + if (Test->Prerequisite (Test->Context) !=3D UNIT_TEST_PASSED) { + DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n")); + Test->Result =3D UNIT_TEST_ERROR_PREREQUISITE_NOT_MET; + ParentFramework->CurrentTest =3D NULL; + continue; + } + } + + // + // Now we should be ready to call the actual test. + // We set the status to UNIT_TEST_RUNNING in case the test needs to re= boot + // or quit. The UNIT_TEST_RUNNING state will allow the test to resume + // but will prevent the Prerequisite from being dispatched a second ti= me. + Test->Result =3D UNIT_TEST_RUNNING; + Test->Result =3D Test->RunTest (Test->Context); + + // + // Finally, clean everything up, if need be. + if (Test->CleanUp !=3D NULL) { + DEBUG ((DEBUG_VERBOSE, "CLEANUP\n")); + Test->CleanUp (Test->Context); + } + + // + // End the test. + // + ParentFramework->CurrentTest =3D NULL; + } + + if (Suite->Teardown !=3D NULL) { + Suite->Teardown (); + } + + return EFI_SUCCESS; +} + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and u= nit + test cases are registered, this function will cause the unit test framew= ork to + dispatch all unit test cases in sequence and record the results for repo= rting. + + @param[in] FrameworkHandle A handle to the current running framework t= hat + dispatched the test. Necessary for recordi= ng + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + EFI_STATUS Status; + + Framework =3D (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Suite =3D NULL; + + if (Framework =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "------------------------------------------------= ---------\n")); + DEBUG ((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES -----= ---------\n")); + DEBUG ((DEBUG_VERBOSE, "------------------------------------------------= ---------\n")); + mFrameworkHandle =3D FrameworkHandle; + + // + // Iterate all suites + // + for (Suite =3D (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->T= estSuiteList); + (LIST_ENTRY *)Suite !=3D &Framework->TestSuiteList; + Suite =3D (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestS= uiteList, (LIST_ENTRY *)Suite)) { + Status =3D RunTestSuite (&(Suite->UTS)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } + + // + // Save current state so if test is started again it doesn't have to run= . It will just report + // + SaveFrameworkState (FrameworkHandle, NULL, 0); + OutputUnitTestFrameworkReport (FrameworkHandle); + + mFrameworkHandle =3D NULL; + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c b/Un= itTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c new file mode 100644 index 0000000000..fb81cc9658 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c @@ -0,0 +1,278 @@ +/** @file + UnitTestLib APIs to run unit tests using cmocka + + Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle =3D NULL; + +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ) +{ + ASSERT (mFrameworkHandle !=3D NULL); + return mFrameworkHandle; +} + +// +// The currently active test suite +// +UNIT_TEST_SUITE *mActiveUnitTestSuite =3D NULL; + +void +CmockaUnitTestFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest =3D (UNIT_TEST *)(*state); + Suite =3D (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework =3D (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->RunTest =3D=3D NULL) { + UnitTest->Result =3D UNIT_TEST_SKIPPED; + } else { + UnitTest->Result =3D UNIT_TEST_RUNNING; + + Framework->CurrentTest =3D UnitTest; + UnitTest->Result =3D UnitTest->RunTest (UnitTest->Context); + Framework->CurrentTest =3D NULL; + + // Print out the log messages - This is a partial solution as it + // does not get the log into the XML. Need cmocka changes to support + // stdout and stderr in their xml format + // + if (UnitTest->Log !=3D NULL) { + print_message("UnitTest: %s - %s\n", UnitTest->Name, UnitTest->Descr= iption); + print_message("Log Output Start\n"); + print_message("%s", UnitTest->Log); + print_message("Log Output End\n"); + } + } +} + +int +CmockaUnitTestSetupFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_STATUS Result; + + UnitTest =3D (UNIT_TEST *)(*state); + Suite =3D (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework =3D (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->Prerequisite =3D=3D NULL) { + return 0; + } + + Framework->CurrentTest =3D UnitTest; + Result =3D UnitTest->Prerequisite (UnitTest->Context); + Framework->CurrentTest =3D NULL; + + // + // Return 0 for success. Non-zero for error. + // + return (int)Result; +} + +int +CmockaUnitTestTeardownFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest =3D (UNIT_TEST *)(*state); + Suite =3D (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework =3D (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->CleanUp =3D=3D NULL) { + return 0; + } + + Framework->CurrentTest =3D UnitTest; + UnitTest->CleanUp (UnitTest->Context); + Framework->CurrentTest =3D NULL; + // + // Return 0 for success. Non-zero for error. + // + return 0; +} + +int +CmockaUnitTestSuiteSetupFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite =3D=3D NULL) { + return -1; + } + if (mActiveUnitTestSuite->Setup =3D=3D NULL) { + return 0; + } + + mActiveUnitTestSuite->Setup (); + // + // Always succeed + // + return 0; +} + +int +CmockaUnitTestSuiteTeardownFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite =3D=3D NULL) { + return -1; + } + if (mActiveUnitTestSuite->Teardown =3D=3D NULL) { + return 0; + } + + mActiveUnitTestSuite->Teardown (); + // + // Always succeed + // + return 0; +} + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry; + UNIT_TEST *UnitTest; + struct CMUnitTest *Tests; + UINTN Index; + + TestEntry =3D NULL; + + if (Suite =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "------------------------------------------------= ---------\n")); + DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title)); + DEBUG ((DEBUG_VERBOSE, "------------------------------------------------= ---------\n")); + + // + // Allocate buffer of CMUnitTest entries + // + Tests =3D AllocateZeroPool (Suite->NumTests * sizeof (struct CMUnitTest)= ); + ASSERT (Tests !=3D NULL); + + // + // Populate buffer of CMUnitTest entries + // + Index =3D 0; + for (TestEntry =3D (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCa= seList)); + (LIST_ENTRY *)TestEntry !=3D &(Suite->TestCaseList); + TestEntry =3D (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCas= eList), (LIST_ENTRY *)TestEntry)) { + UnitTest =3D &TestEntry->UT; + Tests[Index].name =3D UnitTest->Description; + Tests[Index].test_func =3D CmockaUnitTestFunctionRunner; + Tests[Index].setup_func =3D CmockaUnitTestSetupFunctionRunner; + Tests[Index].teardown_func =3D CmockaUnitTestTeardownFunctionRunner; + Tests[Index].initial_state =3D UnitTest; + Index++; + } + ASSERT (Index =3D=3D Suite->NumTests); + + // + // Run all unit tests in a test suite + // + mActiveUnitTestSuite =3D Suite; + _cmocka_run_group_tests ( + Suite->Title, + Tests, + Suite->NumTests, + CmockaUnitTestSuiteSetupFunctionRunner, + CmockaUnitTestSuiteTeardownFunctionRunner + ); + mActiveUnitTestSuite =3D NULL; + FreePool (Tests); + + return EFI_SUCCESS; +} + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and u= nit + test cases are registered, this function will cause the unit test framew= ork to + dispatch all unit test cases in sequence and record the results for repo= rting. + + @param[in] FrameworkHandle A handle to the current running framework t= hat + dispatched the test. Necessary for recordi= ng + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + EFI_STATUS Status; + + Framework =3D (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Suite =3D NULL; + + if (Framework =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG((DEBUG_VERBOSE, "-------------------------------------------------= --------\n")); + DEBUG((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES ------= --------\n")); + DEBUG((DEBUG_VERBOSE, "-------------------------------------------------= --------\n")); + mFrameworkHandle =3D FrameworkHandle; + + // + // Iterate all suites + // + for (Suite =3D (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->T= estSuiteList); + (LIST_ENTRY *)Suite !=3D &Framework->TestSuiteList; + Suite =3D (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestS= uiteList, (LIST_ENTRY *)Suite)) { + Status =3D RunTestSuite (&(Suite->UTS)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } + + mFrameworkHandle =3D NULL; + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c b/UnitT= estFrameworkPkg/Library/UnitTestLib/UnitTestLib.c new file mode 100644 index 0000000000..fd15991ea4 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c @@ -0,0 +1,853 @@ +/** + Implement UnitTestLib + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/// +/// Forward declaration of prototype +/// +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ); + +/** + This function will determine whether the short name violates any rules t= hat would + prevent it from being used as a reporting name or as a serialization nam= e. + + Example: If the name cannot be serialized to a filesystem file name. + + @param[in] ShortTitleString A pointer to the short title string to be = evaluated. + + @retval TRUE The string is acceptable. + @retval FALSE The string should not be used. + +**/ +STATIC +BOOLEAN +IsFrameworkShortNameValid ( + IN CHAR8 *ShortTitleString + ) +{ + // TODO: Finish this function. + return TRUE; +} + +STATIC +CHAR8* +AllocateAndCopyString ( + IN CHAR8 *StringToCopy + ) +{ + CHAR8 *NewString; + UINTN NewStringLength; + + NewString =3D NULL; + NewStringLength =3D AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LE= NGTH) + 1; + NewString =3D AllocatePool (NewStringLength * sizeof( CHAR8 )); + if (NewString !=3D NULL) { + AsciiStrCpyS (NewString, NewStringLength, StringToCopy); + } + return NewString; +} + +STATIC +VOID +SetFrameworkFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework + ) +{ + UINT32 NewFingerprint; + + // For this one we'll just use the title and version as the unique finge= rprint. + NewFingerprint =3D CalculateCrc32( Framework->Title, (AsciiStrLen( Frame= work->Title ) * sizeof( CHAR8 )) ); + NewFingerprint =3D (NewFingerprint >> 8) ^ CalculateCrc32( Framework->Ve= rsionString, (AsciiStrLen( Framework->VersionString ) * sizeof( CHAR8 )) ); + + CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE ); + return; +} + +STATIC +VOID +SetSuiteFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework, + IN UNIT_TEST_SUITE *Suite + ) +{ + UINT32 NewFingerprint; + + // For this one, we'll use the fingerprint from the framework, and the t= itle of the suite. + NewFingerprint =3D CalculateCrc32( &Framework->Fingerprint[0], UNIT_TEST= _FINGERPRINT_SIZE ); + NewFingerprint =3D (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Title,= (AsciiStrLen( Suite->Title ) * sizeof( CHAR8 )) ); + NewFingerprint =3D (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Name, = (AsciiStrLen(Suite->Name) * sizeof(CHAR8)) ); + + CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE ); + return; +} + +STATIC +VOID +SetTestFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_SUITE *Suite, + IN UNIT_TEST *Test + ) +{ + UINT32 NewFingerprint; + + // For this one, we'll use the fingerprint from the suite, and the descr= iption and classname of the test. + NewFingerprint =3D CalculateCrc32( &Suite->Fingerprint[0], UNIT_TEST_FIN= GERPRINT_SIZE ); + NewFingerprint =3D (NewFingerprint >> 8) ^ CalculateCrc32( Test->Descrip= tion, (AsciiStrLen( Test->Description ) * sizeof( CHAR8 )) ); + NewFingerprint =3D (NewFingerprint >> 8) ^ CalculateCrc32( Test->Name, (= AsciiStrLen(Test->Name) * sizeof(CHAR8)) ); + + CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE ); + return; +} + +STATIC +BOOLEAN +CompareFingerprints ( + IN UINT8 *FingerprintA, + IN UINT8 *FingerprintB + ) +{ + return (CompareMem( FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SI= ZE ) =3D=3D 0); +} + +/** + Cleanup a test framework. + + After tests are run, this will teardown the entire framework and free all + allocated data within. + + @param[in] FrameworkHandle A handle to the current running framework t= hat + dispatched the test. Necessary for recordi= ng + certain test events with the framework. + + @retval EFI_SUCCESS All resources associated with framework = were + freed. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +FreeUnitTestFramework ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FreeUnitTestSuiteEntry ( + IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FreeUnitTestTestEntry ( + IN UNIT_TEST_LIST_ENTRY *TestEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} + +/** + Method to Initialize the Unit Test framework. This function registers t= he + test name and also initializes the internal state of the test framework = to + receive any new suites and tests. + + @param[out] FrameworkHandle Unit test framework to be created. + @param[in] Title Null-terminated ASCII string that is the u= ser + friendly name of the framework. String is + copied. + @param[in] ShortTitle Null-terminated ASCII short string that is= the + short name of the framework with no spaces. + String is copied. + @param[in] VersionString Null-terminated ASCII version string for t= he + framework. String is copied. + + @retval EFI_SUCCESS The unit test framework was initialized. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is NULL. + @retval EFI_INVALID_PARAMETER VersionString is NULL. + @retval EFI_INVALID_PARAMETER ShortTitle is invalid. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + initialize the unit test framework. +**/ +EFI_STATUS +EFIAPI +InitUnitTestFramework ( + OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *ShortTitle, + IN CHAR8 *VersionString + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle; + UNIT_TEST_FRAMEWORK *NewFramework; + UNIT_TEST_SAVE_HEADER *SavedState; + + Status =3D EFI_SUCCESS; + NewFramework =3D NULL; + + // + // First, check all pointers and make sure nothing's broked. + // + if (FrameworkHandle =3D=3D NULL || Title =3D=3D NULL || + ShortTitle =3D=3D NULL || VersionString =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Next, determine whether all of the strings are good to use. + // + if (!IsFrameworkShortNameValid (ShortTitle)) { + return EFI_INVALID_PARAMETER; + } + + // + // Next, set aside some space to start messing with the framework. + // + NewFramework =3D AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK)); + if (NewFramework =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Next, set up all the test data. + // + NewFrameworkHandle =3D (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework; + NewFramework->Title =3D AllocateAndCopyString (Title); + NewFramework->ShortTitle =3D AllocateAndCopyString (ShortTitle); + NewFramework->VersionString =3D AllocateAndCopyString (VersionString); + NewFramework->Log =3D NULL; + NewFramework->CurrentTest =3D NULL; + NewFramework->SavedState =3D NULL; + if (NewFramework->Title =3D=3D NULL || + NewFramework->ShortTitle =3D=3D NULL || + NewFramework->VersionString =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + InitializeListHead (&(NewFramework->TestSuiteList)); + + // + // Create the framework fingerprint. + // + SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework); + + // + // If there is a persisted context, load it now. + // + if (DoesCacheExist (NewFrameworkHandle)) { + SavedState =3D (UNIT_TEST_SAVE_HEADER *)NewFramework->SavedState; + Status =3D LoadUnitTestCache (NewFrameworkHandle, &SavedState); + if (EFI_ERROR (Status)) { + // + // Don't actually report it as an error, but emit a warning. + // + DEBUG (( DEBUG_ERROR, "%a - Cache was detected, but failed to load.\= n", __FUNCTION__ )); + Status =3D EFI_SUCCESS; + } + } + +Exit: + // + // If we're good, then let's copy the framework. + // + if (!EFI_ERROR (Status)) { + *FrameworkHandle =3D NewFrameworkHandle; + } else { + // + // Otherwise, we need to undo this horrible thing that we've done. + // + FreeUnitTestFramework (NewFrameworkHandle); + } + + return Status; +} + +/** + Registers a Unit Test Suite in the Unit Test Framework. + At least one test suite must be registered, because all test cases must = be + within a unit test suite. + + @param[out] SuiteHandle Unit test suite to create + @param[in] FrameworkHandle Unit test framework to add unit test suite= to + @param[in] Title Null-terminated ASCII string that is the u= ser + friendly name of the test suite. String is + copied. + @param[in] Name Null-terminated ASCII string that is the s= hort + name of the test suite with no spaces. St= ring + is copied. + @param[in] Setup Setup function, runs before suite. This i= s an + optional parameter that may be NULL. + @param[in] Teardown Teardown function, runs after suite. This= is an + optional parameter that may be NULL. + + @retval EFI_SUCCESS The unit test suite was created. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER Title is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + initialize the unit test suite. +**/ +EFI_STATUS +EFIAPI +CreateUnitTestSuite ( + OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle, + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN CHAR8 *Title, + IN CHAR8 *Name, + IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL, + IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL + ) +{ + EFI_STATUS Status; + UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry; + UNIT_TEST_FRAMEWORK *Framework; + + Status =3D EFI_SUCCESS; + Framework =3D (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + + // + // First, let's check to make sure that our parameters look good. + // + if ((SuiteHandle =3D=3D NULL) || (Framework =3D=3D NULL) || (Title =3D= =3D NULL) || (Name =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Create the new entry. + // + NewSuiteEntry =3D AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY)); + if (NewSuiteEntry =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the fields we think we need. + // + NewSuiteEntry->UTS.NumTests =3D 0; + NewSuiteEntry->UTS.Title =3D AllocateAndCopyString (Title); + NewSuiteEntry->UTS.Name =3D AllocateAndCopyString (Name); + NewSuiteEntry->UTS.Setup =3D Setup; + NewSuiteEntry->UTS.Teardown =3D Teardown; + NewSuiteEntry->UTS.ParentFramework =3D FrameworkHandle; + InitializeListHead (&(NewSuiteEntry->Entry)); // List entry = for sibling suites. + InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList)); // List entry = for child tests. + if (NewSuiteEntry->UTS.Title =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + if (NewSuiteEntry->UTS.Name =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Create the suite fingerprint. + // + SetSuiteFingerprint( &NewSuiteEntry->UTS.Fingerprint[0], Framework, &New= SuiteEntry->UTS ); + +Exit: + // + // If everything is going well, add the new suite to the tail list for t= he framework. + // + if (!EFI_ERROR( Status )) { + InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEnt= ry); + *SuiteHandle =3D (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS); + } else { + // + // Otherwise, make with the destruction. + // + FreeUnitTestSuiteEntry (NewSuiteEntry); + } + + return Status; +} + +/** + Adds test case to Suite + + @param[in] SuiteHandle Unit test suite to add test to. + @param[in] Description Null-terminated ASCII string that is the user + friendly description of a test. String is cop= ied. + @param[in] Name Null-terminated ASCII string that is the short= name + of the test with no spaces. String is copied. + @param[in] Function Unit test function. + @param[in] Prerequisite Prerequisite function, runs before test. This= is + an optional parameter that may be NULL. + @param[in] CleanUp Clean up function, runs after test. This is an + optional parameter that may be NULL. + @param[in] Context Pointer to context. This is an optional par= ameter + that may be NULL. + + @retval EFI_SUCCESS The unit test case was added to Suite. + @retval EFI_INVALID_PARAMETER SuiteHandle is NULL. + @retval EFI_INVALID_PARAMETER Description is NULL. + @retval EFI_INVALID_PARAMETER Name is NULL. + @retval EFI_INVALID_PARAMETER Function is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + add the unit test case to Suite. +**/ +EFI_STATUS +EFIAPI +AddTestCase ( + IN UNIT_TEST_SUITE_HANDLE SuiteHandle, + IN CHAR8 *Description, + IN CHAR8 *Name, + IN UNIT_TEST_FUNCTION Function, + IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL, + IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, + IN UNIT_TEST_CONTEXT Context OPTIONAL + ) +{ + EFI_STATUS Status; + UNIT_TEST_LIST_ENTRY *NewTestEntry; + UNIT_TEST_FRAMEWORK *ParentFramework; + UNIT_TEST_SUITE *Suite; + + Status =3D EFI_SUCCESS; + Suite =3D (UNIT_TEST_SUITE *)SuiteHandle; + ParentFramework =3D (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework; + + // + // First, let's check to make sure that our parameters look good. + // + if ((Suite =3D=3D NULL) || (Description =3D=3D NULL) || (Name =3D=3D NUL= L) || (Function =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Create the new entry. + NewTestEntry =3D AllocateZeroPool (sizeof( UNIT_TEST_LIST_ENTRY )); + if (NewTestEntry =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the fields we think we need. + NewTestEntry->UT.Description =3D AllocateAndCopyString (Descriptio= n); + NewTestEntry->UT.Name =3D AllocateAndCopyString (Name); + NewTestEntry->UT.FailureType =3D FAILURETYPE_NOFAILURE; + NewTestEntry->UT.FailureMessage[0] =3D '\0'; + NewTestEntry->UT.Log =3D NULL; + NewTestEntry->UT.Prerequisite =3D Prerequisite; + NewTestEntry->UT.CleanUp =3D CleanUp; + NewTestEntry->UT.RunTest =3D Function; + NewTestEntry->UT.Context =3D Context; + NewTestEntry->UT.Result =3D UNIT_TEST_PENDING; + NewTestEntry->UT.ParentSuite =3D SuiteHandle; + InitializeListHead (&(NewTestEntry->Entry)); // List entry for sibling = tests. + if (NewTestEntry->UT.Description =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + if (NewTestEntry->UT.Name =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Create the test fingerprint. + // + SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEnt= ry->UT); + + // TODO: Make sure that duplicate fingerprints cannot be created. + + // + // If there is saved test data, update this record. + // + if (ParentFramework->SavedState !=3D NULL) { + UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState); + } + +Exit: + // + // If everything is going well, add the new suite to the tail list for t= he framework. + // + if (!EFI_ERROR (Status)) { + InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY*)NewTestEntry); + Suite->NumTests++; + } else { + // + // Otherwise, make with the destruction. + // + FreeUnitTestTestEntry (NewTestEntry); + } + + return Status; +} + +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ) +{ + UNIT_TEST_SAVE_TEST *CurrentTest; + UNIT_TEST_SAVE_TEST *MatchingTest; + UINT8 *FloatingPointer; + UNIT_TEST_SAVE_CONTEXT *SavedContext; + UINTN Index; + + // + // First, evaluate the inputs. + // + if (Test =3D=3D NULL || SavedState =3D=3D NULL) { + return; + } + if (SavedState->TestCount =3D=3D 0) { + return; + } + + // + // Next, determine whether a matching test can be found. + // Start at the beginning. + // + MatchingTest =3D NULL; + FloatingPointer =3D (UINT8 *)SavedState + sizeof (*SavedState); + for (Index =3D 0; Index < SavedState->TestCount; Index++) { + CurrentTest =3D (UNIT_TEST_SAVE_TEST *)FloatingPointer; + if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerpr= int[0])) { + MatchingTest =3D CurrentTest; + // + // If there's a saved context, it's important that we iterate throug= h the entire list. + // + if (!SavedState->HasSavedContext) { + break; + } + } + + // + // If we didn't find it, we have to increment to the next test. + // + FloatingPointer =3D (UINT8 *)CurrentTest + CurrentTest->Size; + } + + // + // If a matching test was found, copy the status. + // + if (MatchingTest) { + // + // Override the test status with the saved status. + // + Test->Result =3D MatchingTest->Result; + + Test->FailureType =3D MatchingTest->FailureType; + AsciiStrnCpyS ( + &Test->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH, + &MatchingTest->FailureMessage[0], + UNIT_TEST_TESTFAILUREMSG_LENGTH + ); + + // + // If there is a log string associated, grab that. + // We can tell that there's a log string because the "size" will be la= rger than + // the structure size. + // IMPORTANT NOTE: There are security implications here. + // This data is user-supplied and we're about to play = kinda + // fast and loose with data buffers. + // + if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) { + UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Siz= e - sizeof (UNIT_TEST_SAVE_TEST)); + } + } + + // + // If the saved context exists and matches this test, grab it, too. + // + if (SavedState->HasSavedContext) { + // + // If there was a saved context, the "matching test" loop will have pl= aced the FloatingPointer + // at the beginning of the context structure. + // + SavedContext =3D (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer; + if ((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0 && + CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerp= rint[0])) { + // + // Override the test context with the saved context. + // + Test->Context =3D (VOID*)SavedContext->Data; + } + } +} + +STATIC +UNIT_TEST_SAVE_HEADER* +SerializeState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave, OPTIONAL + IN UINTN ContextToSaveSize + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SAVE_HEADER *Header; + LIST_ENTRY *SuiteListHead; + LIST_ENTRY *Suite; + LIST_ENTRY *TestListHead; + LIST_ENTRY *Test; + UINT32 TestCount; + UINT32 TotalSize; + UINTN LogSize; + UNIT_TEST_SAVE_TEST *TestSaveData; + UNIT_TEST_SAVE_CONTEXT *TestSaveContext; + UNIT_TEST *UnitTest; + UINT8 *FloatingPointer; + + Framework =3D (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Header =3D NULL; + + // + // First, let's not make assumptions about the parameters. + // + if (Framework =3D=3D NULL || + (ContextToSave !=3D NULL && ContextToSaveSize =3D=3D 0) || + ContextToSaveSize > MAX_UINT32) { + return NULL; + } + + // + // Next, we've gotta figure out the resources that will be required to s= erialize the + // the framework state so that we can persist it. + // To start with, we're gonna need a header. + // + TotalSize =3D sizeof (UNIT_TEST_SAVE_HEADER); + // + // Now we need to figure out how many tests there are. + // + TestCount =3D 0; + // + // Iterate all suites. + // + SuiteListHead =3D &Framework->TestSuiteList; + for (Suite =3D GetFirstNode (SuiteListHead); Suite !=3D SuiteListHead; S= uite =3D GetNextNode (SuiteListHead, Suite)) { + // + // Iterate all tests within the suite. + // + TestListHead =3D &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseL= ist; + for (Test =3D GetFirstNode (TestListHead); Test !=3D TestListHead; Tes= t =3D GetNextNode (TestListHead, Test)) { + UnitTest =3D &((UNIT_TEST_LIST_ENTRY *)Test)->UT; + // + // Account for the size of a test structure. + // + TotalSize +=3D sizeof( UNIT_TEST_SAVE_TEST ); + // + // If there's a log, make sure to account for the log size. + // + if (UnitTest->Log !=3D NULL) { + // + // The +1 is for the NULL character. Can't forget the NULL charact= er. + // + LogSize =3D (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8); + ASSERT (LogSize < MAX_UINT32); + TotalSize +=3D (UINT32)LogSize; + } + // + // Increment the test count. + // + TestCount++; + } + } + // + // If there are no tests, we're done here. + // + if (TestCount =3D=3D 0) { + return NULL; + } + // + // Add room for the context, if there is one. + // + if (ContextToSave !=3D NULL) { + TotalSize +=3D sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSave= Size; + } + + // + // Now that we know the size, we need to allocate space for the serializ= ed output. + // + Header =3D AllocateZeroPool (TotalSize); + if (Header =3D=3D NULL) { + return NULL; + } + + // + // Alright, let's start setting up some data. + // + Header->Version =3D UNIT_TEST_PERSISTENCE_LIB_VERSION; + Header->SaveStateSize =3D TotalSize; + CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_= FINGERPRINT_SIZE); + CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME)); + Header->TestCount =3D TestCount; + Header->HasSavedContext =3D FALSE; + + // + // Start adding all of the test cases. + // Set the floating pointer to the start of the current test save buffer. + // + FloatingPointer =3D (UINT8*)Header + sizeof( UNIT_TEST_SAVE_HEADER ); + // + // Iterate all suites. + // + SuiteListHead =3D &Framework->TestSuiteList; + for (Suite =3D GetFirstNode (SuiteListHead); Suite !=3D SuiteListHead; S= uite =3D GetNextNode (SuiteListHead, Suite)) { + // + // Iterate all tests within the suite. + // + TestListHead =3D &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseL= ist; + for (Test =3D GetFirstNode (TestListHead); Test !=3D TestListHead; Tes= t =3D GetNextNode (TestListHead, Test)) { + TestSaveData =3D (UNIT_TEST_SAVE_TEST *)FloatingPointer; + UnitTest =3D &((UNIT_TEST_LIST_ENTRY *)Test)->UT; + + // + // Save the fingerprint. + // + CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], U= NIT_TEST_FINGERPRINT_SIZE); + + // + // Save the result. + // + TestSaveData->Result =3D UnitTest->Result; + TestSaveData->FailureType =3D UnitTest->FailureType; + AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_TESTFAILU= REMSG_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH= ); + + + // + // If there is a log, save the log. + // + FloatingPointer +=3D sizeof (UNIT_TEST_SAVE_TEST); + if (UnitTest->Log !=3D NULL) { + // + // The +1 is for the NULL character. Can't forget the NULL charact= er. + // + LogSize =3D (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8); + CopyMem (FloatingPointer, UnitTest->Log, LogSize); + FloatingPointer +=3D LogSize; + } + + // + // Update the size once the structure is complete. + // NOTE: Should this be a straight cast without validation? + // + TestSaveData->Size =3D (UINT32)(FloatingPointer - (UINT8 *)TestSaveD= ata); + } + } + + // + // If there is a context to save, let's do that now. + // + if (ContextToSave !=3D NULL && Framework->CurrentTest !=3D NULL) { + TestSaveContext =3D (UNIT_TEST_SAVE_CONTEXT*)FloatingPointer; + TestSaveContext->Size =3D (UINT32)ContextToSaveSize + sizeof (UNIT_T= EST_SAVE_CONTEXT); + CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fi= ngerprint[0], UNIT_TEST_FINGERPRINT_SIZE); + CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)),= ContextToSave, ContextToSaveSize); + Header->HasSavedContext =3D TRUE; + } + + return Header; +} + +/** + Leverages a framework-specific mechanism (see UnitTestPersistenceLib if = you're + a framework author) to save the state of the executing framework along w= ith + any allocated data so that the test may be resumed upon reentry. A test = case + should pass any needed context (which, to prevent an infinite loop, shou= ld be + at least the current execution count) which will be saved by the framewo= rk and + passed to the test case upon resume. + + Generally called from within a test case prior to quitting or rebooting. + + @param[in] FrameworkHandle A handle to the current running framework= that + dispatched the test. Necessary for recor= ding + certain test events with the framework. + @param[in] ContextToSave A buffer of test case-specific data to be= saved + along with framework state. Will be pass= ed as + "Context" to the test case upon resume. = This + is an optional parameter that may be NULL. + @param[in] ContextToSaveSize Size of the ContextToSave buffer. + + @retval EFI_SUCCESS The framework state and context were sav= ed. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. + @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and + ContextToSaveSize is 0. + @retval EFI_INVALID_PARAMETER ContextToSave is >=3D 4GB. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available= to + save the framework and context state. + @retval EFI_DEVICE_ERROR The framework and context state could no= t be + saved to a persistent storage device due= to a + device error. +**/ +EFI_STATUS +EFIAPI +SaveFrameworkState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ) +{ + EFI_STATUS Status; + UNIT_TEST_SAVE_HEADER *Header; + + Header =3D NULL; + + // + // First, let's not make assumptions about the parameters. + // + if (FrameworkHandle =3D=3D NULL || + (ContextToSave !=3D NULL && ContextToSaveSize =3D=3D 0) || + ContextToSaveSize > MAX_UINT32) { + return EFI_INVALID_PARAMETER; + } + + // + // Now, let's package up all the data for saving. + // + Header =3D SerializeState (FrameworkHandle, ContextToSave, ContextToSave= Size); + if (Header =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // All that should be left to do is save it using the associated persist= ence lib. + // + Status =3D SaveUnitTestCache (FrameworkHandle, Header); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __FUNCTION__, = Status)); + Status =3D EFI_DEVICE_ERROR; + } + + // + // Free data that was used. + // + FreePool (Header); + + return Status; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf b/Uni= tTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf new file mode 100644 index 0000000000..96e40e973c --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf @@ -0,0 +1,37 @@ +## @file +# Library to support Unit Testing from PEI, DXE, SMM, and UEFI Application= s. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestLib + MODULE_UNI_FILE =3D UnitTestLib.uni + FILE_GUID =3D 98CEF9CA-15CE-40A3-ADE8-C299953CD0F6 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_DRIVER + LIBRARY_CLASS =3D UnitTestLib|PEIM DXE_DRIVER DXE_SMM_DRIVER UEFI_DRIV= ER UEFI_APPLICATION + +[Sources] + UnitTestLib.c + RunTests.c + Assert.c + Log.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + PcdLib + DebugLib + MemoryAllocationLib + UnitTestPersistenceLib + UnitTestResultReportLib + +[Pcd] + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni b/Uni= tTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni new file mode 100644 index 0000000000..fe7c9c7f71 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applicatio= ns. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to suppor= t Unit Testing from PEI, DXE, SMM, and UEFI Applications" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to suppor= t Unit Testing from PEI, DXE, SMM, and UEFI Applications." diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf= b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf new file mode 100644 index 0000000000..b12af91576 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf @@ -0,0 +1,38 @@ +## @file +# Library to support Unit Testing from host environments using Cmocka serv= ices. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestLibCmocka + MODULE_UNI_FILE =3D UnitTestLibCmocka.uni + FILE_GUID =3D C800595F-45A3-45A1-8B50-28F01C2A5A4F + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_DRIVER + LIBRARY_CLASS =3D UnitTestLib|HOST_APPLICATION + +[Sources] + UnitTestLib.c + RunTestsCmocka.c + AssertCmocka.c + Log.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + PcdLib + DebugLib + MemoryAllocationLib + UnitTestPersistenceLib + UnitTestResultReportLib + CmockaLib + +[Pcd] + gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel ## CONSUMES diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni= b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni new file mode 100644 index 0000000000..aa25a44e35 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support Unit Testing from host environments using Cmocka ser= vices. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to suppor= t Unit Testing from host environments using Cmocka services" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to suppor= t Unit Testing from host environments using Cmocka services." diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTe= stPersistenceLibNull.c b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLi= bNull/UnitTestPersistenceLibNull.c new file mode 100644 index 0000000000..e28327652e --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersi= stenceLibNull.c @@ -0,0 +1,75 @@ +/** @file + This is an instance of the Unit Test Persistence Lib that does nothing. + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +/** + Determines whether a persistence cache already exists for + the given framework. + + @param[in] FrameworkHandle A pointer to the framework that is being pe= rsisted. + + @retval TRUE + @retval FALSE Cache doesn't exist or an error occurred. + +**/ +BOOLEAN +EFIAPI +DoesCacheExist ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + return FALSE; +} + +/** + Will save the data associated with an internal Unit Test Framework + state in a manner that can persist a Unit Test Application quit or + even a system reboot. + + @param[in] FrameworkHandle A pointer to the framework that is being pe= rsisted. + @param[in] SaveData A pointer to the buffer containing the seri= alized + framework internal state. + + @retval EFI_SUCCESS Data is persisted and the test can be safely quit. + @retval Others Data is not persisted and test cannot be resumed u= pon exit. + +**/ +EFI_STATUS +EFIAPI +SaveUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_SAVE_HEADER *SaveData + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Will retrieve any cached state associated with the given framework. + Will allocate a buffer to hold the loaded data. + + @param[in] FrameworkHandle A pointer to the framework that is being pe= rsisted. + @param[in] SaveData A pointer pointer that will be updated with= the address + of the loaded data buffer. + + @retval EFI_SUCCESS Data has been loaded successfully and SaveData is = updated + with a pointer to the buffer. + @retval Others An error has occurred and no data has been loaded.= SaveData + is set to NULL. + +**/ +EFI_STATUS +EFIAPI +LoadUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + OUT UNIT_TEST_SAVE_HEADER **SaveData + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTe= stPersistenceLibNull.inf b/UnitTestFrameworkPkg/Library/UnitTestPersistence= LibNull/UnitTestPersistenceLibNull.inf new file mode 100644 index 0000000000..1175772662 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersi= stenceLibNull.inf @@ -0,0 +1,28 @@ +## @file +# This is an instance of the Unit Test Persistence Lib does nothing. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestPersistenceLibNull + MODULE_UNI_FILE =3D UnitTestPersistenceLibNull.uni + FILE_GUID =3D B8553C7A-0B0B-4BBD-9DF3-825804BF26AB + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_DRIVER + LIBRARY_CLASS =3D UnitTestPersistenceLib + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + UnitTestPersistenceLibNull.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTe= stPersistenceLibNull.uni b/UnitTestFrameworkPkg/Library/UnitTestPersistence= LibNull/UnitTestPersistenceLibNull.uni new file mode 100644 index 0000000000..00f7d8d7f0 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersi= stenceLibNull.uni @@ -0,0 +1,11 @@ +// /** @file +// NULL library for Unit Test Persistence Lib. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "NULL library for = Unit Test Persistence Lib" + +#string STR_MODULE_DESCRIPTION #language en-US "NULL library for = Unit Test Persistence Lib." diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileS= ystem/UnitTestPersistenceLibSimpleFileSystem.c b/UnitTestFrameworkPkg/Libra= ry/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileS= ystem.c new file mode 100644 index 0000000000..ccca9bfacb --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/U= nitTestPersistenceLibSimpleFileSystem.c @@ -0,0 +1,416 @@ +/** @file + This is an instance of the Unit Test Persistence Lib that will utilize + the filesystem that a test application is running from to save a seriali= zed + version of the internal test state in case the test needs to quit and re= store. + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CACHE_FILE_SUFFIX L"_Cache.dat" + +/** + Generate the device path to the cache file. + + @param[in] FrameworkHandle A pointer to the framework that is being pe= rsisted. + + @retval !NULL A pointer to the EFI_FILE protocol instance for the file= system. + @retval NULL Filesystem could not be found or an error occurred. + +**/ +STATIC +EFI_DEVICE_PATH_PROTOCOL* +GetCacheFileDevicePath ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK *Framework; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR16 *AppPath; + CHAR16 *CacheFilePath; + CHAR16 *TestName; + UINTN DirectorySlashOffset; + UINTN CacheFilePathLength; + EFI_DEVICE_PATH_PROTOCOL *CacheFileDevicePath; + + Framework =3D (UNIT_TEST_FRAMEWORK*)FrameworkHandle; + AppPath =3D NULL; + CacheFilePath =3D NULL; + TestName =3D NULL; + CacheFileDevicePath =3D NULL; + + // + // First, we need to get some information from the loaded image. + // + Status =3D gBS->HandleProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a - Failed to locate DevicePath for loaded image= . %r\n", __FUNCTION__, Status)); + return NULL; + } + + // + // Before we can start, change test name from ASCII to Unicode. + // + CacheFilePathLength =3D AsciiStrLen (Framework->ShortTitle) + 1; + TestName =3D AllocatePool (CacheFilePathLength); + if (!TestName) { + goto Exit; + } + AsciiStrToUnicodeStrS (Framework->ShortTitle, TestName, CacheFilePathLen= gth); + + // + // Now we should have the device path of the root device and a file path= for the rest. + // In order to target the directory for the test application, we must pr= ocess + // the file path a little. + // + // NOTE: This may not be necessary... Path processing functions exist... + // PathCleanUpDirectories (FileNameCopy); + // if (PathRemoveLastItem (FileNameCopy)) { + // + AppPath =3D ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);= // NOTE: This must be freed. + DirectorySlashOffset =3D StrLen (AppPath); + // + // Make sure we didn't get any weird data. + // + if (DirectorySlashOffset =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a - Weird 0-length string when processing app p= ath.\n", __FUNCTION__)); + goto Exit; + } + + // + // Now that we know we have a decent string, let's take a deeper look. + // + do { + if (AppPath[DirectorySlashOffset] =3D=3D L'\\') { + break; + } + DirectorySlashOffset--; + } while (DirectorySlashOffset > 0); + + // + // After that little maneuver, DirectorySlashOffset should be pointing a= t the last '\' in AppString. + // That would be the path to the parent directory that the test app is e= xecuting from. + // Let's check and make sure that's right. + // + if (AppPath[DirectorySlashOffset] !=3D L'\\') { + DEBUG ((DEBUG_ERROR, "%a - Could not find a single directory separator= in app path.\n", __FUNCTION__)); + goto Exit; + } + + // + // Now we know some things, we're ready to produce our output string, I = think. + // + CacheFilePathLength =3D DirectorySlashOffset + 1; + CacheFilePathLength +=3D StrLen (TestName); + CacheFilePathLength +=3D StrLen (CACHE_FILE_SUFFIX); + CacheFilePathLength +=3D 1; // Don't forget the NULL terminator. + CacheFilePath =3D AllocateZeroPool (CacheFilePathLength * sizeof (= CHAR16)); + if (!CacheFilePath) { + goto Exit; + } + + // + // Let's produce our final path string, shall we? + // + StrnCpyS (CacheFilePath, CacheFilePathLength, AppPath, DirectorySlashOff= set + 1); // Copy the path for the parent directory. + StrCatS (CacheFilePath, CacheFilePathLength, TestName); = // Copy the base name for the test cache. + StrCatS (CacheFilePath, CacheFilePathLength, CACHE_FILE_SUFFIX); = // Copy the file suffix. + + // + // Finally, try to create the device path for the thing thing. + // + CacheFileDevicePath =3D FileDevicePath (LoadedImage->DeviceHandle, Cache= FilePath); + +Exit: + // + // Free allocated buffers. + // + if (AppPath !=3D NULL) { + FreePool (AppPath); + } + if (CacheFilePath !=3D NULL) { + FreePool (CacheFilePath); + } + if (TestName !=3D NULL) { + FreePool (TestName); + } + + return CacheFileDevicePath; +} + +/** + Determines whether a persistence cache already exists for + the given framework. + + @param[in] FrameworkHandle A pointer to the framework that is being pe= rsisted. + + @retval TRUE + @retval FALSE Cache doesn't exist or an error occurred. + +**/ +BOOLEAN +EFIAPI +DoesCacheExist ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + + // + // NOTE: This devpath is allocated and must be freed. + // + FileDevicePath =3D GetCacheFileDevicePath (FrameworkHandle); + + // + // Check to see whether the file exists. If the file can be opened for + // reading, it exists. Otherwise, probably not. + // + Status =3D ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + EFI_FILE_MODE_READ, + 0 + ); + if (!EFI_ERROR (Status)) { + ShellCloseFile (&FileHandle); + } + + if (FileDevicePath !=3D NULL) { + FreePool (FileDevicePath); + } + + DEBUG ((DEBUG_VERBOSE, "%a - Returning %d\n", __FUNCTION__, !EFI_ERROR (= Status))); + + return (!EFI_ERROR (Status)); +} + +/** + Will save the data associated with an internal Unit Test Framework + state in a manner that can persist a Unit Test Application quit or + even a system reboot. + + @param[in] FrameworkHandle A pointer to the framework that is being pe= rsisted. + @param[in] SaveData A pointer to the buffer containing the seri= alized + framework internal state. + + @retval EFI_SUCCESS Data is persisted and the test can be safely quit. + @retval Others Data is not persisted and test cannot be resumed u= pon exit. + +**/ +EFI_STATUS +EFIAPI +SaveUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_SAVE_HEADER *SaveData + ) +{ + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + UINTN WriteCount; + + // + // Check the inputs for sanity. + // + if (FrameworkHandle =3D=3D NULL || SaveData =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine the path for the cache file. + // NOTE: This devpath is allocated and must be freed. + // + FileDevicePath =3D GetCacheFileDevicePath (FrameworkHandle); + + // + //First lets open the file if it exists so we can delete it...This is th= e work around for truncation + // + Status =3D ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE), + 0 + ); + + if (!EFI_ERROR (Status)) { + // + // If file handle above was opened it will be closed by the delete. + // + Status =3D ShellDeleteFile (&FileHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a failed to delete file %r\n", __FUNCTION__, = Status)); + } + } + + // + // Now that we know the path to the file... let's open it for writing. + // + Status =3D ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CRE= ATE), + 0 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __F= UNCTION__, Status)); + goto Exit; + } + + // + // Write the data to the file. + // + WriteCount =3D SaveData->SaveStateSize; + DEBUG ((DEBUG_INFO, "%a - Writing %d bytes to file...\n", __FUNCTION__, = WriteCount)); + Status =3D ShellWriteFile ( + FileHandle, + &WriteCount, + SaveData + ); + + if (EFI_ERROR (Status) || WriteCount !=3D SaveData->SaveStateSize) { + DEBUG ((DEBUG_ERROR, "%a - Writing to file failed! %r\n", __FUNCTION__= , Status)); + } else { + DEBUG ((DEBUG_INFO, "%a - SUCCESS!\n", __FUNCTION__)); + } + + // + // No matter what, we should probably close the file. + // + ShellCloseFile (&FileHandle); + +Exit: + if (FileDevicePath !=3D NULL) { + FreePool (FileDevicePath); + } + + return Status; +} + +/** + Will retrieve any cached state associated with the given framework. + Will allocate a buffer to hold the loaded data. + + @param[in] FrameworkHandle A pointer to the framework that is being pe= rsisted. + @param[in] SaveData A pointer pointer that will be updated with= the address + of the loaded data buffer. + + @retval EFI_SUCCESS Data has been loaded successfully and SaveData is = updated + with a pointer to the buffer. + @retval Others An error has occurred and no data has been loaded.= SaveData + is set to NULL. + +**/ +EFI_STATUS +EFIAPI +LoadUnitTestCache ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + OUT UNIT_TEST_SAVE_HEADER **SaveData + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + SHELL_FILE_HANDLE FileHandle; + BOOLEAN IsFileOpened; + UINT64 LargeFileSize; + UINTN FileSize; + UNIT_TEST_SAVE_HEADER *Buffer; + + IsFileOpened =3D FALSE; + Buffer =3D NULL; + + // + // Check the inputs for sanity. + // + if (FrameworkHandle =3D=3D NULL || SaveData =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine the path for the cache file. + // NOTE: This devpath is allocated and must be freed. + // + FileDevicePath =3D GetCacheFileDevicePath (FrameworkHandle); + + // + // Now that we know the path to the file... let's open it for writing. + // + Status =3D ShellOpenFileByDevicePath ( + &FileDevicePath, + &FileHandle, + EFI_FILE_MODE_READ, + 0 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __F= UNCTION__, Status)); + goto Exit; + } else { + IsFileOpened =3D TRUE; + } + + // + // Now that the file is opened, we need to determine how large a buffer = we need. + // + Status =3D ShellGetFileSize (FileHandle, &LargeFileSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to determine file size! %r\n", __FUN= CTION__, Status)); + goto Exit; + } + + // + // Now that we know the size, let's allocated a buffer to hold the conte= nts. + // + FileSize =3D (UINTN)LargeFileSize; // You know what... if it's too la= rge, this lib don't care. + Buffer =3D AllocatePool (FileSize); + if (Buffer =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a - Failed to allocate a pool to hold the file = contents! %r\n", __FUNCTION__, Status)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Finally, let's read the data. + // + Status =3D ShellReadFile (FileHandle, &FileSize, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to read the file contents! %r\n", __= FUNCTION__, Status)); + } + +Exit: + // + // Free allocated buffers + // + if (FileDevicePath !=3D NULL) { + FreePool (FileDevicePath); + } + if (IsFileOpened) { + ShellCloseFile (&FileHandle); + } + + // + // If we're returning an error, make sure + // the state is sane. + if (EFI_ERROR (Status) && Buffer !=3D NULL) { + FreePool (Buffer); + Buffer =3D NULL; + } + + *SaveData =3D Buffer; + return Status; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileS= ystem/UnitTestPersistenceLibSimpleFileSystem.inf b/UnitTestFrameworkPkg/Lib= rary/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFil= eSystem.inf new file mode 100644 index 0000000000..c518c4e5ce --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/U= nitTestPersistenceLibSimpleFileSystem.inf @@ -0,0 +1,47 @@ +## @file +# UEFI Simple File System based version of the Unit Test Persistence Lib +# +# Instance of the Unit Test Persistence Lib that utilizes the UEFI filesys= tem +# that a test application is running from to save a serialized version of = the +# internal test state in case the test needs to quit and restore. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestPersistenceLibSimpleFileSystem + MODULE_UNI_FILE =3D UnitTestPersistenceLibSimpleFileSystem.uni + FILE_GUID =3D 9200844A-CDFD-4368-B4BD-106354702605 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_APPLICATION + LIBRARY_CLASS =3D UnitTestPersistenceLib + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + UnitTestPersistenceLibSimpleFileSystem.c + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + BaseLib + ShellLib + +[Protocols] + gEfiLoadedImageProtocolGuid + gEfiSimpleFileSystemProtocolGuid + +[Guids] + gEfiFileInfoGuid + gEfiFileSystemInfoGuid diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileS= ystem/UnitTestPersistenceLibSimpleFileSystem.uni b/UnitTestFrameworkPkg/Lib= rary/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFil= eSystem.uni new file mode 100644 index 0000000000..e6593be137 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/U= nitTestPersistenceLibSimpleFileSystem.uni @@ -0,0 +1,15 @@ +// /** @file +// UEFI Simple File System based version of the Unit Test Persistence Lib +// +// Instance of the Unit Test Persistence Lib that utilizes the UEFI filesy= stem +// that a test application is running from to save a serialized version of= the +// internal test state in case the test needs to quit and restore. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "UEFI Simple File = System based version of the Unit Test Persistence Lib" + +#string STR_MODULE_DESCRIPTION #language en-US "UEFI Simple File = System based version of the Unit Test Persistence Lib." diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestR= esultReportLib.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/Uni= tTestResultReportLib.c new file mode 100644 index 0000000000..687a04f55d --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRe= portLib.c @@ -0,0 +1,216 @@ +/** @file + Implement UnitTestResultReportLib doing plain txt out to console + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include + +VOID +ReportPrint ( + IN CONST CHAR8 *Format, + ... + ); + +VOID +ReportOutput ( + IN CONST CHAR8 *Output + ); + +struct _UNIT_TEST_STATUS_STRING { + UNIT_TEST_STATUS Status; + CHAR8 *String; +}; + +struct _UNIT_TEST_FAILURE_TYPE_STRING { + FAILURE_TYPE Type; + CHAR8 *String; +}; + +struct _UNIT_TEST_STATUS_STRING mStatusStrings[] =3D { + { UNIT_TEST_PASSED, "PASSED"}, + { UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, "NOT RUN - PREREQUISITE FAILED"}, + { UNIT_TEST_ERROR_TEST_FAILED, "FAILED"}, + { UNIT_TEST_RUNNING, "RUNNING"}, + { UNIT_TEST_PENDING, "PENDING"}, + { 0, "**UNKNOWN**"} +}; + +struct _UNIT_TEST_FAILURE_TYPE_STRING mFailureTypeStrings[] =3D { + { FAILURETYPE_NOFAILURE, "NO FAILURE"}, + { FAILURETYPE_OTHER, "OTHER FAILURE"}, + { FAILURETYPE_ASSERTTRUE, "ASSERT_TRUE FAILURE"}, + { FAILURETYPE_ASSERTFALSE, "ASSERT_FALSE FAILURE"}, + { FAILURETYPE_ASSERTEQUAL, "ASSERT_EQUAL FAILURE"}, + { FAILURETYPE_ASSERTNOTEQUAL, "ASSERT_NOTEQUAL FAILURE"}, + { FAILURETYPE_ASSERTNOTEFIERROR, "ASSERT_NOTEFIERROR FAILURE"}, + { FAILURETYPE_ASSERTSTATUSEQUAL, "ASSERT_STATUSEQUAL FAILURE"}, + { FAILURETYPE_ASSERTNOTNULL , "ASSERT_NOTNULL FAILURE"}, + { 0, "*UNKNOWN* Failure"} +}; + +// +// TEST REPORTING FUNCTIONS +// + +STATIC +CONST CHAR8* +GetStringForUnitTestStatus ( + IN UNIT_TEST_STATUS Status + ) +{ + UINTN Index; + + for (Index =3D 0; Index < ARRAY_SIZE (mStatusStrings); Index++) { + if (mStatusStrings[Index].Status =3D=3D Status) { + // + // Return string from matching entry + // + return mStatusStrings[Index].String; + } + } + // + // Return last entry if no match found. + // + return mStatusStrings[Index].String; +} + +STATIC +CONST CHAR8* +GetStringForFailureType ( + IN FAILURE_TYPE Failure + ) +{ + UINTN Index; + + for (Index =3D 0; Index < ARRAY_SIZE (mFailureTypeStrings); Index++) { + if (mFailureTypeStrings[Index].Type =3D=3D Failure) { + // + // Return string from matching entry + // + return mFailureTypeStrings[Index].String; + } + } + // + // Return last entry if no match found. + // + DEBUG((DEBUG_INFO, "%a Failure Type does not have string defined 0x%X\n"= , __FUNCTION__, (UINT32)Failure)); + return mFailureTypeStrings[Index].String; +} + +/* + Method to print the Unit Test run results + + @retval Success +*/ +EFI_STATUS +EFIAPI +OutputUnitTestFrameworkReport ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + INTN Passed; + INTN Failed; + INTN NotRun; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + UNIT_TEST_LIST_ENTRY *Test; + INTN SPassed; + INTN SFailed; + INTN SNotRun; + + Passed =3D 0; + Failed =3D 0; + NotRun =3D 0; + Suite =3D NULL; + + Framework =3D (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + if (Framework =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + ReportPrint ("---------------------------------------------------------\= n"); + ReportPrint ("------------- UNIT TEST FRAMEWORK RESULTS ---------------\= n"); + ReportPrint ("---------------------------------------------------------\= n"); + + //print the version and time + + // + // Iterate all suites + // + for (Suite =3D (UNIT_TEST_SUITE_LIST_ENTRY*)GetFirstNode(&Framework->Tes= tSuiteList); + (LIST_ENTRY*)Suite !=3D &Framework->TestSuiteList; + Suite =3D (UNIT_TEST_SUITE_LIST_ENTRY*)GetNextNode(&Framework->TestSui= teList, (LIST_ENTRY*)Suite)) { + + Test =3D NULL; + SPassed =3D 0; + SFailed =3D 0; + SNotRun =3D 0; + + ReportPrint ("////////////////////////////////////////////////////////= /\n"); + ReportPrint (" SUITE: %a\n", Suite->UTS.Title); + ReportPrint (" PACKAGE: %a\n", Suite->UTS.Name); + ReportPrint ("////////////////////////////////////////////////////////= /\n"); + + // + // Iterate all tests within the suite + // + for (Test =3D (UNIT_TEST_LIST_ENTRY*)GetFirstNode(&(Suite->UTS.TestCas= eList)); + (LIST_ENTRY*)Test !=3D &(Suite->UTS.TestCaseList); + Test =3D (UNIT_TEST_LIST_ENTRY*)GetNextNode(&(Suite->UTS.TestCaseLis= t), (LIST_ENTRY*)Test)) { + + ReportPrint ("******************************************************= ***\n"); + ReportPrint (" CLASS NAME: %a\n", Test->UT.Name); + ReportPrint (" TEST: %a\n", Test->UT.Description); + ReportPrint (" STATUS: %a\n", GetStringForUnitTestStatus (Test->UT= .Result)); + ReportPrint (" FAILURE: %a\n", GetStringForFailureType (Test->UT.Fa= ilureType)); + ReportPrint (" FAILURE MESSAGE:\n%a\n", Test->UT.FailureMessage); + + if (Test->UT.Log !=3D NULL) { + ReportPrint (" LOG:\n"); + ReportOutput (Test->UT.Log); + } + + switch (Test->UT.Result) { + case UNIT_TEST_PASSED: + SPassed++; + break; + case UNIT_TEST_ERROR_TEST_FAILED: + SFailed++; + break; + case UNIT_TEST_PENDING: // Fall through... + case UNIT_TEST_RUNNING: // Fall through... + case UNIT_TEST_ERROR_PREREQUISITE_NOT_MET: + SNotRun++; + break; + default: + break; + } + ReportPrint ("******************************************************= ****\n"); + } //End Test iteration + + ReportPrint ("++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +\n"); + ReportPrint ("Suite Stats\n"); + ReportPrint (" Passed: %d (%d%%)\n", SPassed, (SPassed * 100)/(SPass= ed+SFailed+SNotRun)); + ReportPrint (" Failed: %d (%d%%)\n", SFailed, (SFailed * 100) / (SPa= ssed + SFailed + SNotRun)); + ReportPrint (" Not Run: %d (%d%%)\n", SNotRun, (SNotRun * 100) / (SPa= ssed + SFailed + SNotRun)); + ReportPrint ("++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +\n" ); + + Passed +=3D SPassed; //add to global counters + Failed +=3D SFailed; //add to global counters + NotRun +=3D SNotRun; //add to global counters + }//End Suite iteration + + ReportPrint ("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); + ReportPrint ("Total Stats\n"); + ReportPrint (" Passed: %d (%d%%)\n", Passed, (Passed * 100) / (Passed = + Failed + NotRun)); + ReportPrint (" Failed: %d (%d%%)\n", Failed, (Failed * 100) / (Passed = + Failed + NotRun)); + ReportPrint (" Not Run: %d (%d%%)\n", NotRun, (NotRun * 100) / (Passed = + Failed + NotRun)); + ReportPrint ("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n" ); + + return EFI_SUCCESS; +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestR= esultReportLibConOut.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportL= ib/UnitTestResultReportLibConOut.c new file mode 100644 index 0000000000..139360ee16 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRe= portLibConOut.c @@ -0,0 +1,48 @@ +/** @file + Implement UnitTestResultReportLib doing plain txt out to console + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include + +VOID +ReportPrint ( + IN CONST CHAR8 *Format, + ... + ) +{ + VA_LIST Marker; + CHAR16 String[256]; + UINTN Length; + + VA_START (Marker, Format); + Length =3D UnicodeVSPrintAsciiFormat (String, sizeof (String), Format, M= arker); + if (Length =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__= )); + } else { + gST->ConOut->OutputString (gST->ConOut, String); + } + VA_END (Marker); +} + +VOID +ReportOutput ( + IN CONST CHAR8 *Output + ) +{ + CHAR8 AsciiString[128]; + UINTN Length; + UINTN Index; + + Length =3D AsciiStrLen (Output); + for (Index =3D 0; Index < Length; Index +=3D (sizeof (AsciiString) - 1))= { + AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]); + ReportPrint ("%a", AsciiString); + } +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestR= esultReportLibConOut.inf b/UnitTestFrameworkPkg/Library/UnitTestResultRepor= tLib/UnitTestResultReportLibConOut.inf new file mode 100644 index 0000000000..4382199fbc --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRe= portLibConOut.inf @@ -0,0 +1,29 @@ +## @file +# Library to support printing out the unit test report to a UEFI console +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestResultReportLibConOut + MODULE_UNI_FILE =3D UnitTestResultReportLibConOut.uni + FILE_GUID =3D C659641D-BA1F-4B58-946E-B1E1103903F9 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_DRIVER + LIBRARY_CLASS =3D UnitTestResultReportLib + +[LibraryClasses] + BaseLib + DebugLib + UefiBootServicesTableLib + PrintLib + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[Sources] + UnitTestResultReportLib.c + UnitTestResultReportLibConOut.c diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestR= esultReportLibConOut.uni b/UnitTestFrameworkPkg/Library/UnitTestResultRepor= tLib/UnitTestResultReportLibConOut.uni new file mode 100644 index 0000000000..92ba1b84da --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRe= portLibConOut.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support printing out the unit test report to a UEFI console +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to suppor= t printing out the unit test report to a UEFI console" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to suppor= t printing out the unit test report to a UEFI console." diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestR= esultReportLibDebugLib.c b/UnitTestFrameworkPkg/Library/UnitTestResultRepor= tLib/UnitTestResultReportLibDebugLib.c new file mode 100644 index 0000000000..743aad2958 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRe= portLibDebugLib.c @@ -0,0 +1,47 @@ +/** @file + Implement UnitTestResultReportLib doing plain txt out to console + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include + +VOID +ReportPrint ( + IN CONST CHAR8 *Format, + ... + ) +{ + VA_LIST Marker; + CHAR8 String[256]; + UINTN Length; + + VA_START (Marker, Format); + Length =3D AsciiVSPrint (String, sizeof (String), Format, Marker); + if (Length =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__= )); + } else { + DEBUG ((DEBUG_INFO, String)); + } + VA_END (Marker); +} + +VOID +ReportOutput ( + IN CONST CHAR8 *Output + ) +{ + CHAR8 AsciiString[128]; + UINTN Length; + UINTN Index; + + Length =3D AsciiStrLen (Output); + for (Index =3D 0; Index < Length; Index +=3D (sizeof (AsciiString) - 1))= { + AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]); + DEBUG ((DEBUG_INFO, AsciiString)); + } +} diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestR= esultReportLibDebugLib.inf b/UnitTestFrameworkPkg/Library/UnitTestResultRep= ortLib/UnitTestResultReportLibDebugLib.inf new file mode 100644 index 0000000000..a1c786a700 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRe= portLibDebugLib.inf @@ -0,0 +1,28 @@ +## @file +# Library to support printing out the unit test report using DEBUG() macro= s. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestResultReportLibDebugLib + MODULE_UNI_FILE =3D UnitTestResultReportLibDebugLib.uni + FILE_GUID =3D BED736D4-D197-475F-B7CE-0D828FF2C9A6 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_DRIVER + LIBRARY_CLASS =3D UnitTestResultReportLib + +[LibraryClasses] + BaseLib + DebugLib + PrintLib + +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[Sources] + UnitTestResultReportLib.c + UnitTestResultReportLibDebugLib.c diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestR= esultReportLibDebugLib.uni b/UnitTestFrameworkPkg/Library/UnitTestResultRep= ortLib/UnitTestResultReportLibDebugLib.uni new file mode 100644 index 0000000000..4f1993417a --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRe= portLibDebugLib.uni @@ -0,0 +1,11 @@ +// /** @file +// Library to support printing out the unit test report using DEBUG() macr= os. +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Library to suppor= t printing out the unit test report using DEBUG() macros" + +#string STR_MODULE_DESCRIPTION #language en-US "Library to suppor= t printing out the unit test report using DEBUG() macros." --=20 2.21.0.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 (#54055): https://edk2.groups.io/g/devel/message/54055 Mute This Topic: https://groups.io/mt/71060083/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54056+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54056+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099242431239.37515317760426; Fri, 7 Feb 2020 10:14:02 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id AZuNYY1788612x2fkLwV9BzV; Fri, 07 Feb 2020 10:14:02 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web12.9025.1581099240821545376 for ; Fri, 07 Feb 2020 10:14:01 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:14:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500545" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:14:00 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew Subject: [edk2-devel] [Patch v2 06/11] UnitTestFrameworkPkg/Test: Add unit test samples Date: Fri, 7 Feb 2020 10:13:49 -0800 Message-Id: <20200207181354.31632-7-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: YSpfiG44q1oJ24vXqeBAT3NYx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099242; bh=nBQYjgZJYT5Sz2Ec9b4U2FSHwI5zoGhiDmOkDqkmhSA=; h=Cc:Date:From:Reply-To:Subject:To; b=B6FZJA+wlFK2lkB7N8mbNsRgp9iEtdzdTjzkjqlOyz6CKCekuRgwecuAiXpIYWpdzDc 0H+2H0T6iR7/vzgl9i2Qg7rLfiNYDQfaKCkdzBWYnmKIl1zNOr9118U6NLLOU6ikJZhbg zFdFYuJWDQ074ZVEcyq2SnpnPXZAHn/PAXM= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 Add an implementation of a sample unit test that demonstrates the use of the UnitTestLib services and macros and supports being built for execution in a host environment or for execution on a target in PEI, DXE, SMM, or UEFI Shell. Cc: Sean Brogan Cc: Bret Barkelew Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew --- .../Sample/SampleUnitTest/SampleUnitTest.c | 289 ++++++++++++++++++ .../SampleUnitTest/SampleUnitTestDxe.inf | 36 +++ .../SampleUnitTest/SampleUnitTestHost.inf | 30 ++ .../SampleUnitTest/SampleUnitTestPei.inf | 36 +++ .../SampleUnitTest/SampleUnitTestSmm.inf | 37 +++ .../SampleUnitTestUefiShell.inf | 33 ++ 6 files changed, 461 insertions(+) create mode 100644 UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTes= t/SampleUnitTest.c create mode 100644 UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTes= t/SampleUnitTestDxe.inf create mode 100644 UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTes= t/SampleUnitTestHost.inf create mode 100644 UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTes= t/SampleUnitTestPei.inf create mode 100644 UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTes= t/SampleUnitTestSmm.inf create mode 100644 UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTes= t/SampleUnitTestUefiShell.inf diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/Sampl= eUnitTest.c b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/Samp= leUnitTest.c new file mode 100644 index 0000000000..37d5747bca --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTe= st.c @@ -0,0 +1,289 @@ +/** @file + This is a sample to demostrate the usage of the Unit Test Library that + supports the PEI, DXE, SMM, UEFI SHell, and host execution environments. + + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include + +#define UNIT_TEST_NAME "Sample Unit Test" +#define UNIT_TEST_VERSION "0.1" + +/// +/// Global variables used in unit tests +/// +BOOLEAN mSampleGlobalTestBoolean =3D FALSE; +VOID *mSampleGlobalTestPointer =3D NULL; + +/** + Sample Unit-Test Prerequisite Function that checks to make sure the glob= al + pointer used in the test is already set to NULL. + + Functions with this prototype are registered to be dispatched by the uni= t test + framework prior to a given test case. If this prereq function returns + UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, the test case will be skipped. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED Unit test case prerequisi= tes + are met. + @retval UNIT_TEST_ERROR_PREREQUISITE_NOT_MET Test case should be skipp= ed. + +**/ +UNIT_TEST_STATUS +EFIAPI +MakeSureThatPointerIsNull ( + IN UNIT_TEST_CONTEXT Context + ) +{ + UT_ASSERT_EQUAL ((UINTN)mSampleGlobalTestPointer, (UINTN)NULL); + return UNIT_TEST_PASSED; +} + +/** + Sample Unit-Test Cleanup (after) function that resets the global pointer= to + NULL. + + Functions with this prototype are registered to be dispatched by the + unit test framework after a given test case. This will be called even if= the + test case returns an error, but not if the prerequisite fails and the te= st is + skipped. The purpose of this function is to clean up any global state or + test data. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED Test case cleanup succeeded. + @retval UNIT_TEST_ERROR_CLEANUP_FAILED Test case cleanup failed. + +**/ +VOID +EFIAPI +ClearThePointer ( + IN UNIT_TEST_CONTEXT Context + ) +{ + mSampleGlobalTestPointer =3D NULL; +} + +/** + Sample unit test that verifies the expected result of an unsigned integer + addition operation. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +OnePlusOneShouldEqualTwo ( + IN UNIT_TEST_CONTEXT Context + ) +{ + UINTN A; + UINTN B; + UINTN C; + + A =3D 1; + B =3D 1; + C =3D A + B; + + UT_ASSERT_EQUAL (C, 2); + + return UNIT_TEST_PASSED; +} + +/** + Sample unit test that verifies that a global BOOLEAN is updatable. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +GlobalBooleanShouldBeChangeable ( + IN UNIT_TEST_CONTEXT Context + ) +{ + mSampleGlobalTestBoolean =3D TRUE; + UT_ASSERT_TRUE (mSampleGlobalTestBoolean); + + mSampleGlobalTestBoolean =3D FALSE; + UT_ASSERT_FALSE (mSampleGlobalTestBoolean); + + return UNIT_TEST_PASSED; +} + +/** + Sample unit test that logs a warning message and verifies that a global + pointer is updatable. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +GlobalPointerShouldBeChangeable ( + IN UNIT_TEST_CONTEXT Context + ) +{ + // + // Example of logging. + // + UT_LOG_WARNING ("About to change a global pointer! Current value is 0x%X= \n", mSampleGlobalTestPointer); + + mSampleGlobalTestPointer =3D (VOID *)-1; + UT_ASSERT_EQUAL ((UINTN)mSampleGlobalTestPointer, (UINTN)((VOID *)-1)); + return UNIT_TEST_PASSED; +} + +/** + Initialize the unit test framework, suite, and unit tests for the + sample unit tests and run the unit tests. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to + initialize the unit tests. +**/ +EFI_STATUS +EFIAPI +UefiTestMain ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + UNIT_TEST_SUITE_HANDLE SimpleMathTests; + UNIT_TEST_SUITE_HANDLE GlobalVarTests; + + Framework =3D NULL; + + DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION )); + + // + // Start setting up the test framework for running the tests. + // + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCaller= BaseName, UNIT_TEST_VERSION); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r\n"= , Status)); + goto EXIT; + } + + // + // Populate the SimpleMathTests Unit Test Suite. + // + Status =3D CreateUnitTestSuite (&SimpleMathTests, Framework, "Simple Mat= h Tests", "Sample.Math", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for SimpleMathTest= s\n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (SimpleMathTests, "Adding 1 to 1 should produce 2", "Additio= n", OnePlusOneShouldEqualTwo, NULL, NULL, NULL); + + // + // Populate the GlobalVarTests Unit Test Suite. + // + Status =3D CreateUnitTestSuite (&GlobalVarTests, Framework, "Global Vari= able Tests", "Sample.Globals", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for GlobalVarTests= \n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (GlobalVarTests, "You should be able to change a global BOOL= EAN", "Boolean", GlobalBooleanShouldBeChangeable, NULL, NULL, NULL); + AddTestCase (GlobalVarTests, "You should be able to change a global poin= ter", "Pointer", GlobalPointerShouldBeChangeable, MakeSureThatPointerIsNull= , ClearThePointer, NULL); + + // + // Execute the tests. + // + Status =3D RunAllTestSuites (Framework); + +EXIT: + if (Framework) { + FreeUnitTestFramework (Framework); + } + + return Status; +} + +/** + Standard PEIM entry point for target based unit test execution from PEI. +**/ +EFI_STATUS +EFIAPI +PeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return UefiTestMain (); +} + +/** + Standard UEFI entry point for target based unit test execution from DXE,= SMM, + UEFI Shell. +**/ +EFI_STATUS +EFIAPI +DxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return UefiTestMain (); +} + +/** + Standard POSIX C entry point for host based unit test execution. +**/ +int +main ( + int argc, + char *argv[] + ) +{ + return UefiTestMain (); +} diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/Sampl= eUnitTestDxe.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest= /SampleUnitTestDxe.inf new file mode 100644 index 0000000000..e253cf6e16 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTe= stDxe.inf @@ -0,0 +1,36 @@ +## @file +# Sample UnitTest built for execution in DXE. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D SampleUnitTestDxe + FILE_GUID =3D 96BB18BD-FF2B-4B51-B683-0DC9A4BF12CF + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D DxeEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib + +[Depex] + TRUE diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/Sampl= eUnitTestHost.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTes= t/SampleUnitTestHost.inf new file mode 100644 index 0000000000..59a367cc6e --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTe= stHost.inf @@ -0,0 +1,30 @@ +## @file +# Sample UnitTest built for execution on a Host/Dev machine. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SampleUnitTestHost + FILE_GUID =3D CC0EA77E-BF2D-4134-B419-0C02E15CE08E + MODULE_TYPE =3D HOST_APPLICATION + VERSION_STRING =3D 1.0 + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + UnitTestLib diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/Sampl= eUnitTestPei.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest= /SampleUnitTestPei.inf new file mode 100644 index 0000000000..60f5252c34 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTe= stPei.inf @@ -0,0 +1,36 @@ +## @file +# Sample UnitTest built for execution in PEI. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D SampleUnitTestPei + FILE_GUID =3D B9BD9451-3DC8-48EA-A6F0-55753BF186F1 + MODULE_TYPE =3D PEIM + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D PeiEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + PeimEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/Sampl= eUnitTestSmm.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest= /SampleUnitTestSmm.inf new file mode 100644 index 0000000000..324ad2686e --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTe= stSmm.inf @@ -0,0 +1,37 @@ +## @file +# Sample UnitTest built for execution in SMM. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D SampleUnitTestSmm + FILE_GUID =3D 389B16DB-F622-424C-9000-9E43C69CBF71 + MODULE_TYPE =3D DXE_SMM_DRIVER + VERSION_STRING =3D 1.0 + PI_SPECIFICATION_VERSION =3D 0x0001000A + ENTRY_POINT =3D DxeEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib + +[Depex] + gEfiSmmCpuProtocolGuid diff --git a/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/Sampl= eUnitTestUefiShell.inf b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUn= itTest/SampleUnitTestUefiShell.inf new file mode 100644 index 0000000000..6e39c229d4 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTe= stUefiShell.inf @@ -0,0 +1,33 @@ +## @file +# Sample UnitTest built for execution in UEFI Shell. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D SampleUnitTestUefiShell + FILE_GUID =3D 9E8F461A-17E1-4312-B49C-E66F0A88EA8B + MODULE_TYPE =3D UEFI_APPLICATION + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D DxeEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + SampleUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + DebugLib + UnitTestLib + PrintLib --=20 2.21.0.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 (#54056): https://edk2.groups.io/g/devel/message/54056 Mute This Topic: https://groups.io/mt/71060084/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54057+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54057+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 158109924305083.05533751054793; Fri, 7 Feb 2020 10:14:03 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id UVclYY1788612xjO6GXMlF3Y; Fri, 07 Feb 2020 10:14:02 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web12.9025.1581099240821545376 for ; Fri, 07 Feb 2020 10:14:01 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:14:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500546" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:14:00 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew Subject: [edk2-devel] [Patch v2 07/11] UnitTestFrameworkPkg: Add DSC, DSC INC, and YAML files Date: Fri, 7 Feb 2020 10:13:50 -0800 Message-Id: <20200207181354.31632-8-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: 7BHARGcMYZBpFHOZKS1l5fazx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099242; bh=2KHDbnhJxEgclDBvVckRbBM9OR/ziCHKxsCSYvzZZr0=; h=Cc:Date:From:Reply-To:Subject:To; b=Xnkrw48swcygBO7CY9yIco2KBWpdV0N76OEMBzWxZq8cTcLVD//jpnOPyKcBeofCj8O a4Cfok8g5exhPQqT7oqkSMY3pcQ17itsRvD4APf073KbczaG+1Vnq4Gx7jYlQkntgPI+U R/ux25Q2dYafkaua22TyIva7x5+odfk+92Q= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 * DSC in root of package file to perform a package build of the UnitTestFrameworkPkg and build sample unit test for all supported target environments. * DSC file in Test directory to build the sample unit test for the host environment. * UnitTestFrameworkPkgTarget.dsc.inc - DSC include file to !include when building unit tests for target environments. * UnitTestFrameworkPkgHost.dsc.inc - DSC include file to !include when building unit tests for target environments. * YAML file with set of CI checks to perform on UnitTestFrameworkPkg. Cc: Sean Brogan Cc: Bret Barkelew Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew Reviewed-by: Sean Brogan --- .../Test/UnitTestFrameworkPkgHostTest.dsc | 33 ++++++++ .../UnitTestFrameworkPkg.ci.yaml | 76 +++++++++++++++++++ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc | 34 +++++++++ .../UnitTestFrameworkPkgHost.dsc.inc | 56 ++++++++++++++ .../UnitTestFrameworkPkgTarget.dsc.inc | 58 ++++++++++++++ 5 files changed, 257 insertions(+) create mode 100644 UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.= dsc create mode 100644 UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml create mode 100644 UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc create mode 100644 UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc create mode 100644 UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc diff --git a/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc b/U= nitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc new file mode 100644 index 0000000000..701e7299d7 --- /dev/null +++ b/UnitTestFrameworkPkg/Test/UnitTestFrameworkPkgHostTest.dsc @@ -0,0 +1,33 @@ +## @file +# UnitTestFrameworkPkg DSC file used to build host-based unit tests. +# +# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME =3D UnitTestFrameworkPkgHostTest + PLATFORM_GUID =3D C7F97D6D-54AC-45A9-8197-CC99B20CC7EC + PLATFORM_VERSION =3D 0.1 + DSC_SPECIFICATION =3D 0x00010005 + OUTPUT_DIRECTORY =3D Build/UnitTestFrameworkPkg/HostTest + SUPPORTED_ARCHITECTURES =3D IA32|X64 + BUILD_TARGETS =3D NOOPT + SKUID_IDENTIFIER =3D DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + +[Components] + # + # Build HOST_APPLICATION that tests the SampleUnitTest + # + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestH= ost.inf + + # + # Build Libraries + # + UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf + UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf + UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAlloca= tionLibPosix.inf + UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml b/UnitTestFr= ameworkPkg/UnitTestFrameworkPkg.ci.yaml new file mode 100644 index 0000000000..0164859505 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml @@ -0,0 +1,76 @@ +## @file +# CI configuration for UnitTestFrameworkPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + ## options defined .pytool/Plugin/CompilerPlugin + "CompilerPlugin": { + "DscPath": "UnitTestFrameworkPkg.dsc" + }, + ## options defined .pytool/Plugin/HostUnitTestCompilerPlugin + "HostUnitTestCompilerPlugin": { + "DscPath": "Test/UnitTestFrameworkPkgHostTest.dsc" + }, + ## options defined .pytool/Plugin/CharEncodingCheck + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + + ## options defined .pytool/Plugin/DependencyCheck + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[ + "MdeModulePkg/MdeModulePkg.dec", + "ShellPkg/ShellPkg.dec" + ], + "IgnoreInf": [] + }, + ## options defined .pytool/Plugin/DscCompleteCheck + "DscCompleteCheck": { + "DscPath": "UnitTestFrameworkPkg.dsc", + "IgnoreInf": [] + }, + ## options defined .pytool/Plugin/HostUnitTestDscCompleteCheck + "HostUnitTestDscCompleteCheck": { + "IgnoreInf": [], + "DscPath": "Test/UnitTestFrameworkPkgHostTest.dsc" + }, + ## options defined .pytool/Plugin/GuidCheck + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [] + }, + ## options defined .pytool/Plugin/LibraryClassCheck + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + + ## options defined .pytool/Plugin/SpellCheck + "SpellCheck": { + "AuditOnly": False, # Fails test but run in AuditOnly mo= de to collect log + "IgnoreFiles": [ # use gitignore syntax to ignore erro= rs in matching files + "/Library/CmockaLib/cmocka/**/*.*" # not going to spell check= a submodule + ], + "ExtendWords": [ # words to extend to the dictionary f= or this package + "cmocka", + "buildmodule", + "criterium", + "pytool", + "pytools", + "NOFAILURE", + "DHAVE" # build flag for cmocka in the INF + ], + "IgnoreStandardPaths": [], # Standard Plugin defined paths that = should be ignore + "AdditionalIncludePaths": [] # Additional paths to spell check (wi= ldcards supported) + } +} diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc b/UnitTestFramew= orkPkg/UnitTestFrameworkPkg.dsc new file mode 100644 index 0000000000..0ad4482273 --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dsc @@ -0,0 +1,34 @@ +## @file +# UnitTestFrameworkPkg +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME =3D UnitTestFrameworkPkg + PLATFORM_GUID =3D 7420CC7E-334E-4EFF-B974-A39613455168 + PLATFORM_VERSION =3D 1.00 + DSC_SPECIFICATION =3D 0x00010005 + OUTPUT_DIRECTORY =3D Build/UnitTestFrameworkPkg + SUPPORTED_ARCHITECTURES =3D IA32|X64|EBC|ARM|AARCH64 + BUILD_TARGETS =3D DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER =3D DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc + +[Components] + UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf + UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersiste= nceLibNull.inf + UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRepor= tLibDebugLib.inf + UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf + UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultRepor= tLibConOut.inf + UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbC= lass.inf + UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/Unit= TestPersistenceLibSimpleFileSystem.inf + + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestD= xe.inf + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestP= ei.inf + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestS= mm.inf + UnitTestFrameworkPkg/Test/UnitTest/Sample/SampleUnitTest/SampleUnitTestU= efiShell.inf diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc b/UnitTe= stFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc new file mode 100644 index 0000000000..e954968efc --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc @@ -0,0 +1,56 @@ +## @file +# UnitTestFrameworkPkg DSC include file for host based test DSC +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc + +[LibraryClasses.common.HOST_APPLICATION] + CmockaLib|UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf + UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.i= nf + DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.= inf + MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationL= ibPosix/MemoryAllocationLibPosix.inf + +[BuildOptions] + GCC:*_*_*_CC_FLAGS =3D -fno-pie + +[BuildOptions.common.EDKII.HOST_APPLICATION] + # + # MSFT + # + MSFT:*_*_*_DLINK_FLAGS =3D=3D /out:"$(BIN_DIR)\$(BASE_NAME).e= xe" /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /IGNORE:4001 /NOLOGO /SUBSYSTEM:CONS= OLE /DEBUG /NODEFAULTLIB:libcmt.lib libcmtd.lib + MSFT:*_*_IA32_DLINK_FLAGS =3D /MACHINE:I386 + MSFT:*_*_X64_DLINK_FLAGS =3D /MACHINE:AMD64 + + MSFT:*_VS2015_IA32_DLINK_FLAGS =3D /LIBPATH:"%VS2015_PREFIX%Lib" /LIB= PATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion= %\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + MSFT:*_VS2015x86_IA32_DLINK_FLAGS =3D /LIBPATH:"%VS2015_PREFIX%Lib" /LIB= PATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion= %\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + MSFT:*_VS2017_IA32_DLINK_FLAGS =3D /LIBPATH:"%VCToolsInstallDir%lib\x= 86" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%Wi= ndowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + MSFT:*_VS2019_IA32_DLINK_FLAGS =3D /LIBPATH:"%VCToolsInstallDir%lib\x= 86" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%Wi= ndowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" + + MSFT:*_VS2015_X64_DLINK_FLAGS =3D /LIBPATH:"%VS2015_PREFIX%VC\Lib\AM= D64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%W= indowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + MSFT:*_VS2015x86_X64_DLINK_FLAGS =3D /LIBPATH:"%VS2015_PREFIX%VC\Lib\AM= D64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%W= indowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + MSFT:*_VS2017_X64_DLINK_FLAGS =3D /LIBPATH:"%VCToolsInstallDir%lib\x= 64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%Wi= ndowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + MSFT:*_VS2019_X64_DLINK_FLAGS =3D /LIBPATH:"%VCToolsInstallDir%lib\x= 64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%Wi= ndowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" + + # + # GCC + # + GCC:*_*_IA32_DLINK_FLAGS =3D=3D -o $(BIN_DIR)/$(BASE_NAME) -m32 -no-pie + GCC:*_*_X64_DLINK_FLAGS =3D=3D -o $(BIN_DIR)/$(BASE_NAME) -m64 -no-pie + GCC:*_*_*_DLINK2_FLAGS =3D=3D -lgcov + + # + # Need to do this link via gcc and not ld as the pathing to libraries ch= anges from OS version to OS version + # + XCODE:*_*_IA32_DLINK_PATH =3D=3D gcc + XCODE:*_*_IA32_CC_FLAGS =3D -I$(WORKSPACE)/EmulatorPkg/Unix/Host/X11Incl= udeHack + XCODE:*_*_IA32_DLINK_FLAGS =3D=3D -arch i386 -o $(BIN_DIR)/Host -L/usr/X= 11R6/lib -lXext -lX11 -framework Carbon + XCODE:*_*_IA32_ASM_FLAGS =3D=3D -arch i386 -g + + XCODE:*_*_X64_DLINK_PATH =3D=3D gcc + XCODE:*_*_X64_DLINK_FLAGS =3D=3D -o $(BIN_DIR)/Host -L/usr/X11R6/lib -lX= ext -lX11 -framework Carbon -Wl,-no_pie + XCODE:*_*_X64_ASM_FLAGS =3D=3D -g + XCODE:*_*_X64_CC_FLAGS =3D -O0 -target x86_64-apple-darwin -I$(WORKSPACE= )/EmulatorPkg/Unix/Host/X11IncludeHack "-DEFIAPI=3D__attribute__((ms_abi))" diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc b/Unit= TestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc new file mode 100644 index 0000000000..c29b056fca --- /dev/null +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc @@ -0,0 +1,58 @@ +## @file +# UnitTestFrameworkPkg DSC include file for target based test DSC +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[LibraryClasses] + # + # Entry point + # + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntry= Point.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiA= pplicationEntryPoint.inf + + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAll= ocationLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibN= ull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBoo= tServicesTableLib.inf + + UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf + UnitTestPersistenceLib|UnitTestFrameworkPkg/Library/UnitTestPersistenceL= ibNull/UnitTestPersistenceLibNull.inf + UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultRepor= tLib/UnitTestResultReportLibDebugLib.inf + +[LibraryClasses.ARM, LibraryClasses.AARCH64] + # + # It is not possible to prevent ARM compiler calls to generic intrinsic = functions. + # This library provides the instrinsic functions generated by a given co= mpiler. + # [LibraryClasses.ARM] and NULL mean link this library into all ARM imag= es. + # + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + + # + # Since software stack checking may be heuristically enabled by the comp= iler + # include BaseStackCheckLib unconditionally. + # + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + +[LibraryClasses.common.PEIM] + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAlloc= ationLib.inf + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/Pei= ServicesTablePointerLib.inf + +[LibraryClasses.common.UEFI_APPLICATION] + UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultRepor= tLib/UnitTestResultReportLibConOut.inf + +[PcdsFixedAtBuild] + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17 + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES + GCC:*_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES --=20 2.21.0.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 (#54057): https://edk2.groups.io/g/devel/message/54057 Mute This Topic: https://groups.io/mt/71060085/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54058+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54058+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099243397925.45192760265; Fri, 7 Feb 2020 10:14:03 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id Dt75YY1788612xtcBx5N3gVG; Fri, 07 Feb 2020 10:14:03 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web12.9025.1581099240821545376 for ; Fri, 07 Feb 2020 10:14:02 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:14:01 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500552" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:14:01 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew , Liming Gao , Hao A Wu Subject: [edk2-devel] [Patch v2 08/11] MdePkg/Test: Add SafeIntLib and BaseLib Base64 unit tests Date: Fri, 7 Feb 2020 10:13:51 -0800 Message-Id: <20200207181354.31632-9-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: QzNa0wa2r6yzfrQGRYgX1kCRx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099243; bh=WYbOTKKNJNyq6OztpzvEVyQO+ohHlP00LM0HA0hgfBs=; h=Cc:Date:From:Reply-To:Subject:To; b=alzsPiteZBRvkE7twicl+e4Ee5s4YAqrCAaApVqwtkU9rcCoYNcYGztWr5LAmcJ1qCP iPSJmbd+mUAuOKSG8iiJGTOOPuv7592gWb7yo7vtA8zJ4AWwuqS3+fCd9XOT4Wmj1qbnQ FB75cnG/aucdlVgVXOObWvSyIgRR51BykaQ= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 * Add unit tests for SafeIntLib class * Add unit tests for BaseLib Base64 conversion APIs. * Add Test/MdePkgHostTest.dsc -to build host based unit tests * Update MdePkg.dsc to build target based tests for SafeIntLib and BaseLib * Update MdePkg.ci.yaml to build and run host based tests for SafeIntLib and BaseLib Cc: Sean Brogan Cc: Bret Barkelew Cc: Liming Gao Signed-off-by: Michael D Kinney Acked-by: Hao A Wu Reviewed-by: Bret Barkelew --- MdePkg/MdePkg.ci.yaml | 19 +- MdePkg/MdePkg.dsc | 18 + MdePkg/Test/MdePkgHostTest.dsc | 30 + .../UnitTest/Library/BaseLib/Base64UnitTest.c | 404 +++ .../Library/BaseLib/BaseLibUnitTestsHost.inf | 32 + .../Library/BaseLib/BaseLibUnitTestsUefi.inf | 33 + .../SafeIntLibUintnIntnUnitTests32.c | 540 +++ .../SafeIntLibUintnIntnUnitTests64.c | 544 +++ .../BaseSafeIntLib/TestBaseSafeIntLib.c | 3064 +++++++++++++++++ .../BaseSafeIntLib/TestBaseSafeIntLib.h | 123 + .../BaseSafeIntLib/TestBaseSafeIntLib.uni | 13 + .../BaseSafeIntLib/TestBaseSafeIntLibDxe.inf | 45 + .../BaseSafeIntLib/TestBaseSafeIntLibHost.inf | 40 + .../BaseSafeIntLib/TestBaseSafeIntLibPei.inf | 45 + .../BaseSafeIntLib/TestBaseSafeIntLibSmm.inf | 45 + .../TestBaseSafeIntLibUefiShell.inf | 42 + 16 files changed, 5034 insertions(+), 3 deletions(-) create mode 100644 MdePkg/Test/MdePkgHostTest.dsc create mode 100644 MdePkg/Test/UnitTest/Library/BaseLib/Base64UnitTest.c create mode 100644 MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHo= st.inf create mode 100644 MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUe= fi.inf create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibU= intnIntnUnitTests32.c create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibU= intnIntnUnitTests64.c create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLib.c create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLib.h create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLib.uni create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLibDxe.inf create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLibHost.inf create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLibPei.inf create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLibSmm.inf create mode 100644 MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSaf= eIntLibUefiShell.inf diff --git a/MdePkg/MdePkg.ci.yaml b/MdePkg/MdePkg.ci.yaml index 65c4ec3bec..88e490fcb6 100644 --- a/MdePkg/MdePkg.ci.yaml +++ b/MdePkg/MdePkg.ci.yaml @@ -10,8 +10,13 @@ "DscPath": "MdePkg.dsc" }, =20 + ## options defined ci/Plugin/HostUnitTestCompilerPlugin + "HostUnitTestCompilerPlugin": { + "DscPath": "Test/MdePkgHostTest.dsc" + }, + ## options defined ci/Plugin/CharEncodingCheck -"CharEncodingCheck": { + "CharEncodingCheck": { "IgnoreFiles": [] }, =20 @@ -21,7 +26,9 @@ "MdePkg/MdePkg.dec" ], # For host based unit tests - "AcceptableDependencies-HOST_APPLICATION":[], + "AcceptableDependencies-HOST_APPLICATION":[ + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" + ], # For UEFI shell based apps "AcceptableDependencies-UEFI_APPLICATION":[], "IgnoreInf": [] @@ -29,10 +36,16 @@ =20 ## options defined ci/Plugin/DscCompleteCheck "DscCompleteCheck": { - "IgnoreInf": [], + "IgnoreInf": [""], "DscPath": "MdePkg.dsc" }, =20 + ## options defined ci/Plugin/HostUnitTestDscCompleteCheck + "HostUnitTestDscCompleteCheck": { + "IgnoreInf": [""], + "DscPath": "Test/MdePkgHostTest.dsc" + }, + ## options defined ci/Plugin/GuidCheck "GuidCheck": { "IgnoreGuidName": [ diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index 0aeafaaacc..87af740853 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -18,6 +18,8 @@ [Defines] BUILD_TARGETS =3D DEBUG|RELEASE|NOOPT SKUID_IDENTIFIER =3D DEFAULT =20 +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgTarget.dsc.inc + [PcdsFeatureFlag] gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport|TRUE =20 @@ -26,6 +28,9 @@ [PcdsFixedAtBuild] gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000 gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xE0000000 =20 +[LibraryClasses] + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + [Components] MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf @@ -115,6 +120,19 @@ [Components] MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint= .inf MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib= .inf =20 + # + # Add UEFI Target Based Unit Tests + # + MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf + + # + # Build PEIM, DXE_DRIVER, SMM_DRIVER, UEFI Shell components that test Sa= feIntLib + # + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibPei.inf + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibDxe.inf + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibSmm.inf + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibUefiShell.= inf + [Components.IA32, Components.X64] MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf diff --git a/MdePkg/Test/MdePkgHostTest.dsc b/MdePkg/Test/MdePkgHostTest.dsc new file mode 100644 index 0000000000..3d677ee75c --- /dev/null +++ b/MdePkg/Test/MdePkgHostTest.dsc @@ -0,0 +1,30 @@ +## @file +# MdePkg DSC file used to build host-based unit tests. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME =3D MdePkgHostTest + PLATFORM_GUID =3D 50652B4C-88CB-4481-96E8-37F2D0034440 + PLATFORM_VERSION =3D 0.1 + DSC_SPECIFICATION =3D 0x00010005 + OUTPUT_DIRECTORY =3D Build/MdePkg/HostTest + SUPPORTED_ARCHITECTURES =3D IA32|X64 + BUILD_TARGETS =3D NOOPT + SKUID_IDENTIFIER =3D DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + +[LibraryClasses] + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + +[Components] + # + # Build HOST_APPLICATION that tests the SafeIntLib + # + MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf + MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf diff --git a/MdePkg/Test/UnitTest/Library/BaseLib/Base64UnitTest.c b/MdePkg= /Test/UnitTest/Library/BaseLib/Base64UnitTest.c new file mode 100644 index 0000000000..6f7c31cab4 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseLib/Base64UnitTest.c @@ -0,0 +1,404 @@ +/** @file + Unit tests of Base64 conversion APIs in BaseLib. + + Copyright (C) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#define UNIT_TEST_APP_NAME "BaseLib Unit Test Application" +#define UNIT_TEST_APP_VERSION "1.0" + +/** + RFC 4648 https://tools.ietf.org/html/rfc4648 test vectors + + BASE64("") =3D "" + BASE64("f") =3D "Zg=3D=3D" + BASE64("fo") =3D "Zm8=3D" + BASE64("foo") =3D "Zm9v" + BASE64("foob") =3D "Zm9vYg=3D=3D" + BASE64("fooba") =3D "Zm9vYmE=3D" + BASE64("foobar") =3D "Zm9vYmFy" + + The test vectors are using ascii strings for the binary data + */ + +typedef struct { + CHAR8 *TestInput; + CHAR8 *TestOutput; + EFI_STATUS ExpectedStatus; + VOID *BufferToFree; + UINTN ExpectedSize; +} BASIC_TEST_CONTEXT; + +#define B64_TEST_1 "" +#define BIN_TEST_1 "" + +#define B64_TEST_2 "Zg=3D=3D" +#define BIN_TEST_2 "f" + +#define B64_TEST_3 "Zm8=3D" +#define BIN_TEST_3 "fo" + +#define B64_TEST_4 "Zm9v" +#define BIN_TEST_4 "foo" + +#define B64_TEST_5 "Zm9vYg=3D=3D" +#define BIN_TEST_5 "foob" + +#define B64_TEST_6 "Zm9vYmE=3D" +#define BIN_TEST_6 "fooba" + +#define B64_TEST_7 "Zm9vYmFy" +#define BIN_TEST_7 "foobar" + +// Adds all white space - also ends the last quantum with only spaces afte= rwards +#define B64_TEST_8_IN " \t\v Zm9\r\nvYmFy \f " +#define BIN_TEST_8 "foobar" + +// Not a quantum multiple of 4 +#define B64_ERROR_1 "Zm9vymFy=3D" + +// Invalid characters in the string +#define B64_ERROR_2 "Zm$vymFy" + +// Too many '=3D' characters +#define B64_ERROR_3 "Z=3D=3D=3D" + +// Poorly placed '=3D' +#define B64_ERROR_4 "Zm=3DvYmFy" + +#define MAX_TEST_STRING_SIZE (200) + +// ------------------------------------------------ Input----------Output-= ----------Result-------Free--Expected Output Size +static BASIC_TEST_CONTEXT mBasicEncodeTest1 =3D {BIN_TEST_1, B64_T= EST_1, EFI_SUCCESS, NULL, sizeof(B64_TEST_1)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest2 =3D {BIN_TEST_2, B64_T= EST_2, EFI_SUCCESS, NULL, sizeof(B64_TEST_2)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest3 =3D {BIN_TEST_3, B64_T= EST_3, EFI_SUCCESS, NULL, sizeof(B64_TEST_3)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest4 =3D {BIN_TEST_4, B64_T= EST_4, EFI_SUCCESS, NULL, sizeof(B64_TEST_4)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest5 =3D {BIN_TEST_5, B64_T= EST_5, EFI_SUCCESS, NULL, sizeof(B64_TEST_5)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest6 =3D {BIN_TEST_6, B64_T= EST_6, EFI_SUCCESS, NULL, sizeof(B64_TEST_6)}; +static BASIC_TEST_CONTEXT mBasicEncodeTest7 =3D {BIN_TEST_7, B64_T= EST_7, EFI_SUCCESS, NULL, sizeof(B64_TEST_7)}; +static BASIC_TEST_CONTEXT mBasicEncodeError1 =3D {BIN_TEST_7, B64_T= EST_1, EFI_BUFFER_TOO_SMALL, NULL, sizeof(B64_TEST_7)}; + +static BASIC_TEST_CONTEXT mBasicDecodeTest1 =3D {B64_TEST_1, BIN_T= EST_1, EFI_SUCCESS, NULL, sizeof(BIN_TEST_1)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest2 =3D {B64_TEST_2, BIN_T= EST_2, EFI_SUCCESS, NULL, sizeof(BIN_TEST_2)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest3 =3D {B64_TEST_3, BIN_T= EST_3, EFI_SUCCESS, NULL, sizeof(BIN_TEST_3)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest4 =3D {B64_TEST_4, BIN_T= EST_4, EFI_SUCCESS, NULL, sizeof(BIN_TEST_4)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest5 =3D {B64_TEST_5, BIN_T= EST_5, EFI_SUCCESS, NULL, sizeof(BIN_TEST_5)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest6 =3D {B64_TEST_6, BIN_T= EST_6, EFI_SUCCESS, NULL, sizeof(BIN_TEST_6)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest7 =3D {B64_TEST_7, BIN_T= EST_7, EFI_SUCCESS, NULL, sizeof(BIN_TEST_7)-1}; +static BASIC_TEST_CONTEXT mBasicDecodeTest8 =3D {B64_TEST_8_IN, BIN_T= EST_8, EFI_SUCCESS, NULL, sizeof(BIN_TEST_8)-1}; + +static BASIC_TEST_CONTEXT mBasicDecodeError1 =3D {B64_ERROR_1, B64_E= RROR_1, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError2 =3D {B64_ERROR_2, B64_E= RROR_2, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError3 =3D {B64_ERROR_3, B64_E= RROR_3, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError4 =3D {B64_ERROR_4, B64_E= RROR_4, EFI_INVALID_PARAMETER, NULL, 0}; +static BASIC_TEST_CONTEXT mBasicDecodeError5 =3D {B64_TEST_7, BIN_T= EST_1, EFI_BUFFER_TOO_SMALL, NULL, sizeof(BIN_TEST_7)-1}; + +/** + Simple clean up method to make sure tests clean up even if interrupted a= nd fail + in the middle. +**/ +STATIC +VOID +EFIAPI +CleanUpB64TestContext ( + IN UNIT_TEST_CONTEXT Context + ) +{ + BASIC_TEST_CONTEXT *Btc; + + Btc =3D (BASIC_TEST_CONTEXT *)Context; + if (Btc !=3D NULL) { + //free string if set + if (Btc->BufferToFree !=3D NULL) { + FreePool (Btc->BufferToFree); + Btc->BufferToFree =3D NULL; + } + } +} + +/** + Unit test for Base64 encode APIs of BaseLib. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +STATIC +UNIT_TEST_STATUS +EFIAPI +RfcEncodeTest ( + IN UNIT_TEST_CONTEXT Context + ) +{ + BASIC_TEST_CONTEXT *Btc; + CHAR8 *b64String; + CHAR8 *binString; + UINTN b64StringSize; + EFI_STATUS Status; + UINT8 *BinData; + UINTN BinSize; + CHAR8 *b64WorkString; + UINTN ReturnSize; + INTN CompareStatus; + UINTN indx; + + Btc =3D (BASIC_TEST_CONTEXT *) Context; + binString =3D Btc->TestInput; + b64String =3D Btc->TestOutput; + + // + // Only testing the the translate functionality, so preallocate the prop= er + // string buffer. + // + + b64StringSize =3D AsciiStrnSizeS(b64String, MAX_TEST_STRING_SIZE); + BinSize =3D AsciiStrnLenS(binString, MAX_TEST_STRING_SIZE); + BinData =3D (UINT8 *) binString; + + b64WorkString =3D (CHAR8 *) AllocatePool(b64StringSize); + UT_ASSERT_NOT_NULL(b64WorkString); + + Btc->BufferToFree =3D b64WorkString; + ReturnSize =3D b64StringSize; + + Status =3D Base64Encode(BinData, BinSize, b64WorkString, &ReturnSize); + + UT_ASSERT_STATUS_EQUAL(Status, Btc->ExpectedStatus); + + UT_ASSERT_EQUAL(ReturnSize, Btc->ExpectedSize); + + if (!EFI_ERROR (Btc->ExpectedStatus)) { + if (ReturnSize !=3D 0) { + CompareStatus =3D AsciiStrnCmp (b64String, b64WorkString, ReturnSize= ); + if (CompareStatus !=3D 0) { + UT_LOG_ERROR ("b64 string compare error - size=3D%d\n", ReturnSize= ); + for (indx =3D 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & b64String[indx]); + } + UT_LOG_ERROR ("\n b64 work string:\n"); + for (indx =3D 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & b64WorkString[indx]); + } + UT_LOG_ERROR ("\n"); + } + UT_ASSERT_EQUAL (CompareStatus, 0); + } + } + + Btc->BufferToFree =3D NULL; + FreePool (b64WorkString); + return UNIT_TEST_PASSED; +} + +/** + Unit test for Base64 decode APIs of BaseLib. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +STATIC +UNIT_TEST_STATUS +EFIAPI +RfcDecodeTest( + IN UNIT_TEST_CONTEXT Context + ) +{ + BASIC_TEST_CONTEXT *Btc; + CHAR8 *b64String; + CHAR8 *binString; + EFI_STATUS Status; + UINTN b64StringLen; + UINTN ReturnSize; + UINT8 *BinData; + UINTN BinSize; + INTN CompareStatus; + UINTN indx; + + Btc =3D (BASIC_TEST_CONTEXT *)Context; + b64String =3D Btc->TestInput; + binString =3D Btc->TestOutput; + + // + // Only testing the the translate functionality + // + + b64StringLen =3D AsciiStrnLenS (b64String, MAX_TEST_STRING_SIZE); + BinSize =3D AsciiStrnLenS (binString, MAX_TEST_STRING_SIZE); + + BinData =3D AllocatePool (BinSize); + Btc->BufferToFree =3D BinData; + + ReturnSize =3D BinSize; + Status =3D Base64Decode (b64String, b64StringLen, BinData, &ReturnSize); + + UT_ASSERT_STATUS_EQUAL (Status, Btc->ExpectedStatus); + + // If an error is not expected, check the results + if (EFI_ERROR (Btc->ExpectedStatus)) { + if (Btc->ExpectedStatus =3D=3D EFI_BUFFER_TOO_SMALL) { + UT_ASSERT_EQUAL (ReturnSize, Btc->ExpectedSize); + } + } else { + UT_ASSERT_EQUAL (ReturnSize, Btc->ExpectedSize); + if (ReturnSize !=3D 0) { + CompareStatus =3D CompareMem (binString, BinData, ReturnSize); + if (CompareStatus !=3D 0) { + UT_LOG_ERROR ("bin string compare error - size=3D%d\n", ReturnSize= ); + for (indx =3D 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & binString[indx]); + } + UT_LOG_ERROR ("\nBinData:\n"); + for (indx =3D 0; indx < ReturnSize; indx++) { + UT_LOG_ERROR (" %2.2x", 0xff & BinData[indx]); + } + UT_LOG_ERROR ("\n"); + } + UT_ASSERT_EQUAL (CompareStatus, 0); + } + } + + Btc->BufferToFree =3D NULL; + FreePool (BinData); + return UNIT_TEST_PASSED; +} + +/** + Initialze the unit test framework, suite, and unit tests for the + Base64 conversion APIs of BaseLib and run the unit tests. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to + initialize the unit tests. +**/ +STATIC +EFI_STATUS +EFIAPI +UnitTestingEntry ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Fw; + UNIT_TEST_SUITE_HANDLE b64EncodeTests; + UNIT_TEST_SUITE_HANDLE b64DecodeTests; + + Fw =3D NULL; + + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSIO= N)); + + // + // Start setting up the test framework for running the tests. + // + Status =3D InitUnitTestFramework (&Fw, UNIT_TEST_APP_NAME, gEfiCallerBas= eName, UNIT_TEST_APP_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r= \n", Status)); + goto EXIT; + } + + // + // Populate the B64 Encode Unit Test Suite. + // + Status =3D CreateUnitTestSuite (&b64EncodeTests, Fw, "b64 Encode binary = to Ascii string", "BaseLib.b64Encode", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for b64EncodeTests= \n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // --------------Suite-----------Description--------------Class Name----= ------Function--------Pre---Post-------------------Context----------- + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - Empty", "Test1", Rf= cEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest1); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - f", "Test2", RfcEnc= odeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest2); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - fo", "Test3", RfcEn= codeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest3); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - foo", "Test4", RfcE= ncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest4); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - foob", "Test5", Rfc= EncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest5); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - fooba", "Test6", Rf= cEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest6); + AddTestCase (b64EncodeTests, "RFC 4686 Test Vector - foobar", "Test7", R= fcEncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeTest7); + AddTestCase (b64EncodeTests, "Too small of output buffer", "Error1", Rfc= EncodeTest, NULL, CleanUpB64TestContext, &mBasicEncodeError1); + // + // Populate the B64 Decode Unit Test Suite. + // + Status =3D CreateUnitTestSuite (&b64DecodeTests, Fw, "b64 Decode Ascii s= tring to binary", "BaseLib.b64Decode", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for b64Decode Te= sts\n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - Empty", "Test1", R= fcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest1); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - f", "Test2", RfcDe= codeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest2); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - fo", "Test3", RfcD= ecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest3); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - foo", "Test4", Rfc= DecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest4); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - foob", "Test5", Rf= cDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest5); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - fooba", "Test6", R= fcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest6); + AddTestCase (b64DecodeTests, "RFC 4686 Test Vector - foobar", "Test7", = RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest7); + AddTestCase (b64DecodeTests, "Ignore Whitespace test", "Test8", RfcDeco= deTest, NULL, CleanUpB64TestContext, &mBasicDecodeTest8); + + AddTestCase (b64DecodeTests, "Not a quantum multiple of 4", "Error1", Rf= cDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError1); + AddTestCase (b64DecodeTests, "Invalid characters in the string", "Error2= ", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError2); + AddTestCase (b64DecodeTests, "Too many padding characters", "Error3", Rf= cDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError3); + AddTestCase (b64DecodeTests, "Incorrectly placed padding character", "Er= ror4", RfcDecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError4); + AddTestCase (b64DecodeTests, "Too small of output buffer", "Error5", Rfc= DecodeTest, NULL, CleanUpB64TestContext, &mBasicDecodeError5); + + // + // Execute the tests. + // + Status =3D RunAllTestSuites (Fw); + +EXIT: + if (Fw) { + FreeUnitTestFramework (Fw); + } + + return Status; +} + +/** + Standard UEFI entry point for target based unit test execution from UEFI= Shell. +**/ +EFI_STATUS +EFIAPI +BaseLibUnitTestAppEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return UnitTestingEntry (); +} + +/** + Standard POSIX C entry point for host based unit test execution. +**/ +int +main ( + int argc, + char *argv[] + ) +{ + return UnitTestingEntry (); +} diff --git a/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf = b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf new file mode 100644 index 0000000000..b31afae633 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf @@ -0,0 +1,32 @@ +## @file +# Unit tests of Base64 conversion APIs in BaseLib that are run from host +# environment. +# +# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D BaseLibUnitTestsHost + FILE_GUID =3D 1d005f4c-4dfa-41b5-ab0c-be91fe121459 + MODULE_TYPE =3D HOST_APPLICATION + VERSION_STRING =3D 1.0 + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + Base64UnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + UnitTestLib diff --git a/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf = b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf new file mode 100644 index 0000000000..907503898a --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsUefi.inf @@ -0,0 +1,33 @@ +## @file +# Unit tests of Base64 conversion APIs in BaseLib that are run from UEFI S= hell. +# +# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D BaseLibUnitTestsUefi + FILE_GUID =3D df5a6fed-8786-4a9d-9d02-eab39497b4a1 + MODULE_TYPE =3D UEFI_APPLICATION + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D BaseLibUnitTestAppEntry + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + Base64UnitTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiApplicationEntryPoint + DebugLib + UnitTestLib diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibUintnInt= nUnitTests32.c b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibUint= nIntnUnitTests32.c new file mode 100644 index 0000000000..be5c0e15d3 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibUintnIntnUnitTe= sts32.c @@ -0,0 +1,540 @@ +/** @file + IA32-specific functions for unit-testing INTN and UINTN functions in + SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TestBaseSafeIntLib.h" + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-1537977259); + Status =3D SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INTN Result; + + // + // If Operand is <=3D MAX_INTN, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeUint32ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUint32ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT32 Result; + + // + // INTN is same as INT32 in IA32, so this is just a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeIntnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT32 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeIntnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-1537977259); + Status =3D SafeIntnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT32 Result; + + // + // UINTN is same as UINT32 in IA32, so this is just a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeUintnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INTN Result; + + // + // If Operand is <=3D MAX_INTN, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeUintnToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUintnToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT64 Result; + + // + // UINTN is same as UINT32 in IA32, and UINT32 is a subset of + // INT64, so this is just a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeUintnToInt64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INTN Result; + + // + // If Operand is between MIN_INTN and MAX_INTN2 inclusive, then it's a = cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + Operand =3D (-1537977259); + Status =3D SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1537977259), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINTN Result; + + // + // If Operand is between 0 and MAX_UINTN inclusive, then it's a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INTN Result; + + // + // If Operand is <=3D MAX_INTN, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINTN Result; + + // + // If Operand is <=3D MAX_UINTN, then it's a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeUint64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Augend; + UINTN Addend; + UINTN Result; + + // + // If the result of addition doesn't overflow MAX_UINTN, then it's addit= ion + // + Augend =3D 0x3a3a3a3a; + Addend =3D 0x3a3a3a3a; + Result =3D 0; + Status =3D SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0xabababab; + Addend =3D 0xbcbcbcbc; + Status =3D SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Augend; + INTN Addend; + INTN Result; + + // + // If the result of addition doesn't overflow MAX_INTN + // and doesn't underflow MIN_INTN, then it's addition + // + Augend =3D 0x3a3a3a3a; + Addend =3D 0x3a3a3a3a; + Result =3D 0; + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + Augend =3D (-976894522); + Addend =3D (-976894522); + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1953789044), Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0x5a5a5a5a; + Addend =3D 0x5a5a5a5a; + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend =3D (-1515870810); + Addend =3D (-1515870810); + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Minuend; + UINTN Subtrahend; + UINTN Result; + + // + // If Minuend >=3D Subtrahend, then it's subtraction + // + Minuend =3D 0x5a5a5a5a; + Subtrahend =3D 0x3b3b3b3b; + Result =3D 0; + Status =3D SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend =3D 0x5a5a5a5a; + Subtrahend =3D 0x6d6d6d6d; + Status =3D SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Minuend; + INTN Subtrahend; + INTN Result; + + // + // If the result of subtractions doesn't overflow MAX_INTN or + // underflow MIN_INTN, then it's subtraction + // + Minuend =3D 0x5a5a5a5a; + Subtrahend =3D 0x3a3a3a3a; + Result =3D 0; + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x20202020, Result); + + Minuend =3D 0x3a3a3a3a; + Subtrahend =3D 0x5a5a5a5a; + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-538976288), Result); + + // + // Otherwise should result in an error status + // + Minuend =3D (-2054847098); + Subtrahend =3D 2054847098; + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend =3D (2054847098); + Subtrahend =3D (-2054847098); + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Multiplicand; + UINTN Multiplier; + UINTN Result; + + // + // If the result of multiplication doesn't overflow MAX_UINTN, it will s= ucceed + // + Multiplicand =3D 0xa122a; + Multiplier =3D 0xd23; + Result =3D 0; + Status =3D SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x844c9dbe, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0xa122a; + Multiplier =3D 0xed23; + Status =3D SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Multiplicand; + INTN Multiplier; + INTN Result; + + // + // If the result of multiplication doesn't overflow MAX_INTN and doesn't + // underflow MIN_UINTN, it will succeed + // + Multiplicand =3D 0x123456; + Multiplier =3D 0x678; + Result =3D 0; + Status =3D SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75c28c50, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x123456; + Multiplier =3D 0xabc; + Status =3D SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibUintnInt= nUnitTests64.c b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibUint= nIntnUnitTests64.c new file mode 100644 index 0000000000..0fee298172 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/SafeIntLibUintnIntnUnitTe= sts64.c @@ -0,0 +1,544 @@ +/** @file + x64-specific functions for unit-testing INTN and UINTN functions in + SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TestBaseSafeIntLib.h" + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-1537977259); + Status =3D SafeInt32ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INTN Result; + + // + // For x64, INTN is same as INT64 which is a superset of INT32 + // This is just a cast then, and it'll never fail + // + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeUint32ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT32 Result; + + // + // If Operand is between MIN_INT32 and MAX_INT32 inclusive, then it's a= cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeIntnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + Operand =3D (-1537977259); + Status =3D SafeIntnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1537977259), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeIntnToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeIntnToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT32 Result; + + // + // If Operand is between 0 and MAX_UINT32 inclusive, then it's a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeIntnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeIntnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeIntnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT32 Result; + + // + // If Operand is <=3D MAX_UINT32, then it's a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeUintnToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUintnToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INTN Result; + + // + // If Operand is <=3D MAX_INTN (0x7fff_ffff_ffff_ffff), then it's a cast + // + Operand =3D 0x5babababefefefef; + Result =3D 0; + Status =3D SafeUintnToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUintnToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT64 Result; + + // + // If Operand is <=3D MAX_INT64, then it's a cast + // + Operand =3D 0x5babababefefefef; + Result =3D 0; + Status =3D SafeUintnToInt64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUintnToInt64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INTN Result; + + // + // INTN is same as INT64 in x64, so this is just a cast + // + Operand =3D 0x5babababefefefef; + Result =3D 0; + Status =3D SafeInt64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5babababefefefef; + Result =3D 0; + Status =3D SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToIntn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INTN Result; + + // + // If Operand is <=3D MAX_INTN (0x7fff_ffff_ffff_ffff), then it's a cast + // + Operand =3D 0x5babababefefefef; + Result =3D 0; + Status =3D SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToIntn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINTN Result; + + // + // UINTN is same as UINT64 in x64, so this is just a cast + // + Operand =3D 0xababababefefefef; + Result =3D 0; + Status =3D SafeUint64ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xababababefefefef, Result); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Augend; + UINTN Addend; + UINTN Result; + + // + // If the result of addition doesn't overflow MAX_UINTN, then it's addit= ion + // + Augend =3D 0x3a3a3a3a12121212; + Addend =3D 0x3a3a3a3a12121212; + Result =3D 0; + Status =3D SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747424242424, Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0xababababefefefef; + Addend =3D 0xbcbcbcbcdededede; + Status =3D SafeUintnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnAdd ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Augend; + INTN Addend; + INTN Result; + + // + // If the result of addition doesn't overflow MAX_INTN + // and doesn't underflow MIN_INTN, then it's addition + // + Augend =3D 0x3a3a3a3a3a3a3a3a; + Addend =3D 0x3a3a3a3a3a3a3a3a; + Result =3D 0; + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747474747474, Result); + + Augend =3D (-4195730024608447034); + Addend =3D (-4195730024608447034); + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-8391460049216894068), Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0x5a5a5a5a5a5a5a5a; + Addend =3D 0x5a5a5a5a5a5a5a5a; + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend =3D (-6510615555426900570); + Addend =3D (-6510615555426900570); + Status =3D SafeIntnAdd(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Minuend; + UINTN Subtrahend; + UINTN Result; + + // + // If Minuend >=3D Subtrahend, then it's subtraction + // + Minuend =3D 0x5a5a5a5a5a5a5a5a; + Subtrahend =3D 0x3b3b3b3b3b3b3b3b; + Result =3D 0; + Status =3D SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend =3D 0x5a5a5a5a5a5a5a5a; + Subtrahend =3D 0x6d6d6d6d6d6d6d6d; + Status =3D SafeUintnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnSub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Minuend; + INTN Subtrahend; + INTN Result; + + // + // If the result of subtractions doesn't overflow MAX_INTN or + // underflow MIN_INTN, then it's subtraction + // + Minuend =3D 0x5a5a5a5a5a5a5a5a; + Subtrahend =3D 0x3a3a3a3a3a3a3a3a; + Result =3D 0; + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x2020202020202020, Result); + + Minuend =3D 0x3a3a3a3a3a3a3a3a; + Subtrahend =3D 0x5a5a5a5a5a5a5a5a; + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-2314885530818453536), Result); + + // + // Otherwise should result in an error status + // + Minuend =3D (-8825501086245354106); + Subtrahend =3D 8825501086245354106; + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend =3D (8825501086245354106); + Subtrahend =3D (-8825501086245354106); + Status =3D SafeIntnSub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Multiplicand; + UINTN Multiplier; + UINTN Result; + + // + // If the result of multiplication doesn't overflow MAX_UINTN, it will s= ucceed + // + Multiplicand =3D 0x123456789a; + Multiplier =3D 0x1234567; + Result =3D 0; + Status =3D SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x14b66db9745a07f6, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x123456789a; + Multiplier =3D 0x12345678; + Status =3D SafeUintnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnMult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Multiplicand; + INTN Multiplier; + INTN Result; + + // + // If the result of multiplication doesn't overflow MAX_INTN and doesn't + // underflow MIN_UINTN, it will succeed + // + Multiplicand =3D 0x123456789; + Multiplier =3D 0x6789abcd; + Result =3D 0; + Status =3D SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75cd9045220d6bb5, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x123456789; + Multiplier =3D 0xa789abcd; + Status =3D SafeIntnMult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= .c b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.c new file mode 100644 index 0000000000..2b1a2223a0 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.c @@ -0,0 +1,3064 @@ +/** @file + UEFI OS based application for unit testing the SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TestBaseSafeIntLib.h" + +#define UNIT_TEST_NAME "Int Safe Lib Unit Test Application" +#define UNIT_TEST_VERSION "0.1" + +// +// Conversion function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT8 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt8ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand =3D (-56); + Status =3D SafeInt8ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT16 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt8ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand =3D (-56); + Status =3D SafeInt8ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT32 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt8ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand =3D (-56); + Status =3D SafeInt8ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINTN Result; + + // + // Positive UINT8 should result in just a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt8ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand =3D (-56); + Status =3D SafeInt8ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Operand; + UINT64 Result; + + // + // Positive UINT8 should result in just a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt8ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Negative number should result in an error status + // + Operand =3D (-56); + Status =3D SafeInt8ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Operand; + INT8 Result; + + // + // Operand <=3D 0x7F (MAX_INT8) should result in a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint8ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Operand larger than 0x7f should result in an error status + // + Operand =3D 0xaf; + Status =3D SafeUint8ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + // + + // + // Operand <=3D 0x7F (MAX_INT8) should result in a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint8ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Operand larger than 0x7f should result in an error status + // + Operand =3D 0xaf; + Status =3D SafeUint8ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a ca= st + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D (-35); + Status =3D SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-35), Result); + + // + // Otherwise should result in an error status + // + Operand =3D 0x1234; + Status =3D SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-17835); + Status =3D SafeInt16ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 an= d MAX_INT8. + // + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D 0; + Result =3D 0; + Status =3D SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand =3D MAX_INT8; + Result =3D 0; + Status =3D SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-35); + Status =3D SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D 0x1234; + Status =3D SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-17835); + Status =3D SafeInt16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt16ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D 0x1234; + Status =3D SafeInt16ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-17835); + Status =3D SafeInt16ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand =3D 0x5b5b; + UINT16 Result =3D 0; + + // + // If Operand is non-negative, then it's a cast + // + Status =3D SafeInt16ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-17835); + Status =3D SafeInt16ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINT32 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5b5b; + Result =3D 0; + Status =3D SafeInt16ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-17835); + Status =3D SafeInt16ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5b5b; + Result =3D 0; + Status =3D SafeInt16ToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-17835); + Status =3D SafeInt16ToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5b5b; + Result =3D 0; + Status =3D SafeInt16ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-17835); + Status =3D SafeInt16ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + INT8 Result; + + // + // If Operand is <=3D MAX_INT8, it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint16ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5b5b); + Status =3D SafeUint16ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <=3D MAX_INT8, it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint16ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5b5b); + Status =3D SafeUint16ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + UINT8 Result; + + // + // If Operand is <=3D MAX_UINT8 (0xff), it's a cast + // + Operand =3D 0xab; + Result =3D 0; + Status =3D SafeUint16ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5b5b); + Status =3D SafeUint16ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Operand; + INT16 Result; + + // + // If Operand is <=3D MAX_INT16 (0x7fff), it's a cast + // + Operand =3D 0x5b5b; + Result =3D 0; + Status =3D SafeUint16ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabab); + Status =3D SafeUint16ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a ca= st + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D (-57); + Status =3D SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-57), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeInt32ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 an= d MAX_INT8. + // + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D 0; + Result =3D 0; + Status =3D SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand =3D MAX_INT8; + Result =3D 0; + Status =3D SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-57); + Status =3D SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (0x5bababab); + Status =3D SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeInt32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_INT8 inclusive, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-57); + Status =3D SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (0x5bababab); + Status =3D SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeInt32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + INT16 Result; + + // + // If Operand is between MIN_INT16 and MAX_INT16 inclusive, then it's a = cast + // + Operand =3D 0x5b5b; + Result =3D 0; + Status =3D SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b5b, Result); + + Operand =3D (-17857); + Status =3D SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-17857), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeInt32ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT16 Result; + + // + // If Operand is between 0 and MAX_UINT16 inclusive, then it's a cast + // + Operand =3D 0xabab; + Result =3D 0; + Status =3D SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-17857); + Status =3D SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (0x5bababab); + Status =3D SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeInt32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT32 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeInt32ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-1537977259); + Status =3D SafeInt32ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeInt32ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-1537977259); + Status =3D SafeInt32ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INT8 Result; + + // + // If Operand is <=3D MAX_INT8, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint32ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeUint32ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <=3D MAX_INT8, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint32ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeUint32ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + UINT8 Result; + + // + // If Operand is <=3D MAX_UINT8, then it's a cast + // + Operand =3D 0xab; + Result =3D 0; + Status =3D SafeUint32ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUint32ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INT16 Result; + + // + // If Operand is <=3D MAX_INT16, then it's a cast + // + Operand =3D 0x5bab; + Result =3D 0; + Status =3D SafeUint32ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUint32ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + UINT16 Result; + + // + // If Operand is <=3D MAX_UINT16, then it's a cast + // + Operand =3D 0xabab; + Result =3D 0; + Status =3D SafeUint32ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUint32ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Operand; + INT32 Result; + + // + // If Operand is <=3D MAX_INT32, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeUint32ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUint32ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a ca= st + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeIntnToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D (-53); + Status =3D SafeIntnToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-53), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeIntnToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeIntnToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 an= d MAX_INT8. + // + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a ca= st + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeIntnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D 0; + Result =3D 0; + Status =3D SafeIntnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand =3D MAX_INT8; + Result =3D 0; + Status =3D SafeIntnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-53); + Status =3D SafeIntnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (0x5bababab); + Status =3D SafeIntnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeIntnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_UINT8 inclusive, then it's a cast + // + Operand =3D 0xab; + Result =3D 0; + Status =3D SafeIntnToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeIntnToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeIntnToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + INT16 Result; + + // + // If Operand is between MIN_INT16 and MAX_INT16 inclusive, then it's a = cast + // + Operand =3D 0x5bab; + Result =3D 0; + Status =3D SafeIntnToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + Operand =3D (-23467); + Status =3D SafeIntnToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-23467), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeIntnToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeIntnToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT16 Result; + + // + // If Operand is between 0 and MAX_UINT16 inclusive, then it's a cast + // + Operand =3D 0xabab; + Result =3D 0; + Status =3D SafeIntnToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5bababab); + Status =3D SafeIntnToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-1537977259); + Status =3D SafeIntnToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUintn ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINTN Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeIntnToUintn(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-1537977259); + Status =3D SafeIntnToUintn(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INTN Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeIntnToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-1537977259); + Status =3D SafeIntnToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT8 Result; + + // + // If Operand is <=3D MAX_INT8, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUintnToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabab); + Status =3D SafeUintnToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <=3D MAX_INT8, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUintnToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabab); + Status =3D SafeUintnToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT8 Result; + + // + // If Operand is <=3D MAX_UINT8, then it's a cast + // + Operand =3D 0xab; + Result =3D 0; + Status =3D SafeUintnToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabab); + Status =3D SafeUintnToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT16 Result; + + // + // If Operand is <=3D MAX_INT16, then it's a cast + // + Operand =3D 0x5bab; + Result =3D 0; + Status =3D SafeUintnToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabab); + Status =3D SafeUintnToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + UINT16 Result; + + // + // If Operand is <=3D MAX_UINT16, then it's a cast + // + Operand =3D 0xabab; + Result =3D 0; + Status =3D SafeUintnToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUintnToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN Operand; + INT32 Result; + + // + // If Operand is <=3D MAX_INT32, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeUintnToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xabababab); + Status =3D SafeUintnToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INT8 Result; + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a c= ast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D (-37); + Status =3D SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-37), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + CHAR8 Result; + + // + // CHAR8 is typedefed as char, which may be signed or unsigned based + // on the compiler. Thus, for compatibility CHAR8 should be between 0 an= d MAX_INT8. + // + + // + // If Operand is between MIN_INT8 and MAX_INT8 inclusive, then it's a c= ast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + Operand =3D 0; + Result =3D 0; + Status =3D SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0, Result); + + Operand =3D MAX_INT8; + Result =3D 0; + Status =3D SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(MAX_INT8, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-37); + Status =3D SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT8 Result; + + // + // If Operand is between 0 and MAX_UINT8 inclusive, then it's a cast + // + Operand =3D 0xab; + Result =3D 0; + Status =3D SafeInt64ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INT16 Result; + + // + // If Operand is between MIN_INT16 and MAX_INT16 inclusive, then it's a= cast + // + Operand =3D 0x5bab; + Result =3D 0; + Status =3D SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + Operand =3D (-23467); + Status =3D SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-23467), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT16 Result; + + // + // If Operand is between 0 and MAX_UINT16 inclusive, then it's a cast + // + Operand =3D 0xabab; + Result =3D 0; + Status =3D SafeInt64ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + INT32 Result; + + // + // If Operand is between MIN_INT32 and MAX_INT32 inclusive, then it's a= cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + Operand =3D (-1537977259); + Status =3D SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1537977259), Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT32 Result; + + // + // If Operand is between 0 and MAX_UINT32 inclusive, then it's a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeInt64ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0x5babababefefefef); + Status =3D SafeInt64ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUint64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Operand; + UINT64 Result; + + // + // If Operand is non-negative, then it's a cast + // + Operand =3D 0x5babababefefefef; + Result =3D 0; + Status =3D SafeInt64ToUint64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (-6605562033422200815); + Status =3D SafeInt64ToUint64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT8 Result; + + // + // If Operand is <=3D MAX_INT8, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint64ToInt8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToInt8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToChar8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + CHAR8 Result; + + // CHAR8 is typedefed as char, which by default is signed, thus + // CHAR8 is same as INT8, so same tests as above: + + // + // If Operand is <=3D MAX_INT8, then it's a cast + // + Operand =3D 0x5b; + Result =3D 0; + Status =3D SafeUint64ToChar8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5b, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToChar8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUint8 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINT8 Result; + + // + // If Operand is <=3D MAX_UINT8, then it's a cast + // + Operand =3D 0xab; + Result =3D 0; + Status =3D SafeUint64ToUint8(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToUint8(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT16 Result; + + // + // If Operand is <=3D MAX_INT16, then it's a cast + // + Operand =3D 0x5bab; + Result =3D 0; + Status =3D SafeUint64ToInt16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToInt16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUint16 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINT16 Result; + + // + // If Operand is <=3D MAX_UINT16, then it's a cast + // + Operand =3D 0xabab; + Result =3D 0; + Status =3D SafeUint64ToUint16(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToUint16(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT32 Result; + + // + // If Operand is <=3D MAX_INT32, then it's a cast + // + Operand =3D 0x5bababab; + Result =3D 0; + Status =3D SafeUint64ToInt32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5bababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToInt32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUint32 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + UINT32 Result; + + // + // If Operand is <=3D MAX_UINT32, then it's a cast + // + Operand =3D 0xabababab; + Result =3D 0; + Status =3D SafeUint64ToUint32(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xabababab, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToUint32(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToInt64 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Operand; + INT64 Result; + + // + // If Operand is <=3D MAX_INT64, then it's a cast + // + Operand =3D 0x5babababefefefef; + Result =3D 0; + Status =3D SafeUint64ToInt64(Operand, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x5babababefefefef, Result); + + // + // Otherwise should result in an error status + // + Operand =3D (0xababababefefefef); + Status =3D SafeUint64ToInt64(Operand, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +// +// Addition function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Augend; + UINT8 Addend; + UINT8 Result; + + // + // If the result of addition doesn't overflow MAX_UINT8, then it's addit= ion + // + Augend =3D 0x3a; + Addend =3D 0x3a; + Result =3D 0; + Status =3D SafeUint8Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74, Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0xab; + Addend =3D 0xbc; + Status =3D SafeUint8Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Augend =3D 0x3a3a; + UINT16 Addend =3D 0x3a3a; + UINT16 Result =3D 0; + + // + // If the result of addition doesn't overflow MAX_UINT16, then it's addi= tion + // + Status =3D SafeUint16Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474, Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0xabab; + Addend =3D 0xbcbc; + Status =3D SafeUint16Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Augend; + UINT32 Addend; + UINT32 Result; + + // + // If the result of addition doesn't overflow MAX_UINT32, then it's addi= tion + // + Augend =3D 0x3a3a3a3a; + Addend =3D 0x3a3a3a3a; + Result =3D 0; + Status =3D SafeUint32Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0xabababab; + Addend =3D 0xbcbcbcbc; + Status =3D SafeUint32Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Augend; + UINT64 Addend; + UINT64 Result; + + // + // If the result of addition doesn't overflow MAX_UINT64, then it's addi= tion + // + Augend =3D 0x3a3a3a3a12121212; + Addend =3D 0x3a3a3a3a12121212; + Result =3D 0; + Status =3D SafeUint64Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747424242424, Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0xababababefefefef; + Addend =3D 0xbcbcbcbcdededede; + Status =3D SafeUint64Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Augend; + INT8 Addend; + INT8 Result; + + // + // If the result of addition doesn't overflow MAX_INT8 + // and doesn't underflow MIN_INT8, then it's addition + // + Augend =3D 0x3a; + Addend =3D 0x3a; + Result =3D 0; + Status =3D SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74, Result); + + Augend =3D (-58); + Addend =3D (-58); + Status =3D SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-116), Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0x5a; + Addend =3D 0x5a; + Status =3D SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend =3D (-90); + Addend =3D (-90); + Status =3D SafeInt8Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; + +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Augend; + INT16 Addend; + INT16 Result; + + // + // If the result of addition doesn't overflow MAX_INT16 + // and doesn't underflow MIN_INT16, then it's addition + // + Augend =3D 0x3a3a; + Addend =3D 0x3a3a; + Result =3D 0; + Status =3D SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474, Result); + + Augend =3D (-14906); + Addend =3D (-14906); + Status =3D SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-29812), Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0x5a5a; + Addend =3D 0x5a5a; + Status =3D SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend =3D (-23130); + Addend =3D (-23130); + Status =3D SafeInt16Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Augend; + INT32 Addend; + INT32 Result; + + // + // If the result of addition doesn't overflow MAX_INT32 + // and doesn't underflow MIN_INT32, then it's addition + // + Augend =3D 0x3a3a3a3a; + Addend =3D 0x3a3a3a3a; + Result =3D 0; + Status =3D SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x74747474, Result); + + Augend =3D (-976894522); + Addend =3D (-976894522); + Status =3D SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-1953789044), Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0x5a5a5a5a; + Addend =3D 0x5a5a5a5a; + Status =3D SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend =3D (-1515870810); + Addend =3D (-1515870810); + Status =3D SafeInt32Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64Add ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Augend; + INT64 Addend; + INT64 Result; + + // + // If the result of addition doesn't overflow MAX_INT64 + // and doesn't underflow MIN_INT64, then it's addition + // + Augend =3D 0x3a3a3a3a3a3a3a3a; + Addend =3D 0x3a3a3a3a3a3a3a3a; + Result =3D 0; + Status =3D SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7474747474747474, Result); + + Augend =3D (-4195730024608447034); + Addend =3D (-4195730024608447034); + Status =3D SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-8391460049216894068), Result); + + // + // Otherwise should result in an error status + // + Augend =3D 0x5a5a5a5a5a5a5a5a; + Addend =3D 0x5a5a5a5a5a5a5a5a; + Status =3D SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Augend =3D (-6510615555426900570); + Addend =3D (-6510615555426900570); + Status =3D SafeInt64Add(Augend, Addend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +// +// Subtraction function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Minuend; + UINT8 Subtrahend; + UINT8 Result; + + // + // If Minuend >=3D Subtrahend, then it's subtraction + // + Minuend =3D 0x5a; + Subtrahend =3D 0x3b; + Result =3D 0; + Status =3D SafeUint8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f, Result); + + // + // Otherwise should result in an error status + // + Minuend =3D 0x5a; + Subtrahend =3D 0x6d; + Status =3D SafeUint8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Minuend; + UINT16 Subtrahend; + UINT16 Result; + + // + // If Minuend >=3D Subtrahend, then it's subtraction + // + Minuend =3D 0x5a5a; + Subtrahend =3D 0x3b3b; + Result =3D 0; + Status =3D SafeUint16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend =3D 0x5a5a; + Subtrahend =3D 0x6d6d; + Status =3D SafeUint16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Minuend; + UINT32 Subtrahend; + UINT32 Result; + + // + // If Minuend >=3D Subtrahend, then it's subtraction + // + Minuend =3D 0x5a5a5a5a; + Subtrahend =3D 0x3b3b3b3b; + Result =3D 0; + Status =3D SafeUint32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend =3D 0x5a5a5a5a; + Subtrahend =3D 0x6d6d6d6d; + Status =3D SafeUint32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Minuend; + UINT64 Subtrahend; + UINT64 Result; + + // + // If Minuend >=3D Subtrahend, then it's subtraction + // + Minuend =3D 0x5a5a5a5a5a5a5a5a; + Subtrahend =3D 0x3b3b3b3b3b3b3b3b; + Result =3D 0; + Status =3D SafeUint64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x1f1f1f1f1f1f1f1f, Result); + + // + // Otherwise should result in an error status + // + Minuend =3D 0x5a5a5a5a5a5a5a5a; + Subtrahend =3D 0x6d6d6d6d6d6d6d6d; + Status =3D SafeUint64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Minuend; + INT8 Subtrahend; + INT8 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT8 or + // underflow MIN_INT8, then it's subtraction + // + Minuend =3D 0x5a; + Subtrahend =3D 0x3a; + Result =3D 0; + Status =3D SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x20, Result); + + Minuend =3D 58; + Subtrahend =3D 78; + Status =3D SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-20), Result); + + // + // Otherwise should result in an error status + // + Minuend =3D (-80); + Subtrahend =3D 80; + Status =3D SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend =3D (80); + Subtrahend =3D (-80); + Status =3D SafeInt8Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Minuend; + INT16 Subtrahend; + INT16 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT16 or + // underflow MIN_INT16, then it's subtraction + // + Minuend =3D 0x5a5a; + Subtrahend =3D 0x3a3a; + Result =3D 0; + Status =3D SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x2020, Result); + + Minuend =3D 0x3a3a; + Subtrahend =3D 0x5a5a; + Status =3D SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-8224), Result); + + // + // Otherwise should result in an error status + // + Minuend =3D (-31354); + Subtrahend =3D 31354; + Status =3D SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend =3D (31354); + Subtrahend =3D (-31354); + Status =3D SafeInt16Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Minuend; + INT32 Subtrahend; + INT32 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT32 or + // underflow MIN_INT32, then it's subtraction + // + Minuend =3D 0x5a5a5a5a; + Subtrahend =3D 0x3a3a3a3a; + Result =3D 0; + Status =3D SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x20202020, Result); + + Minuend =3D 0x3a3a3a3a; + Subtrahend =3D 0x5a5a5a5a; + Status =3D SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-538976288), Result); + + // + // Otherwise should result in an error status + // + Minuend =3D (-2054847098); + Subtrahend =3D 2054847098; + Status =3D SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend =3D (2054847098); + Subtrahend =3D (-2054847098); + Status =3D SafeInt32Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64Sub ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Minuend; + INT64 Subtrahend; + INT64 Result; + + // + // If the result of subtractions doesn't overflow MAX_INT64 or + // underflow MIN_INT64, then it's subtraction + // + Minuend =3D 0x5a5a5a5a5a5a5a5a; + Subtrahend =3D 0x3a3a3a3a3a3a3a3a; + Result =3D 0; + Status =3D SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x2020202020202020, Result); + + Minuend =3D 0x3a3a3a3a3a3a3a3a; + Subtrahend =3D 0x5a5a5a5a5a5a5a5a; + Status =3D SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL((-2314885530818453536), Result); + + // + // Otherwise should result in an error status + // + Minuend =3D (-8825501086245354106); + Subtrahend =3D 8825501086245354106; + Status =3D SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + Minuend =3D (8825501086245354106); + Subtrahend =3D (-8825501086245354106); + Status =3D SafeInt64Sub(Minuend, Subtrahend, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +// +// Multiplication function tests: +// +UNIT_TEST_STATUS +EFIAPI +TestSafeUint8Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT8 Multiplicand; + UINT8 Multiplier; + UINT8 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT8, it will s= ucceed + // + Multiplicand =3D 0x12; + Multiplier =3D 0xa; + Result =3D 0; + Status =3D SafeUint8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xb4, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x12; + Multiplier =3D 0x23; + Status =3D SafeUint8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint16Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT16 Multiplicand; + UINT16 Multiplier; + UINT16 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT16, it will = succeed + // + Multiplicand =3D 0x212; + Multiplier =3D 0x7a; + Result =3D 0; + Status =3D SafeUint16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0xfc94, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x1234; + Multiplier =3D 0x213; + Status =3D SafeUint16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT32 Multiplicand; + UINT32 Multiplier; + UINT32 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT32, it will = succeed + // + Multiplicand =3D 0xa122a; + Multiplier =3D 0xd23; + Result =3D 0; + Status =3D SafeUint32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x844c9dbe, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0xa122a; + Multiplier =3D 0xed23; + Status =3D SafeUint32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINT64 Multiplicand; + UINT64 Multiplier; + UINT64 Result; + + // + // If the result of multiplication doesn't overflow MAX_UINT64, it will = succeed + // + Multiplicand =3D 0x123456789a; + Multiplier =3D 0x1234567; + Result =3D 0; + Status =3D SafeUint64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x14b66db9745a07f6, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x123456789a; + Multiplier =3D 0x12345678; + Status =3D SafeUint64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt8Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT8 Multiplicand; + INT8 Multiplier; + INT8 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT8 and doesn't + // underflow MIN_UINT8, it will succeed + // + Multiplicand =3D 0x12; + Multiplier =3D 0x7; + Result =3D 0; + Status =3D SafeInt8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7e, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x12; + Multiplier =3D 0xa; + Status =3D SafeInt8Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt16Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT16 Multiplicand; + INT16 Multiplier; + INT16 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT16 and doesn't + // underflow MIN_UINT16, it will succeed + // + Multiplicand =3D 0x123; + Multiplier =3D 0x67; + Result =3D 0; + Status =3D SafeInt16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x7515, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x123; + Multiplier =3D 0xab; + Status =3D SafeInt16Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT32 Multiplicand; + INT32 Multiplier; + INT32 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT32 and doesn't + // underflow MIN_UINT32, it will succeed + // + Multiplicand =3D 0x123456; + Multiplier =3D 0x678; + Result =3D 0; + Status =3D SafeInt32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75c28c50, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x123456; + Multiplier =3D 0xabc; + Status =3D SafeInt32Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64Mult ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + INT64 Multiplicand; + INT64 Multiplier; + INT64 Result; + + // + // If the result of multiplication doesn't overflow MAX_INT64 and doesn't + // underflow MIN_UINT64, it will succeed + // + Multiplicand =3D 0x123456789; + Multiplier =3D 0x6789abcd; + Result =3D 0; + Status =3D SafeInt64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_NOT_EFI_ERROR(Status); + UT_ASSERT_EQUAL(0x75cd9045220d6bb5, Result); + + // + // Otherwise should result in an error status + // + Multiplicand =3D 0x123456789; + Multiplier =3D 0xa789abcd; + Status =3D SafeInt64Mult(Multiplicand, Multiplier, &Result); + UT_ASSERT_EQUAL(RETURN_BUFFER_TOO_SMALL, Status); + + return UNIT_TEST_PASSED; +} + +/** + + Main fuction sets up the unit test environment + +**/ +EFI_STATUS +EFIAPI +UefiTestMain ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + UNIT_TEST_SUITE_HANDLE ConversionTestSuite; + UNIT_TEST_SUITE_HANDLE AdditionSubtractionTestSuite; + UNIT_TEST_SUITE_HANDLE MultiplicationTestSuite; + + Framework =3D NULL; + ConversionTestSuite =3D NULL; + AdditionSubtractionTestSuite =3D NULL; + MultiplicationTestSuite =3D NULL; + + DEBUG((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION)); + + // + // Start setting up the test framework for running the tests. + // + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCaller= BaseName, UNIT_TEST_VERSION); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r\n"= , Status)); + goto EXIT; + } + + /// + // Test the conversion functions + // + Status =3D CreateUnitTestSuite (&ConversionTestSuite, Framework, "Int Sa= fe Conversions Test Suite", "Common.SafeInt.Convert", NULL, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Conversions Tes= t Suite\n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint8", "TestSafeInt= 8ToUint8", TestSafeInt8ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint16", "TestSafeInt= 8ToUint16", TestSafeInt8ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint32", "TestSafeInt= 8ToUint32", TestSafeInt8ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUintn", "TestSafeInt= 8ToUintn", TestSafeInt8ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt8ToUint64", "TestSafeInt= 8ToUint64", TestSafeInt8ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint8ToInt8", "TestSafeUin= t8ToInt8", TestSafeUint8ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint8ToChar8", "TestSafeUin= t8ToChar8", TestSafeUint8ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToInt8", "TestSafeInt= 16ToInt8", TestSafeInt16ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToChar8", "TestSafeInt= 16ToChar8", TestSafeInt16ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint8", "TestSafeInt= 16ToUint8", TestSafeInt16ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint16", "TestSafeInt= 16ToUint16", TestSafeInt16ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint32", "TestSafeInt= 16ToUint32", TestSafeInt16ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUintn", "TestSafeInt= 16ToUintn", TestSafeInt16ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt16ToUint64", "TestSafeInt= 16ToUint64", TestSafeInt16ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToInt8", "TestSafeUin= t16ToInt8", TestSafeUint16ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToChar8", "TestSafeUin= t16ToChar8", TestSafeUint16ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToUint8", "TestSafeUin= t16ToUint8", TestSafeUint16ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint16ToInt16", "TestSafeUin= t16ToInt16", TestSafeUint16ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToInt8", "TestSafeInt= 32ToInt8", TestSafeInt32ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToChar8", "TestSafeInt= 32ToChar8", TestSafeInt32ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint8", "TestSafeInt= 32ToUint8", TestSafeInt32ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToInt16", "TestSafeInt= 32ToInt16", TestSafeInt32ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint16", "TestSafeInt= 32ToUint16", TestSafeInt32ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint32", "TestSafeInt= 32ToUint32", TestSafeInt32ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUintn", "TestSafeInt= 32ToUintn", TestSafeInt32ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt32ToUint64", "TestSafeInt= 32ToUint64", TestSafeInt32ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToInt8", "TestSafeUin= t32ToInt8", TestSafeUint32ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToChar8", "TestSafeUin= t32ToChar8", TestSafeUint32ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToUint8", "TestSafeUin= t32ToUint8", TestSafeUint32ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToInt16", "TestSafeUin= t32ToInt16", TestSafeUint32ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToUint16", "TestSafeUin= t32ToUint16", TestSafeUint32ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToInt32", "TestSafeUin= t32ToInt32", TestSafeUint32ToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint32ToIntn", "TestSafeUin= t32ToIntn", TestSafeUint32ToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToInt8", "TestSafeInt= nToInt8", TestSafeIntnToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToChar8", "TestSafeInt= nToChar8", TestSafeIntnToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint8", "TestSafeInt= nToUint8", TestSafeIntnToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToInt16", "TestSafeInt= nToInt16", TestSafeIntnToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint16", "TestSafeInt= nToUint16", TestSafeIntnToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToInt32", "TestSafeInt= nToInt32", TestSafeIntnToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint32", "TestSafeInt= nToUint32", TestSafeIntnToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUintn", "TestSafeInt= nToUintn", TestSafeIntnToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeIntnToUint64", "TestSafeInt= nToUint64", TestSafeIntnToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt8", "TestSafeUin= tnToInt8", TestSafeUintnToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToChar8", "TestSafeUin= tnToChar8", TestSafeUintnToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToUint8", "TestSafeUin= tnToUint8", TestSafeUintnToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt16", "TestSafeUin= tnToInt16", TestSafeUintnToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToUint16", "TestSafeUin= tnToUint16", TestSafeUintnToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt32", "TestSafeUin= tnToInt32", TestSafeUintnToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToUint32", "TestSafeUin= tnToUint32", TestSafeUintnToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToIntn", "TestSafeUin= tnToIntn", TestSafeUintnToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUintnToInt64", "TestSafeUin= tnToInt64", TestSafeUintnToInt64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToInt8", "TestSafeInt= 64ToInt8", TestSafeInt64ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToChar8", "TestSafeInt= 64ToChar8", TestSafeInt64ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint8", "TestSafeInt= 64ToUint8", TestSafeInt64ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToInt16", "TestSafeInt= 64ToInt16", TestSafeInt64ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint16", "TestSafeInt= 64ToUint16", TestSafeInt64ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToInt32", "TestSafeInt= 64ToInt32", TestSafeInt64ToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint32", "TestSafeInt= 64ToUint32", TestSafeInt64ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToIntn", "TestSafeInt= 64ToIntn", TestSafeInt64ToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUintn", "TestSafeInt= 64ToUintn", TestSafeInt64ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeInt64ToUint64", "TestSafeInt= 64ToUint64", TestSafeInt64ToUint64, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt8", "TestSafeUin= t64ToInt8", TestSafeUint64ToInt8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToChar8", "TestSafeUin= t64ToChar8", TestSafeUint64ToChar8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUint8", "TestSafeUin= t64ToUint8", TestSafeUint64ToUint8, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt16", "TestSafeUin= t64ToInt16", TestSafeUint64ToInt16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUint16", "TestSafeUin= t64ToUint16", TestSafeUint64ToUint16, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt32", "TestSafeUin= t64ToInt32", TestSafeUint64ToInt32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUint32", "TestSafeUin= t64ToUint32", TestSafeUint64ToUint32, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToIntn", "TestSafeUin= t64ToIntn", TestSafeUint64ToIntn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToUintn", "TestSafeUin= t64ToUintn", TestSafeUint64ToUintn, NULL, NULL, NULL); + AddTestCase(ConversionTestSuite, "Test SafeUint64ToInt64", "TestSafeUin= t64ToInt64", TestSafeUint64ToInt64, NULL, NULL, NULL); + + // + // Test the addition and subtraction functions + // + Status =3D CreateUnitTestSuite(&AdditionSubtractionTestSuite, Framework,= "Int Safe Add/Subtract Test Suite", "Common.SafeInt.AddSubtract", NULL, NU= LL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Int Safe Add/Su= btract Test Suite\n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint8Add", "TestSaf= eUint8Add", TestSafeUint8Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint16Add", "TestSaf= eUint16Add", TestSafeUint16Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint32Add", "TestSaf= eUint32Add", TestSafeUint32Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUintnAdd", "TestSaf= eUintnAdd", TestSafeUintnAdd, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint64Add", "TestSaf= eUint64Add", TestSafeUint64Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt8Add", "TestSaf= eInt8Add", TestSafeInt8Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt16Add", "TestSaf= eInt16Add", TestSafeInt16Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt32Add", "TestSaf= eInt32Add", TestSafeInt32Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeIntnAdd", "TestSaf= eIntnAdd", TestSafeIntnAdd, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt64Add", "TestSaf= eInt64Add", TestSafeInt64Add, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint8Sub", "TestSaf= eUint8Sub", TestSafeUint8Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint16Sub", "TestSaf= eUint16Sub", TestSafeUint16Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint32Sub", "TestSaf= eUint32Sub", TestSafeUint32Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUintnSub", "TestSaf= eUintnSub", TestSafeUintnSub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeUint64Sub", "TestSaf= eUint64Sub", TestSafeUint64Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt8Sub", "TestSaf= eInt8Sub", TestSafeInt8Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt16Sub", "TestSaf= eInt16Sub", TestSafeInt16Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt32Sub", "TestSaf= eInt32Sub", TestSafeInt32Sub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeIntnSub", "TestSaf= eIntnSub", TestSafeIntnSub, NULL, NULL, NULL); + AddTestCase(AdditionSubtractionTestSuite, "Test SafeInt64Sub", "TestSaf= eInt64Sub", TestSafeInt64Sub, NULL, NULL, NULL); + + // + // Test the multiplication functions + // + Status =3D CreateUnitTestSuite(&MultiplicationTestSuite, Framework, "Int= Safe Multiply Test Suite", "Common.SafeInt.Multiply", NULL, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Int Safe Multip= ly Test Suite\n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase(MultiplicationTestSuite, "Test SafeUint8Mult", "TestSafeUin= t8Mult", TestSafeUint8Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUint16Mult", "TestSafeUin= t16Mult", TestSafeUint16Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUint32Mult", "TestSafeUin= t32Mult", TestSafeUint32Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUintnMult", "TestSafeUin= tnMult", TestSafeUintnMult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeUint64Mult", "TestSafeUin= t64Mult", TestSafeUint64Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt8Mult", "TestSafeInt= 8Mult", TestSafeInt8Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt16Mult", "TestSafeInt= 16Mult", TestSafeInt16Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt32Mult", "TestSafeInt= 32Mult", TestSafeInt32Mult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeIntnMult", "TestSafeInt= nMult", TestSafeIntnMult, NULL, NULL, NULL); + AddTestCase(MultiplicationTestSuite, "Test SafeInt64Mult", "TestSafeInt= 64Mult", TestSafeInt64Mult, NULL, NULL, NULL); + + // + // Execute the tests. + // + Status =3D RunAllTestSuites(Framework); + +EXIT: + if (Framework !=3D NULL) { + FreeUnitTestFramework(Framework); + } + + return Status; +} + +EFI_STATUS +EFIAPI +PeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return UefiTestMain (); +} + +EFI_STATUS +EFIAPI +DxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return UefiTestMain (); +} + +int +main ( + int argc, + char *argv[] + ) +{ + return UefiTestMain (); +} diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= .h b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.h new file mode 100644 index 0000000000..7957c99a85 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.h @@ -0,0 +1,123 @@ +/** @file + UEFI OS based application for unit testing the SafeIntLib. + + Copyright (c) Microsoft Corporation.
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _TEST_BASE_SAFE_INT_LIB_H_ +#define _TEST_BASE_SAFE_INT_LIB_H_ + +#include +#include +#include +#include +#include +#include +#include + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt32ToUintn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint32ToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToInt32( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnToUint32( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToUint32( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnToInt64( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeInt64ToUintn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToIntn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUint64ToUintn( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnAdd( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnAdd( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnSub( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnSub( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeUintnMult( + IN UNIT_TEST_CONTEXT Context + ); + +UNIT_TEST_STATUS +EFIAPI +TestSafeIntnMult( + IN UNIT_TEST_CONTEXT Context + ); + +#endif diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= .uni b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.uni new file mode 100644 index 0000000000..956835c30d --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib.uni @@ -0,0 +1,13 @@ +// /** @file +// Application that Unit Tests the SafeIntLib +// +// Copyright (c) 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Application that = Unit Tests the SafeIntLib" + +#string STR_MODULE_DESCRIPTION #language en-US "Application that = Unit Tests the SafeIntLib." + diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= Dxe.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibDxe= .inf new file mode 100644 index 0000000000..de67b04bd5 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibDxe.inf @@ -0,0 +1,45 @@ +## @file +# DXE Driver that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D TestBaseSafeIntLibDxe + MODULE_UNI_FILE =3D TestBaseSafeIntLib.uni + FILE_GUID =3D 9729DB60-FB9D-4625-9EE1-93B21EC246B8 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D DxeEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32, Sources.ARM] + SafeIntLibUintnIntnUnitTests32.c + +[Sources.X64, Sources.AARCH64] + SafeIntLibUintnIntnUnitTests64.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib + +[Depex] + TRUE diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= Host.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHo= st.inf new file mode 100644 index 0000000000..35c93fdeac --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibHost.inf @@ -0,0 +1,40 @@ +## @file +# Host OS based Application that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D TestBaseSafeIntLibHost + MODULE_UNI_FILE =3D TestBaseSafeIntLib.uni + FILE_GUID =3D 95487689-9E30-41AD-B773-3650C94BCBE2 + MODULE_TYPE =3D HOST_APPLICATION + VERSION_STRING =3D 1.0 + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32, Sources.ARM] + SafeIntLibUintnIntnUnitTests32.c + +[Sources.X64, Sources.AARCH64] + SafeIntLibUintnIntnUnitTests64.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + SafeIntLib + UnitTestLib diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= Pei.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibPei= .inf new file mode 100644 index 0000000000..c8ba4f44ef --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibPei.inf @@ -0,0 +1,45 @@ +## @file +# PEIM that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D TestBaseSafeIntLibPei + MODULE_UNI_FILE =3D TestBaseSafeIntLib.uni + FILE_GUID =3D 7D910602-ED53-45E6-826E-8266705B9734 + MODULE_TYPE =3D PEIM + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D PeiEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32, Sources.ARM] + SafeIntLibUintnIntnUnitTests32.c + +[Sources.X64, Sources.AARCH64] + SafeIntLibUintnIntnUnitTests64.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + PeimEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib + +[Depex] + TRUE diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= Smm.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibSmm= .inf new file mode 100644 index 0000000000..df7288501d --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibSmm.inf @@ -0,0 +1,45 @@ +## @file +# SMM Driver that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D TestBaseSafeIntLibSmm + MODULE_UNI_FILE =3D TestBaseSafeIntLib.uni + FILE_GUID =3D 2F2A1907-B1B4-4E33-8B83-62A60AB4F0D4 + MODULE_TYPE =3D DXE_SMM_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D DxeEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32, Sources.ARM] + SafeIntLibUintnIntnUnitTests32.c + +[Sources.X64, Sources.AARCH64] + SafeIntLibUintnIntnUnitTests64.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib + +[Depex] + TRUE diff --git a/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLib= UefiShell.inf b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeInt= LibUefiShell.inf new file mode 100644 index 0000000000..5a13c1c845 --- /dev/null +++ b/MdePkg/Test/UnitTest/Library/BaseSafeIntLib/TestBaseSafeIntLibUefiShe= ll.inf @@ -0,0 +1,42 @@ +## @file +# UEFI Shell based Application that Unit Tests the SafeIntLib +# +# Copyright (c) Microsoft Corporation.
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D TestBaseSafeIntLibUefiShell + MODULE_UNI_FILE =3D TestBaseSafeIntLib.uni + FILE_GUID =3D 1F91B73E-5B6A-4317-80E8-E7C36A3C7AF4 + MODULE_TYPE =3D UEFI_APPLICATION + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D DxeEntryPoint + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + TestBaseSafeIntLib.c + TestBaseSafeIntLib.h + +[Sources.Ia32, Sources.ARM] + SafeIntLibUintnIntnUnitTests32.c + +[Sources.X64, Sources.AARCH64] + SafeIntLibUintnIntnUnitTests64.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + BaseLib + DebugLib + SafeIntLib + UnitTestLib --=20 2.21.0.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 (#54058): https://edk2.groups.io/g/devel/message/54058 Mute This Topic: https://groups.io/mt/71060086/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54059+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54059+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099244845926.2010051587017; Fri, 7 Feb 2020 10:14:04 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id n70CYY1788612xd7FRaRjJ8K; Fri, 07 Feb 2020 10:14:03 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web12.9025.1581099240821545376 for ; Fri, 07 Feb 2020 10:14:02 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:14:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500557" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:14:01 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew , Liming Gao , Hao A Wu Subject: [edk2-devel] [Patch v2 09/11] MdeModulePkg: Add DxeResetSystemLib unit test Date: Fri, 7 Feb 2020 10:13:52 -0800 Message-Id: <20200207181354.31632-10-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: kiGRA7l1NmlpL01bhAgvf2Cqx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099243; bh=NRw8f7k9GdYHfZB1+ZrQDyApJ7/u0fhq8cgr6ObzASM=; h=Cc:Date:From:Reply-To:Subject:To; b=C77Jar0iC/HWb1+HCN8WwwBjqIWSl3avY9GpU/47NcRyzMY/W/0f6FLHuBmvHDXiFoJ UZEL+SFnlbk5RKYn03SOIkwUoLWWF4cyG2gtX+vFq7wR8zVTLsE4P139zpkizQergJYI9 QTsnUcSz0c/X5q+dt6nL3U1kwsAY5a6fKNE= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 * Add unit test of DxeResetSystemLib library instance that uses cmocka interfaces to mock the UEFI Runtime Services Table and its ResetSystem() service. When a unit test uses the cmocka interfaces, the unit test does not support being run from target environments. cmocka APIs: https://api.cmocka.org/index.html This example puts the unit test in a UnitTest directory below the library INF file and this location means the unit test is only designed to work this this one library instance. * Add Test/MdeModulePkgHostTest.dsc to build host based unit tests Cc: Sean Brogan Cc: Bret Barkelew Cc: Liming Gao Cc: Hao A Wu Signed-off-by: Michael D Kinney Acked-by: Hao A Wu Reviewed-by: Bret Barkelew --- .../UnitTest/DxeResetSystemLibUnitTest.c | 312 ++++++++++++++++++ .../DxeResetSystemLibUnitTestHost.inf | 34 ++ .../MockUefiRuntimeServicesTableLib.c | 13 + .../MockUefiRuntimeServicesTableLib.inf | 25 ++ MdeModulePkg/MdeModulePkg.ci.yaml | 13 +- MdeModulePkg/Test/MdeModulePkgHostTest.dsc | 32 ++ 6 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeRese= tSystemLibUnitTest.c create mode 100644 MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeRese= tSystemLibUnitTestHost.inf create mode 100644 MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUef= iRuntimeServicesTableLib.c create mode 100644 MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUef= iRuntimeServicesTableLib.inf create mode 100644 MdeModulePkg/Test/MdeModulePkgHostTest.dsc diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystem= LibUnitTest.c b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSys= temLibUnitTest.c new file mode 100644 index 0000000000..3bba38b579 --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnit= Test.c @@ -0,0 +1,312 @@ +/** @file + Unit tests of the DxeResetSystemLib instance of the ResetSystemLib class + + Copyright (C) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define UNIT_TEST_APP_NAME "DxeResetSystemLib Unit Tests" +#define UNIT_TEST_APP_VERSION "1.0" + +/** + Resets the entire platform. + + @param[in] ResetType The type of reset to perform. + @param[in] ResetStatus The status code for the reset. + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData For a ResetType of EfiResetCold, EfiResetW= arm, or + EfiResetShutdown the data buffer starts wi= th a Null-terminated + string, optionally followed by additional = binary data. + The string is a description that the calle= r may use to further + indicate the reason for the system reset. + For a ResetType of EfiResetPlatformSpecifi= c the data buffer + also starts with a Null-terminated string = that is followed + by an EFI_GUID that describes the specific= type of reset to perform. +**/ +STATIC +VOID +EFIAPI +MockResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + check_expected_ptr (ResetType); + check_expected_ptr (ResetStatus); + + // + // NOTE: Mocked functions can also return values, but that + // is for another demo. +} + +/// +/// Mock version of the UEFI Runtime Services Table +/// +EFI_RUNTIME_SERVICES MockRuntime =3D { + { + EFI_RUNTIME_SERVICES_SIGNATURE, // Signature + EFI_RUNTIME_SERVICES_REVISION, // Revision + sizeof (EFI_RUNTIME_SERVICES), // HeaderSize + 0, // CRC32 + 0 // Reserved + }, + NULL, // GetTime + NULL, // SetTime + NULL, // GetWakeupTime + NULL, // SetWakeupTime + NULL, // SetVirtualAddressMap + NULL, // ConvertPointer + NULL, // GetVariable + NULL, // GetNextVariableName + NULL, // SetVariable + NULL, // GetNextHighMonotonicCount + MockResetSystem, // ResetSystem + NULL, // UpdateCapsule + NULL, // QueryCapsuleCapabilities + NULL // QueryVariableInfo +}; + +/** + Unit test for ColdReset () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetColdShouldIssueAColdReset ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetCold); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetCold (); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for WarmReset () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetWarmShouldIssueAWarmReset ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetWarm); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetWarm (); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for ResetShutdown () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetShutdownShouldIssueAShutdown ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetShutdown); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetShutdown (); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for ResetPlatformSpecific () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetPlatformSpecificShouldIssueAPlatformSpecificReset ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetPlatformSpecific); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetPlatformSpecific (0, NULL); + + return UNIT_TEST_PASSED; +} + +/** + Unit test for ResetSystem () API of the ResetSystemLib. + + @param[in] Context [Optional] An optional parameter that enables: + 1) test-case reuse with varied parameters and + 2) test-case re-entry for Target tests that need a + reboot. This parameter is a VOID* and it is the + responsibility of the test author to ensure that = the + contents are well understood by all test cases th= at may + consume it. + + @retval UNIT_TEST_PASSED The Unit test has completed and th= e test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +ResetSystemShouldPassTheParametersThrough ( + IN UNIT_TEST_CONTEXT Context + ) +{ + expect_value (MockResetSystem, ResetType, EfiResetCold); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + + expect_value (MockResetSystem, ResetType, EfiResetShutdown); + expect_value (MockResetSystem, ResetStatus, EFI_SUCCESS); + + ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + + return UNIT_TEST_PASSED; +} + +/** + Initialze the unit test framework, suite, and unit tests for the + ResetSystemLib and run the ResetSystemLib unit test. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available = to + initialize the unit tests. +**/ +STATIC +EFI_STATUS +EFIAPI +UnitTestingEntry ( + VOID + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + UNIT_TEST_SUITE_HANDLE ResetTests; + + Framework =3D NULL; + + DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSIO= N )); + + // + // Start setting up the test framework for running the tests. + // + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCa= llerBaseName, UNIT_TEST_APP_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r= \n", Status)); + goto EXIT; + } + + // + // Populate the ResetSytemLib Unit Test Suite. + // + Status =3D CreateUnitTestSuite (&ResetTests, Framework, "DxeResetSystemL= ib Reset Tests", "ResetSystemLib.Reset", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ResetTests\n")= ); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // + // --------------Suite-----------Description--------------Name----------= Function--------Pre---Post-------------------Context----------- + // + AddTestCase (ResetTests, "ResetCold should issue a cold reset", "Cold", = ResetColdShouldIssueAColdReset, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetWarm should issue a warm reset", "Warm", = ResetWarmShouldIssueAWarmReset, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetShutdown should issue a shutdown", "Shutd= own", ResetShutdownShouldIssueAShutdown, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetPlatformSpecific should issue a platform-= specific reset", "Platform", ResetPlatformSpecificShouldIssueAPlatformSpeci= ficReset, NULL, NULL, NULL); + AddTestCase (ResetTests, "ResetSystem should pass all parameters through= ", "Parameters", ResetSystemShouldPassTheParametersThrough, NULL, NULL, NUL= L); + + // + // Execute the tests. + // + Status =3D RunAllTestSuites (Framework); + +EXIT: + if (Framework) { + FreeUnitTestFramework (Framework); + } + + return Status; +} + +/** + Standard POSIX C entry point for host based unit test execution. +**/ +int +main ( + int argc, + char *argv[] + ) +{ + return UnitTestingEntry (); +} diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystem= LibUnitTestHost.inf b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeRe= setSystemLibUnitTestHost.inf new file mode 100644 index 0000000000..54f968e810 --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnit= TestHost.inf @@ -0,0 +1,34 @@ +## @file +# Unit tests of the DxeResetSystemLib instance of the ResetSystemLib class +# +# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D DxeResetSystemLibUnitTestHost + FILE_GUID =3D 83E35653-B943-4C5F-BA08-9B2996AE9273 + MODULE_TYPE =3D HOST_APPLICATION + VERSION_STRING =3D 1.0 + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + DxeResetSystemLibUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[LibraryClasses] + ResetSystemLib + BaseLib + BaseMemoryLib + DebugLib + UnitTestLib diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntim= eServicesTableLib.c b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockU= efiRuntimeServicesTableLib.c new file mode 100644 index 0000000000..3540e1c039 --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServic= esTableLib.c @@ -0,0 +1,13 @@ +/** @file + Mock implementation of the UEFI Runtime Services Table Library. + + Copyright (C) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +extern EFI_RUNTIME_SERVICES MockRuntime; + +EFI_RUNTIME_SERVICES *gRT =3D &MockRuntime; diff --git a/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntim= eServicesTableLib.inf b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/Moc= kUefiRuntimeServicesTableLib.inf new file mode 100644 index 0000000000..e716b855a3 --- /dev/null +++ b/MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServic= esTableLib.inf @@ -0,0 +1,25 @@ +## @file +# Mock implementation of the UEFI Runtime Services Table Library. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D MockUefiRuntimeServicesTableLib + FILE_GUID =3D 4EA215EE-85C1-4A0A-847F-D2A8DE20805F + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D UefiRuntimeServicesTableLib|HOST_APPL= ICATION + +# +# VALID_ARCHITECTURES =3D IA32 X64 EBC +# + +[Sources] + MockUefiRuntimeServicesTableLib.c + +[Packages] + MdePkg/MdePkg.dec diff --git a/MdeModulePkg/MdeModulePkg.ci.yaml b/MdeModulePkg/MdeModulePkg.= ci.yaml index 0bf149f205..3b6e747075 100644 --- a/MdeModulePkg/MdeModulePkg.ci.yaml +++ b/MdeModulePkg/MdeModulePkg.ci.yaml @@ -9,6 +9,10 @@ "CompilerPlugin": { "DscPath": "MdeModulePkg.dsc" }, + ## options defined ci/Plugin/HostUnitTestCompilerPlugin + "HostUnitTestCompilerPlugin": { + "DscPath": "Test/MdeModulePkgHostTest.dsc" + }, =20 ## options defined ci/Plugin/CharEncodingCheck "CharEncodingCheck": { @@ -24,7 +28,9 @@ "ArmPkg/ArmPkg.dec" # this should be fixed by promoting an ab= straction ], # For host based unit tests - "AcceptableDependencies-HOST_APPLICATION":[], + "AcceptableDependencies-HOST_APPLICATION":[ + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" + ], # For UEFI shell based apps "AcceptableDependencies-UEFI_APPLICATION":[], "IgnoreInf": [] @@ -35,6 +41,11 @@ "IgnoreInf": [], "DscPath": "MdeModulePkg.dsc" }, + ## options defined ci/Plugin/HostUnitTestDscCompleteCheck + "HostUnitTestDscCompleteCheck": { + "IgnoreInf": [""], + "DscPath": "Test/MdeModulePkgHostTest.dsc" + }, =20 ## options defined ci/Plugin/GuidCheck "GuidCheck": { diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test= /MdeModulePkgHostTest.dsc new file mode 100644 index 0000000000..72a119db45 --- /dev/null +++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc @@ -0,0 +1,32 @@ +## @file +# MdeModulePkg DSC file used to build host-based unit tests. +# +# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+# Copyright (C) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME =3D MdeModulePkgHostTest + PLATFORM_GUID =3D F74AF7C6-698C-4EBA-BA49-FF6816916354 + PLATFORM_VERSION =3D 0.1 + DSC_SPECIFICATION =3D 0x00010005 + OUTPUT_DIRECTORY =3D Build/MdeModulePkg/HostTest + SUPPORTED_ARCHITECTURES =3D IA32|X64 + BUILD_TARGETS =3D NOOPT + SKUID_IDENTIFIER =3D DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + +[Components] + MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesT= ableLib.inf + + # + # Build MdeModulePkg HOST_APPLICATION Tests + # + MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTes= tHost.inf { + + ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystem= Lib.inf + UefiRuntimeServicesTableLib|MdeModulePkg/Library/DxeResetSystemLib/U= nitTest/MockUefiRuntimeServicesTableLib.inf + } --=20 2.21.0.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 (#54059): https://edk2.groups.io/g/devel/message/54059 Mute This Topic: https://groups.io/mt/71060088/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54060+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54060+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1581099245163236.05585019366424; Fri, 7 Feb 2020 10:14:05 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id eqk3YY1788612xfht71FiC7V; Fri, 07 Feb 2020 10:14:03 -0800 X-Received: from mga06.intel.com (mga06.intel.com []) by mx.groups.io with SMTP id smtpd.web12.9025.1581099240821545376 for ; Fri, 07 Feb 2020 10:14:03 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:14:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500561" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:14:02 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew , Liming Gao Subject: [edk2-devel] [Patch v2 10/11] .azurepipelines: Enable CI for UnitTestFrameworkPkg and host tests Date: Fri, 7 Feb 2020 10:13:53 -0800 Message-Id: <20200207181354.31632-11-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: vHNA9AL7psPvNb7z5Jw2YTKgx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099243; bh=a324+89vJ7ujrqEhsh4vnmmZm5QFfZ4Ai2bFnvIA3UA=; h=Cc:Date:From:Reply-To:Subject:To; b=d38lpb9DT3ZyretUbExVeXdtYAtSROboulhspb/9JS23hhatTUJ+MR/aTvimnCd9jPv pYADbJNZ7TNq7emUniNmP2SaGGqsVJNjyHKl6ZWWWy3fsBolpuqywboQUtyp/vXXLO1AA uowebCp95lGuo7/MBsObEi6QAzkLdrgJZ4Q= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 * Add NOOPT target to MdePkg, MdeModulePkg, and UnitTestFrameworkPkg to support building host based unit tests with optimization disabled. Cc: Sean Brogan Cc: Bret Barkelew Cc: Liming Gao Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew --- .azurepipelines/templates/pr-gate-build-job.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.azurepipelines/templates/pr-gate-build-job.yml b/.azurepipeli= nes/templates/pr-gate-build-job.yml index 981acd68a1..61868554d4 100644 --- a/.azurepipelines/templates/pr-gate-build-job.yml +++ b/.azurepipelines/templates/pr-gate-build-job.yml @@ -22,10 +22,10 @@ jobs: matrix: TARGET_MDE_CPU: Build.Pkgs: 'MdePkg,UefiCpuPkg' - Build.Targets: 'DEBUG,RELEASE,NO-TARGET' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET,NOOPT' TARGET_MDEMODULE_DEBUG: Build.Pkgs: 'MdeModulePkg' - Build.Targets: 'DEBUG' + Build.Targets: 'DEBUG,NOOPT' TARGET_MDEMODULE_RELEASE: Build.Pkgs: 'MdeModulePkg' Build.Targets: 'RELEASE,NO-TARGET' @@ -35,9 +35,9 @@ jobs: TARGET_OTHER: Build.Pkgs: 'PcAtChipsetPkg,ShellPkg' Build.Targets: 'DEBUG,RELEASE,NO-TARGET' - TARGET_FMP: - Build.Pkgs: 'FmpDevicePkg,FatPkg' - Build.Targets: 'DEBUG,RELEASE,NO-TARGET' + TARGET_FMP_FAT_TEST: + Build.Pkgs: 'FmpDevicePkg,FatPkg,UnitTestFrameworkPkg' + Build.Targets: 'DEBUG,RELEASE,NO-TARGET,NOOPT' TARGET_CRYPTO: Build.Pkgs: 'CryptoPkg' Build.Targets: 'DEBUG,RELEASE,NO-TARGET' --=20 2.21.0.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 (#54060): https://edk2.groups.io/g/devel/message/54060 Mute This Topic: https://groups.io/mt/71060090/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- From nobody Sat Apr 20 00:40:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54061+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54061+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 158109924533392.23112213348259; Fri, 7 Feb 2020 10:14:05 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id Q2tKYY1788612xT4y95KrBQ2; Fri, 07 Feb 2020 10:14:03 -0800 X-Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by mx.groups.io with SMTP id smtpd.web11.8960.1581099243319780612 for ; Fri, 07 Feb 2020 10:14:03 -0800 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Feb 2020 10:14:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.70,414,1574150400"; d="scan'208";a="250500562" X-Received: from unknown (HELO mdkinney-MOBL2.amr.corp.intel.com) ([10.241.98.74]) by orsmga002.jf.intel.com with ESMTP; 07 Feb 2020 10:14:02 -0800 From: "Michael D Kinney" To: devel@edk2.groups.io Cc: Sean Brogan , Bret Barkelew , Andrew Fish , Laszlo Ersek , Leif Lindholm Subject: [edk2-devel] [Patch v2 11/11] Maintainers.txt: Add UnitTestFrameworkPkg Date: Fri, 7 Feb 2020 10:13:54 -0800 Message-Id: <20200207181354.31632-12-michael.d.kinney@intel.com> In-Reply-To: <20200207181354.31632-1-michael.d.kinney@intel.com> References: <20200207181354.31632-1-michael.d.kinney@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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,michael.d.kinney@intel.com X-Gm-Message-State: X4kLSEWdbxMR9zxductkdIJ7x1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1581099243; bh=JTYguvpQaMp5BvCJZnjSuMYbfXX2k9pzwr3xEtY2eaA=; h=Cc:Date:From:Reply-To:Subject:To; b=BOuZSopxcf42HIsL8pbaPDuczB75CKh+J8Wc6EoYChfg1ZyaDUBo9nGRtV505aQ66KT JH49hqamesVhgfm09R2McB60m8f4zXzd9yQXBGvpqNA75KFDckZ3nTffBjbzN1jLdi5Ct VUautLo2eeBbjLQnsBUCEok5Fa6u5gtPeJU= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D2505 Add maintainers and reviewers for UnitTestFrameworkPkg Cc: Sean Brogan Cc: Bret Barkelew Cc: Andrew Fish Cc: Laszlo Ersek Cc: Leif Lindholm Signed-off-by: Michael D Kinney Reviewed-by: Laszlo Ersek --- Maintainers.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Maintainers.txt b/Maintainers.txt index ca9da28925..91059db937 100644 --- a/Maintainers.txt +++ b/Maintainers.txt @@ -479,6 +479,13 @@ M: Guo Dong M: Benjamin You S: Maintained =20 +UnitTestFrameworkPkg +F: UnitTestFrameworkPkg/ +M: Michael D Kinney +R: Sean Brogan +R: Bret Barkelew +S: Maintained + StandaloneMmPkg F: StandaloneMmPkg/ M: Ard Biesheuvel --=20 2.21.0.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 (#54061): https://edk2.groups.io/g/devel/message/54061 Mute This Topic: https://groups.io/mt/71060091/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-