HyperDbg Debugger
Loading...
Searching...
No Matches
test-parser.cpp File Reference

Perform test on command parser. More...

#include "pch.h"

Typedefs

typedef CHAR ** CHAR_PTR_PTR

Functions

CHAR_PTR_PTR CreateTestCaseArray (const std::vector< std::string > &TestCases)
 Create an array of strings from a vector of strings.
VOID FreeTestCaseArray (CHAR_PTR_PTR TestCaseArray, SIZE_T Size)
 Free the memory allocated for the test case array.
std::vector< std::pair< std::string, std::vector< std::string > > > ParseTestCases (const std::string &Filename)
 Parse the test cases from the file.
INT32 CountBackslashNUpToPosition (const std::string &Str, std::size_t Limit)
 Count the number of occurrences of the substring "\\n" up to a specified position.
VOID ShowParsedCommandAndTokens (const std::pair< std::string, std::vector< std::string > > &TestCase, UINT32 FailedTokenNum, UINT32 FailedTokenPosition)
 Show parsed command and tokens.
BOOLEAN TestCommandParser ()
 Test command parser.

Detailed Description

Perform test on command parser.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.11
Date
2024-08-11

Typedef Documentation

◆ CHAR_PTR_PTR

typedef CHAR** CHAR_PTR_PTR

Function Documentation

◆ CountBackslashNUpToPosition()

INT32 CountBackslashNUpToPosition ( const std::string & Str,
std::size_t Limit )

Count the number of occurrences of the substring "\\n" up to a specified position.

Parameters
StrThe string to search
LimitThe position to search up to
Returns
INT32 The number of occurrences of the substring "\\n"
188{
189 INT32 Count = 0;
190 std::string::size_type Pos = 0;
191 std::string Target = "\\n";
192
193 //
194 // Limit the string to search within the specified range
195 //
196 while ((Pos = Str.find(Target, Pos)) != std::string::npos && Pos < Limit)
197 {
198 ++Count;
199 Pos += Target.length(); // Move past the current occurrence
200 }
201
202 return Count;
203}
signed int INT32
Definition BasicTypes.h:50

◆ CreateTestCaseArray()

CHAR_PTR_PTR CreateTestCaseArray ( const std::vector< std::string > & TestCases)

Create an array of strings from a vector of strings.

Parameters
TestCasesThe vector of strings to copy
Returns
A pointer to the array of strings
24{
25 //
26 // Allocate memory for the array of pointers (size: number of test cases)
27 //
28 CHAR_PTR_PTR TestCaseArray = (CHAR_PTR_PTR)malloc(TestCases.size() * sizeof(UINT64));
29
30 //
31 // Allocate memory for each string and copy the content
32 //
33 for (SIZE_T i = 0; i < TestCases.size(); ++i)
34 {
35 TestCaseArray[i] = (CHAR *)malloc(TestCases[i].length() + 1); // +1 for the null terminator
36
37 if (TestCaseArray[i] == NULL)
38 {
39 return NULL;
40 }
41 std::strcpy(TestCaseArray[i], TestCases[i].c_str());
42 }
43
44 return TestCaseArray;
45}
char CHAR
Definition BasicTypes.h:33
NULL()
Definition test-case-generator.py:530
CHAR ** CHAR_PTR_PTR
Definition test-parser.cpp:14

◆ FreeTestCaseArray()

VOID FreeTestCaseArray ( CHAR_PTR_PTR TestCaseArray,
SIZE_T Size )

Free the memory allocated for the test case array.

Parameters
TestCaseArrayThe array of pointers to free
SizeThe size of the array
Returns
VOID
56{
57 //
58 // Free each string
59 //
60 for (SIZE_T i = 0; i < Size; ++i)
61 {
62 free(TestCaseArray[i]);
63 }
64
65 //
66 // Free the array of pointers
67 //
68 free(TestCaseArray);
69}

◆ ParseTestCases()

std::vector< std::pair< std::string, std::vector< std::string > > > ParseTestCases ( const std::string & Filename)

Parse the test cases from the file.

Parameters
FilenameThe name of the file to parse
Returns
A vector of pairs, where each pair contains a command and a vector of tokens
79{
80 std::ifstream file(Filename);
81 std::string Line;
82 std::string Command;
83 std::string CurrentToken;
84 std::vector<std::string> Tokens;
85 std::vector<std::pair<std::string, std::vector<std::string>>> TestCases;
86 BOOLEAN IsCommand = FALSE;
87 BOOLEAN AddNewline = FALSE;
88
89 const std::string TokenDelimiter = "----------------------------------";
90 const std::string CommandDelimiter = "_____________________________________________________________";
91
92 while (std::getline(file, Line))
93 {
94 if (Line == CommandDelimiter)
95 {
96 //
97 // No new line is needed after this token
98 //
99 AddNewline = FALSE;
100
101 //
102 // Save the previous command and its tokens if any
103 //
104 if (!Command.empty())
105 {
106 if (!CurrentToken.empty())
107 {
108 Tokens.push_back(CurrentToken);
109 CurrentToken.clear();
110 }
111 TestCases.push_back({Command, Tokens});
112 Command.clear();
113 Tokens.clear();
114 }
115
116 //
117 // is command is true since a command is started
118 //
119 IsCommand = TRUE;
120 }
121 else if (Line == TokenDelimiter)
122 {
123 //
124 // No new line is needed after this token
125 //
126 AddNewline = FALSE;
127
128 //
129 // not in command anymore
130 //
131 IsCommand = FALSE;
132
133 //
134 // If we're in the middle of collecting a token, save it
135 //
136 if (!CurrentToken.empty())
137 {
138 Tokens.push_back(CurrentToken);
139 CurrentToken.clear();
140 }
141 }
142 else
143 {
144 //
145 // Accumulate lines for the command or token
146 //
147 if (IsCommand)
148 {
149 if (AddNewline)
150 Command += "\n";
151 Command += Line;
152 }
153 else
154 {
155 if (AddNewline)
156 CurrentToken += "\n";
157 CurrentToken += Line;
158 }
159
160 AddNewline = TRUE;
161 }
162 }
163
164 //
165 // Store the last command and tokens if any
166 //
167 if (!Command.empty())
168 {
169 if (!CurrentToken.empty())
170 {
171 Tokens.push_back(CurrentToken);
172 }
173 TestCases.push_back({Command, Tokens});
174 }
175
176 return TestCases;
177}
UCHAR BOOLEAN
Definition BasicTypes.h:35
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113
list Tokens
Definition generator.py:217

◆ ShowParsedCommandAndTokens()

VOID ShowParsedCommandAndTokens ( const std::pair< std::string, std::vector< std::string > > & TestCase,
UINT32 FailedTokenNum,
UINT32 FailedTokenPosition )

Show parsed command and tokens.

Parameters
TestCaseA pair containing a command and a vector of tokens
FailedTokenNumThe number of the failed token
FailedTokenPositionThe position of the failed token
Returns
VOID
218{
219 UINT32 TokenNum = 0;
220
221 //
222 // Output the parsed test case
223 //
224
225 string ShowingCommand = TestCase.first;
226
227 std::string::size_type Pos = 0;
228 while ((Pos = ShowingCommand.find("\n", Pos)) != std::string::npos)
229 {
230 ShowingCommand.replace(Pos, 1, "\\n");
231 Pos += 2; // Move past the newly added characters
232 }
233
234 std::cout << "Command: \"" << ShowingCommand << "\"" << std::endl;
235 std::cout << "____________________________________\n";
236
237 std::cout << "Expected Tokens: " << std::endl;
238
239 for (const auto & Token : TestCase.second)
240 {
241 string ShowingToken = Token;
242
243 Pos = 0;
244 while ((Pos = ShowingToken.find("\n", Pos)) != std::string::npos)
245 {
246 ShowingToken.replace(Pos, 1, "\\n");
247 Pos += 2; // Move past the newly added characters
248 }
249
250 if (TokenNum == FailedTokenNum)
251 {
252 std::cout << " x ";
253 }
254 else
255 {
256 std::cout << " - ";
257 }
258
259 std::cout << "\"" << ShowingToken << "\"" << std::endl;
260
261 if (TokenNum == FailedTokenNum)
262 {
263 std::cout << " ";
264 INT32 CountOfSpaces = CountBackslashNUpToPosition(ShowingToken, FailedTokenPosition);
265
266 CountOfSpaces += FailedTokenPosition;
267
268 for (INT32 i = 0; i < CountOfSpaces; i++)
269 {
270 std::cout << " ";
271 }
272 std::cout << "^" << std::endl;
273 }
274
275 TokenNum++;
276 }
277}
unsigned int UINT32
Definition BasicTypes.h:54
BOOLEAN TestCase(std::vector< std::string > &TestCase)
INT32 CountBackslashNUpToPosition(const std::string &Str, std::size_t Limit)
Count the number of occurrences of the substring "\\n" up to a specified position.
Definition test-parser.cpp:187

◆ TestCommandParser()

BOOLEAN TestCommandParser ( )

Test command parser.

Returns
BOOLEAN
286{
287 BOOLEAN OverallResult = TRUE;
288 INT32 TestNum = 0;
289 CHAR FilePath[MAX_PATH] = {0};
290 UINT32 FailedTokenNum = 0;
291 UINT32 FailedTokenPosition = 0;
292
293 //
294 // Parse the test cases from the file
295 // Setup the path for the filename
296 //
298 {
299 //
300 // Error could not find the test case files
301 //
302 cout << "[-] Could not find the test case files" << endl;
303 return FALSE;
304 }
305
306 //
307 // Parse the test cases from the file
308 //
309 auto TestCases = ParseTestCases(FilePath);
310
311 //
312 // Perform testing test cases with parsed file
313 //
314 cout << "Perform testing test cases with parsed file:" << endl;
315
316 //
317 // Output the parsed test cases
318 //
319 for (const auto & TestCase : TestCases)
320 {
321 TestNum++;
322
323 //
324 // Create CHAR**
325 //
326 CHAR_PTR_PTR TestCaseArray = CreateTestCaseArray(TestCase.second);
327
328 //
329 // Check token with actual parser
330 //
331 if (hyperdbg_u_test_command_parser((CHAR *)TestCase.first.c_str(),
332 (UINT32)TestCase.second.size(),
333 TestCaseArray,
334 &FailedTokenNum,
335 &FailedTokenPosition))
336 {
337 cout << "[+] Test number " << TestNum << " Passed " << endl;
338 }
339 else
340 {
341 //
342 // Set overall result to FALSE since one of the test cases failed
343 //
344 OverallResult = FALSE;
345
346 //
347 // Show parsed command and tokens
348 //
349 cout << "\n============================================================" << endl;
350 cout << "\n********************* " << endl;
351 cout << "*** Error details *** " << endl;
352 cout << "********************* " << endl;
353 cout << "\nParsed tokens from HyperDbg main command parser:\n"
354 << endl;
355
356 //
357 // Show tokens
358 //
360
361 cout << "\n============================================================" << endl;
362
363 cout << "\nThe parsed command and tokens (From file):" << endl;
364 ShowParsedCommandAndTokens(TestCase, FailedTokenNum, FailedTokenPosition);
365
366 cout << "\n[-] Test number " << TestNum << " Failed " << endl;
367 cout << "============================================================\n"
368 << endl;
369
370 break;
371 }
372
373 //
374 // Clean up memory
375 //
376 FreeTestCaseArray(TestCaseArray, TestCase.second.size());
377 }
378
379 return OverallResult;
380}
#define COMMAND_PARSER_TEST_CASES_FILE
Test cases file name for command parser.
Definition Definition.h:70
IMPORT_EXPORT_LIBHYPERDBG VOID hyperdbg_u_test_command_parser_show_tokens(CHAR *command)
Parse and show tokens for the command (used for testing purposes).
Definition export.cpp:237
IMPORT_EXPORT_LIBHYPERDBG BOOLEAN hyperdbg_u_test_command_parser(CHAR *command, UINT32 number_of_tokens, CHAR **tokens_list, UINT32 *failed_token_num, UINT32 *failed_token_position)
Parse the command (used for testing purposes).
Definition export.cpp:220
IMPORT_EXPORT_LIBHYPERDBG BOOLEAN hyperdbg_u_setup_path_for_filename(const CHAR *filename, CHAR *file_location, UINT32 buffer_len, BOOLEAN check_file_existence)
Setip the path for the filename.
Definition export.cpp:725
std::vector< std::pair< std::string, std::vector< std::string > > > ParseTestCases(const std::string &Filename)
Parse the test cases from the file.
Definition test-parser.cpp:78
VOID FreeTestCaseArray(CHAR_PTR_PTR TestCaseArray, SIZE_T Size)
Free the memory allocated for the test case array.
Definition test-parser.cpp:55
CHAR_PTR_PTR CreateTestCaseArray(const std::vector< std::string > &TestCases)
Create an array of strings from a vector of strings.
Definition test-parser.cpp:23
VOID ShowParsedCommandAndTokens(const std::pair< std::string, std::vector< std::string > > &TestCase, UINT32 FailedTokenNum, UINT32 FailedTokenPosition)
Show parsed command and tokens.
Definition test-parser.cpp:214