1 /**
2   Implement UnitTestLib assert services
3 
4   Copyright (c) Microsoft Corporation.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 **/
7 
8 #include <Uefi.h>
9 #include <UnitTestFrameworkTypes.h>
10 #include <Library/UnitTestLib.h>
11 #include <Library/BaseLib.h>
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/PrintLib.h>
15 
16 extern BASE_LIBRARY_JUMP_BUFFER  gUnitTestJumpBuffer;
17 
18 STATIC
19 EFI_STATUS
AddUnitTestFailure(IN OUT UNIT_TEST * UnitTest,IN CONST CHAR8 * FailureMessage,IN FAILURE_TYPE FailureType)20 AddUnitTestFailure (
21   IN OUT UNIT_TEST     *UnitTest,
22   IN     CONST CHAR8   *FailureMessage,
23   IN     FAILURE_TYPE  FailureType
24   )
25 {
26   //
27   // Make sure that you're cooking with gas.
28   //
29   if (UnitTest == NULL || FailureMessage == NULL) {
30     return EFI_INVALID_PARAMETER;
31   }
32 
33   UnitTest->FailureType = FailureType;
34   AsciiStrCpyS (
35     &UnitTest->FailureMessage[0],
36     UNIT_TEST_TESTFAILUREMSG_LENGTH,
37     FailureMessage
38     );
39 
40   return EFI_SUCCESS;
41 }
42 
43 STATIC
44 VOID
UnitTestLogFailure(IN FAILURE_TYPE FailureType,IN CONST CHAR8 * Format,...)45 UnitTestLogFailure (
46   IN FAILURE_TYPE  FailureType,
47   IN CONST CHAR8   *Format,
48   ...
49   )
50 {
51   UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle;
52   CHAR8                       LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH];
53   VA_LIST                     Marker;
54 
55   //
56   // Get active Framework handle
57   //
58   FrameworkHandle = GetActiveFrameworkHandle ();
59 
60   //
61   // Convert the message to an ASCII String
62   //
63   VA_START (Marker, Format);
64   AsciiVSPrint (LogString, sizeof (LogString), Format, Marker);
65   VA_END (Marker);
66 
67   //
68   // Finally, add the string to the log.
69   //
70   AddUnitTestFailure (
71     ((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest,
72     LogString,
73     FailureType
74     );
75 
76   LongJump (&gUnitTestJumpBuffer, 1);
77 }
78 
79 /**
80   If Expression is TRUE, then TRUE is returned.
81   If Expression is FALSE, then an assert is triggered and the location of the
82   assert provided by FunctionName, LineNumber, FileName, and Description are
83   recorded and FALSE is returned.
84 
85   @param[in]  Expression    The BOOLEAN result of the expression evaluation.
86   @param[in]  FunctionName  Null-terminated ASCII string of the function
87                             executing the assert macro.
88   @param[in]  LineNumber    The source file line number of the assert macro.
89   @param[in]  FileName      Null-terminated ASCII string of the filename
90                             executing the assert macro.
91   @param[in]  Description   Null-terminated ASCII string of the expression being
92                             evaluated.
93 
94   @retval  TRUE   Expression is TRUE.
95   @retval  FALSE  Expression is FALSE.
96 **/
97 BOOLEAN
98 EFIAPI
UnitTestAssertTrue(IN BOOLEAN Expression,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * Description)99 UnitTestAssertTrue (
100   IN BOOLEAN      Expression,
101   IN CONST CHAR8  *FunctionName,
102   IN UINTN        LineNumber,
103   IN CONST CHAR8  *FileName,
104   IN CONST CHAR8  *Description
105   )
106 {
107   if (!Expression) {
108     UT_LOG_ERROR (
109       "[ASSERT FAIL] %a:%d: Expression (%a) is not TRUE!\n",
110       FileName,
111       LineNumber,
112       Description
113       );
114     UnitTestLogFailure (
115       FAILURETYPE_ASSERTTRUE,
116       "%a:%d: Expression (%a) is not TRUE!\n",
117       FileName,
118       LineNumber,
119       Description
120       );
121   }
122   return Expression;
123 }
124 
125 /**
126   If Expression is FALSE, then TRUE is returned.
127   If Expression is TRUE, then an assert is triggered and the location of the
128   assert provided by FunctionName, LineNumber, FileName, and Description are
129   recorded and FALSE is returned.
130 
131   @param[in]  Expression    The BOOLEAN result of the expression evaluation.
132   @param[in]  FunctionName  Null-terminated ASCII string of the function
133                             executing the assert macro.
134   @param[in]  LineNumber    The source file line number of the assert macro.
135   @param[in]  FileName      Null-terminated ASCII string of the filename
136                             executing the assert macro.
137   @param[in]  Description   Null-terminated ASCII string of the expression being
138                             evaluated.
139 
140   @retval  TRUE   Expression is FALSE.
141   @retval  FALSE  Expression is TRUE.
142 **/
143 BOOLEAN
144 EFIAPI
UnitTestAssertFalse(IN BOOLEAN Expression,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * Description)145 UnitTestAssertFalse (
146   IN BOOLEAN      Expression,
147   IN CONST CHAR8  *FunctionName,
148   IN UINTN        LineNumber,
149   IN CONST CHAR8  *FileName,
150   IN CONST CHAR8  *Description
151   )
152 {
153   if (Expression) {
154     UT_LOG_ERROR (
155       "[ASSERT FAIL] %a:%d: Expression (%a) is not FALSE!\n",
156       FileName,
157       LineNumber,
158       Description
159       );
160     UnitTestLogFailure (
161       FAILURETYPE_ASSERTFALSE,
162       "%a:%d: Expression(%a) is not FALSE!\n",
163       FileName,
164       LineNumber,
165       Description
166       );
167   }
168   return !Expression;
169 }
170 
171 /**
172   If Status is not an EFI_ERROR(), then TRUE is returned.
173   If Status is an EFI_ERROR(), then an assert is triggered and the location of
174   the assert provided by FunctionName, LineNumber, FileName, and Description are
175   recorded and FALSE is returned.
176 
177   @param[in]  Status        The EFI_STATUS value to evaluate.
178   @param[in]  FunctionName  Null-terminated ASCII string of the function
179                             executing the assert macro.
180   @param[in]  LineNumber    The source file line number of the assert macro.
181   @param[in]  FileName      Null-terminated ASCII string of the filename
182                             executing the assert macro.
183   @param[in]  Description   Null-terminated ASCII string of the status
184                             expression being evaluated.
185 
186   @retval  TRUE   Status is not an EFI_ERROR().
187   @retval  FALSE  Status is an EFI_ERROR().
188 **/
189 BOOLEAN
190 EFIAPI
UnitTestAssertNotEfiError(IN EFI_STATUS Status,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * Description)191 UnitTestAssertNotEfiError (
192   IN EFI_STATUS   Status,
193   IN CONST CHAR8  *FunctionName,
194   IN UINTN        LineNumber,
195   IN CONST CHAR8  *FileName,
196   IN CONST CHAR8  *Description
197   )
198 {
199   if (EFI_ERROR (Status)) {
200     UT_LOG_ERROR (
201       "[ASSERT FAIL] %a:%d: Status '%a' is EFI_ERROR (%r)!\n",
202       FileName,
203       LineNumber,
204       Description,
205       Status
206       );
207     UnitTestLogFailure (
208       FAILURETYPE_ASSERTNOTEFIERROR,
209       "%a:%d: Status '%a' is EFI_ERROR (%r)!\n",
210       FileName,
211       LineNumber,
212       Description,
213       Status
214       );
215   }
216   return !EFI_ERROR( Status );
217 }
218 
219 /**
220   If ValueA is equal ValueB, then TRUE is returned.
221   If ValueA is not equal to ValueB, then an assert is triggered and the location
222   of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,
223   and DescriptionB are recorded and FALSE is returned.
224 
225   @param[in]  ValueA        64-bit value.
226   @param[in]  ValueB        64-bit value.
227   @param[in]  FunctionName  Null-terminated ASCII string of the function
228                             executing the assert macro.
229   @param[in]  LineNumber    The source file line number of the assert macro.
230   @param[in]  FileName      Null-terminated ASCII string of the filename
231                             executing the assert macro.
232   @param[in]  DescriptionA  Null-terminated ASCII string that is a description
233                             of ValueA.
234   @param[in]  DescriptionB  Null-terminated ASCII string that is a description
235                             of ValueB.
236 
237   @retval  TRUE   ValueA is equal to ValueB.
238   @retval  FALSE  ValueA is not equal to ValueB.
239 **/
240 BOOLEAN
241 EFIAPI
UnitTestAssertEqual(IN UINT64 ValueA,IN UINT64 ValueB,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * DescriptionA,IN CONST CHAR8 * DescriptionB)242 UnitTestAssertEqual (
243   IN UINT64       ValueA,
244   IN UINT64       ValueB,
245   IN CONST CHAR8  *FunctionName,
246   IN UINTN        LineNumber,
247   IN CONST CHAR8  *FileName,
248   IN CONST CHAR8  *DescriptionA,
249   IN CONST CHAR8  *DescriptionB
250   )
251 {
252   if (ValueA != ValueB) {
253     UT_LOG_ERROR (
254       "[ASSERT FAIL] %a:%d: Value %a != %a (%d != %d)!\n",
255       FileName,
256       LineNumber,
257       DescriptionA,
258       DescriptionB,
259       ValueA,
260       ValueB
261       );
262     UnitTestLogFailure (
263       FAILURETYPE_ASSERTEQUAL,
264       "%a:%d: Value %a != %a (%d != %d)!\n",
265       FileName,
266       LineNumber,
267       DescriptionA,
268       DescriptionB,
269       ValueA,
270       ValueB
271       );
272   }
273   return (ValueA == ValueB);
274 }
275 
276 /**
277   If the contents of BufferA are identical to the contents of BufferB, then TRUE
278   is returned.  If the contents of BufferA are not identical to the contents of
279   BufferB, then an assert is triggered and the location of the assert provided
280   by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are
281   recorded and FALSE is returned.
282 
283   @param[in]  BufferA       Pointer to a buffer for comparison.
284   @param[in]  BufferB       Pointer to a buffer for comparison.
285   @param[in]  Length        Number of bytes to compare in BufferA and BufferB.
286   @param[in]  FunctionName  Null-terminated ASCII string of the function
287                             executing the assert macro.
288   @param[in]  LineNumber    The source file line number of the assert macro.
289   @param[in]  FileName      Null-terminated ASCII string of the filename
290                             executing the assert macro.
291   @param[in]  DescriptionA  Null-terminated ASCII string that is a description
292                             of BufferA.
293   @param[in]  DescriptionB  Null-terminated ASCII string that is a description
294                             of BufferB.
295 
296   @retval  TRUE   The contents of BufferA are identical to the contents of
297                   BufferB.
298   @retval  FALSE  The contents of BufferA are not identical to the contents of
299                   BufferB.
300 **/
301 BOOLEAN
302 EFIAPI
UnitTestAssertMemEqual(IN VOID * BufferA,IN VOID * BufferB,IN UINTN Length,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * DescriptionA,IN CONST CHAR8 * DescriptionB)303 UnitTestAssertMemEqual (
304   IN VOID         *BufferA,
305   IN VOID         *BufferB,
306   IN UINTN        Length,
307   IN CONST CHAR8  *FunctionName,
308   IN UINTN        LineNumber,
309   IN CONST CHAR8  *FileName,
310   IN CONST CHAR8  *DescriptionA,
311   IN CONST CHAR8  *DescriptionB
312   )
313 {
314   if (CompareMem(BufferA, BufferB, Length) != 0) {
315     UT_LOG_ERROR (
316       "[ASSERT FAIL] %a:%d: Value %a != %a for length %d bytes!\n",
317       FileName,
318       LineNumber,
319       DescriptionA,
320       DescriptionB,
321       Length
322       );
323     UnitTestLogFailure (
324       FAILURETYPE_ASSERTEQUAL,
325       "%a:%d: Memory at %a != %a for length %d bytes!\n",
326       FileName,
327       LineNumber,
328       DescriptionA,
329       DescriptionB,
330       Length
331       );
332     return FALSE;
333   }
334   return TRUE;
335 }
336 
337 /**
338   If ValueA is not equal ValueB, then TRUE is returned.
339   If ValueA is equal to ValueB, then an assert is triggered and the location
340   of the assert provided by FunctionName, LineNumber, FileName, DescriptionA
341   and DescriptionB are recorded and FALSE is returned.
342 
343   @param[in]  ValueA        64-bit value.
344   @param[in]  ValueB        64-bit value.
345   @param[in]  FunctionName  Null-terminated ASCII string of the function
346                             executing the assert macro.
347   @param[in]  LineNumber    The source file line number of the assert macro.
348   @param[in]  FileName      Null-terminated ASCII string of the filename
349                             executing the assert macro.
350   @param[in]  DescriptionA  Null-terminated ASCII string that is a description
351                             of ValueA.
352   @param[in]  DescriptionB  Null-terminated ASCII string that is a description
353                             of ValueB.
354 
355   @retval  TRUE   ValueA is not equal to ValueB.
356   @retval  FALSE  ValueA is equal to ValueB.
357 **/
358 BOOLEAN
359 EFIAPI
UnitTestAssertNotEqual(IN UINT64 ValueA,IN UINT64 ValueB,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * DescriptionA,IN CONST CHAR8 * DescriptionB)360 UnitTestAssertNotEqual (
361   IN UINT64       ValueA,
362   IN UINT64       ValueB,
363   IN CONST CHAR8  *FunctionName,
364   IN UINTN        LineNumber,
365   IN CONST CHAR8  *FileName,
366   IN CONST CHAR8  *DescriptionA,
367   IN CONST CHAR8  *DescriptionB
368   )
369 {
370   if (ValueA == ValueB) {
371     UT_LOG_ERROR (
372       "[ASSERT FAIL] %a:%d: Value %a == %a (%d == %d)!\n",
373       FileName,
374       LineNumber,
375       DescriptionA,
376       DescriptionB,
377       ValueA,
378       ValueB
379       );
380     UnitTestLogFailure (
381       FAILURETYPE_ASSERTNOTEQUAL,
382       "%a:%d: Value %a == %a (%d == %d)!\n",
383       FileName,
384       LineNumber,
385       DescriptionA,
386       DescriptionB,
387       ValueA,
388       ValueB
389       );
390   }
391   return (ValueA != ValueB);
392 }
393 
394 /**
395   If Status is equal to Expected, then TRUE is returned.
396   If Status is not equal to Expected, then an assert is triggered and the
397   location of the assert provided by FunctionName, LineNumber, FileName, and
398   Description are recorded and FALSE is returned.
399 
400   @param[in]  Status        EFI_STATUS value returned from an API under test.
401   @param[in]  Expected      The expected EFI_STATUS return value from an API
402                             under test.
403   @param[in]  FunctionName  Null-terminated ASCII string of the function
404                             executing the assert macro.
405   @param[in]  LineNumber    The source file line number of the assert macro.
406   @param[in]  FileName      Null-terminated ASCII string of the filename
407                             executing the assert macro.
408   @param[in]  Description   Null-terminated ASCII string that is a description
409                             of Status.
410 
411   @retval  TRUE   Status is equal to Expected.
412   @retval  FALSE  Status is not equal to Expected.
413 **/
414 BOOLEAN
415 EFIAPI
UnitTestAssertStatusEqual(IN EFI_STATUS Status,IN EFI_STATUS Expected,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * Description)416 UnitTestAssertStatusEqual (
417   IN EFI_STATUS   Status,
418   IN EFI_STATUS   Expected,
419   IN CONST CHAR8  *FunctionName,
420   IN UINTN        LineNumber,
421   IN CONST CHAR8  *FileName,
422   IN CONST CHAR8  *Description
423   )
424 {
425   if (Status != Expected) {
426     UT_LOG_ERROR (
427       "[ASSERT FAIL] %a:%d: Status '%a' is %r, should be %r!\n",
428       FileName,
429       LineNumber,
430       Description,
431       Status,
432       Expected
433       );
434     UnitTestLogFailure (
435       FAILURETYPE_ASSERTSTATUSEQUAL,
436       "%a:%d: Status '%a' is %r, should be %r!\n",
437       FileName,
438       LineNumber,
439       Description,
440       Status,
441       Expected
442       );
443   }
444   return (Status == Expected);
445 }
446 
447 /**
448   If Pointer is not equal to NULL, then TRUE is returned.
449   If Pointer is equal to NULL, then an assert is triggered and the location of
450   the assert provided by FunctionName, LineNumber, FileName, and PointerName
451   are recorded and FALSE is returned.
452 
453   @param[in]  Pointer       Pointer value to be checked against NULL.
454   @param[in]  Expected      The expected EFI_STATUS return value from a function
455                             under test.
456   @param[in]  FunctionName  Null-terminated ASCII string of the function
457                             executing the assert macro.
458   @param[in]  LineNumber    The source file line number of the assert macro.
459   @param[in]  FileName      Null-terminated ASCII string of the filename
460                             executing the assert macro.
461   @param[in]  PointerName   Null-terminated ASCII string that is a description
462                             of Pointer.
463 
464   @retval  TRUE   Pointer is not equal to NULL.
465   @retval  FALSE  Pointer is equal to NULL.
466 **/
467 BOOLEAN
468 EFIAPI
UnitTestAssertNotNull(IN VOID * Pointer,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * PointerName)469 UnitTestAssertNotNull (
470   IN VOID         *Pointer,
471   IN CONST CHAR8  *FunctionName,
472   IN UINTN        LineNumber,
473   IN CONST CHAR8  *FileName,
474   IN CONST CHAR8  *PointerName
475   )
476 {
477   if (Pointer == NULL) {
478     UT_LOG_ERROR (
479       "[ASSERT FAIL] %a:%d: Pointer (%a) is NULL!\n",
480       FileName,
481       LineNumber,
482       PointerName
483       );
484     UnitTestLogFailure (
485       FAILURETYPE_ASSERTNOTNULL,
486       "%a:%d: Pointer (%a) is NULL!\n",
487       FileName,
488       LineNumber,
489       PointerName
490       );
491   }
492   return (Pointer != NULL);
493 }
494 
495 /**
496   If UnitTestStatus is UNIT_TEST_PASSED, then log an info message and return
497   TRUE because an ASSERT() was expected when FunctionCall was executed and an
498   ASSERT() was triggered. If UnitTestStatus is UNIT_TEST_SKIPPED, then log a
499   warning message and return TRUE because ASSERT() macros are disabled.  If
500   UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED, then log an error message and
501   return FALSE because an ASSERT() was expected when FunctionCall was executed,
502   but no ASSERT() conditions were triggered.  The log messages contain
503   FunctionName, LineNumber, and FileName strings to provide the location of the
504   UT_EXPECT_ASSERT_FAILURE() macro.
505 
506   @param[in]  UnitTestStatus  The status from UT_EXPECT_ASSERT_FAILURE() that
507                               is either pass, skipped, or failed.
508   @param[in]  FunctionName    Null-terminated ASCII string of the function
509                               executing the UT_EXPECT_ASSERT_FAILURE() macro.
510   @param[in]  LineNumber      The source file line number of the the function
511                               executing the UT_EXPECT_ASSERT_FAILURE() macro.
512   @param[in]  FileName        Null-terminated ASCII string of the filename
513                               executing the UT_EXPECT_ASSERT_FAILURE() macro.
514   @param[in]  FunctionCall    Null-terminated ASCII string of the function call
515                               executed by the UT_EXPECT_ASSERT_FAILURE() macro.
516   @param[out] ResultStatus    Used to return the UnitTestStatus value to the
517                               caller of UT_EXPECT_ASSERT_FAILURE().  This is
518                               optional parameter that may be NULL.
519 
520   @retval  TRUE   UnitTestStatus is UNIT_TEST_PASSED.
521   @retval  TRUE   UnitTestStatus is UNIT_TEST_SKIPPED.
522   @retval  FALSE  UnitTestStatus is UNIT_TEST_ERROR_TEST_FAILED.
523 **/
524 BOOLEAN
525 EFIAPI
UnitTestExpectAssertFailure(IN UNIT_TEST_STATUS UnitTestStatus,IN CONST CHAR8 * FunctionName,IN UINTN LineNumber,IN CONST CHAR8 * FileName,IN CONST CHAR8 * FunctionCall,OUT UNIT_TEST_STATUS * ResultStatus OPTIONAL)526 UnitTestExpectAssertFailure (
527   IN  UNIT_TEST_STATUS  UnitTestStatus,
528   IN  CONST CHAR8       *FunctionName,
529   IN  UINTN             LineNumber,
530   IN  CONST CHAR8       *FileName,
531   IN  CONST CHAR8       *FunctionCall,
532   OUT UNIT_TEST_STATUS  *ResultStatus  OPTIONAL
533   )
534 {
535   if (ResultStatus != NULL) {
536     *ResultStatus = UnitTestStatus;
537   }
538   if (UnitTestStatus == UNIT_TEST_PASSED) {
539     UT_LOG_INFO (
540       "[ASSERT PASS] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) detected expected assert\n",
541       FileName,
542       LineNumber,
543       FunctionCall
544       );
545   }
546   if (UnitTestStatus == UNIT_TEST_SKIPPED) {
547     UT_LOG_WARNING (
548       "[ASSERT WARN] %a:%d: UT_EXPECT_ASSERT_FAILURE(%a) disabled\n",
549       FileName,
550       LineNumber,
551       FunctionCall
552       );
553   }
554   if (UnitTestStatus == UNIT_TEST_ERROR_TEST_FAILED) {
555     UT_LOG_ERROR (
556       "[ASSERT FAIL] %a:%d: Function call (%a) did not ASSERT()!\n",
557       FileName,
558       LineNumber,
559       FunctionCall
560       );
561     UnitTestLogFailure (
562       FAILURETYPE_EXPECTASSERT,
563       "%a:%d: Function call (%a) did not ASSERT()!\n",
564       FileName,
565       LineNumber,
566       FunctionCall
567       );
568   }
569   return (UnitTestStatus != UNIT_TEST_ERROR_TEST_FAILED);
570 }
571