From nobody Tue Jan 14 22:46:43 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1513728025790638.9911399043214; Tue, 19 Dec 2017 16:00:25 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 71EDA221A2B97; Tue, 19 Dec 2017 15:55:37 -0800 (PST) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 366DC221523B9 for ; Tue, 19 Dec 2017 15:55:35 -0800 (PST) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Dec 2017 16:00:22 -0800 Received: from mdkinney-mobl2.amr.corp.intel.com ([10.241.98.58]) by FMSMGA003.fm.intel.com with ESMTP; 19 Dec 2017 16:00:21 -0800 X-Original-To: edk2-devel@lists.01.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.43; helo=mga05.intel.com; envelope-from=michael.d.kinney@intel.com; receiver=edk2-devel@lists.01.org X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.45,429,1508828400"; d="scan'208";a="13197380" From: "Kinney, Michael D" To: edk2-devel@lists.01.org Date: Tue, 19 Dec 2017 16:00:05 -0800 Message-Id: <20171220000014.9140-2-michael.d.kinney@intel.com> X-Mailer: git-send-email 2.14.2.windows.3 In-Reply-To: <20171220000014.9140-1-michael.d.kinney@intel.com> References: <20171220000014.9140-1-michael.d.kinney@intel.com> Subject: [edk2] [staging/edk2-test Patch 01/10] MsUnitTestPkg: Add Unit Test Support and sample X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Michael D Kinney , Liming Gao MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: Sean Brogan Cherry-picked from branch: https://github.com/Microsoft/MS_UEFI/tree/share/XmlAndUnitTest Commit: https://github.com/Microsoft/MS_UEFI/commit/f2b2a2cb8f4331692297d0cab67a333= 714d71165 Cc: Sean Brogan Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney --- .../Include/Guid/MsUnitTestPkgTokenSpace.h | 12 + MsUnitTestPkg/Include/Library/UnitTestAssertLib.h | 127 +++ MsUnitTestPkg/Include/Library/UnitTestBootUsbLib.h | 24 + MsUnitTestPkg/Include/Library/UnitTestLib.h | 95 ++ MsUnitTestPkg/Include/Library/UnitTestLogLib.h | 62 ++ .../Include/Library/UnitTestPersistenceLib.h | 88 ++ .../Include/Library/UnitTestResultReportLib.h | 24 + MsUnitTestPkg/Include/UnitTestTypes.h | 202 +++++ .../Library/UnitTestAssertLib/UnitTestAssertLib.c | 173 ++++ .../UnitTestAssertLib/UnitTestAssertLib.inf | 37 + .../UnitTestBootUsbClassLib/UnitTestBootUsb.c | 110 +++ .../UnitTestBootUsbClassLib.inf | 42 + .../UnitTestBootUsbMicrosoftLib/UnitTestBootUsb.c | 119 +++ .../UnitTestBootUsbMicrosoftLib.inf | 41 + MsUnitTestPkg/Library/UnitTestLib/Md5.c | 353 ++++++++ MsUnitTestPkg/Library/UnitTestLib/Md5.h | 75 ++ MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.c | 958 +++++++++++++++++= ++++ MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.inf | 44 + .../Library/UnitTestLogLib/UnitTestLogLib.c | 252 ++++++ .../Library/UnitTestLogLib/UnitTestLogLib.inf | 43 + .../UnitTestPersistenceFileSystemLib.c | 406 +++++++++ .../UnitTestPersistenceFileSystemLib.inf | 64 ++ .../UnitTestPersistenceLibNull.c | 93 ++ .../UnitTestPersistenceLibNull.inf | 44 + .../UnitTestResultReportLib.c | 208 +++++ .../UnitTestResultReportLib.inf | 37 + MsUnitTestPkg/MsUnitTestPkg.dec | 42 + MsUnitTestPkg/ReadMe.md | 65 ++ .../Sample/SampleUnitTestApp/SampleUnitTestApp.c | 210 +++++ .../Sample/SampleUnitTestApp/SampleUnitTestApp.inf | 41 + 30 files changed, 4091 insertions(+) create mode 100644 MsUnitTestPkg/Include/Guid/MsUnitTestPkgTokenSpace.h create mode 100644 MsUnitTestPkg/Include/Library/UnitTestAssertLib.h create mode 100644 MsUnitTestPkg/Include/Library/UnitTestBootUsbLib.h create mode 100644 MsUnitTestPkg/Include/Library/UnitTestLib.h create mode 100644 MsUnitTestPkg/Include/Library/UnitTestLogLib.h create mode 100644 MsUnitTestPkg/Include/Library/UnitTestPersistenceLib.h create mode 100644 MsUnitTestPkg/Include/Library/UnitTestResultReportLib.h create mode 100644 MsUnitTestPkg/Include/UnitTestTypes.h create mode 100644 MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertL= ib.c create mode 100644 MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertL= ib.inf create mode 100644 MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestB= ootUsb.c create mode 100644 MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestB= ootUsbClassLib.inf create mode 100644 MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/UnitT= estBootUsb.c create mode 100644 MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/UnitT= estBootUsbMicrosoftLib.inf create mode 100644 MsUnitTestPkg/Library/UnitTestLib/Md5.c create mode 100644 MsUnitTestPkg/Library/UnitTestLib/Md5.h create mode 100644 MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.c create mode 100644 MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.inf create mode 100644 MsUnitTestPkg/Library/UnitTestLogLib/UnitTestLogLib.c create mode 100644 MsUnitTestPkg/Library/UnitTestLogLib/UnitTestLogLib.inf create mode 100644 MsUnitTestPkg/Library/UnitTestPersistenceFileSystemLib/= UnitTestPersistenceFileSystemLib.c create mode 100644 MsUnitTestPkg/Library/UnitTestPersistenceFileSystemLib/= UnitTestPersistenceFileSystemLib.inf create mode 100644 MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTe= stPersistenceLibNull.c create mode 100644 MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTe= stPersistenceLibNull.inf create mode 100644 MsUnitTestPkg/Library/UnitTestResultReportPlainTextOutp= utLib/UnitTestResultReportLib.c create mode 100644 MsUnitTestPkg/Library/UnitTestResultReportPlainTextOutp= utLib/UnitTestResultReportLib.inf create mode 100644 MsUnitTestPkg/MsUnitTestPkg.dec create mode 100644 MsUnitTestPkg/ReadMe.md create mode 100644 MsUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestAp= p.c create mode 100644 MsUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestAp= p.inf diff --git a/MsUnitTestPkg/Include/Guid/MsUnitTestPkgTokenSpace.h b/MsUnitT= estPkg/Include/Guid/MsUnitTestPkgTokenSpace.h new file mode 100644 index 0000000000..6a14ea216e --- /dev/null +++ b/MsUnitTestPkg/Include/Guid/MsUnitTestPkgTokenSpace.h @@ -0,0 +1,12 @@ +/** @file + GUID for MsUnitTest Pkg PCD Token Space. + + +**/ + +#ifndef _MSUNITTESTPKG_TOKEN_SPACE_GUID_H_ +#define _MSUNITTESTPKG_TOKEN_SPACE_GUID_H_ + +extern EFI_GUID gMsUnitTestPkgTokenSpaceGuid; + +#endif diff --git a/MsUnitTestPkg/Include/Library/UnitTestAssertLib.h b/MsUnitTest= Pkg/Include/Library/UnitTestAssertLib.h new file mode 100644 index 0000000000..7279b911cd --- /dev/null +++ b/MsUnitTestPkg/Include/Library/UnitTestAssertLib.h @@ -0,0 +1,127 @@ +/** @file +Provides a unit test assert helpers. This allows tests to focus on testin= g logic +and the library to handle common assertions. + + +Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+ +**/ + +#ifndef __UNIT_TEST_ASSERT_LIB_H__ +#define __UNIT_TEST_ASSERT_LIB_H__ + + +#define UT_ASSERT_TRUE(Expression) \ + if(!UnitTestAssertTrue( Framework, (Expression), __FUNCTION__, __LINE__,= #Expression )) { return UNIT_TEST_ERROR_TEST_FAILED;} + +#define UT_ASSERT_FALSE(Expression) \ + if(!UnitTestAssertFalse( Framework, (Expression), __FUNCTION__, __LINE__= , #Expression )) { return UNIT_TEST_ERROR_TEST_FAILED;} + +#define UT_ASSERT_EQUAL(ValueA, ValueB) \ + if(!UnitTestAssertEqual( Framework, (UINTN)ValueA, (UINTN)ValueB, __FUNC= TION__, __LINE__, #ValueA, #ValueB )) { return UNIT_TEST_ERROR_TEST_FAILED;} + +#define UT_ASSERT_MEM_EQUAL(ValueA, ValueB, Length) \ + if(!UnitTestAssertMemEqual( Framework, (UINTN)ValueA, (UINTN)ValueB, (UI= NTN)Length, __FUNCTION__, __LINE__, #ValueA, #ValueB )) { return UNIT_TEST_= ERROR_TEST_FAILED;} + +#define UT_ASSERT_NOT_EQUAL(ValueA, ValueB) \ + if(!UnitTestAssertNotEqual( Framework, ValueA, ValueB, __FUNCTION__, __L= INE__, #ValueA, #ValueB )) { return UNIT_TEST_ERROR_TEST_FAILED;} + +#define UT_ASSERT_NOT_EFI_ERROR(Status) \ + if(!UnitTestAssertNotEfiError( Framework, Status, __FUNCTION__, __LINE__= , #Status )) { return UNIT_TEST_ERROR_TEST_FAILED;} + +#define UT_ASSERT_STATUS_EQUAL(Status, Expected) \ + if(! UnitTestAssertStatusEqual( Framework, Status, Expected, __FUNCTION_= _, __LINE__, #Status )) { return UNIT_TEST_ERROR_TEST_FAILED;} + +#define UT_ASSERT_NOT_NULL(Pointer) \ + if(!UnitTestAssertNotNull(Framework, Pointer, __FUNCTION__, __LINE__, #P= ointer)) { return UNIT_TEST_ERROR_TEST_FAILED; } + + +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ); + +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ); + +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ); + +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ValueA, + IN UINTN ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +BOOLEAN +EFIAPI +UnitTestAssertMemEqual( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ValueA, + IN UINTN ValueB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB +); + +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ValueA, + IN UINTN ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ); + +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ); + +BOOLEAN +EFIAPI +UnitTestAssertNotNull( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN VOID* Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *PointerName +); + +#endif diff --git a/MsUnitTestPkg/Include/Library/UnitTestBootUsbLib.h b/MsUnitTes= tPkg/Include/Library/UnitTestBootUsbLib.h new file mode 100644 index 0000000000..4b6d30e7e2 --- /dev/null +++ b/MsUnitTestPkg/Include/Library/UnitTestBootUsbLib.h @@ -0,0 +1,24 @@ +/** @file +Provides a library function that can be customized to set the platform to = boot from USB on the next boot. +This allows the test framework to reboot back 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= easier. + + +Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+ +**/ + +#ifndef __UNIT_TEST_BOOT_USB_LIB_H__ +#define __UNIT_TEST_BOOT_USB_LIB_H__ + +/** +Set the boot manager to boot from USB on the next boot. +This should be set only for the next boot and shouldn't +require any manual clean up +**/ +EFI_STATUS +EFIAPI +SetUsbBootNext ( VOID ); + + +#endif diff --git a/MsUnitTestPkg/Include/Library/UnitTestLib.h b/MsUnitTestPkg/In= clude/Library/UnitTestLib.h new file mode 100644 index 0000000000..5abfebb039 --- /dev/null +++ b/MsUnitTestPkg/Include/Library/UnitTestLib.h @@ -0,0 +1,95 @@ +/** @file +Provides a unit test framework. This allows tests to focus on testing log= ic +and the framework to focus on runnings, reporting, statistics, etc. + + +Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+ +**/ + +#ifndef __UNIT_TEST_LIB_H__ +#define __UNIT_TEST_LIB_H__ + +/* +Method to Initialize the Unit Test framework + +@retval Success - Unit Test init. +@retval EFI_ERROR - Unit Tests init failed. +*/ +EFI_STATUS +EFIAPI +InitUnitTestFramework ( + OUT UNIT_TEST_FRAMEWORK **Framework, + IN CHAR16 *Title, + IN CHAR16 *ShortTitle, + IN CHAR16 *VersionString + ); + +EFI_STATUS +EFIAPI +CreateUnitTestSuite ( + OUT UNIT_TEST_SUITE **Suite, + IN UNIT_TEST_FRAMEWORK *Framework, + IN CHAR16 *Title, + IN CHAR16 *Package, + IN UNIT_TEST_SUITE_SETUP Sup OPTIONAL, + IN UNIT_TEST_SUITE_TEARDOWN Tdn OPTIONAL + ); + +EFI_STATUS +EFIAPI +AddTestCase ( + IN UNIT_TEST_SUITE *Suite, + IN CHAR16 *Description, + IN CHAR16 *ClassName, + IN UNIT_TEST_FUNCTION Func, + IN UNIT_TEST_PREREQ PreReq OPTIONAL, + IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, + IN UNIT_TEST_CONTEXT Context OPTIONAL + ); + +EFI_STATUS +EFIAPI +RunAllTestSuites( + IN UNIT_TEST_FRAMEWORK *Framework + ); + +EFI_STATUS +EFIAPI +FreeUnitTestFramework ( + IN UNIT_TEST_FRAMEWORK *Framework + ); + +EFI_STATUS +EFIAPI +SaveFrameworkState ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ); + +EFI_STATUS +EFIAPI +SaveFrameworkStateAndQuit ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ); + +/** + NOTE: Takes in a ResetType, but currently only supports EfiResetCold + and EfiResetWarm. All other types will return EFI_INVALID_PARAMETE= R. + If a more specific reset is required, use SaveFrameworkState() and + call gRT->ResetSystem() directly. + +**/ +EFI_STATUS +EFIAPI +SaveFrameworkStateAndReboot ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize, + IN EFI_RESET_TYPE ResetType + ); + +#endif diff --git a/MsUnitTestPkg/Include/Library/UnitTestLogLib.h b/MsUnitTestPkg= /Include/Library/UnitTestLogLib.h new file mode 100644 index 0000000000..f971b274ea --- /dev/null +++ b/MsUnitTestPkg/Include/Library/UnitTestLogLib.h @@ -0,0 +1,62 @@ +/** @file +Provides a unit test framework logging. This allows tests to focus on tes= ting logic +and the library to handle unit test specific logging. + + +Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+ +**/ + +#ifndef __UNIT_TEST_LOG_LIB_H__ +#define __UNIT_TEST_LOG_LIB_H__ + + + +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +/// +/// UNIT TEST LOGGING DEFINITIONS AND FUNCTIONS +/// +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +// IMPORTANT NOTE: These macros should ONLY be used in a Unit Test. +// They will consume the Framework Handle and update the F= ramework->CurrentTest. + +#define UT_LOG_ERROR(Format, ...) \ + UnitTestLog( Framework, DEBUG_ERROR, Format, __VA_ARGS__ ); +#define UT_LOG_WARNING(Format, ...) \ + UnitTestLog( Framework, DEBUG_WARN, Format, __VA_ARGS__ ); +#define UT_LOG_INFO(Format, ...) \ + UnitTestLog( Framework, DEBUG_INFO, Format, __VA_ARGS__ ); +#define UT_LOG_VERBOSE(Format, ...) \ + UnitTestLog( Framework, DEBUG_VERBOSE, Format, __VA_ARGS__ ); + +VOID +EFIAPI +UnitTestLog ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ); + +VOID +EFIAPI +UnitTestLogInit ( +IN OUT UNIT_TEST *Test, +IN UINT8 *Buffer OPTIONAL, +IN UINTN BufferSize +); + +VOID +EFIAPI +UnitTestLogFailure( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + FAILURE_TYPE FailureType, + IN CONST CHAR8 *Format, + ... +); + +#endif diff --git a/MsUnitTestPkg/Include/Library/UnitTestPersistenceLib.h b/MsUni= tTestPkg/Include/Library/UnitTestPersistenceLib.h new file mode 100644 index 0000000000..f885601c7b --- /dev/null +++ b/MsUnitTestPkg/Include/Library/UnitTestPersistenceLib.h @@ -0,0 +1,88 @@ +/** @file -- UnitTestPersistenceLib.h +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 resu= me +(eg. a reboot-based test). + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. + +**/ + +#ifndef _UNIT_TEST_PERSISTENCE_LIB_H_ +#define _UNIT_TEST_PERSISTENCE_LIB_H_ + +#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 // _UNIT_TEST_PERSISTENCE_LIB_H_ diff --git a/MsUnitTestPkg/Include/Library/UnitTestResultReportLib.h b/MsUn= itTestPkg/Include/Library/UnitTestResultReportLib.h new file mode 100644 index 0000000000..60f2f6677b --- /dev/null +++ b/MsUnitTestPkg/Include/Library/UnitTestResultReportLib.h @@ -0,0 +1,24 @@ +/** @file +Provides a unit test result report. This allows new result output formats= to be easily +customized. + + +Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+ +**/ + +#ifndef __UNIT_TEST_RESULT_REPORT_LIB_H__ +#define __UNIT_TEST_RESULT_REPORT_LIB_H__ + +/* +Method to produce the Unit Test run results + +@retval Success +*/ +EFI_STATUS +EFIAPI +OutputUnitTestFrameworkReport( + IN UNIT_TEST_FRAMEWORK *Framework +); + +#endif diff --git a/MsUnitTestPkg/Include/UnitTestTypes.h b/MsUnitTestPkg/Include/= UnitTestTypes.h new file mode 100644 index 0000000000..49b51defe4 --- /dev/null +++ b/MsUnitTestPkg/Include/UnitTestTypes.h @@ -0,0 +1,202 @@ +/** @file +Provides the basic types and common elements of the unit test framework + + +Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+ +**/ + +#ifndef __UNIT_TEST_TYPES_H__ +#define __UNIT_TEST_TYPES_H__ + +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +/// +/// HANDY DEFINITIONS +/// +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +#define UNIT_TEST_MAX_STRING_LENGTH (120) + +#define UNIT_TEST_FINGERPRINT_SIZE (16) // Hardcoded to MD5_HASHSI= ZE. +#define UNIT_TEST_TESTFAILUREMSG_LENGTH (120) + +typedef UINT32 UNIT_TEST_STATUS; +#define UNIT_TEST_PASSED (0) +#define UNIT_TEST_ERROR_PREREQ_NOT_MET (1) +#define UNIT_TEST_ERROR_TEST_FAILED (2) +#define UNIT_TEST_SKIPPED (0xFFFFFFFD) +#define UNIT_TEST_RUNNING (0xFFFFFFFE) +#define UNIT_TEST_PENDING (0xFFFFFFFF) + +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) + +typedef VOID* UNIT_TEST_FRAMEWORK_HANDLE; // Same as a UNIT_TEST_FRAMEWO= RK*, but with fewer build errors. +typedef VOID* UNIT_TEST_SUITE_HANDLE; // Same as a UNIT_TEST_SUITE*,= but with fewer build errors. +typedef VOID* UNIT_TEST_CONTEXT; + + +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +/// +/// UNIT TEST FUNCTION TYPE DEFINITIONS +/// +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +// +// Unit-Test Function pointer type. +// +typedef +UNIT_TEST_STATUS +(EFIAPI *UNIT_TEST_FUNCTION) ( + UNIT_TEST_FRAMEWORK_HANDLE Framework, + UNIT_TEST_CONTEXT Context + ); + +// +// Unit-Test Prerequisite Function pointer type. +// NOTE: Should be the same as UnitTest. +// +typedef +UNIT_TEST_STATUS +(EFIAPI *UNIT_TEST_PREREQ) ( + UNIT_TEST_FRAMEWORK_HANDLE Framework, + UNIT_TEST_CONTEXT Context + ); + +// +// Unit-Test Test Cleanup (after) function pointer type. +// +typedef +VOID +(EFIAPI *UNIT_TEST_CLEANUP) ( + UNIT_TEST_FRAMEWORK_HANDLE Framework, + UNIT_TEST_CONTEXT Context + ); + +// +// Unit-Test Test Suite Setup (before) function pointer type. +// +typedef +VOID +(EFIAPI *UNIT_TEST_SUITE_SETUP) ( + UNIT_TEST_FRAMEWORK_HANDLE Framework + ); + +// +// Unit-Test Test Suite Teardown (after) function pointer type. +// +typedef +VOID +(EFIAPI *UNIT_TEST_SUITE_TEARDOWN) ( + UNIT_TEST_FRAMEWORK_HANDLE Framework + ); + + +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +/// +/// UNIT TEST DATA STRUCTURE DEFINITIONS +/// +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +typedef struct { + CHAR16 *Description; + CHAR16 *ClassName; //can't have spaces and should be= short + CHAR16 *Log; + FAILURE_TYPE FailureType; + CHAR16 FailureMessage[UNIT_TEST_TESTFAILUREMSG_LENGTH= ]; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; + UNIT_TEST_STATUS Result; + UNIT_TEST_FUNCTION RunTest; + UNIT_TEST_PREREQ PreReq; + UNIT_TEST_CLEANUP CleanUp; + UNIT_TEST_CONTEXT Context; + UNIT_TEST_SUITE_HANDLE ParentSuite; +} UNIT_TEST; + +typedef struct { + LIST_ENTRY Entry; + UNIT_TEST UT; +} UNIT_TEST_LIST_ENTRY; + +typedef struct { + CHAR16 *Title; + CHAR16 *Package; + 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; + +typedef struct { + LIST_ENTRY Entry; + UNIT_TEST_SUITE UTS; +} UNIT_TEST_SUITE_LIST_ENTRY; + +typedef struct { + CHAR16 *Title; + CHAR16 *ShortTitle; // This title should contain= NO spaces or non-filename charatecters. Is used in reporting and serializa= tion. + CHAR16 *VersionString; + CHAR16 *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 UN= IT_TEST_SAVE_HEADER*, if present. +} UNIT_TEST_FRAMEWORK; + + +// +//Structures for the framework to serializing unit test status +// +#pragma pack (1) + +typedef struct +{ + UINT32 Size; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Finge= rprint of the test itself. + CHAR16 FailureMessage[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + FAILURE_TYPE FailureType; + UNIT_TEST_STATUS Result; + // CHAR16 Log[]; +} UNIT_TEST_SAVE_TEST; + +typedef struct +{ + UINT32 Size; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Finge= rprint of the corresponding test. + // UINT8 Data[]; // Actua= l data of the context. +} UNIT_TEST_SAVE_CONTEXT; + +typedef struct +{ + UINT8 Version; + UINT32 BlobSize; + UINT8 Fingerprint[UNIT_TEST_FINGERPRINT_SIZE]; // Finge= rprint of the 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 currently running test. + // CHAR16 Log[]; // NOTE:= Not yet implemented!! +} UNIT_TEST_SAVE_HEADER; + +#pragma pack () + +#endif diff --git a/MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertLib.c b/= MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertLib.c new file mode 100644 index 0000000000..0aeb5564dc --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertLib.c @@ -0,0 +1,173 @@ +/** + +Implement UnitTestLib + +Copyright (c) Microsoft +**/ + +#include +#include +#include +#include +#include +#include + + +BOOLEAN +EFIAPI +UnitTestAssertTrue ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + if (!Expression) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTTRUE, "%a::%d Expressi= on (%a) is not TRUE!\n", FunctionName, LineNumber, Description); + UnitTestLog(Framework, DEBUG_ERROR, "[ASSERT FAIL] %a::%d Expression (= %a) is not TRUE!\n", FunctionName, LineNumber, Description ); + } + return Expression; +} + + +BOOLEAN +EFIAPI +UnitTestAssertFalse ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN BOOLEAN Expression, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + if (Expression) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTFALSE, "%a::%d Express= ion(%a) is not FALSE!\n", FunctionName, LineNumber, Description ); + UnitTestLog(Framework, DEBUG_ERROR,"[ASSERT FAIL] %a::%d Expression (%= a) is not FALSE!\n", FunctionName, LineNumber, Description ); + } + return !Expression; +} + + +BOOLEAN +EFIAPI +UnitTestAssertNotEfiError ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN EFI_STATUS Status, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + if (EFI_ERROR( Status )) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTNOTEFIERROR, "%a::%d S= tatus '%a' is EFI_ERROR (%r)!\n", FunctionName, LineNumber, Description, St= atus); + UnitTestLog(Framework, DEBUG_ERROR,"[ASSERT FAIL] %a::%d Status '%a' i= s EFI_ERROR (%r)!\n", FunctionName, LineNumber, Description, Status ); + } + return !EFI_ERROR( Status ); +} + + +BOOLEAN +EFIAPI +UnitTestAssertEqual ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ValueA, + IN UINTN ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if ((ValueA !=3D ValueB)) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTEQUAL, "%a::%d Value %= a !=3D %a (%d !=3D %d)!\n", FunctionName, LineNumber, DescriptionA, Descrip= tionB, ValueA, ValueB); + UnitTestLog(Framework, DEBUG_ERROR,"[ASSERT FAIL] %a::%d Value %a !=3D= %a (%d !=3D %d)!\n", FunctionName, LineNumber, DescriptionA, DescriptionB,= ValueA, ValueB ); + } + return (ValueA =3D=3D ValueB); +} + +BOOLEAN +EFIAPI +UnitTestAssertMemEqual( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ValueA, + IN UINTN ValueB, + IN UINTN Length, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB +) +{ + if (CompareMem((VOID*)ValueA, (VOID*)ValueB, Length) !=3D 0) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTEQUAL, __FUNCTION__, "= %a::%d Memory at %a !=3D %a for length %d bytes!\n", FunctionName, LineNumb= er, DescriptionA, DescriptionB, Length); + UnitTestLog(Framework, DEBUG_ERROR, "[ASSERT FAIL] %a::%d Value %a != =3D %a for length %d bytes!\n", FunctionName, LineNumber, DescriptionA, Des= criptionB, Length); + return FALSE; + } + return TRUE; +} + + +BOOLEAN +EFIAPI +UnitTestAssertNotEqual ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ValueA, + IN UINTN ValueB, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *DescriptionA, + IN CONST CHAR8 *DescriptionB + ) +{ + if ((ValueA =3D=3D ValueB)) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTNOTEQUAL,"%a::%d Value= %a =3D=3D %a (%d =3D=3D %d)!\n", FunctionName, LineNumber, DescriptionA, D= escriptionB, ValueA, ValueB); + UnitTestLog(Framework, DEBUG_ERROR,"[ASSERT FAIL] %a::%d Value %a =3D= =3D %a (%d =3D=3D %d)!\n", FunctionName, LineNumber,DescriptionA, Descripti= onB, ValueA, ValueB ); + } + return (ValueA !=3D ValueB); +} + + +BOOLEAN +EFIAPI +UnitTestAssertStatusEqual ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN EFI_STATUS Status, + IN EFI_STATUS Expected, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + if ((Status !=3D Expected)) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTSTATUSEQUAL, "%a::%d S= tatus '%a' is %r, should be %r!\n", FunctionName, LineNumber, Description, = Status, Expected); + UnitTestLog(Framework, DEBUG_ERROR,"[ASSERT FAIL] %a::%d Status '%a' i= s %r, should be %r!\n", FunctionName, LineNumber, Description, Status, Expe= cted ); + } + return (Status =3D=3D Expected); +} + +BOOLEAN +EFIAPI +UnitTestAssertNotNull( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN VOID* Pointer, + IN CONST CHAR8 *FunctionName, + IN UINTN LineNumber, + IN CONST CHAR8 *PointerName +) +{ + if (Pointer =3D=3D NULL) + { + UnitTestLogFailure(Framework, FAILURETYPE_ASSERTNOTNULL, "%a::%d Point= er (%a) is NULL!\n", FunctionName, LineNumber, PointerName); + UnitTestLog(Framework, DEBUG_ERROR, "[ASSERT FAIL] %a::%d Pointer (%a)= is NULL!\n", FunctionName, LineNumber, PointerName); + } + return (Pointer !=3D NULL); + +} diff --git a/MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertLib.inf = b/MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertLib.inf new file mode 100644 index 0000000000..b59defffa2 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestAssertLib/UnitTestAssertLib.inf @@ -0,0 +1,37 @@ +## @file +# Library to support simple and readable Unit Test Assert +# +# +# @copyright +# Copyright (c) 2017 Microsoft Corporation. All rights reserved +# +# @par Specification Reference: +# +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D UnitTestAssertLib +FILE_GUID =3D FDDB0735-04FE-447C-B987-305988BDC983 +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_DRIVER +LIBRARY_CLASS =3D UnitTestAssertLib|DXE_DRIVER UEFI_APPLICATION + + +[LibraryClasses] + DebugLib + BaseLib + BaseMemoryLib + UnitTestLogLib + + +[Packages] + MdePkg/MdePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + + +[Guids] + +[Sources] + UnitTestAssertLib.c diff --git a/MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestBootUsb.= c b/MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestBootUsb.c new file mode 100644 index 0000000000..0fefcc9526 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestBootUsb.c @@ -0,0 +1,110 @@ +/** + +Implement UnitTestBootUsbLib using USB Class Boot option. This should be = industry standard and should +work on all platforms + +Copyright (c) Microsoft +**/ + +#include +#include +#include +#include +#include +#include +#include + +EFI_STATUS +EFIAPI +SetUsbBootNext( + VOID +) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION NewOption; + UINT32 Attributes; + UINT8 *OptionalData =3D NULL; + UINT32 OptionalDataSize =3D 0; + UINT16 BootNextValue =3D 0xABCD; // this should= be a safe number... + USB_CLASS_DEVICE_PATH UsbDp; + EFI_DEVICE_PATH_PROTOCOL *DpEnd =3D NULL; + EFI_DEVICE_PATH_PROTOCOL *Dp =3D NULL; + BOOLEAN 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, __FUNCTION__ ": Unable to create device path. DpE= nd is NULL.\n")); + goto CLEANUP; + } + + Dp =3D AppendDevicePathNode(DpEnd, (EFI_DEVICE_PATH_PROTOCOL *)&UsbDp); = //@MRT --- Is this memory leak becasue we lose the old Dp memory + if (Dp =3D=3D NULL) + { + DEBUG((DEBUG_ERROR, __FUNCTION__ ": Unable to create device path. Dp = is NULL.\n")); + 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, __FUNCTION__ ": Error creating load option. Statu= s =3D %r\n", Status)); + goto CLEANUP; + } + + NewOptionValid =3D TRUE; + DEBUG((DEBUG_VERBOSE, __FUNCTION__ ": Generic USB Class Device boot opti= on created.\n")); + Status =3D EfiBootManagerLoadOptionToVariable(&NewOption); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, __FUNCTION__ ": Error Saving boot option NV variab= le. Status =3D %r\n", Status)); + goto CLEANUP; + } + + //Set Boot Next + Status =3D gRT->SetVariable(L"BootNext", + &gEfiGlobalVariableGuid, + (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_V= ARIABLE_NON_VOLATILE), + sizeof(BootNextValue), + &(BootNextValue)); + + DEBUG((DEBUG_VERBOSE, __FUNCTION__" - Set BootNext Status (%r)\n", Statu= s)); + +CLEANUP: + if (Dp !=3D NULL) + { + FreePool(Dp); + } + + if (DpEnd !=3D NULL) + { + FreePool(DpEnd); + } + + if (NewOptionValid) + { + EfiBootManagerFreeLoadOption(&NewOption); + } + + return Status; +} diff --git a/MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestBootUsbC= lassLib.inf b/MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestBootUsb= ClassLib.inf new file mode 100644 index 0000000000..7c1c24794c --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestBootUsbClassLib/UnitTestBootUsbClassLib= .inf @@ -0,0 +1,42 @@ +## @file +# Library to support booting to USB on the next boot +# This instance uses the industry standard usb class boot option. +# +# +# @copyright +# Copyright (c) 2016 Microsoft Corporation. All rights reserved +# +# @par Specification Reference: +# +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D UnitTestBootUsbClassLib +FILE_GUID =3D DFADE2A2-DB69-47DE-A37A-40FB6D52E844 +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_DRIVER +LIBRARY_CLASS =3D UnitTestBootUsbLib|UEFI_APPLICATION + + +[LibraryClasses] + DebugLib + UefiRuntimeServicesTableLib + MemoryAllocationLib + DevicePathLib + UefiBootManagerLib + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + + +[Guids] + gEfiGlobalVariableGuid ## CONSUMES ## Used to probe= boot options and set BootNext. + + +[Sources] + UnitTestBootUsb.c diff --git a/MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/UnitTestBoot= Usb.c b/MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/UnitTestBootUsb.c new file mode 100644 index 0000000000..485b7a2663 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/UnitTestBootUsb.c @@ -0,0 +1,119 @@ +/** + +Implement UnitTestBootUsbLib using internal microsoft uefi boot usb boot o= ption + +Copyright (c) Microsoft +**/ + +#include +#include +#include +#include +#include +#include + +EFI_STATUS +EFIAPI +SetUsbBootNext ( + VOID + ) +{ + EFI_STATUS Status; + INT16 BootOptionIndex; + CHAR16 BootOptionName[30]; + CHAR16 *BootOptionIndexChar =3D NULL; + UINT8 *OptionBuffer =3D NULL; + UINTN OptionBufferSize =3D 0, VariableSize =3D 0; + BOOLEAN IsUsbOptionFound =3D FALSE; + + StrCpy(BootOptionName, L"Boot000"); + BootOptionIndexChar =3D BootOptionName + StrLen(BootOptionName); + + // + // Walk through each of the first 10 boot options looking for the + // generic USB boot option. + for (BootOptionIndex =3D 0; BootOptionIndex < 10; BootOptionIndex++) + { + // Construct the BootOption name for this boot option. + // Do this by altering the last character of the name. + UnicodeValueToString(BootOptionIndexChar, 0, (INT64)BootOptionIndex, 1= ); + + // Attempt to retrieve the option. + DEBUG(( DEBUG_VERBOSE, __FUNCTION__" - Checking for %s...\n", BootOpti= onName )); + VariableSize =3D OptionBufferSize; + Status =3D gRT->GetVariable( BootOptionName, + &gEfiGlobalVariableGuid, + NULL, + &VariableSize, + OptionBuffer ); + // If we need a larger buffer, let's do that now. + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) + { + // Free the existing buffer. + if (OptionBuffer !=3D NULL) + { + FreePool( OptionBuffer ); + } + // Allocate a larger buffer. + OptionBuffer =3D AllocatePool( VariableSize ); + // If you fail to... we've gotta get out of here. + if (OptionBuffer =3D=3D NULL) + { + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Failed to allocate memory for= Boot option variable %s...\n", BootOptionName )); + return EFI_OUT_OF_RESOURCES; + } + OptionBufferSize =3D VariableSize; + + // Now that we've got a larger buffer, try that again. + Status =3D gRT->GetVariable( BootOptionName, + &gEfiGlobalVariableGuid, + NULL, + &VariableSize, + OptionBuffer ); + } + + // If we failed to retrieve this option... move on with your life. + if (EFI_ERROR( Status )) + { + DEBUG(( DEBUG_VERBOSE, __FUNCTION__" - Failed to locate option (%r).= Moving on.\n", Status )); + continue; + } + + // If we found the option, check to see whether this is the generic US= B option. + // For now... we're lazy... just check the last four bytes (which shou= ld be the + // optional data) and see whether it's "USB". + if (VariableSize > 4 && + OptionBuffer[VariableSize - 4] =3D=3D 'U' && OptionBuffer[Variable= Size - 3] =3D=3D 'S' && + OptionBuffer[VariableSize - 2] =3D=3D 'B' && OptionBuffer[Variable= Size - 1] =3D=3D 0x00 ) + { + IsUsbOptionFound =3D TRUE; + break; + } + } + + // + // If the correct boot option was found, + // set it to the BootNext variable. + if (IsUsbOptionFound) + { + Status =3D gRT->SetVariable( L"BootNext", + &gEfiGlobalVariableGuid, + (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARI= ABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE), + sizeof( BootOptionIndex ), + &BootOptionIndex ); + DEBUG(( DEBUG_VERBOSE, __FUNCTION__" - Set BootNext Status (%r)\n", St= atus )); + } + else + { + DEBUG(( DEBUG_WARN, __FUNCTION__" - Could not find generic USB boot op= tion.\n" )); + Status =3D EFI_NOT_FOUND; + } + + // Always put away your toys. + if (OptionBuffer !=3D NULL) + { + FreePool( OptionBuffer ); + } + + return Status; +} // SetUsbBootNext() diff --git a/MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/UnitTestBoot= UsbMicrosoftLib.inf b/MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/Uni= tTestBootUsbMicrosoftLib.inf new file mode 100644 index 0000000000..b23ca7f210 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestBootUsbMicrosoftLib/UnitTestBootUsbMicr= osoftLib.inf @@ -0,0 +1,41 @@ +## @file +# Library to support booting to USB on the next boot +# This instance uses a Microsoft UEFI internal/private boot option to do t= hat. +# +# +# @copyright +# Copyright (c) 2016 Microsoft Corporation. All rights reserved +# +# @par Specification Reference: +# +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D UnitTestBootUsbMicrosoftLib +FILE_GUID =3D A56FB4AA-479F-46FB-916B-300EBC47B964 +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_DRIVER +LIBRARY_CLASS =3D UnitTestBootUsbLib|UEFI_APPLICATION + + +[LibraryClasses] + DebugLib + UefiRuntimeServicesTableLib + MemoryAllocationLib + BaseLib + PrintLib + + +[Packages] + MdePkg/MdePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + + +[Guids] + gEfiGlobalVariableGuid ## CONSUMES ## Used to probe= boot options and set BootNext. + + +[Sources] + UnitTestBootUsb.c diff --git a/MsUnitTestPkg/Library/UnitTestLib/Md5.c b/MsUnitTestPkg/Librar= y/UnitTestLib/Md5.c new file mode 100644 index 0000000000..495b41730a --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestLib/Md5.c @@ -0,0 +1,353 @@ +/** @file + Implementation of MD5 algorithm. + +Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD = License +which accompanies this distribution. The full text of the license may be = found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLI= ED. + +**/ + +#include +#include + +#include "Md5.h" + +CONST UINT32 Md5_Data[][2] =3D { + { 0, 1 }, + { 1, 5 }, + { 5, 3 }, + { 0, 7 } +}; + +CONST UINT32 Md5_S[][4] =3D { + { 7, 22, 17, 12 }, + { 5, 20, 14, 9 }, + { 4, 23, 16 ,11 }, + { 6, 21, 15, 10 }, +}; + +CONST UINT32 Md5_T[] =3D { + 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, + 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, + 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, + 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821, + 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, + 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, + 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, + 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A, + 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, + 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, + 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, + 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665, + 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, + 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, + 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, + 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391 +}; + +CONST UINT8 Md5HashPadding[] =3D +{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// +// ROTATE_LEFT rotates x left n bits. +// +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define SA MedStates[Index2 & 3] +#define SB MedStates[(Index2 + 1) & 3] +#define SC MedStates[(Index2 + 2) & 3] +#define SD MedStates[(Index2 + 3) & 3] + +/** + Tf1 is one basic MD5 transform function. + + @param[in] A A 32-bit quantity. + @param[in] B A 32-bit quantity. + @param[in] C A 32-bit quantity. + + @return Output was produced as a 32-bit quantity based on the + three 32-bit input quantity. +**/ +UINT32 +Tf1 ( + IN UINT32 A, + IN UINT32 B, + IN UINT32 C + ) +{ + return (A & B) | (~A & C); +} + +/** + Tf2 is one basic MD5 transform function. + + @param[in] A A 32-bit quantity. + @param[in] B A 32-bit quantity. + @param[in] C A 32-bit quantity. + + @return Output was produced as a 32-bit quantity based on the + three 32-bit input quantity. +**/ +UINT32 +Tf2 ( + IN UINT32 A, + IN UINT32 B, + IN UINT32 C + ) +{ + return (A & C) | (B & ~C); +} + +/** + Tf3 is one basic MD5 transform function. + + @param[in] A A 32-bit quantity. + @param[in] B A 32-bit quantity. + @param[in] C A 32-bit quantity. + + @return Output was produced as a 32-bit quantity based on the + three 32-bit input quantity. +**/ +UINT32 +Tf3 ( + IN UINT32 A, + IN UINT32 B, + IN UINT32 C + ) +{ + return A ^ B ^ C; +} + +/** + Tf4 is one basic MD5 transform function. + + @param[in] A A 32-bit quantity. + @param[in] B A 32-bit quantity. + @param[in] C A 32-bit quantity. + + @return Output was produced as a 32-bit quantity based on the + three 32-bit input quantity. +**/ +UINT32 +Tf4 ( + IN UINT32 A, + IN UINT32 B, + IN UINT32 C + ) +{ + return B ^ (A | ~C); +} + +typedef +UINT32 +(*MD5_TRANSFORM_FUNC) ( + IN UINT32 A, + IN UINT32 B, + IN UINT32 C + ); + +CONST MD5_TRANSFORM_FUNC Md5_F[] =3D { + Tf1, + Tf2, + Tf3, + Tf4 +}; + +/** + Perform the MD5 transform on 64 bytes data segment. + + @param[in, out] Md5Ctx It includes the data segment for Md5 transform. +**/ +VOID +MD5Transform ( + IN OUT MD5_CTX *Md5Ctx + ) +{ + UINT32 Index1; + UINT32 Index2; + UINT32 MedStates[MD5_HASHSIZE >> 2]; + UINT32 *Data; + UINT32 IndexD; + UINT32 IndexT; + + Data =3D (UINT32 *) Md5Ctx->M; + + // + // Copy MD5 states to MedStates + // + CopyMem (MedStates, Md5Ctx->States, MD5_HASHSIZE); + + IndexT =3D 0; + for (Index1 =3D 0; Index1 < 4; Index1++) { + IndexD =3D Md5_Data[Index1][0]; + for (Index2 =3D 16; Index2 > 0; Index2--) { + SA +=3D (*Md5_F[Index1]) (SB, SC, SD) + Data[IndexD] + Md5_T[IndexT]; + SA =3D ROTATE_LEFT (SA, Md5_S[Index1][Index2 & 3]); + SA +=3D SB; + + IndexD +=3D Md5_Data[Index1][1]; + IndexD &=3D 15; + + IndexT++; + } + } + + for (Index1 =3D 0; Index1 < 4; Index1++) { + Md5Ctx->States[Index1] +=3D MedStates[Index1]; + } +} + +/** + Copy data segment into the M field of MD5_CTX structure for later transf= orm. + If the length of data segment is larger than 64 bytes, then does the tra= nsform + immediately and the generated Md5 code is stored in the States field of = MD5_CTX + data struct for later accumulation. + All of Md5 code generated for the sequential 64-bytes data segaments are= be + accumulated in MD5Final() function. + + @param[in, out] Md5Ctx The data structure of storing the original data + segment and the final result. + @param[in] Data The data wanted to be transformed. + @param[in] DataLen The length of data. +**/ +VOID +MD5UpdateBlock ( + IN OUT MD5_CTX *Md5Ctx, + IN CONST UINT8 *Data, + IN UINTN DataLen + ) +{ + UINTN Limit; + + for (Limit =3D 64 - Md5Ctx->Count; DataLen >=3D 64 - Md5Ctx->Count; Limi= t =3D 64) { + CopyMem (Md5Ctx->M + Md5Ctx->Count, (VOID *)Data, Limit); + MD5Transform (Md5Ctx); + + Md5Ctx->Count =3D 0; + Data +=3D Limit; + DataLen -=3D Limit; + } + + CopyMem (Md5Ctx->M + Md5Ctx->Count, (VOID *)Data, DataLen); + Md5Ctx->Count +=3D DataLen; +} + +/** + Initialize four 32-bits chaining variables and use them to do the Md5 tr= ansform. + + @param[out] Md5Ctx The data structure of Md5. + + @retval EFI_SUCCESS Initialization is ok. +**/ +EFI_STATUS +MD5Init ( + OUT MD5_CTX *Md5Ctx + ) +{ + ZeroMem (Md5Ctx, sizeof (*Md5Ctx)); + + // + // Set magic initialization constants. + // + Md5Ctx->States[0] =3D 0x67452301; + Md5Ctx->States[1] =3D 0xefcdab89; + Md5Ctx->States[2] =3D 0x98badcfe; + Md5Ctx->States[3] =3D 0x10325476; + + return EFI_SUCCESS; +} + +/** + the external interface of Md5 algorithm + + @param[in, out] Md5Ctx The data structure of storing the original data + segment and the final result. + @param[in] Data The data wanted to be transformed. + @param[in] DataLen The length of data. + + @retval EFI_SUCCESS The transform is ok. + @retval Others Other errors as indicated. +**/ +EFI_STATUS +MD5Update ( + IN OUT MD5_CTX *Md5Ctx, + IN VOID *Data, + IN UINTN DataLen + ) +{ + if (EFI_ERROR (Md5Ctx->Status)) { + return Md5Ctx->Status; + } + + MD5UpdateBlock (Md5Ctx, (CONST UINT8 *) Data, DataLen); + Md5Ctx->Length +=3D DataLen; + return EFI_SUCCESS; +} + +/** + Accumulate the MD5 value of every data segment and generate the finial + result according to MD5 algorithm. + + @param[in, out] Md5Ctx The data structure of storing the original data + segment and the final result. + @param[out] HashVal The final 128-bits output. + + @retval EFI_SUCCESS The transform is ok. + @retval Others Other errors as indicated. +**/ +EFI_STATUS +MD5Final ( + IN OUT MD5_CTX *Md5Ctx, + OUT UINT8 *HashVal + ) +{ + UINTN PadLength; + + if (Md5Ctx->Status =3D=3D EFI_ALREADY_STARTED) { + // + // Store Hashed value & Zeroize sensitive context information. + // + CopyMem (HashVal, (UINT8 *) Md5Ctx->States, MD5_HASHSIZE); + ZeroMem ((UINT8 *)Md5Ctx, sizeof (*Md5Ctx)); + + return EFI_SUCCESS; + } + + if (EFI_ERROR (Md5Ctx->Status)) { + return Md5Ctx->Status; + } + + PadLength =3D Md5Ctx->Count >=3D 56 ? 120 : 56; + PadLength -=3D Md5Ctx->Count; + MD5UpdateBlock (Md5Ctx, Md5HashPadding, PadLength); + Md5Ctx->Length =3D LShiftU64 (Md5Ctx->Length, 3); + MD5UpdateBlock (Md5Ctx, (CONST UINT8 *) &Md5Ctx->Length, 8); + + ZeroMem (Md5Ctx->M, sizeof (Md5Ctx->M)); + Md5Ctx->Length =3D 0; + Md5Ctx->Status =3D EFI_ALREADY_STARTED; + return MD5Final (Md5Ctx, HashVal); +} + diff --git a/MsUnitTestPkg/Library/UnitTestLib/Md5.h b/MsUnitTestPkg/Librar= y/UnitTestLib/Md5.h new file mode 100644 index 0000000000..ef1aa87d79 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestLib/Md5.h @@ -0,0 +1,75 @@ +/** @file + Header file for Md5. + +Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD = License +which accompanies this distribution. The full text of the license may be = found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLI= ED. + +**/ + +#ifndef _MD5_H_ +#define _MD5_H_ + +#define MD5_HASHSIZE 16 + +typedef struct _MD5_CTX { + EFI_STATUS Status; + UINT64 Length; + UINT32 States[MD5_HASHSIZE / sizeof (UINT32)]; + UINT8 M[64]; + UINTN Count; +} MD5_CTX; + +/** + Initialize four 32-bits chaining variables and use them to do the Md5 tr= ansform. + + @param[out] Md5Ctx The data structure of Md5. + + @retval EFI_SUCCESS Initialization is ok. +**/ +EFI_STATUS +MD5Init ( + OUT MD5_CTX *Md5Ctx + ); + +/** + the external interface of Md5 algorithm + + @param[in, out] Md5Ctx The data structure of storing the original data + segment and the final result. + @param[in] Data The data wanted to be transformed. + @param[in] DataLen The length of data. + + @retval EFI_SUCCESS The transform is ok. + @retval Others Other errors as indicated. +**/ +EFI_STATUS +MD5Update ( + IN OUT MD5_CTX *Md5Ctx, + IN VOID *Data, + IN UINTN DataLen + ); + +/** + Accumulate the MD5 value of every data segment and generate the finial + result according to MD5 algorithm. + + @param[in, out] Md5Ctx The data structure of storing the original data + segment and the final result. + @param[out] HashVal The final 128-bits output. + + @retval EFI_SUCCESS The transform is ok. + @retval Others Other errors as indicated. +**/ +EFI_STATUS +MD5Final ( + IN OUT MD5_CTX *Md5Ctx, + OUT UINT8 *HashVal + ); + +#endif diff --git a/MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.c b/MsUnitTestPk= g/Library/UnitTestLib/UnitTestLib.c new file mode 100644 index 0000000000..6f2c0e2994 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.c @@ -0,0 +1,958 @@ +/** + +Implement UnitTestLib + +Copyright (c) Microsoft +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Md5.h" + +MD5_CTX mFingerprintCtx; + + +// Prototyped here so that it can be included near the functions that +// it logically goes with. +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ); + + +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +// +// ---------------- TEST HELPER FUNCTIONS -------------------------------= ----- +// +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + + +/** + 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 CHAR16 *ShortTitleString + ) +{ + // TODO: Finish this function. + return TRUE; +} // IsFrameworkShortNameValid() + + +STATIC +CHAR16* +AllocateAndCopyString ( + IN CHAR16 *StringToCopy + ) +{ + CHAR16 *NewString =3D NULL; + UINTN NewStringLength; + + NewStringLength =3D StrnLenS( StringToCopy, UNIT_TEST_MAX_STRING_LENGTH = ) + 1; + NewString =3D AllocatePool( NewStringLength * sizeof( CHAR16 ) ); + if (NewString !=3D NULL) + { + StrCpyS( NewString, NewStringLength, StringToCopy ); + } + + return NewString; +} // AllocateAndCopyString () + + +STATIC +VOID +SetFrameworkFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework + ) +{ + MD5Init( &mFingerprintCtx ); + + // For this one we'll just use the title and version as the unique finge= rprint. + MD5Update( &mFingerprintCtx, Framework->Title, (StrLen( Framework->Title= ) * sizeof( CHAR16 )) ); + MD5Update( &mFingerprintCtx, Framework->VersionString, (StrLen( Framewor= k->VersionString ) * sizeof( CHAR16 )) ); + + MD5Final( &mFingerprintCtx, &Framework->Fingerprint[0] ); + return; +} // SetFrameworkFingerprint() + + +STATIC +VOID +SetSuiteFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_FRAMEWORK *Framework, + IN UNIT_TEST_SUITE *Suite + ) +{ + MD5Init( &mFingerprintCtx ); + + // For this one, we'll use the fingerprint from the framework, and the t= itle of the suite. + MD5Update( &mFingerprintCtx, &Framework->Fingerprint[0], UNIT_TEST_FINGE= RPRINT_SIZE ); + MD5Update( &mFingerprintCtx, Suite->Title, (StrLen( Suite->Title ) * siz= eof( CHAR16 )) ); + MD5Update(&mFingerprintCtx, Suite->Package, (StrLen(Suite->Package) * si= zeof(CHAR16))); + + MD5Final( &mFingerprintCtx, &Suite->Fingerprint[0] ); + return; +} // SetSuiteFingerprint() + + +STATIC +VOID +SetTestFingerprint ( + OUT UINT8 *Fingerprint, + IN UNIT_TEST_SUITE *Suite, + IN UNIT_TEST *Test + ) +{ + MD5Init( &mFingerprintCtx ); + + // For this one, we'll use the fingerprint from the suite, and the descr= iption and classname of the test. + MD5Update( &mFingerprintCtx, &Suite->Fingerprint[0], UNIT_TEST_FINGERPRI= NT_SIZE ); + MD5Update( &mFingerprintCtx, Test->Description, (StrLen( Test->Descripti= on ) * sizeof( CHAR16 )) ); + MD5Update(&mFingerprintCtx, Test->ClassName, (StrLen(Test->ClassName) * = sizeof(CHAR16))); + + MD5Final( &mFingerprintCtx, &Test->Fingerprint[0] ); + return; +} // SetTestFingerprint() + + +STATIC +BOOLEAN +CompareFingerprints ( + IN UINT8 *FingerprintA, + IN UINT8 *FingerprintB + ) +{ + return (CompareMem( FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SI= ZE ) =3D=3D 0); +} // SetTestFingerprint() + + +EFI_STATUS +EFIAPI +FreeUnitTestFramework ( + IN UNIT_TEST_FRAMEWORK *Framework + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} // FreeUnitTestFramework() + + +STATIC +EFI_STATUS +FreeUnitTestSuiteEntry ( + IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} // FreeUnitTestSuiteEntry() + + +STATIC +EFI_STATUS +FreeUnitTestTestEntry ( + IN UNIT_TEST_LIST_ENTRY *TestEntry + ) +{ + // TODO: Finish this function. + return EFI_SUCCESS; +} // FreeUnitTestTestEntry() + + +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +// +// ---------------- TEST SETUP FUNCTIONS --------------------------------= ----- +// +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + + +/* +Method to Initialize the Unit Test framework + +@retval Success - Unit Test init. +@retval EFI_ERROR - Unit Tests init failed. +*/ +EFI_STATUS +EFIAPI +InitUnitTestFramework ( + OUT UNIT_TEST_FRAMEWORK **Framework, + IN CHAR16 *Title, + IN CHAR16 *ShortTitle, + IN CHAR16 *VersionString + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + UNIT_TEST_FRAMEWORK *NewFramework =3D NULL; + + // + // First, check all pointers and make sure nothing's broked. + if (Framework =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. + 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 N= ULL || + 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( NewFramework )) + { + Status =3D LoadUnitTestCache( NewFramework, &(UNIT_TEST_SAVE_HEADER*)(= NewFramework->SavedState) ); + if (EFI_ERROR( Status )) + { + // Don't actually report it as an error, but emit a warning. + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Cache was detected, but failed = to load.\n" )); + Status =3D EFI_SUCCESS; + } + } + +Exit: + // + // If we're good, then let's copy the framework. + if (!EFI_ERROR( Status )) + { + *Framework =3D NewFramework; + } + // Otherwise, we need to undo this horrible thing that we've done. + else + { + FreeUnitTestFramework( NewFramework ); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +CreateUnitTestSuite ( + OUT UNIT_TEST_SUITE **Suite, + IN UNIT_TEST_FRAMEWORK *Framework, + IN CHAR16 *Title, + IN CHAR16 *Package, + IN UNIT_TEST_SUITE_SETUP Sup OPTIONAL, + IN UNIT_TEST_SUITE_TEARDOWN Tdn OPTIONAL + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry; + + // + // First, let's check to make sure that our parameters look good. + if ((Framework =3D=3D NULL) || (Title =3D=3D NULL) || (Package =3D=3D NU= LL)) + { + 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.Title =3D AllocateAndCopyString( Title ); + NewSuiteEntry->UTS.Package =3D AllocateAndCopyString(Package); + NewSuiteEntry->UTS.Setup =3D Sup; + NewSuiteEntry->UTS.Teardown =3D Tdn; + NewSuiteEntry->UTS.ParentFramework =3D Framework; + 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.Package =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*)NewSuiteEntr= y ); + *Suite =3D &NewSuiteEntry->UTS; + } + // Otherwise, make with the destruction. + else + { + FreeUnitTestSuiteEntry( NewSuiteEntry ); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +AddTestCase ( + IN UNIT_TEST_SUITE *Suite, + IN CHAR16 *Description, + IN CHAR16 *ClassName, + IN UNIT_TEST_FUNCTION Func, + IN UNIT_TEST_PREREQ PreReq OPTIONAL, + IN UNIT_TEST_CLEANUP CleanUp OPTIONAL, + IN UNIT_TEST_CONTEXT Context OPTIONAL + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + UNIT_TEST_LIST_ENTRY *NewTestEntry; + UNIT_TEST_FRAMEWORK *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) || (ClassName =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( Description ); + NewTestEntry->UT.ClassName =3D AllocateAndCopyString(ClassName); + NewTestEntry->UT.FailureType =3D FAILURETYPE_NOFAILURE; + NewTestEntry->UT.FailureMessage[0] =3D '\0'; + NewTestEntry->UT.Log =3D NULL; + NewTestEntry->UT.PreReq =3D PreReq; + NewTestEntry->UT.CleanUp =3D CleanUp; + NewTestEntry->UT.RunTest =3D Func; + NewTestEntry->UT.Context =3D Context; + NewTestEntry->UT.Result =3D UNIT_TEST_PENDING; + NewTestEntry->UT.ParentSuite =3D Suite; + InitializeListHead( &(NewTestEntry->Entry) ); // List entry for sib= ling tests. + if (NewTestEntry->UT.Description =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 ); + } + // Otherwise, make with the destruction. + else + { + FreeUnitTestTestEntry( NewTestEntry ); + } + + return Status; +} + + +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +// +// ---------------- TEST EXECUTION FUNCTIONS ----------------------------= ----- +// +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry =3D NULL; + UNIT_TEST *Test; + UNIT_TEST_FRAMEWORK *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: %s\n", Suite->Title)); + DEBUG((DEBUG_VERBOSE, "-------------------------------------------------= --------\n")); + + if (Suite->Setup !=3D NULL) + { + Suite->Setup( Suite->ParentFramework ); + } + + // + // Iterate all tests within the suite + // + for (TestEntry =3D (UNIT_TEST_LIST_ENTRY*)GetFirstNode( &(Suite->TestCas= eList) ); // Start at the beginning. + (LIST_ENTRY*)TestEntry !=3D &(Suite->TestCaseList); = // Go until you loop back to the head. + TestEntry =3D (UNIT_TEST_LIST_ENTRY*)GetNextNode( &(Suite->TestCase= List), (LIST_ENTRY*)TestEntry) ) // Always get the next test. + { + Test =3D &TestEntry->UT; + ParentFramework->CurrentTest =3D Test; + + DEBUG((DEBUG_VERBOSE, "***********************************************= **********\n")); + DEBUG((DEBUG_VERBOSE, " RUNNING TEST: %s:\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->PreReq !=3D NULL) + { + DEBUG(( DEBUG_VERBOSE, "PREREQ\n" )); + if (Test->PreReq( Suite->ParentFramework, Test->Context ) !=3D UNIT_= TEST_PASSED) + { + DEBUG(( DEBUG_ERROR, "PreReq Not Met\n" )); + Test->Result =3D UNIT_TEST_ERROR_PREREQ_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 PreReq from being dispatched a second time. + Test->Result =3D UNIT_TEST_RUNNING; + Test->Result =3D Test->RunTest( Suite->ParentFramework, Test->Context = ); + + // + // Finally, clean everything up, if need be. + if (Test->CleanUp !=3D NULL) + { + DEBUG(( DEBUG_VERBOSE, "CLEANUP\n" )); + Test->CleanUp( Suite->ParentFramework, Test->Context ); + } + + // + // End the test. + ParentFramework->CurrentTest =3D NULL; + } // End Test iteration + + + if (Suite->Teardown !=3D NULL) + { + Suite->Teardown( Suite->ParentFramework ); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +RunAllTestSuites( + IN UNIT_TEST_FRAMEWORK *Framework + ) +{ + UNIT_TEST_SUITE_LIST_ENTRY *Suite =3D NULL; + EFI_STATUS Status; + + 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")); + + // + // 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)) + { + Status =3D RunTestSuite(&(Suite->UTS)); + if (EFI_ERROR(Status)) + { + DEBUG((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } // End Suite iteration + + //Save current state so if test is started again it doesn't have to run.= It will just report + SaveFrameworkState(Framework, NULL, 0); + OutputUnitTestFrameworkReport(Framework); + + return EFI_SUCCESS; +} + +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +// +// ---------------- TEST UTILITY FUNCTIONS ------------------------------= ----- +// +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + + +STATIC +VOID +UpdateTestFromSave ( + IN OUT UNIT_TEST *Test, + IN UNIT_TEST_SAVE_HEADER *SavedState + ) +{ + UNIT_TEST_SAVE_TEST *CurrentTest, *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; + StrnCpy(&Test->FailureMessage[0], &MatchingTest->FailureMessage[0], UN= IT_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 + sizeof( UNIT_TEST_SAVE= _TEST )), MatchingTest->Size - sizeof( UNIT_TEST_SAVE_TEST ) ); + } + } + + // + // If the saved context exists and matches this test, grab it, too. + if (SavedState->HasSavedContext) + { + // TODO: Reconcile the difference between the way "size" works for Tes= t Saves + // and the way it works for Context Saves. Too confusing to use= it different ways. + + // 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 > 0 && + CompareFingerprints( &Test->Fingerprint[0], &SavedContext->Fingerp= rint[0] )) + { + // Override the test context with the saved context. + Test->Context =3D (VOID*)((UINT8*)SavedContext + sizeof( *SavedConte= xt )); + } + } + + return; +} // UpdateTestFromSave() + + +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 =3D FrameworkHandle; + UNIT_TEST_SAVE_HEADER *Header =3D NULL; + LIST_ENTRY *SuiteListHead, *Suite, *TestListHead, *Test; + UINT32 TestCount, TotalSize; + UINTN LogSize; + UNIT_TEST_SAVE_TEST *TestSaveData; + UNIT_TEST_SAVE_CONTEXT *TestSaveContext; + UNIT_TEST *UnitTest; + UINT8 *FloatingPointer; + + // + // First, let's not make assumptions about the parameters. + if (Framework =3D=3D NULL || (ContextToSave !=3D NULL && ContextToSaveSi= ze =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; = Suite =3D GetNextNode( SuiteListHead, Suite )) + { + // Iterate all tests within the suite. + TestListHead =3D &((UNIT_TEST_SUITE_LIST_ENTRY*)Suite)->UTS.TestCaseLi= st; + for (Test =3D GetFirstNode( TestListHead ); Test !=3D TestListHead; Te= st =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 (StrLen( UnitTest->Log ) + 1) * sizeof( CHAR16 ); + 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)ContextToSav= eSize; + } + + // + // 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->BlobSize =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; = Suite =3D GetNextNode( SuiteListHead, Suite )) + { + // Iterate all tests within the suite. + TestListHead =3D &((UNIT_TEST_SUITE_LIST_ENTRY*)Suite)->UTS.TestCaseLi= st; + for (Test =3D GetFirstNode( TestListHead ); Test !=3D TestListHead; Te= st =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; + StrnCpy(&TestSaveData->FailureMessage[0], &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 (StrLen( UnitTest->Log ) + 1) * sizeof( CHAR16 ); + CopyMem( FloatingPointer, UnitTest->Log, LogSize ); + FloatingPointer +=3D LogSize; + } + + // Update the size once the structure is complete. + // NOTE: Should thise be a straight cast without validation? + // Maybe. + // Am I tired of writing code? + // Yes. + TestSaveData->Size =3D (UINT32)(FloatingPointer - (UINT8*)TestSaveDa= ta); + } + } + + // + // 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; + 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; +} + + +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 =3D NULL; + + // + // First, let's not make assumptions about the parameters. + if (FrameworkHandle =3D=3D NULL || (ContextToSave !=3D NULL && ContextTo= SaveSize =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, __FUNCTION__" - Could not save state! %r\n", Stat= us )); + Status =3D EFI_DEVICE_ERROR; + } + + // + // Free data that was used. + FreePool( Header ); + + return Status; +} // SaveFrameworkState() + + +EFI_STATUS +EFIAPI +SaveFrameworkStateAndQuit ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize + ) +{ + EFI_STATUS Status; + + // + // First, let's not make assumptions about the parameters. + if (FrameworkHandle =3D=3D NULL) + { + return EFI_INVALID_PARAMETER; + } + + // + // Now, save all the data associated with this framework. + Status =3D SaveFrameworkState( FrameworkHandle, ContextToSave, ContextTo= SaveSize ); + + // + // If we're all good, let's book... + if (!EFI_ERROR( Status )) + { + // + // Free data that was used. + FreeUnitTestFramework( (UNIT_TEST_FRAMEWORK*)FrameworkHandle ); + + // + // Quit + gBS->Exit( gImageHandle, EFI_SUCCESS, 0, NULL ); + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Unit test failed to quit! Framewo= rk can no longer be used!\n" )); + + // + // We REALLY shouldn't be here. + Status =3D EFI_ABORTED; + } + + return Status; +} // SaveFrameworkStateAndQuit() + + +/** + NOTE: Takes in a ResetType, but currently only supports EfiResetCold + and EfiResetWarm. All other types will return EFI_INVALID_PARAMETE= R. + If a more specific reset is required, use SaveFrameworkState() and + call gRT->ResetSystem() directly. + +**/ +EFI_STATUS +EFIAPI +SaveFrameworkStateAndReboot ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle, + IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL, + IN UINTN ContextToSaveSize, + IN EFI_RESET_TYPE ResetType + ) +{ + EFI_STATUS Status; + + // + // First, let's not make assumptions about the parameters. + if (FrameworkHandle =3D=3D NULL || + (ResetType !=3D EfiResetCold && ResetType !=3D EfiResetWarm)) + { + return EFI_INVALID_PARAMETER; + } + + // + // Now, save all the data associated with this framework. + Status =3D SaveFrameworkState( FrameworkHandle, ContextToSave, ContextTo= SaveSize ); + + // + // If we're all good, let's book... + if (!EFI_ERROR( Status )) + { + // + // Next, we want to update the BootNext variable to USB + // so that we have a fighting chance of coming back here. + // + SetUsbBootNext(); + + // + // Free data that was used. + FreeUnitTestFramework( (UNIT_TEST_FRAMEWORK*)FrameworkHandle ); + + // + // Reset + gRT->ResetSystem( ResetType, EFI_SUCCESS, 0, NULL ); + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Unit test failed to quit! Framewo= rk can no longer be used!\n" )); + + // + // We REALLY shouldn't be here. + Status =3D EFI_ABORTED; + } + + return Status; +} // SaveFrameworkStateAndReboot() diff --git a/MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.inf b/MsUnitTest= Pkg/Library/UnitTestLib/UnitTestLib.inf new file mode 100644 index 0000000000..959775037f --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestLib/UnitTestLib.inf @@ -0,0 +1,44 @@ +## @file +# Library to support Unit Testing from UEFI shell +# +# +# @copyright +# Copyright (c) 2016 Microsoft Corporation. All rights reserved +# +# @par Specification Reference: +# +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D UnitTestLib +FILE_GUID =3D 98CEF9CA-15CE-40A3-ADE8-C299953CD0F6 +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_DRIVER +LIBRARY_CLASS =3D UnitTestLib|DXE_DRIVER UEFI_APPLICATION + + +[LibraryClasses] + DebugLib + MemoryAllocationLib + BaseMemoryLib + UefiRuntimeServicesTableLib + UefiLib + UnitTestLogLib + UnitTestPersistenceLib + UnitTestBootUsbLib + UnitTestResultReportLib + + +[Packages] + MdePkg/MdePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + + +[Guids] + + +[Sources] + UnitTestLib.c + Md5.c diff --git a/MsUnitTestPkg/Library/UnitTestLogLib/UnitTestLogLib.c b/MsUnit= TestPkg/Library/UnitTestLogLib/UnitTestLogLib.c new file mode 100644 index 0000000000..62b724bbcb --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestLogLib/UnitTestLogLib.c @@ -0,0 +1,252 @@ +/** + +Implement UnitTestLogLib - Unit test debugging log + +Copyright (c) Microsoft +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH (512) +#define UNIT_TEST_MAX_LOG_BUFFER (16 * 1024) + + + +struct _UNIT_TEST_LOG_PREFIX_STRING +{ + UNIT_TEST_STATUS LogLevel; + CHAR8 *String; +}; + +struct _UNIT_TEST_LOG_PREFIX_STRING mLogPrefixStrings[] =3D +{ + { DEBUG_ERROR, "[ERROR] " }, + { DEBUG_WARN, "[WARNING] " }, + { DEBUG_INFO, "[INFO] " }, + { DEBUG_VERBOSE, "[VERBOSE] " } +}; +UINTN mLogPrefixStringsCount =3D sizeof( mLogPrefixStrings ) / sizeof( mLo= gPrefixStrings[0] ); + + + + +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +// +// ---------------- TEST HELPER FUNCTIONS -------------------------------= ----- +// +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +STATIC +CONST CHAR8* +GetStringForStatusLogPrefix ( + IN UINTN LogLevel + ) +{ + UINTN Index; + CHAR8 *Result =3D NULL; + + for (Index =3D 0; Index < mLogPrefixStringsCount; 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 CHAR16 *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 StrnCatS(UnitTest->Log, UNIT_TEST_MAX_LOG_BUFFER/ sizeof(CHAR= 16), 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; +} + +STATIC +EFI_STATUS +AddUnitTestFailure( + IN OUT UNIT_TEST *UnitTest, + IN CONST CHAR16 *FailureMessage, + 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; + StrCpyS(&UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH, F= ailureMessage); + + return EFI_SUCCESS; +} + + +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +// +// ---------------- PUBLIC FUNCTIONS ------------------------------------ +// +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +VOID +EFIAPI +UnitTestLogInit ( +IN OUT UNIT_TEST *Test, +IN UINT8 *Buffer, +IN UINTN BufferSize +) +{ + // + // Make sure that you're cooking with gas. + // + if (Test =3D=3D NULL) + { + DEBUG((DEBUG_ERROR, __FUNCTION__ " called with invalid Test parameter\= n")); + 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); + } +} + +VOID +EFIAPI +UnitTestLog ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + CHAR8 NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH]; + CHAR16 LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH]; + CONST CHAR8 *LogTypePrefix =3D NULL; + VA_LIST Marker; + UINTN LogLevel =3D (UINTN) PcdGet32(UnitTestLogLevel); + // + // Make sure that this debug mode is enabled. + // + if ((ErrorLevel & LogLevel) =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", LogTy= pePrefix, Format ); + } + else + { + AsciiStrCpyS( NewFormatString, sizeof( NewFormatString ), Format ); + } + + // + // Convert the message to an ASCII String + // + VA_START (Marker, Format); + UnicodeVSPrintAsciiFormat( LogString, sizeof( LogString ), NewFormatStri= ng, Marker ); + VA_END (Marker); + + // + // Finally, add the string to the log. + // + AddStringToUnitTestLog( ((UNIT_TEST_FRAMEWORK*)Framework)->CurrentTest, = LogString ); + + return; +} + +VOID +EFIAPI +UnitTestLogFailure( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + FAILURE_TYPE FailureType, + IN CONST CHAR8 *Format, + ... +) +{ + CHAR16 LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH]; + VA_LIST Marker; + + + // + // Convert the message to an ASCII String + // + VA_START(Marker, Format); + UnicodeVSPrintAsciiFormat(LogString, sizeof(LogString), Format, Marker); + VA_END(Marker); + + // + // Finally, add the string to the log. + // + AddUnitTestFailure(((UNIT_TEST_FRAMEWORK*)Framework)->CurrentTest, LogSt= ring, FailureType); + + return; +} + diff --git a/MsUnitTestPkg/Library/UnitTestLogLib/UnitTestLogLib.inf b/MsUn= itTestPkg/Library/UnitTestLogLib/UnitTestLogLib.inf new file mode 100644 index 0000000000..e43d7c9690 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestLogLib/UnitTestLogLib.inf @@ -0,0 +1,43 @@ +## @file +# Library to support Logging in the Unit Tests +# +# +# @copyright +# Copyright (c) 2016 Microsoft Corporation. All rights reserved +# +# +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D UnitTestLogLib +FILE_GUID =3D D5F2DF71-6378-4E17-AE59-AE4109D34B5A +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_DRIVER +LIBRARY_CLASS =3D UnitTestLib|DXE_DRIVER UEFI_APPLICATION + +[LibraryClasses] + DebugLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + UefiLib + PrintLib + PcdLib + + +[Packages] + MdePkg/MdePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + + +[Guids] + + +[Sources] + UnitTestLogLib.c + +[Pcd] + gMsUnitTestPkgTokenSpaceGuid.UnitTestLogLevel ## CONSUMES + diff --git a/MsUnitTestPkg/Library/UnitTestPersistenceFileSystemLib/UnitTes= tPersistenceFileSystemLib.c b/MsUnitTestPkg/Library/UnitTestPersistenceFile= SystemLib/UnitTestPersistenceFileSystemLib.c new file mode 100644 index 0000000000..e00e30358b --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestPersistenceFileSystemLib/UnitTestPersis= tenceFileSystemLib.c @@ -0,0 +1,406 @@ +/** @file -- UnitTestPersistenceFilesystemLib.c + +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 serialized +version of the internal test state in case the test needs to quit and rest= ore. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. + +**/ +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#include + +/** + TODO: STUFF!! + + @retval !NULL A pointer to the EFI_FILE protocol instance for the = filesystem. + @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 =3D (UNIT_TEST_FRAMEWORK*)Fra= meworkHandle; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR16 *AppPath =3D NULL, *CacheFilePath =3D NU= LL; + CHAR16 *FileSuffix =3D L"_Cache.dat"; + UINTN DirectorySlashOffset, CacheFilePathLengt= h; + EFI_DEVICE_PATH_PROTOCOL *CacheFileDevicePath =3D NULL; + + // + // First, we need to get some information from the loaded image. + // Namely, where the hell are you? + // + Status =3D gBS->HandleProtocol( gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage ); + if (EFI_ERROR( Status )) + { + DEBUG(( DEBUG_WARN, __FUNCTION__" - Failed to locate DevicePath for lo= aded image. %r\n", Status )); + return NULL; + } + + // + // 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, __FUNCTION__" - Weird 0-length string when proces= sing app path.\n" )); + 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, __FUNCTION__" - Could not find a single directory= separator in app path.\n" )); + goto Exit; + } + + // + // Now we know some things, we're ready to produce our output string, I = think. + // + CacheFilePathLength =3D DirectorySlashOffset + 1; + CacheFilePathLength +=3D StrLen( Framework->ShortTitle ); + CacheFilePathLength +=3D StrLen( FileSuffix ); + CacheFilePathLength +=3D 1; // Don't forget the NULL terminator. + CacheFilePath =3D AllocateZeroPool( CacheFilePathLength * sizeof( = CHAR16 ) ); + + // + // 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, Framework->ShortTitle ); = // Copy the base name for the test cache. + StrCatS( CacheFilePath, CacheFilePathLength, FileSuffix ); = // Copy the file suffix. + + // + // Finally, try to create the device path for the thing thing. + // + CacheFileDevicePath =3D FileDevicePath( LoadedImage->DeviceHandle, Cache= FilePath ); + +Exit: + // Always put away your toys. + if (AppPath !=3D NULL) + { + FreePool( AppPath ); + } + if (CacheFilePath !=3D NULL) + { + FreePool( CacheFilePath); + } + + return CacheFileDevicePath; +} // GetCacheFileDevicePath() + + +/** + 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 + ) +{ + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + EFI_STATUS Status; + EFI_HANDLE FileDeviceHandle; + 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, + &FileDeviceHandle, + &FileHandle, + EFI_FILE_MODE_READ, + 0 ); + if (!EFI_ERROR( Status )) + { + ShellCloseFile( &FileHandle ); + } + + if (FileDevicePath !=3D NULL) + { + FreePool( FileDevicePath ); + } + + DEBUG(( DEBUG_VERBOSE, __FUNCTION__" - Returning %d\n", !EFI_ERROR( Stat= us ) )); + + return !EFI_ERROR( Status ); +} // DoesCacheExist() + + +/** + 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 + ) +{ + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + EFI_STATUS Status; + EFI_HANDLE FileDeviceHandle; + 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, + &FileDeviceHandle, + &FileHandle, + (EFI_FILE_MODE_READ | EFI_FILE_MODE_W= RITE), + 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, __FUNCTION__ " failed to delete file %r\n", Stat= us)); + } + } + + // + // Now that we know the path to the file... let's open it for writing. + // + Status =3D ShellOpenFileByDevicePath( &FileDevicePath, + &FileDeviceHandle, + &FileHandle, + (EFI_FILE_MODE_READ | EFI_FILE_MODE_= WRITE | EFI_FILE_MODE_CREATE), + 0 ); + if (EFI_ERROR( Status )) + { + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Opening file for writing failed! = %r\n", Status )); + goto Exit; + } + + // + // Write the data to the file. + // + WriteCount =3D SaveData->BlobSize; + DEBUG(( DEBUG_INFO, __FUNCTION__" - Writing %d bytes to file...\n", Writ= eCount )); + Status =3D ShellWriteFile( FileHandle, + &WriteCount, + SaveData ); + + if (EFI_ERROR( Status ) || WriteCount !=3D SaveData->BlobSize) + { + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Writing to file failed! %r\n", St= atus )); + } + else + { + DEBUG(( DEBUG_INFO, __FUNCTION__" - SUCCESS!\n" )); + } + + // + // No matter what, we should probably close the file. + // + ShellCloseFile( &FileHandle ); + +Exit: + if (FileDevicePath !=3D NULL) + { + FreePool( FileDevicePath ); + } + + return Status; +} // SaveUnitTestCache() + + +/** + 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 + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + EFI_HANDLE FileDeviceHandle; + SHELL_FILE_HANDLE FileHandle; + BOOLEAN IsFileOpened =3D FALSE; + UINT64 LargeFileSize; + UINTN FileSize; + UNIT_TEST_SAVE_HEADER *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, + &FileDeviceHandle, + &FileHandle, + EFI_FILE_MODE_READ, + 0 ); + if (EFI_ERROR( Status )) + { + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Opening file for writing failed! = %r\n", 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, __FUNCTION__" - Failed to determine file size! %r= \n", 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, __FUNCTION__" - Failed to allocate a pool to hold= the file contents! %r\n", Status )); + Status =3D EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Finally, let's read the bloody data. + Status =3D ShellReadFile( FileHandle, &FileSize, Buffer ); + if (EFI_ERROR( Status )) + { + DEBUG(( DEBUG_ERROR, __FUNCTION__" - Failed to read the file contents!= %r\n", Status )); + } + +Exit: + // + // Always put away your toys. + 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; +} // LoadUnitTestCache() diff --git a/MsUnitTestPkg/Library/UnitTestPersistenceFileSystemLib/UnitTes= tPersistenceFileSystemLib.inf b/MsUnitTestPkg/Library/UnitTestPersistenceFi= leSystemLib/UnitTestPersistenceFileSystemLib.inf new file mode 100644 index 0000000000..6720c015c3 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestPersistenceFileSystemLib/UnitTestPersis= tenceFileSystemLib.inf @@ -0,0 +1,64 @@ +## @file UnitTestPersistenceFileSystemLib.inf +# 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 +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS = IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPO= SE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# +# Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. +# +## + + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestPersistenceFileSystemLib + FILE_GUID =3D 9200844A-CDFD-4368-B4BD-106354702605 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D UEFI_APPLICATION + LIBRARY_CLASS =3D UnitTestPersistenceLib|UEFI_APPLICATION + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + + +[Sources] + UnitTestPersistenceFileSystemLib.c + + +[Packages] + MdePkg/MdePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + ShellPkg/ShellPkg.dec + + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + BaseLib + ShellLib + + +[Protocols] + gEfiLoadedImageProtocolGuid + gEfiSimpleFileSystemProtocolGuid + + +[Guids] + gEfiFileInfoGuid + gEfiFileSystemInfoGuid diff --git a/MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTestPersi= stenceLibNull.c b/MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTest= PersistenceLibNull.c new file mode 100644 index 0000000000..64ee5e39ad --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceL= ibNull.c @@ -0,0 +1,93 @@ +/** @file -- UnitTestNullPersistenceLib.c +This is an instance of the Unit Test Persistence Lib that does nothing. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. + +**/ + +#include +#include +#include +#include + + +/** + 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 + ) +{ + return FALSE; +} // DoesCacheExist() + + +/** + 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 + ) +{ + return EFI_UNSUPPORTED; +} // SaveUnitTestCache() + + +/** + 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 + ) +{ + return EFI_UNSUPPORTED; +} // LoadUnitTestCache() diff --git a/MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTestPersi= stenceLibNull.inf b/MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTe= stPersistenceLibNull.inf new file mode 100644 index 0000000000..3108a01e6e --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceL= ibNull.inf @@ -0,0 +1,44 @@ +## @file UnitTestPersistenceLibNull.inf +# This is an instance of the Unit Test Persistence Lib does nothing. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS = IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPO= SE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# +# Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. +# +## + + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D UnitTestPersistenceLibNull + FILE_GUID =3D B8553C7A-0B0B-4BBD-9DF3-825804BF26AB + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D DXE_DRIVER + LIBRARY_CLASS =3D UnitTestPersistenceLib|DXE_DRIVER UEFI_APPLICATI= ON + +# +# 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 + MsUnitTestPkg/MsUnitTestPkg.dec diff --git a/MsUnitTestPkg/Library/UnitTestResultReportPlainTextOutputLib/U= nitTestResultReportLib.c b/MsUnitTestPkg/Library/UnitTestResultReportPlainT= extOutputLib/UnitTestResultReportLib.c new file mode 100644 index 0000000000..2b1654d3d9 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestResultReportPlainTextOutputLib/UnitTest= ResultReportLib.c @@ -0,0 +1,208 @@ +/** + +Implement UnitTestResultReportLib doing plain txt out to console + +Copyright (c) Microsoft +**/ + +#include +#include +#include +#include +#include +#include + + + +struct _UNIT_TEST_STATUS_STRING +{ + UNIT_TEST_STATUS Status; + CHAR8 *String; +}; + +struct _UNIT_TEST_STATUS_STRING mStatusStrings[] =3D +{ + { UNIT_TEST_PASSED, "PASSED" }, + { UNIT_TEST_ERROR_PREREQ_NOT_MET, "NOT RUN - PREREQ FAILED" }, + { UNIT_TEST_ERROR_TEST_FAILED, "FAILED" }, + { UNIT_TEST_RUNNING, "RUNNING" }, + { UNIT_TEST_PENDING, "PENDING" } +}; +UINTN mStatusStringsCount =3D sizeof( mStatusS= trings ) / sizeof( mStatusStrings[0] ); +CHAR8 *mUnknownStatus =3D "**UNKNOWN**"; + +struct _UNIT_TEST_FAILURE_TYPE_STRING +{ + FAILURE_TYPE Type; + CHAR8 *String; +}; + +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" } +}; +UINTN mFailureTypeStringsCount =3D sizeof(mFailureTypeStrings) / sizeof(mF= ailureTypeStrings[0]); +CHAR8 *mUnknownFailureType =3D "*UNKNOWN* Failure"; + +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +// +// ---------------- TEST REPORTING FUNCTIONS ----------------------------= ----- +// +//=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +STATIC +CONST CHAR8* +GetStringForUnitTestStatus ( + IN UNIT_TEST_STATUS Status + ) +{ + UINTN Index; + CHAR8 *Result; + + Result =3D mUnknownStatus; + for (Index =3D 0; Index < mStatusStringsCount; Index++) + { + if (mStatusStrings[Index].Status =3D=3D Status) + { + Result =3D mStatusStrings[Index].String; + break; + } + } + + return Result; +} + +STATIC +CONST CHAR8* +GetStringForFailureType( + IN FAILURE_TYPE Failure +) +{ + UINTN Index; + CHAR8 *Result; + + Result =3D mUnknownFailureType; + for (Index =3D 0; Index < mFailureTypeStringsCount; Index++) + { + if (mFailureTypeStrings[Index].Type =3D=3D Failure) + { + Result =3D mFailureTypeStrings[Index].String; + break; + } + } + if (Result =3D=3D mUnknownFailureType) + { + DEBUG((DEBUG_INFO, __FUNCTION__ " Failure Type does not have string de= fined 0x%X\n", (UINT32)Failure)); + } + + return Result; +} + +/* +Method to print the Unit Test run results + +@retval Success +*/ +EFI_STATUS +EFIAPI +OutputUnitTestFrameworkReport( + IN UNIT_TEST_FRAMEWORK *Framework + ) +{ + INTN Passed =3D 0; + INTN Failed =3D 0; + INTN NotRun =3D 0; + UNIT_TEST_SUITE_LIST_ENTRY *Suite =3D NULL; + + if (Framework =3D=3D NULL) + { + return EFI_INVALID_PARAMETER; + } + + Print( L"---------------------------------------------------------\n" ); + Print( L"------------- UNIT TEST FRAMEWORK RESULTS ---------------\n" ); + Print( L"---------------------------------------------------------\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)) + { + UNIT_TEST_LIST_ENTRY *Test =3D NULL; + INTN SPassed =3D 0; + INTN SFailed =3D 0; + INTN SNotRun =3D 0; + + Print( L"/////////////////////////////////////////////////////////\n" = ); + Print( L" SUITE: %s\n", Suite->UTS.Title ); + Print( L" PACKAGE: %s\n", Suite->UTS.Package); + Print( L"/////////////////////////////////////////////////////////\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)) + { + + Print (L"*********************************************************\n= " ); + Print (L" CLASS NAME: %s\n", Test->UT.ClassName); + Print( L" TEST: %s\n", Test->UT.Description ); + Print( L" STATUS: %a\n", GetStringForUnitTestStatus( Test->UT.Resu= lt ) ); + Print( L" FAILURE: %a\n", GetStringForFailureType(Test->UT.FailureT= ype)); + Print( L" FAILURE MESSAGE:\n%a\n", Test->UT.FailureMessage); + + if (Test->UT.Log !=3D NULL) + { + Print( L" LOG:\n" ); + // NOTE: This has to be done directly because all of the other + // "formatted" print statements have caps on the string size. + gST->ConOut->OutputString( gST->ConOut, 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_PREREQ_NOT_MET: SNotRun++; break; + default: break; + } + Print( L"**********************************************************\= n" ); + } //End Test iteration + + Print( L"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" = ); + Print( L"Suite Stats\n" ); + Print( L" Passed: %d (%d%%)\n", SPassed, (SPassed * 100)/(SPassed+SF= ailed+SNotRun) ); + Print( L" Failed: %d (%d%%)\n", SFailed, (SFailed * 100) / (SPassed = + SFailed + SNotRun) ); + Print( L" Not Run: %d (%d%%)\n", SNotRun, (SNotRun * 100) / (SPassed = + SFailed + SNotRun) ); + Print( L"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" = ); + + Passed +=3D SPassed; //add to global counters + Failed +=3D SFailed; //add to global counters + NotRun +=3D SNotRun; //add to global coutners + }//End Suite iteration + + Print( L"=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" ); + Print( L"Total Stats\n" ); + Print( L" Passed: %d (%d%%)\n", Passed, (Passed * 100) / (Passed + Fai= led + NotRun) ); + Print( L" Failed: %d (%d%%)\n", Failed, (Failed * 100) / (Passed + Fai= led + NotRun) ); + Print( L" Not Run: %d (%d%%)\n", NotRun, (NotRun * 100) / (Passed + Fai= led + NotRun) ); + Print( L"=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/MsUnitTestPkg/Library/UnitTestResultReportPlainTextOutputLib/U= nitTestResultReportLib.inf b/MsUnitTestPkg/Library/UnitTestResultReportPlai= nTextOutputLib/UnitTestResultReportLib.inf new file mode 100644 index 0000000000..e8134dd0e2 --- /dev/null +++ b/MsUnitTestPkg/Library/UnitTestResultReportPlainTextOutputLib/UnitTest= ResultReportLib.inf @@ -0,0 +1,37 @@ +## @file +# Library to support printing out the unit test report using printlib and = conout +# +# +# @copyright +# Copyright (c) 2016 Microsoft Corporation. All rights reserved +# +# @par Specification Reference: +# +## + + +[Defines] +INF_VERSION =3D 0x00010017 +BASE_NAME =3D UnitTestResultReportPlainTextOutputLib +FILE_GUID =3D C659641D-BA1F-4B58-946E-B1E1103903F9 +VERSION_STRING =3D 1.0 +MODULE_TYPE =3D DXE_DRIVER +LIBRARY_CLASS =3D UnitTestResultReportLib|DXE_DRIVER UEFI_APPLICATION + + +[LibraryClasses] + DebugLib + UefiLib + UefiBootServicesTableLib + + +[Packages] + MdePkg/MdePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + + +[Guids] + + +[Sources] + UnitTestResultReportLib.c diff --git a/MsUnitTestPkg/MsUnitTestPkg.dec b/MsUnitTestPkg/MsUnitTestPkg.= dec new file mode 100644 index 0000000000..224ca92f2c --- /dev/null +++ b/MsUnitTestPkg/MsUnitTestPkg.dec @@ -0,0 +1,42 @@ +## @file MsUnitTestPkg.dec +# +# This Package provides all definitions(including functions, MACROs, struc= tures and library classes) +# and libraries instances, which are used to support Unit Testing and Inte= rface testing +# +# Copyright (c) 2017, Microsoft Corporation. All rights reserved. +# +# +## + + +[Defines] + DEC_SPECIFICATION =3D 0x00010005 + PACKAGE_NAME =3D MsUnitTestPkg + PACKAGE_GUID =3D 4A70C4A0-D72C-4D3F-9943-BE7C41C50BA3 + PACKAGE_VERSION =3D 1.00 + + +[Includes] + Include + +[LibraryClasses] + + +[Guids] + + ## Microsoft Unit Test Package token space guid + # Include/Guid/MsUnitTestPkgTokenSpace.h + # {833D3ABA-39B4-43A2-B930-7A34533931B3} + gMsUnitTestPkgTokenSpaceGuid =3D { 0x833d3aba, 0x39b4, 0x43a2, { 0xb9, 0= x30, 0x7a, 0x34, 0x53, 0x39, 0x31, 0xb3 } } + +[Ppis] + +[Protocols] + +[PcdsFeatureFlag] + +[PcdsDynamic, PcdsDynamicEx] + +[PcdsFixedAtBuild] + gMsUnitTestPkgTokenSpaceGuid.UnitTestLogLevel|0xFFFFFFFF|UINT32|0x000000= 01 + diff --git a/MsUnitTestPkg/ReadMe.md b/MsUnitTestPkg/ReadMe.md new file mode 100644 index 0000000000..1094ed4254 --- /dev/null +++ b/MsUnitTestPkg/ReadMe.md @@ -0,0 +1,65 @@ +# Ms Unit Test Support Package +## 🔹 Copyright +Copyright (c) 2017, Microsoft Corporation + +All rights reserved. Redistribution and use in source and binary forms, wi= th or without modification, are permitted provided that the following condi= tions are met: +1. Redistributions of source code must retain the above copyright notice, = this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notic= e, this list of conditions and the following disclaimer in the documentatio= n and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS= " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE= IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE= ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE = LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQU= ENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GO= ODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) H= OWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT L= IABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OU= T OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH D= AMAGE. + +## 🔹 About +This package adds a unit test framework targeted at the UEFI shell environ= ment. +It allows for unit test development to focus on the tests and leave, error= logging, result formatting, +context persistance, and test running to the framework. The unit test fra= mework works well for low +level unit tests as well as system level tests and fits easily in automati= on frameworks. + +The code is designed for a unit test application to leverage the framework= which is made +up of a number of libraries which allow for easy customization of the diff= erent elements. +A few different instances are created to both show how easy some behaviors= can be customized as +well as provide different implementatiosn that support different use cases. + +### 🔸 UnitTestLib +The main "framework" library. This provides the framework init, suite ini= t, and add test case +functionality. It also supports the running of the suites and logging/rep= orting of results. + +### 🔸 UnitTestAssetLib +The UnitTestAssetLib provides helper macros and functions for checking tes= t conditons and +reporting errors. Status and error info will be logged into the test cont= ext. There are a number +of Assert macros that make the unit test code friendly to view and easy to= understand. + + +### 🔸 UnitTestBootUsbLib +One of the unique features of the unit test framework is to be able to sav= e text context +and reboot the system. Since unit tests are generally run from a bootable= usb key the framework +has library calls to set boot next for usb. There is numerous ways this c= ould be done on a given +platform / BDS implementation and therefore this simple library allows cus= tomization if needed. +This package supplies two intstances: +* UsbClass Lib: This uses the Usb Class boot option as defined in the UEFI= spec and leveraged +by industry standard USB applications. +* UsbMicrosoft Lib: This uses a private boot option found in Microsoft UEF= I to boot to usb + +### 🔸 UnitTestLogLib +Library to support logging information during the test execution. This da= ta is logged to the test +context and will be available in the test reporting phase. This shold be = used for logging test +details and helpful messages to resolve test failures. + +### 🔸 UnitTestResultReportLib +Library provides function to run at the end of a framework test run and re= sponsibile for the +report format. This is a common customization point and allows the unit t= est framework to fit +its output reports into other test infrastructure. In this package a simp= le library instances has +been supplied to output test results to the console as plain text. + + +### 🔸 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. + +## 🔹 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 Sa= mpleUnitTestApp directory. + +## 🔹 Usage +TBD - Write how to use the code + diff --git a/MsUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestApp.c b/M= sUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestApp.c new file mode 100644 index 0000000000..88800e5a0c --- /dev/null +++ b/MsUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestApp.c @@ -0,0 +1,210 @@ +/** @file -- SampleUnitTestApp.c +This is a sample EFI Shell application to demostrate the usage of the Unit= Test Library. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. + +**/ +#include +#include +#include +#include +#include +#include + + +#define UNIT_TEST_APP_NAME L"Sample Unit Test Library Application" +#define UNIT_TEST_APP_SHORT_NAME L"Sample_Unit_Test_Lib_App" +#define UNIT_TEST_APP_VERSION L"0.1" + + +BOOLEAN mSampleGlobalTestBoolean =3D FALSE; +VOID *mSampleGlobalTestPointer =3D NULL; + + +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +/// +/// HELPER FUNCTIONS +/// +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +// +// Anything you think might be helpful that isn't a test itself. +// + +UNIT_TEST_STATUS +EFIAPI +MakeSureThatPointerIsNull ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UNIT_TEST_CONTEXT Context + ) +{ + UT_ASSERT_EQUAL(mSampleGlobalTestPointer, NULL); + return UNIT_TEST_PASSED; +} // ListsShouldHaveTheSameDescriptorSize() + + +VOID +EFIAPI +ClearThePointer ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UNIT_TEST_CONTEXT Context + ) +{ + mSampleGlobalTestPointer =3D NULL; + return; +} // ClearThePointer() + + +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +/// +/// TEST CASES +/// +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +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() + + +UNIT_TEST_STATUS +EFIAPI +GlobalBooleanShouldBeChangeable ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UNIT_TEST_CONTEXT Context + ) +{ + mSampleGlobalTestBoolean =3D TRUE; + UT_ASSERT_TRUE(mSampleGlobalTestBoolean); + + mSampleGlobalTestBoolean =3D FALSE; + UT_ASSERT_FALSE(mSampleGlobalTestBoolean); + + return UNIT_TEST_PASSED; +} // GlobalBooleanShouldBeChangeable() + + +UNIT_TEST_STATUS +EFIAPI +GlobalPointerShouldBeChangeable ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN UNIT_TEST_CONTEXT Context + ) +{ + mSampleGlobalTestPointer =3D (VOID*)-1; + UT_ASSERT_EQUAL(mSampleGlobalTestPointer, ((VOID*)-1)); + return UNIT_TEST_PASSED; +} // GlobalPointerShouldBeChangeable() + + +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +/// +/// TEST ENGINE +/// +///=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=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=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=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + +/** + SampleUnitTestApp + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point executed successfully. + @retval other Some error occured when executing this entry poi= nt. + +**/ +EFI_STATUS +EFIAPI +SampleUnitTestApp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK *Fw =3D NULL; + UNIT_TEST_SUITE *SimpleMathTests, *GlobalVarTests; + + DEBUG(( DEBUG_INFO, "%s v%s\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, UNIT_TEST_APP= _SHORT_NAME, UNIT_TEST_APP_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, Fw, L"Simple Math Test= s", L"Sample.Math", NULL, NULL ); + if (EFI_ERROR( Status )) + { + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for SimpleMathTests= \n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase( SimpleMathTests, L"Adding 1 to 1 should produce 2", L"Sampl= e.Math.Addition", OnePlusOneShouldEqualTwo, NULL, NULL, NULL ); + + // + // Populate the GlobalVarTests Unit Test Suite. + // + Status =3D CreateUnitTestSuite( &GlobalVarTests, Fw, L"Global Variable T= ests", L"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, L"You should be able to change a global BOO= LEAN", L"Sample.Globals.Boolean", GlobalBooleanShouldBeChangeable, NULL, NU= LL, NULL ); + AddTestCase( GlobalVarTests, L"You should be able to change a global poi= nter", L"Sample.Globals.Pointer", GlobalPointerShouldBeChangeable, MakeSure= ThatPointerIsNull, ClearThePointer, NULL ); + + // + // Execute the tests. + // + Status =3D RunAllTestSuites( Fw ); + +EXIT: + if (Fw) + { + FreeUnitTestFramework( Fw ); + } + + return Status; +} diff --git a/MsUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestApp.inf b= /MsUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestApp.inf new file mode 100644 index 0000000000..32c57144ab --- /dev/null +++ b/MsUnitTestPkg/Sample/SampleUnitTestApp/SampleUnitTestApp.inf @@ -0,0 +1,41 @@ +## @file +## Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+## + + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D SampleUnitTestApp + FILE_GUID =3D 9E8F461A-17E1-4312-B49C-E66F0A88EA8B + MODULE_TYPE =3D UEFI_APPLICATION + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D SampleUnitTestApp + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 IPF EBC +# + +[Sources] + SampleUnitTestApp.c + +[Packages] + MdePkg/MdePkg.dec + MsUnitTestPkg/MsUnitTestPkg.dec + +[Protocols] + + +[LibraryClasses] + BaseLib + UefiApplicationEntryPoint + DebugLib + UnitTestLib + UnitTestAssertLib + +[Guids] + + + + --=20 2.14.2.windows.3 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel