Add file write tests and delete functionality
This commit is contained in:
		
							parent
							
								
									93bbc25b11
								
							
						
					
					
						commit
						84149d0ad1
					
				
							
								
								
									
										31
									
								
								dqn.h
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								dqn.h
									
									
									
									
									
								
							| @ -801,7 +801,6 @@ DQN_FILE_SCOPE u32  DqnRnd_PCGNext (DqnRandPCGState *pcg); | ||||
| DQN_FILE_SCOPE f32  DqnRnd_PCGNextf(DqnRandPCGState *pcg); | ||||
| // Returns a random integer N between [min, max]
 | ||||
| DQN_FILE_SCOPE i32  DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max); | ||||
| 
 | ||||
| #endif  /* DQN_H */ | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -817,6 +816,7 @@ DQN_FILE_SCOPE i32  DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max); | ||||
| 
 | ||||
| #ifdef DQN_UNIX_PLATFORM | ||||
| 	#include <sys/stat.h> | ||||
| 	#include <unistd.h>   // unlink() | ||||
| 	#include <stdio.h>    // Basic File I/O | ||||
| 	#include <dirent.h>   // readdir()/opendir()/closedir() | ||||
| #endif | ||||
| @ -854,6 +854,7 @@ typedef struct DqnFile | ||||
| 	u32     permissionFlags; | ||||
| } DqnFile; | ||||
| 
 | ||||
| // NOTE: W(ide) versions of functions only work on Win32, since Unix is UTF-8 compatible.
 | ||||
| // Open a handle to the file
 | ||||
| DQN_FILE_SCOPE bool   DqnFile_Open (const char *const path, DqnFile *const file, const u32 permissionFlags, const enum DqnFileAction action); | ||||
| DQN_FILE_SCOPE bool   DqnFile_OpenW(const wchar_t *const path, DqnFile *const file, const u32 permissionFlags, const enum DqnFileAction action); | ||||
| @ -864,6 +865,10 @@ DQN_FILE_SCOPE size_t DqnFile_Write(const DqnFile *const file, u8 *const buffer, | ||||
| DQN_FILE_SCOPE size_t DqnFile_Read (const DqnFile file, u8 *const buffer, const size_t numBytesToRead); | ||||
| DQN_FILE_SCOPE void   DqnFile_Close(DqnFile *const file); | ||||
| 
 | ||||
| // NOTE: You can't delete a file unless the handle has been closed to it on Win32.
 | ||||
| DQN_FILE_SCOPE bool DqnFile_Delete (const char *const path); | ||||
| DQN_FILE_SCOPE bool DqnFile_DeleteW(const wchar_t *const path); | ||||
| 
 | ||||
| // Return an array of strings of the files in the directory in UTF-8. numFiles
 | ||||
| // returns the number of strings read.
 | ||||
| // This is allocated using malloc and MUST BE FREED! Can be done manually or
 | ||||
| @ -1704,9 +1709,10 @@ DQN_FILE_SCOPE bool DqnMemStack_Pop(DqnMemStack *const stack, void *ptr, size_t | ||||
| 	                   "'ptr' to pop does not belong to current memStack attached block")) | ||||
| 	{ | ||||
| 		size_t calcSize = (size_t)currPtr - (size_t)ptr; | ||||
| 		if (DQN_ASSERT_MSG(calcSize == size, "'ptr' was not the last item allocated to memStack")) | ||||
| 		size_t sizeAligned = DQN_ALIGN_POW_N(size, stack->byteAlign); | ||||
| 		if (DQN_ASSERT_MSG(calcSize == sizeAligned, "'ptr' was not the last item allocated to memStack")) | ||||
| 		{ | ||||
| 			stack->block->used -= size; | ||||
| 			stack->block->used -= sizeAligned; | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| @ -3878,7 +3884,7 @@ DQN_FILE_SCOPE size_t DqnFile_Write(const DqnFile *const file, | ||||
| { | ||||
| 	size_t numBytesWritten = 0; | ||||
| 	// TODO(doyle): Implement when it's needed
 | ||||
| 	if (DQN_ASSERT_MSG(fileOffset != 0, "'fileOffset' not implemented yet")) return 0; | ||||
| 	if (!DQN_ASSERT_MSG(fileOffset == 0, "'fileOffset' not implemented yet")) return 0; | ||||
| 	if (!file || !buffer) return numBytesToWrite; | ||||
| 
 | ||||
| #if defined(DQN_WIN32_PLATFORM) | ||||
| @ -3963,6 +3969,23 @@ DQN_FILE_SCOPE void DqnFile_Close(DqnFile *const file) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| DQN_FILE_SCOPE bool DqnFile_Delete(const char *const path) | ||||
| { | ||||
| 	if (!path) return false; | ||||
| 
 | ||||
| 	// TODO(doyle): Logging
 | ||||
| #if defined(DQN_WIN32_PLATFORM) | ||||
| 	return DeleteFile(path); | ||||
| 
 | ||||
| #elif defined(DQN_UNIX_PLATFORM) | ||||
| 	i32 result = unlink(path); | ||||
| 
 | ||||
| 	if (result == 0) return true; | ||||
| 	return false; | ||||
| 
 | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| DQN_FILE_SCOPE char **DqnDir_Read(const char *const dir, u32 *const numFiles) | ||||
| { | ||||
| 	char **result = DqnDirInternal_PlatformRead(dir, numFiles); | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #if (defined(_WIN32) || defined(_WIN64)) | ||||
| 	#define DQN_WIN32_IMPLEMENTATION | ||||
| 	#include <Windows.h> | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__linux__) | ||||
| @ -1445,21 +1446,46 @@ void FileTest() | ||||
| { | ||||
| 	// File i/o
 | ||||
| 	{ | ||||
| 
 | ||||
| 		// Test file open
 | ||||
| 		{ | ||||
| 			const char *const FILE_TO_OPEN = ".clang-format"; | ||||
| 	        u32 expectedSize = 0; | ||||
| #if defined(DQN_UNIX_IMPLEMENTATION) | ||||
| 	        { | ||||
| 		        struct stat fileStat = {0}; | ||||
| 		        DQN_ASSERT(stat(FILE_TO_OPEN, &fileStat) == 0); | ||||
| 		        expectedSize = fileStat.st_size; | ||||
| 	        } | ||||
| 
 | ||||
| #elif defined(DQN_WIN32_IMPLEMENTATION) | ||||
| 	        { | ||||
| 		        HANDLE handle = | ||||
| 		            CreateFile(FILE_TO_OPEN, GENERIC_READ, 0, NULL, | ||||
| 		                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | ||||
| 		        if (handle == INVALID_HANDLE_VALUE) | ||||
| 		        { | ||||
| 					DqnWin32_DisplayLastError("CreateFile() failed"); | ||||
| 		        } | ||||
| 		        DQN_ASSERT(handle != INVALID_HANDLE_VALUE); | ||||
| 
 | ||||
| 		        LARGE_INTEGER size; | ||||
| 		        DQN_ASSERT(GetFileSizeEx(handle, &size)); | ||||
| 
 | ||||
| 		        CloseHandle(handle); | ||||
| 		        expectedSize = size.LowPart; | ||||
| 	        } | ||||
| #endif | ||||
| 
 | ||||
| 			DqnFile file = {}; | ||||
| 	        DQN_ASSERT(DqnFile_Open( | ||||
| 	            ".clang-format", &file, | ||||
| 	            (DqnFilePermissionFlag_Write | DqnFilePermissionFlag_Read), | ||||
| 	            DqnFileAction_OpenOnly)); | ||||
| 
 | ||||
| #if defined(DQN_UNIX_IMPLEMENTATION) | ||||
| 			const u32 EXPECTED_SIZE = 1274; | ||||
| #elif defined(DQN_WIN32_IMPLEMENTATION) | ||||
| 			const u32 EXPECTED_SIZE = 1320; | ||||
| #endif | ||||
| 	        DQN_ASSERT_MSG(file.size == EXPECTED_SIZE, | ||||
| 	        DQN_ASSERT_MSG(file.size == expectedSize, | ||||
| 	                       "DqnFileOpen() failed: file.size: %d, expected:%d\n", | ||||
| 	                       file.size, EXPECTED_SIZE); | ||||
| 	                       file.size, expectedSize); | ||||
| 
 | ||||
| 	        u8 *buffer = (u8 *)calloc(1, (size_t)file.size * sizeof(u8)); | ||||
| 			DQN_ASSERT(DqnFile_Read(file, buffer, (u32)file.size) == file.size); | ||||
| @ -1470,6 +1496,7 @@ void FileTest() | ||||
| 	                   file.permissionFlags == 0); | ||||
|         } | ||||
| 
 | ||||
| 		// Test invalid file
 | ||||
| 		{ | ||||
| 			DqnFile file = {}; | ||||
| 			DQN_ASSERT(!DqnFile_Open( | ||||
| @ -1482,7 +1509,74 @@ void FileTest() | ||||
| 			printf("FileTest(): FileIO: Completed successfully\n"); | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO(doyle): Write tests for writing out to file
 | ||||
| 	} | ||||
| 
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Write Test
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	{ | ||||
| 	    const char *fileNames[] = {"dqn_1", "dqn_2", "dqn_3", "dqn_4", "dqn_5"}; | ||||
| 	    const char *writeData[] = {"1234", "2468", "36912", "481216", | ||||
| 	                               "5101520"}; | ||||
| 	    DqnFile files[DQN_ARRAY_COUNT(fileNames)] = {}; | ||||
| 
 | ||||
| 	    // Write data out to some files
 | ||||
| 	    for (u32 i = 0; i < DQN_ARRAY_COUNT(fileNames); i++) | ||||
| 	    { | ||||
| 		    u32 permissions = | ||||
| 		        DqnFilePermissionFlag_Read | DqnFilePermissionFlag_Write; | ||||
| 		    if (!DqnFile_Open(fileNames[i], files + i, permissions, | ||||
| 		                      DqnFileAction_ClearIfExist)) | ||||
| 		    { | ||||
| 			    bool result = DqnFile_Open(fileNames[i], files + i, permissions, | ||||
| 			                               DqnFileAction_CreateIfNotExist); | ||||
| 			    DQN_ASSERT(result); | ||||
| 		    } | ||||
| 
 | ||||
| 		    size_t bytesToWrite = DqnStr_Len(writeData[i]); | ||||
| 		    u8 *dataToWrite     = (u8 *)(writeData[i]); | ||||
| 		    size_t bytesWritten = DqnFile_Write(files + i, dataToWrite, bytesToWrite, 0); | ||||
| 		    DQN_ASSERT(bytesWritten == bytesToWrite); | ||||
| 		    DqnFile_Close(&files[i]); | ||||
| 	    } | ||||
| 
 | ||||
| 	    DqnMemStack memStack = {}; | ||||
| 	    DQN_ASSERT(DqnMemStack_Init(&memStack, DQN_MEGABYTE(1), true)); | ||||
| 	    // Read data back in
 | ||||
| 	    for (u32 i = 0; i < DQN_ARRAY_COUNT(fileNames); i++) | ||||
| 	    { | ||||
| 		    u32 permissions = DqnFilePermissionFlag_Read; | ||||
| 		    DqnFile *file   = files + i; | ||||
| 		    bool result     = DqnFile_Open(fileNames[i], file, permissions, | ||||
| 		                               DqnFileAction_OpenOnly); | ||||
| 		    DQN_ASSERT(result); | ||||
| 
 | ||||
| 		    u8 *buffer = (u8 *)DqnMemStack_Push(&memStack, file->size); | ||||
| 		    DQN_ASSERT(buffer); | ||||
| 
 | ||||
| 		    size_t bytesRead = DqnFile_Read(files[i], buffer, file->size); | ||||
| 		    DQN_ASSERT(bytesRead == file->size); | ||||
| 
 | ||||
| 		    // Verify the data is the same as we wrote out
 | ||||
| 		    DQN_ASSERT(DqnStr_Cmp((char *)buffer, (writeData[i])) == 0); | ||||
| 
 | ||||
| 		    // Delete when we're done with it
 | ||||
| 		    DQN_ASSERT(DqnMemStack_Pop(&memStack, buffer, file->size)); | ||||
| 		    DqnFile_Close(file); | ||||
| 
 | ||||
| 		    DQN_ASSERT(DqnFile_Delete(fileNames[i])); | ||||
| 	    } | ||||
| 
 | ||||
| 	    // Then check delete actually worked, files should not exist.
 | ||||
| 	    for (u32 i = 0; i < DQN_ARRAY_COUNT(fileNames); i++) | ||||
| 	    { | ||||
| 		    DqnFile dummy   = {}; | ||||
| 		    u32 permissions = DqnFilePermissionFlag_Read; | ||||
| 		    bool fileExists = DqnFile_Open(fileNames[i], &dummy, permissions, | ||||
| 		                                   DqnFileAction_OpenOnly); | ||||
| 		    DQN_ASSERT(!fileExists); | ||||
| 	    } | ||||
| 	    DqnMemStack_Free(&memStack); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
| @ -1559,6 +1653,10 @@ FILE_SCOPE void JobQueueTest() | ||||
| 	for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++) | ||||
| 		DQN_ASSERT(globalDebugCounterMemoize[i]); | ||||
| 
 | ||||
| 	while (DqnJobQueue_TryExecuteNextJob(jobQueue) && | ||||
| 	       !DqnJobQueue_AllJobsComplete(jobQueue)) | ||||
| 		; | ||||
| 
 | ||||
| 	printf("\nJobQueueTest(): Final incremented value: %d\n", globalDebugCounter); | ||||
| 	DQN_ASSERT(globalDebugCounter == DQN_ARRAY_COUNT(globalDebugCounterMemoize)); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user