From 0eb522987fcd8bec9b7031ae428736936b2bc288 Mon Sep 17 00:00:00 2001 From: Michael D Kinney Date: Wed, 22 Jan 2020 10:07:17 -0800 Subject: UnitTestFrameworkPkg/Library: Add library instances https://bugzilla.tianocore.org/show_bug.cgi?id=2505 Add the following library instances that are used to build unit tests for host and target environments. * CmockaLib with cmocka submodule to: https://git.cryptomilk.org/projects/cmocka.git * DebugLibPosix - Instance of DebugLib based on POSIX APIs (e.g. printf). * MemoryAllocationLibPosix - Instance of MemoryAllocationLib based on POSIX APIs (e.g. malloc/free). * UnitTestBootLibNull - Null instance of the UnitTestBootLib * UnitTestBootLibUsbClass - UnitTestBootLib instances that supports setting boot next to a USB device. * UnitTestLib - UnitTestLib instance that is designed to work with PEI, DXE, SMM, and UEFI Shell target environments. * UnitTestLibCmocka - UintTestLib instance that uses cmocka APIs and can only be use in a host environment. * UnitTestPersistenceLibNull - Null instance of the UnitTestPersistenceLib * UnitTestPersistenceLibSimpleFileSystem - UnitTestPersistenceLib instance that can safe the unit test framework state to a media device that supports the UEFI Simple File System Protocol. * UnitTestResultReportLibConOut - UnitTestResultReportLib instance that sends report results to the UEFI standard output console. * UnitTestResultReportLibDebugLib - UnitTestResultReportLib instance that sends report results to a DebugLib using DEBUG() macros. Cc: Sean Brogan Cc: Bret Barkelew Signed-off-by: Michael D Kinney Reviewed-by: Bret Barkelew --- .../Library/UnitTestLib/RunTestsCmocka.c | 278 +++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c (limited to 'UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c') diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c new file mode 100644 index 0000000000..fb81cc9658 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c @@ -0,0 +1,278 @@ +/** @file + UnitTestLib APIs to run unit tests using cmocka + + Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +STATIC UNIT_TEST_FRAMEWORK_HANDLE mFrameworkHandle = NULL; + +UNIT_TEST_FRAMEWORK_HANDLE +GetActiveFrameworkHandle ( + VOID + ) +{ + ASSERT (mFrameworkHandle != NULL); + return mFrameworkHandle; +} + +// +// The currently active test suite +// +UNIT_TEST_SUITE *mActiveUnitTestSuite = NULL; + +void +CmockaUnitTestFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->RunTest == NULL) { + UnitTest->Result = UNIT_TEST_SKIPPED; + } else { + UnitTest->Result = UNIT_TEST_RUNNING; + + Framework->CurrentTest = UnitTest; + UnitTest->Result = UnitTest->RunTest (UnitTest->Context); + Framework->CurrentTest = NULL; + + // Print out the log messages - This is a partial solution as it + // does not get the log into the XML. Need cmocka changes to support + // stdout and stderr in their xml format + // + if (UnitTest->Log != NULL) { + print_message("UnitTest: %s - %s\n", UnitTest->Name, UnitTest->Description); + print_message("Log Output Start\n"); + print_message("%s", UnitTest->Log); + print_message("Log Output End\n"); + } + } +} + +int +CmockaUnitTestSetupFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_STATUS Result; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->Prerequisite == NULL) { + return 0; + } + + Framework->CurrentTest = UnitTest; + Result = UnitTest->Prerequisite (UnitTest->Context); + Framework->CurrentTest = NULL; + + // + // Return 0 for success. Non-zero for error. + // + return (int)Result; +} + +int +CmockaUnitTestTeardownFunctionRunner ( + void **state + ) +{ + UNIT_TEST *UnitTest; + UNIT_TEST_SUITE *Suite; + UNIT_TEST_FRAMEWORK *Framework; + + UnitTest = (UNIT_TEST *)(*state); + Suite = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite); + Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework); + + if (UnitTest->CleanUp == NULL) { + return 0; + } + + Framework->CurrentTest = UnitTest; + UnitTest->CleanUp (UnitTest->Context); + Framework->CurrentTest = NULL; + // + // Return 0 for success. Non-zero for error. + // + return 0; +} + +int +CmockaUnitTestSuiteSetupFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite == NULL) { + return -1; + } + if (mActiveUnitTestSuite->Setup == NULL) { + return 0; + } + + mActiveUnitTestSuite->Setup (); + // + // Always succeed + // + return 0; +} + +int +CmockaUnitTestSuiteTeardownFunctionRunner ( + void **state + ) +{ + if (mActiveUnitTestSuite == NULL) { + return -1; + } + if (mActiveUnitTestSuite->Teardown == NULL) { + return 0; + } + + mActiveUnitTestSuite->Teardown (); + // + // Always succeed + // + return 0; +} + +STATIC +EFI_STATUS +RunTestSuite ( + IN UNIT_TEST_SUITE *Suite + ) +{ + UNIT_TEST_LIST_ENTRY *TestEntry; + UNIT_TEST *UnitTest; + struct CMUnitTest *Tests; + UINTN Index; + + TestEntry = NULL; + + if (Suite == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title)); + DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + + // + // Allocate buffer of CMUnitTest entries + // + Tests = AllocateZeroPool (Suite->NumTests * sizeof (struct CMUnitTest)); + ASSERT (Tests != NULL); + + // + // Populate buffer of CMUnitTest entries + // + Index = 0; + for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList)); + (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList); + TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) { + UnitTest = &TestEntry->UT; + Tests[Index].name = UnitTest->Description; + Tests[Index].test_func = CmockaUnitTestFunctionRunner; + Tests[Index].setup_func = CmockaUnitTestSetupFunctionRunner; + Tests[Index].teardown_func = CmockaUnitTestTeardownFunctionRunner; + Tests[Index].initial_state = UnitTest; + Index++; + } + ASSERT (Index == Suite->NumTests); + + // + // Run all unit tests in a test suite + // + mActiveUnitTestSuite = Suite; + _cmocka_run_group_tests ( + Suite->Title, + Tests, + Suite->NumTests, + CmockaUnitTestSuiteSetupFunctionRunner, + CmockaUnitTestSuiteTeardownFunctionRunner + ); + mActiveUnitTestSuite = NULL; + FreePool (Tests); + + return EFI_SUCCESS; +} + +/** + Execute all unit test cases in all unit test suites added to a Framework. + + Once a unit test framework is initialized and all unit test suites and unit + test cases are registered, this function will cause the unit test framework to + dispatch all unit test cases in sequence and record the results for reporting. + + @param[in] FrameworkHandle A handle to the current running framework that + dispatched the test. Necessary for recording + certain test events with the framework. + + @retval EFI_SUCCESS All test cases were dispatched. + @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL. +**/ +EFI_STATUS +EFIAPI +RunAllTestSuites ( + IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle + ) +{ + UNIT_TEST_FRAMEWORK *Framework; + UNIT_TEST_SUITE_LIST_ENTRY *Suite; + EFI_STATUS Status; + + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle; + Suite = NULL; + + if (Framework == NULL) { + return EFI_INVALID_PARAMETER; + } + + DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + DEBUG((DEBUG_VERBOSE, "------------ RUNNING ALL TEST SUITES --------------\n")); + DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n")); + mFrameworkHandle = FrameworkHandle; + + // + // Iterate all suites + // + for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList); + (LIST_ENTRY *)Suite != &Framework->TestSuiteList; + Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) { + Status = RunTestSuite (&(Suite->UTS)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error. %r\n", Status)); + } + } + + mFrameworkHandle = NULL; + + return EFI_SUCCESS; +} -- cgit v1.2.3