#ifdef TEST_PASS test "string_test" { } #endif // note: Add a .test file that can be optionally included in the directory which allows a shell command to be executed prior to the test? // todo: Finalization pass over tokenizer // Tokenizer will go into a parse layer which swaps test "foo" { } to an actual function call // int test_foo(test_ctx* Ctx) {} // these function calls are put into _generated.cpp // after tests are compiled and executed the generated files are deleted // maybe have the shell command stuff inside of ctx? // todo: Write and research testing framework! #include #include #include #include #include #include static string msg_prefix = make_string("[Test Suite] "); string ReadEntireFileIntoMemory(char* FileName) { string Result = { }; FILE* File = fopen(FileName, "r"); if (File) { fseek(File, 0, SEEK_END); Result.Count = ftell(File); fseek(File, 0, SEEK_SET); Result.Data = (u8*)malloc(Result.Count); fread(Result.Data, Result.Count, 1, File); fclose(File); } return Result; } #include #include struct lexer_state { char** FileNames; u32 FileNameCount; }; static lexer_state State; void ListContents(const char* Cwd) { char Path[MAX_PATH]; _WIN32_FIND_DATAA FindData; HANDLE FindHandle = INVALID_HANDLE_VALUE; //Specify a file mask. *.* = We want everything! sprintf(Path, "%s\\*.*", Cwd); FindHandle = FindFirstFileA(Path, &FindData); do { if (strcmp(FindData.cFileName, ".") != 0 && strcmp(FindData.cFileName, "..") != 0) { sprintf(Path, "%s\\%s", Cwd, FindData.cFileName); if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { ListContents(Path); } else if (Substring(Path, "src") != NULL) { State.FileNames[State.FileNameCount] = (char*)malloc(sizeof(char) * MAX_PATH); strcpy(State.FileNames[State.FileNameCount], Path); ++State.FileNameCount; } } } while (FindNextFileA(FindHandle, &FindData)); } int main(char** Args, int ArgCount) { TCHAR** lppPart = {NULL}; // For GetFullPath :/ char* cwd; cwd = _getcwd(NULL, 256); printf("%sTest Suite v0.1\n", msg_prefix.Data); printf("%sOperating in directory: %s\n\n", msg_prefix.Data, cwd); // Get the names of the files we will operate on State.FileNames = (char**)malloc(2048 * sizeof(char*)); if (Substring(cwd, "build")) { ListContents("..\\tests"); } else { ListContents("tests"); } for (u32 FileIndex = 0; FileIndex < State.FileNameCount; ++FileIndex) { char* Filename = State.FileNames[FileIndex]; char* FullFilename = (char*)malloc(MAX_PATH * sizeof(char)); GetFullPathNameA(Filename, MAX_PATH, FullFilename, lppPart); printf("%s: \n", FullFilename); string Contents = ReadEntireFileIntoMemory(Filename); tokenizer Tokenizer = Tokenize(Contents, Filename); b32 Parsing = true; while (Parsing) { token Token = GetToken(&Tokenizer); switch (Token.Type) { case Token_EndOfStream: { Parsing = false; } break; case Token_Identifier: { if (StringsMatch(Token.String, "test")) { GetToken(&Tokenizer); token Next = GetToken(&Tokenizer); char* TestName = Next.String; printf(" test '%s'\n", TestName); } } break; case Token_Unknown: default: { } break; } } } return 1; }