UnitTestLib.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. /**
  2. Implement UnitTestLib
  3. Copyright (c) Microsoft Corporation.
  4. Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <Uefi.h>
  8. #include <Library/UnitTestLib.h>
  9. #include <Library/BaseLib.h>
  10. #include <Library/BaseMemoryLib.h>
  11. #include <Library/MemoryAllocationLib.h>
  12. #include <Library/DebugLib.h>
  13. #include <Library/UnitTestPersistenceLib.h>
  14. #include <Library/UnitTestResultReportLib.h>
  15. ///
  16. /// Forward declaration of prototype
  17. ///
  18. STATIC
  19. VOID
  20. UpdateTestFromSave (
  21. IN OUT UNIT_TEST *Test,
  22. IN UNIT_TEST_SAVE_HEADER *SavedState
  23. );
  24. /**
  25. This function will determine whether the short name violates any rules that would
  26. prevent it from being used as a reporting name or as a serialization name.
  27. Example: If the name cannot be serialized to a filesystem file name.
  28. @param[in] ShortTitleString A pointer to the short title string to be evaluated.
  29. @retval TRUE The string is acceptable.
  30. @retval FALSE The string should not be used.
  31. **/
  32. STATIC
  33. BOOLEAN
  34. IsFrameworkShortNameValid (
  35. IN CHAR8 *ShortTitleString
  36. )
  37. {
  38. // TODO: Finish this function.
  39. return TRUE;
  40. }
  41. STATIC
  42. CHAR8 *
  43. AllocateAndCopyString (
  44. IN CHAR8 *StringToCopy
  45. )
  46. {
  47. CHAR8 *NewString;
  48. UINTN NewStringLength;
  49. NewString = NULL;
  50. NewStringLength = AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LENGTH) + 1;
  51. NewString = AllocatePool (NewStringLength * sizeof (CHAR8));
  52. if (NewString != NULL) {
  53. AsciiStrCpyS (NewString, NewStringLength, StringToCopy);
  54. }
  55. return NewString;
  56. }
  57. STATIC
  58. VOID
  59. SetFrameworkFingerprint (
  60. OUT UINT8 *Fingerprint,
  61. IN UNIT_TEST_FRAMEWORK *Framework
  62. )
  63. {
  64. UINT32 NewFingerprint;
  65. // For this one we'll just use the title and version as the unique fingerprint.
  66. NewFingerprint = CalculateCrc32 (Framework->Title, (AsciiStrLen (Framework->Title) * sizeof (CHAR8)));
  67. NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Framework->VersionString, (AsciiStrLen (Framework->VersionString) * sizeof (CHAR8)));
  68. CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
  69. return;
  70. }
  71. STATIC
  72. VOID
  73. SetSuiteFingerprint (
  74. OUT UINT8 *Fingerprint,
  75. IN UNIT_TEST_FRAMEWORK *Framework,
  76. IN UNIT_TEST_SUITE *Suite
  77. )
  78. {
  79. UINT32 NewFingerprint;
  80. // For this one, we'll use the fingerprint from the framework, and the title of the suite.
  81. NewFingerprint = CalculateCrc32 (&Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
  82. NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Title, (AsciiStrLen (Suite->Title) * sizeof (CHAR8)));
  83. NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Suite->Name, (AsciiStrLen (Suite->Name) * sizeof (CHAR8)));
  84. CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
  85. return;
  86. }
  87. STATIC
  88. VOID
  89. SetTestFingerprint (
  90. OUT UINT8 *Fingerprint,
  91. IN UNIT_TEST_SUITE *Suite,
  92. IN UNIT_TEST *Test
  93. )
  94. {
  95. UINT32 NewFingerprint;
  96. // For this one, we'll use the fingerprint from the suite, and the description and classname of the test.
  97. NewFingerprint = CalculateCrc32 (&Suite->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
  98. NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Description, (AsciiStrLen (Test->Description) * sizeof (CHAR8)));
  99. NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32 (Test->Name, (AsciiStrLen (Test->Name) * sizeof (CHAR8)));
  100. CopyMem (Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE);
  101. return;
  102. }
  103. STATIC
  104. BOOLEAN
  105. CompareFingerprints (
  106. IN UINT8 *FingerprintA,
  107. IN UINT8 *FingerprintB
  108. )
  109. {
  110. return (CompareMem (FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE) == 0);
  111. }
  112. /**
  113. Cleanup a test framework.
  114. After tests are run, this will teardown the entire framework and free all
  115. allocated data within.
  116. @param[in] FrameworkHandle A handle to the current running framework that
  117. dispatched the test. Necessary for recording
  118. certain test events with the framework.
  119. @retval EFI_SUCCESS All resources associated with framework were
  120. freed.
  121. @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
  122. **/
  123. EFI_STATUS
  124. EFIAPI
  125. FreeUnitTestFramework (
  126. IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
  127. )
  128. {
  129. // TODO: Finish this function.
  130. return EFI_SUCCESS;
  131. }
  132. STATIC
  133. EFI_STATUS
  134. FreeUnitTestSuiteEntry (
  135. IN UNIT_TEST_SUITE_LIST_ENTRY *SuiteEntry
  136. )
  137. {
  138. // TODO: Finish this function.
  139. return EFI_SUCCESS;
  140. }
  141. STATIC
  142. EFI_STATUS
  143. FreeUnitTestTestEntry (
  144. IN UNIT_TEST_LIST_ENTRY *TestEntry
  145. )
  146. {
  147. // TODO: Finish this function.
  148. return EFI_SUCCESS;
  149. }
  150. /**
  151. Method to Initialize the Unit Test framework. This function registers the
  152. test name and also initializes the internal state of the test framework to
  153. receive any new suites and tests.
  154. @param[out] FrameworkHandle Unit test framework to be created.
  155. @param[in] Title Null-terminated ASCII string that is the user
  156. friendly name of the framework. String is
  157. copied.
  158. @param[in] ShortTitle Null-terminated ASCII short string that is the
  159. short name of the framework with no spaces.
  160. String is copied.
  161. @param[in] VersionString Null-terminated ASCII version string for the
  162. framework. String is copied.
  163. @retval EFI_SUCCESS The unit test framework was initialized.
  164. @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
  165. @retval EFI_INVALID_PARAMETER Title is NULL.
  166. @retval EFI_INVALID_PARAMETER ShortTitle is NULL.
  167. @retval EFI_INVALID_PARAMETER VersionString is NULL.
  168. @retval EFI_INVALID_PARAMETER ShortTitle is invalid.
  169. @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
  170. initialize the unit test framework.
  171. **/
  172. EFI_STATUS
  173. EFIAPI
  174. InitUnitTestFramework (
  175. OUT UNIT_TEST_FRAMEWORK_HANDLE *FrameworkHandle,
  176. IN CHAR8 *Title,
  177. IN CHAR8 *ShortTitle,
  178. IN CHAR8 *VersionString
  179. )
  180. {
  181. EFI_STATUS Status;
  182. UNIT_TEST_FRAMEWORK_HANDLE NewFrameworkHandle;
  183. UNIT_TEST_FRAMEWORK *NewFramework;
  184. UINTN SaveStateSize;
  185. Status = EFI_SUCCESS;
  186. NewFramework = NULL;
  187. //
  188. // First, check all pointers and make sure nothing's broked.
  189. //
  190. if ((FrameworkHandle == NULL) || (Title == NULL) ||
  191. (ShortTitle == NULL) || (VersionString == NULL))
  192. {
  193. return EFI_INVALID_PARAMETER;
  194. }
  195. //
  196. // Next, determine whether all of the strings are good to use.
  197. //
  198. if (!IsFrameworkShortNameValid (ShortTitle)) {
  199. return EFI_INVALID_PARAMETER;
  200. }
  201. //
  202. // Next, set aside some space to start messing with the framework.
  203. //
  204. NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK));
  205. if (NewFramework == NULL) {
  206. return EFI_OUT_OF_RESOURCES;
  207. }
  208. //
  209. // Next, set up all the test data.
  210. //
  211. NewFrameworkHandle = (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework;
  212. NewFramework->Title = AllocateAndCopyString (Title);
  213. NewFramework->ShortTitle = AllocateAndCopyString (ShortTitle);
  214. NewFramework->VersionString = AllocateAndCopyString (VersionString);
  215. NewFramework->Log = NULL;
  216. NewFramework->CurrentTest = NULL;
  217. NewFramework->SavedState = NULL;
  218. if ((NewFramework->Title == NULL) ||
  219. (NewFramework->ShortTitle == NULL) ||
  220. (NewFramework->VersionString == NULL))
  221. {
  222. Status = EFI_OUT_OF_RESOURCES;
  223. goto Exit;
  224. }
  225. InitializeListHead (&(NewFramework->TestSuiteList));
  226. //
  227. // Create the framework fingerprint.
  228. //
  229. SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework);
  230. //
  231. // If there is a persisted context, load it now.
  232. //
  233. if (DoesCacheExist (NewFrameworkHandle)) {
  234. Status = LoadUnitTestCache (NewFrameworkHandle, (VOID **)(&NewFramework->SavedState), &SaveStateSize);
  235. if (EFI_ERROR (Status)) {
  236. //
  237. // Don't actually report it as an error, but emit a warning.
  238. //
  239. DEBUG ((DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __FUNCTION__));
  240. Status = EFI_SUCCESS;
  241. }
  242. }
  243. Exit:
  244. //
  245. // If we're good, then let's copy the framework.
  246. //
  247. if (!EFI_ERROR (Status)) {
  248. *FrameworkHandle = NewFrameworkHandle;
  249. } else {
  250. //
  251. // Otherwise, we need to undo this horrible thing that we've done.
  252. //
  253. FreeUnitTestFramework (NewFrameworkHandle);
  254. }
  255. return Status;
  256. }
  257. /**
  258. Registers a Unit Test Suite in the Unit Test Framework.
  259. At least one test suite must be registered, because all test cases must be
  260. within a unit test suite.
  261. @param[out] SuiteHandle Unit test suite to create
  262. @param[in] FrameworkHandle Unit test framework to add unit test suite to
  263. @param[in] Title Null-terminated ASCII string that is the user
  264. friendly name of the test suite. String is
  265. copied.
  266. @param[in] Name Null-terminated ASCII string that is the short
  267. name of the test suite with no spaces. String
  268. is copied.
  269. @param[in] Setup Setup function, runs before suite. This is an
  270. optional parameter that may be NULL.
  271. @param[in] Teardown Teardown function, runs after suite. This is an
  272. optional parameter that may be NULL.
  273. @retval EFI_SUCCESS The unit test suite was created.
  274. @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
  275. @retval EFI_INVALID_PARAMETER FrameworkHandle is NULL.
  276. @retval EFI_INVALID_PARAMETER Title is NULL.
  277. @retval EFI_INVALID_PARAMETER Name is NULL.
  278. @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
  279. initialize the unit test suite.
  280. **/
  281. EFI_STATUS
  282. EFIAPI
  283. CreateUnitTestSuite (
  284. OUT UNIT_TEST_SUITE_HANDLE *SuiteHandle,
  285. IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
  286. IN CHAR8 *Title,
  287. IN CHAR8 *Name,
  288. IN UNIT_TEST_SUITE_SETUP Setup OPTIONAL,
  289. IN UNIT_TEST_SUITE_TEARDOWN Teardown OPTIONAL
  290. )
  291. {
  292. EFI_STATUS Status;
  293. UNIT_TEST_SUITE_LIST_ENTRY *NewSuiteEntry;
  294. UNIT_TEST_FRAMEWORK *Framework;
  295. Status = EFI_SUCCESS;
  296. Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
  297. //
  298. // First, let's check to make sure that our parameters look good.
  299. //
  300. if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) {
  301. return EFI_INVALID_PARAMETER;
  302. }
  303. //
  304. // Create the new entry.
  305. //
  306. NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY));
  307. if (NewSuiteEntry == NULL) {
  308. return EFI_OUT_OF_RESOURCES;
  309. }
  310. //
  311. // Copy the fields we think we need.
  312. //
  313. NewSuiteEntry->UTS.NumTests = 0;
  314. NewSuiteEntry->UTS.Title = AllocateAndCopyString (Title);
  315. NewSuiteEntry->UTS.Name = AllocateAndCopyString (Name);
  316. NewSuiteEntry->UTS.Setup = Setup;
  317. NewSuiteEntry->UTS.Teardown = Teardown;
  318. NewSuiteEntry->UTS.ParentFramework = FrameworkHandle;
  319. InitializeListHead (&(NewSuiteEntry->Entry)); // List entry for sibling suites.
  320. InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList)); // List entry for child tests.
  321. if (NewSuiteEntry->UTS.Title == NULL) {
  322. Status = EFI_OUT_OF_RESOURCES;
  323. goto Exit;
  324. }
  325. if (NewSuiteEntry->UTS.Name == NULL) {
  326. Status = EFI_OUT_OF_RESOURCES;
  327. goto Exit;
  328. }
  329. //
  330. // Create the suite fingerprint.
  331. //
  332. SetSuiteFingerprint (&NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS);
  333. Exit:
  334. //
  335. // If everything is going well, add the new suite to the tail list for the framework.
  336. //
  337. if (!EFI_ERROR (Status)) {
  338. InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry);
  339. *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS);
  340. } else {
  341. //
  342. // Otherwise, make with the destruction.
  343. //
  344. FreeUnitTestSuiteEntry (NewSuiteEntry);
  345. }
  346. return Status;
  347. }
  348. /**
  349. Adds test case to Suite
  350. @param[in] SuiteHandle Unit test suite to add test to.
  351. @param[in] Description Null-terminated ASCII string that is the user
  352. friendly description of a test. String is copied.
  353. @param[in] Name Null-terminated ASCII string that is the short name
  354. of the test with no spaces. String is copied.
  355. @param[in] Function Unit test function.
  356. @param[in] Prerequisite Prerequisite function, runs before test. This is
  357. an optional parameter that may be NULL.
  358. @param[in] CleanUp Clean up function, runs after test. This is an
  359. optional parameter that may be NULL.
  360. @param[in] Context Pointer to context. This is an optional parameter
  361. that may be NULL.
  362. @retval EFI_SUCCESS The unit test case was added to Suite.
  363. @retval EFI_INVALID_PARAMETER SuiteHandle is NULL.
  364. @retval EFI_INVALID_PARAMETER Description is NULL.
  365. @retval EFI_INVALID_PARAMETER Name is NULL.
  366. @retval EFI_INVALID_PARAMETER Function is NULL.
  367. @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
  368. add the unit test case to Suite.
  369. **/
  370. EFI_STATUS
  371. EFIAPI
  372. AddTestCase (
  373. IN UNIT_TEST_SUITE_HANDLE SuiteHandle,
  374. IN CHAR8 *Description,
  375. IN CHAR8 *Name,
  376. IN UNIT_TEST_FUNCTION Function,
  377. IN UNIT_TEST_PREREQUISITE Prerequisite OPTIONAL,
  378. IN UNIT_TEST_CLEANUP CleanUp OPTIONAL,
  379. IN UNIT_TEST_CONTEXT Context OPTIONAL
  380. )
  381. {
  382. EFI_STATUS Status;
  383. UNIT_TEST_LIST_ENTRY *NewTestEntry;
  384. UNIT_TEST_FRAMEWORK *ParentFramework;
  385. UNIT_TEST_SUITE *Suite;
  386. Status = EFI_SUCCESS;
  387. Suite = (UNIT_TEST_SUITE *)SuiteHandle;
  388. //
  389. // First, let's check to make sure that our parameters look good.
  390. //
  391. if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) {
  392. return EFI_INVALID_PARAMETER;
  393. }
  394. ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
  395. //
  396. // Create the new entry.
  397. NewTestEntry = AllocateZeroPool (sizeof (UNIT_TEST_LIST_ENTRY));
  398. if (NewTestEntry == NULL) {
  399. return EFI_OUT_OF_RESOURCES;
  400. }
  401. //
  402. // Copy the fields we think we need.
  403. NewTestEntry->UT.Description = AllocateAndCopyString (Description);
  404. NewTestEntry->UT.Name = AllocateAndCopyString (Name);
  405. NewTestEntry->UT.FailureType = FAILURETYPE_NOFAILURE;
  406. NewTestEntry->UT.FailureMessage[0] = '\0';
  407. NewTestEntry->UT.Log = NULL;
  408. NewTestEntry->UT.Prerequisite = Prerequisite;
  409. NewTestEntry->UT.CleanUp = CleanUp;
  410. NewTestEntry->UT.RunTest = Function;
  411. NewTestEntry->UT.Context = Context;
  412. NewTestEntry->UT.Result = UNIT_TEST_PENDING;
  413. NewTestEntry->UT.ParentSuite = SuiteHandle;
  414. InitializeListHead (&(NewTestEntry->Entry)); // List entry for sibling tests.
  415. if (NewTestEntry->UT.Description == NULL) {
  416. Status = EFI_OUT_OF_RESOURCES;
  417. goto Exit;
  418. }
  419. if (NewTestEntry->UT.Name == NULL) {
  420. Status = EFI_OUT_OF_RESOURCES;
  421. goto Exit;
  422. }
  423. //
  424. // Create the test fingerprint.
  425. //
  426. SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT);
  427. // TODO: Make sure that duplicate fingerprints cannot be created.
  428. //
  429. // If there is saved test data, update this record.
  430. //
  431. if (ParentFramework->SavedState != NULL) {
  432. UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState);
  433. }
  434. Exit:
  435. //
  436. // If everything is going well, add the new suite to the tail list for the framework.
  437. //
  438. if (!EFI_ERROR (Status)) {
  439. InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY *)NewTestEntry);
  440. Suite->NumTests++;
  441. } else {
  442. //
  443. // Otherwise, make with the destruction.
  444. //
  445. FreeUnitTestTestEntry (NewTestEntry);
  446. }
  447. return Status;
  448. }
  449. STATIC
  450. VOID
  451. UpdateTestFromSave (
  452. IN OUT UNIT_TEST *Test,
  453. IN UNIT_TEST_SAVE_HEADER *SavedState
  454. )
  455. {
  456. UNIT_TEST_SAVE_TEST *CurrentTest;
  457. UNIT_TEST_SAVE_TEST *MatchingTest;
  458. UINT8 *FloatingPointer;
  459. UNIT_TEST_SAVE_CONTEXT *SavedContext;
  460. UINTN Index;
  461. //
  462. // First, evaluate the inputs.
  463. //
  464. if ((Test == NULL) || (SavedState == NULL)) {
  465. return;
  466. }
  467. if (SavedState->TestCount == 0) {
  468. return;
  469. }
  470. //
  471. // Next, determine whether a matching test can be found.
  472. // Start at the beginning.
  473. //
  474. MatchingTest = NULL;
  475. FloatingPointer = (UINT8 *)SavedState + sizeof (*SavedState);
  476. for (Index = 0; Index < SavedState->TestCount; Index++) {
  477. CurrentTest = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
  478. if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerprint[0])) {
  479. MatchingTest = CurrentTest;
  480. //
  481. // If there's a saved context, it's important that we iterate through the entire list.
  482. //
  483. if (!SavedState->HasSavedContext) {
  484. break;
  485. }
  486. }
  487. //
  488. // If we didn't find it, we have to increment to the next test.
  489. //
  490. FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size;
  491. }
  492. //
  493. // If a matching test was found, copy the status.
  494. //
  495. if (MatchingTest) {
  496. //
  497. // Override the test status with the saved status.
  498. //
  499. Test->Result = MatchingTest->Result;
  500. Test->FailureType = MatchingTest->FailureType;
  501. AsciiStrnCpyS (
  502. &Test->FailureMessage[0],
  503. UNIT_TEST_TESTFAILUREMSG_LENGTH,
  504. &MatchingTest->FailureMessage[0],
  505. UNIT_TEST_TESTFAILUREMSG_LENGTH
  506. );
  507. //
  508. // If there is a log string associated, grab that.
  509. // We can tell that there's a log string because the "size" will be larger than
  510. // the structure size.
  511. // IMPORTANT NOTE: There are security implications here.
  512. // This data is user-supplied and we're about to play kinda
  513. // fast and loose with data buffers.
  514. //
  515. if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) {
  516. UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST));
  517. }
  518. }
  519. //
  520. // If the saved context exists and matches this test, grab it, too.
  521. //
  522. if (SavedState->HasSavedContext) {
  523. //
  524. // If there was a saved context, the "matching test" loop will have placed the FloatingPointer
  525. // at the beginning of the context structure.
  526. //
  527. SavedContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;
  528. if (((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0) &&
  529. CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerprint[0]))
  530. {
  531. //
  532. // Override the test context with the saved context.
  533. //
  534. Test->Context = (VOID *)SavedContext->Data;
  535. }
  536. }
  537. }
  538. STATIC
  539. UNIT_TEST_SAVE_HEADER *
  540. SerializeState (
  541. IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle,
  542. IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
  543. IN UINTN ContextToSaveSize
  544. )
  545. {
  546. UNIT_TEST_FRAMEWORK *Framework;
  547. UNIT_TEST_SAVE_HEADER *Header;
  548. LIST_ENTRY *SuiteListHead;
  549. LIST_ENTRY *Suite;
  550. LIST_ENTRY *TestListHead;
  551. LIST_ENTRY *Test;
  552. UINT32 TestCount;
  553. UINT32 TotalSize;
  554. UINTN LogSize;
  555. UNIT_TEST_SAVE_TEST *TestSaveData;
  556. UNIT_TEST_SAVE_CONTEXT *TestSaveContext;
  557. UNIT_TEST *UnitTest;
  558. UINT8 *FloatingPointer;
  559. Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
  560. Header = NULL;
  561. //
  562. // First, let's not make assumptions about the parameters.
  563. //
  564. if ((Framework == NULL) ||
  565. ((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
  566. (ContextToSaveSize > MAX_UINT32))
  567. {
  568. return NULL;
  569. }
  570. //
  571. // Next, we've gotta figure out the resources that will be required to serialize the
  572. // the framework state so that we can persist it.
  573. // To start with, we're gonna need a header.
  574. //
  575. TotalSize = sizeof (UNIT_TEST_SAVE_HEADER);
  576. //
  577. // Now we need to figure out how many tests there are.
  578. //
  579. TestCount = 0;
  580. //
  581. // Iterate all suites.
  582. //
  583. SuiteListHead = &Framework->TestSuiteList;
  584. for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
  585. //
  586. // Iterate all tests within the suite.
  587. //
  588. TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
  589. for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
  590. UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
  591. //
  592. // Account for the size of a test structure.
  593. //
  594. TotalSize += sizeof (UNIT_TEST_SAVE_TEST);
  595. //
  596. // If there's a log, make sure to account for the log size.
  597. //
  598. if (UnitTest->Log != NULL) {
  599. //
  600. // The +1 is for the NULL character. Can't forget the NULL character.
  601. //
  602. LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
  603. ASSERT (LogSize < MAX_UINT32);
  604. TotalSize += (UINT32)LogSize;
  605. }
  606. //
  607. // Increment the test count.
  608. //
  609. TestCount++;
  610. }
  611. }
  612. //
  613. // If there are no tests, we're done here.
  614. //
  615. if (TestCount == 0) {
  616. return NULL;
  617. }
  618. //
  619. // Add room for the context, if there is one.
  620. //
  621. if (ContextToSave != NULL) {
  622. TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize;
  623. }
  624. //
  625. // Now that we know the size, we need to allocate space for the serialized output.
  626. //
  627. Header = AllocateZeroPool (TotalSize);
  628. if (Header == NULL) {
  629. return NULL;
  630. }
  631. //
  632. // Alright, let's start setting up some data.
  633. //
  634. Header->Version = UNIT_TEST_PERSISTENCE_LIB_VERSION;
  635. Header->SaveStateSize = TotalSize;
  636. CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
  637. CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME));
  638. Header->TestCount = TestCount;
  639. Header->HasSavedContext = FALSE;
  640. //
  641. // Start adding all of the test cases.
  642. // Set the floating pointer to the start of the current test save buffer.
  643. //
  644. FloatingPointer = (UINT8 *)Header + sizeof (UNIT_TEST_SAVE_HEADER);
  645. //
  646. // Iterate all suites.
  647. //
  648. SuiteListHead = &Framework->TestSuiteList;
  649. for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
  650. //
  651. // Iterate all tests within the suite.
  652. //
  653. TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
  654. for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
  655. TestSaveData = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
  656. UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
  657. //
  658. // Save the fingerprint.
  659. //
  660. CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
  661. //
  662. // Save the result.
  663. //
  664. TestSaveData->Result = UnitTest->Result;
  665. TestSaveData->FailureType = UnitTest->FailureType;
  666. AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH);
  667. //
  668. // If there is a log, save the log.
  669. //
  670. FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST);
  671. if (UnitTest->Log != NULL) {
  672. //
  673. // The +1 is for the NULL character. Can't forget the NULL character.
  674. //
  675. LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
  676. CopyMem (FloatingPointer, UnitTest->Log, LogSize);
  677. FloatingPointer += LogSize;
  678. }
  679. //
  680. // Update the size once the structure is complete.
  681. // NOTE: Should this be a straight cast without validation?
  682. //
  683. TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData);
  684. }
  685. }
  686. //
  687. // If there is a context to save, let's do that now.
  688. //
  689. if ((ContextToSave != NULL) && (Framework->CurrentTest != NULL)) {
  690. TestSaveContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;
  691. TestSaveContext->Size = (UINT32)ContextToSaveSize + sizeof (UNIT_TEST_SAVE_CONTEXT);
  692. CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
  693. CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)), ContextToSave, ContextToSaveSize);
  694. Header->HasSavedContext = TRUE;
  695. }
  696. return Header;
  697. }
  698. /**
  699. Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're
  700. a framework author) to save the state of the executing framework along with
  701. any allocated data so that the test may be resumed upon reentry. A test case
  702. should pass any needed context (which, to prevent an infinite loop, should be
  703. at least the current execution count) which will be saved by the framework and
  704. passed to the test case upon resume.
  705. This should be called while the current test framework is valid and active. It is
  706. generally called from within a test case prior to quitting or rebooting.
  707. @param[in] ContextToSave A buffer of test case-specific data to be saved
  708. along with framework state. Will be passed as
  709. "Context" to the test case upon resume. This
  710. is an optional parameter that may be NULL.
  711. @param[in] ContextToSaveSize Size of the ContextToSave buffer.
  712. @retval EFI_SUCCESS The framework state and context were saved.
  713. @retval EFI_NOT_FOUND An active framework handle was not found.
  714. @retval EFI_INVALID_PARAMETER ContextToSave is not NULL and
  715. ContextToSaveSize is 0.
  716. @retval EFI_INVALID_PARAMETER ContextToSave is >= 4GB.
  717. @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
  718. save the framework and context state.
  719. @retval EFI_DEVICE_ERROR The framework and context state could not be
  720. saved to a persistent storage device due to a
  721. device error.
  722. **/
  723. EFI_STATUS
  724. EFIAPI
  725. SaveFrameworkState (
  726. IN UNIT_TEST_CONTEXT ContextToSave OPTIONAL,
  727. IN UINTN ContextToSaveSize
  728. )
  729. {
  730. EFI_STATUS Status;
  731. UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle;
  732. UNIT_TEST_SAVE_HEADER *Header;
  733. Header = NULL;
  734. FrameworkHandle = GetActiveFrameworkHandle ();
  735. //
  736. // Return a unique error code if the framework is not set.
  737. //
  738. if (FrameworkHandle == NULL) {
  739. return EFI_NOT_FOUND;
  740. }
  741. //
  742. // First, let's not make assumptions about the parameters.
  743. //
  744. if (((ContextToSave != NULL) && (ContextToSaveSize == 0)) ||
  745. (ContextToSaveSize > MAX_UINT32))
  746. {
  747. return EFI_INVALID_PARAMETER;
  748. }
  749. //
  750. // Now, let's package up all the data for saving.
  751. //
  752. Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize);
  753. if (Header == NULL) {
  754. return EFI_OUT_OF_RESOURCES;
  755. }
  756. //
  757. // All that should be left to do is save it using the associated persistence lib.
  758. //
  759. Status = SaveUnitTestCache (FrameworkHandle, Header, Header->SaveStateSize);
  760. if (EFI_ERROR (Status)) {
  761. DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __FUNCTION__, Status));
  762. Status = EFI_DEVICE_ERROR;
  763. }
  764. //
  765. // Free data that was used.
  766. //
  767. FreePool (Header);
  768. return Status;
  769. }