1 /** @file
2   Unit tests of EvaluateDependency API in FmpDependencyLib.
3 
4   Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <Uefi.h>
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/FmpDependencyLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/UnitTestLib.h>
16 
17 #define UNIT_TEST_APP_NAME     "FmpDependencyLib Unit Test Application"
18 #define UNIT_TEST_APP_VERSION  "1.0"
19 
20 typedef struct {
21     UINT8       *Dependencies;
22     UINTN       DependenciesSize;
23     BOOLEAN     ExpectedResult;
24 } BASIC_TEST_CONTEXT;
25 
26 //
27 // Image Type ID of FMP device A
28 //
29 #define IMAGE_TYPE_ID_1   { 0x97144DFA, 0xEB8E, 0xD14D, {0x8B, 0x4D, 0x39, 0x88, 0x24, 0x96, 0x56, 0x42}}
30 
31 //
32 // Image Type ID of FMP device B
33 //
34 #define IMAGE_TYPE_ID_2   { 0xA42A7370, 0x433A, 0x684D, {0x9A, 0xA1, 0xDE, 0x62, 0x23, 0x30, 0x6C, 0xF3}}
35 
36 //
37 // Device A's version is 0x00000002
38 // Device B's version is 0x00000003
39 //
40 static FMP_DEPEX_CHECK_VERSION_DATA mFmpVersions[] = {
41   {IMAGE_TYPE_ID_1, 0x00000002},
42   {IMAGE_TYPE_ID_2, 0x00000003}
43 };
44 
45 // Valid Dependency Expression 1: (Version(A) > 0x00000001) && (Version(B) >= 0x00000003)
46 static UINT8 mExpression1[] = {
47   EFI_FMP_DEP_PUSH_VERSION, 0x01, 0x00, 0x00, 0x00,
48   EFI_FMP_DEP_PUSH_GUID, 0xFA, 0x4D, 0x14, 0x97, 0x8E, 0xEB, 0x4D, 0xD1, 0x8B, 0x4D, 0x39, 0x88, 0x24, 0x96, 0x56, 0x42,
49   EFI_FMP_DEP_GT,
50   EFI_FMP_DEP_PUSH_VERSION, 0x03, 0x00, 0x00, 0x00,
51   EFI_FMP_DEP_PUSH_GUID, 0x70, 0x73, 0x2A, 0xA4, 0x3A, 0x43, 0x4D, 0x68, 0x9A, 0xA1, 0xDE, 0x62, 0x23, 0x30, 0x6C, 0xF3,
52   EFI_FMP_DEP_GTE,
53   EFI_FMP_DEP_AND,
54   EFI_FMP_DEP_END
55 };
56 
57 // Valid Dependency Expression 2: (Version(A) < 0x00000002) || (Version(B) <= 0x00000003)
58 static UINT8 mExpression2[] = {
59   EFI_FMP_DEP_PUSH_VERSION, 0x02, 0x00, 0x00, 0x00,
60   EFI_FMP_DEP_PUSH_GUID, 0xFA, 0x4D, 0x14, 0x97, 0x8E, 0xEB, 0x4D, 0xD1, 0x8B, 0x4D, 0x39, 0x88, 0x24, 0x96, 0x56, 0x42,
61   EFI_FMP_DEP_LT,
62   EFI_FMP_DEP_PUSH_VERSION, 0x03, 0x00, 0x00, 0x00,
63   EFI_FMP_DEP_PUSH_GUID, 0x70, 0x73, 0x2A, 0xA4, 0x3A, 0x43, 0x4D, 0x68, 0x9A, 0xA1, 0xDE, 0x62, 0x23, 0x30, 0x6C, 0xF3,
64   EFI_FMP_DEP_LTE,
65   EFI_FMP_DEP_OR,
66   EFI_FMP_DEP_END
67 };
68 
69 // Valid Dependency Expression 3: !(Version(A) == 0x0000002)
70 static UINT8 mExpression3[] = {
71   EFI_FMP_DEP_PUSH_VERSION, 0x02, 0x00, 0x00, 0x00,
72   EFI_FMP_DEP_PUSH_GUID, 0xFA, 0x4D, 0x14, 0x97, 0x8E, 0xEB, 0x4D, 0xD1, 0x8B, 0x4D, 0x39, 0x88, 0x24, 0x96, 0x56, 0x42,
73   EFI_FMP_DEP_EQ,
74   EFI_FMP_DEP_NOT,
75   EFI_FMP_DEP_END
76 };
77 
78 // Valid Dependency Expression 4: "Test" TRUE && FALSE
79 static UINT8 mExpression4[] = {
80   EFI_FMP_DEP_VERSION_STR, 'T', 'e', 's', 't', '\0',
81   EFI_FMP_DEP_TRUE,
82   EFI_FMP_DEP_FALSE,
83   EFI_FMP_DEP_AND,
84   EFI_FMP_DEP_END
85 };
86 
87 // Invalid Dependency Expression 1: Invalid Op-code
88 static UINT8 mExpression5[] = {EFI_FMP_DEP_TRUE, 0xAA, EFI_FMP_DEP_END};
89 
90 // Invalid Dependency Expression 2: String doesn't end with '\0'
91 static UINT8 mExpression6[] = {EFI_FMP_DEP_VERSION_STR, 'T', 'e', 's', 't', EFI_FMP_DEP_TRUE, EFI_FMP_DEP_END};
92 
93 // Invalid Dependency Expression 3: GUID is in invalid size
94 static UINT8 mExpression7[] = {
95   EFI_FMP_DEP_PUSH_VERSION, 0x02, 0x00, 0x00, 0x00,
96   EFI_FMP_DEP_PUSH_GUID, 0xAA, 0xBB, 0xCC, 0xDD,
97   EFI_FMP_DEP_GTE,
98   EFI_FMP_DEP_END
99 };
100 
101 // Invalid Dependency Expression 4: Version is in invalid size
102 static UINT8 mExpression8[] = {
103   EFI_FMP_DEP_PUSH_VERSION, 0x02, 0x00,
104   EFI_FMP_DEP_PUSH_GUID, 0xDA, 0xCB, 0x25, 0xAC, 0x9E, 0xCD, 0x5E, 0xE2, 0x9C, 0x5E, 0x4A, 0x99, 0x35, 0xA7, 0x67, 0x53,
105   EFI_FMP_DEP_GTE,
106   EFI_FMP_DEP_END
107 };
108 
109 // Invalid Dependency Expression 5: Operand and operator mismatch
110 static UINT8 mExpression9[] = {EFI_FMP_DEP_TRUE, EFI_FMP_DEP_FALSE, EFI_FMP_DEP_GTE, EFI_FMP_DEP_END};
111 
112 // Invalid Dependency Expression 6: GUID is NOT FOUND
113 static UINT8 mExpression10[] = {
114   EFI_FMP_DEP_PUSH_VERSION, 0x02, 0x00, 0x00, 0x00,
115   EFI_FMP_DEP_PUSH_GUID, 0xDA, 0xCB, 0x25, 0xAC, 0x9E, 0xCD, 0x5E, 0xE2, 0x9C, 0x5E, 0x4A, 0x99, 0x35, 0xA7, 0x67, 0x53,
116   EFI_FMP_DEP_GT,
117   EFI_FMP_DEP_END
118 };
119 
120 // Invalid Dependency Expression 7: Stack underflow
121 static UINT8 mExpression11[] = {
122   EFI_FMP_DEP_PUSH_VERSION, 0x02, 0x00, 0x00, 0x00,
123   EFI_FMP_DEP_GT,
124   EFI_FMP_DEP_END
125 };
126 
127 // ------------------------------------------------Test Depex------Depex Size----------------Expected Result
128 static BASIC_TEST_CONTEXT   mBasicTestTrue1      = {mExpression1,  sizeof(mExpression1),     TRUE};
129 static BASIC_TEST_CONTEXT   mBasicTestTrue2      = {mExpression2,  sizeof(mExpression2),     TRUE};
130 static BASIC_TEST_CONTEXT   mBasicTestFalse1     = {mExpression3,  sizeof(mExpression3),     FALSE};
131 static BASIC_TEST_CONTEXT   mBasicTestFalse2     = {mExpression4,  sizeof(mExpression4),     FALSE};
132 static BASIC_TEST_CONTEXT   mBasicTestInvalid1   = {mExpression1,  sizeof(mExpression1) - 1, FALSE};
133 static BASIC_TEST_CONTEXT   mBasicTestInvalid2   = {mExpression5,  sizeof(mExpression5),     FALSE};
134 static BASIC_TEST_CONTEXT   mBasicTestInvalid3   = {mExpression6,  sizeof(mExpression6),     FALSE};
135 static BASIC_TEST_CONTEXT   mBasicTestInvalid4   = {mExpression7,  sizeof(mExpression7),     FALSE};
136 static BASIC_TEST_CONTEXT   mBasicTestInvalid5   = {mExpression8,  sizeof(mExpression8),     FALSE};
137 static BASIC_TEST_CONTEXT   mBasicTestInvalid6   = {mExpression9,  sizeof(mExpression9),     FALSE};
138 static BASIC_TEST_CONTEXT   mBasicTestInvalid7   = {mExpression10, sizeof(mExpression10),    FALSE};
139 static BASIC_TEST_CONTEXT   mBasicTestInvalid8   = {mExpression11, sizeof(mExpression11),    FALSE};
140 
141 /**
142   Unit test for EvaluateDependency() API of the FmpDependencyLib.
143 
144   @param[in]  Context    [Optional] An optional parameter that enables:
145                          1) test-case reuse with varied parameters and
146                          2) test-case re-entry for Target tests that need a
147                          reboot.  This parameter is a VOID* and it is the
148                          responsibility of the test author to ensure that the
149                          contents are well understood by all test cases that may
150                          consume it.
151 
152   @retval  UNIT_TEST_PASSED             The Unit test has completed and the test
153                                         case was successful.
154   @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
155 **/
156 STATIC
157 UNIT_TEST_STATUS
158 EFIAPI
EvaluateDependencyTest(IN UNIT_TEST_CONTEXT Context)159 EvaluateDependencyTest (
160   IN UNIT_TEST_CONTEXT  Context
161   )
162 {
163   BASIC_TEST_CONTEXT  *TestContext;
164   BOOLEAN             EvaluationResult;
165 
166   TestContext = (BASIC_TEST_CONTEXT *)Context;
167 
168   EvaluationResult = EvaluateDependency (
169                        (EFI_FIRMWARE_IMAGE_DEP *)TestContext->Dependencies,
170                        TestContext->DependenciesSize,
171                        mFmpVersions,
172                        sizeof(mFmpVersions)/sizeof(FMP_DEPEX_CHECK_VERSION_DATA)
173                      );
174 
175   UT_ASSERT_EQUAL (EvaluationResult, TestContext->ExpectedResult);
176 
177   return UNIT_TEST_PASSED;
178 }
179 
180 /**
181   Initialize the unit test framework, suite, and unit tests for the
182   EvaluateDependency API in FmpDependencyLib and run the unit tests.
183 
184   @retval  EFI_SUCCESS           All test cases were dispatched.
185   @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to
186                                  initialize the unit tests.
187 **/
188 STATIC
189 EFI_STATUS
190 EFIAPI
UnitTestingEntry(VOID)191 UnitTestingEntry (
192   VOID
193   )
194 {
195   EFI_STATUS                  Status;
196   UNIT_TEST_FRAMEWORK_HANDLE  Fw;
197   UNIT_TEST_SUITE_HANDLE      DepexEvalTests;
198 
199   Fw = NULL;
200 
201   DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));
202 
203   //
204   // Start setting up the test framework for running the tests.
205   //
206   Status = InitUnitTestFramework (&Fw, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);
207   if (EFI_ERROR (Status)) {
208       DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
209       goto EXIT;
210   }
211 
212   //
213   // Populate the Unit Test Suite.
214   //
215   Status = CreateUnitTestSuite (&DepexEvalTests, Fw, "Evaluate Dependency Test", "FmpDependencyLib.EvaluateDependency", NULL, NULL);
216   if (EFI_ERROR (Status)) {
217     DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for DepexEvalTests\n"));
218     goto EXIT;
219   }
220 
221   AddTestCase (DepexEvalTests, "Evaluate to True - 1", "Test1", EvaluateDependencyTest, NULL, NULL, &mBasicTestTrue1);
222   AddTestCase (DepexEvalTests, "Evaluate to True - 2", "Test2", EvaluateDependencyTest, NULL, NULL, &mBasicTestTrue2);
223   AddTestCase (DepexEvalTests, "Evaluate to False - 1", "Test3", EvaluateDependencyTest, NULL, NULL, &mBasicTestFalse1);
224   AddTestCase (DepexEvalTests, "Evaluate to False - 2", "Test4", EvaluateDependencyTest, NULL, NULL, &mBasicTestFalse2);
225   AddTestCase (DepexEvalTests, "Error: Non-END-terminated expression", "Test5", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid1);
226   AddTestCase (DepexEvalTests, "Error: UNKNOWN Op-Code", "Test6", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid2);
227   AddTestCase (DepexEvalTests, "Error: Non-Null-terminated string", "Test7", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid3);
228   AddTestCase (DepexEvalTests, "Error: GUID size is not 16", "Test8", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid4);
229   AddTestCase (DepexEvalTests, "Error: Version size is not 4", "Test9", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid5);
230   AddTestCase (DepexEvalTests, "Error: Operand and operator mismatch", "Test10", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid6);
231   AddTestCase (DepexEvalTests, "Error: GUID is NOT FOUND", "Test11", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid7);
232   AddTestCase (DepexEvalTests, "Error: Stack Underflow", "Test12", EvaluateDependencyTest, NULL, NULL, &mBasicTestInvalid8);
233 
234   //
235   // Execute the tests.
236   //
237   Status = RunAllTestSuites (Fw);
238 
239 EXIT:
240   if (Fw) {
241     FreeUnitTestFramework (Fw);
242   }
243 
244   return Status;
245 }
246 
247 /**
248   Standard UEFI entry point for target based unit test execution from UEFI Shell.
249 **/
250 EFI_STATUS
251 EFIAPI
FmpDependencyLibUnitTestAppEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)252 FmpDependencyLibUnitTestAppEntry (
253   IN EFI_HANDLE        ImageHandle,
254   IN EFI_SYSTEM_TABLE  *SystemTable
255   )
256 {
257   return UnitTestingEntry ();
258 }
259 
260 /**
261   Standard POSIX C entry point for host based unit test execution.
262 **/
263 int
main(int argc,char * argv[])264 main (
265   int argc,
266   char *argv[]
267   )
268 {
269   return UnitTestingEntry ();
270 }
271