REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4683 Update GetActiveFrameworkHandle() to remove ASSERT() and require caller to check for NULL. This allows GetActiveFrameworkHandle() to be used to determine if the current host-based test environment is framework/cmocka or gtest. In the framework/cmocka host-based environment GetActiveFrameworkHandle() returns non-NULL. In the gtest host-based environment GetActiveFrameworkHandle() returns NULL. Cc: Michael Kubacki <mikuback@linux.microsoft.com> Cc: Sean Brogan <sean.brogan@microsoft.com> Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Michael Kubacki <michael.kubacki@microsoft.com>
		
			
				
	
	
		
			282 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  UnitTestLib APIs to run unit tests using cmocka
 | 
						|
 | 
						|
  Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
**/
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stddef.h>
 | 
						|
#include <setjmp.h>
 | 
						|
#include <cmocka.h>
 | 
						|
 | 
						|
#include <Uefi.h>
 | 
						|
#include <UnitTestFrameworkTypes.h>
 | 
						|
#include <Library/UnitTestLib.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
 | 
						|
STATIC UNIT_TEST_FRAMEWORK_HANDLE  mFrameworkHandle = NULL;
 | 
						|
 | 
						|
UNIT_TEST_FRAMEWORK_HANDLE
 | 
						|
GetActiveFrameworkHandle (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  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;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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) {
 | 
						|
    Framework->CurrentTest = UnitTest;
 | 
						|
    UnitTest->CleanUp (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");
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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;
 | 
						|
}
 |