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); | DQN_FILE_SCOPE f32  DqnRnd_PCGNextf(DqnRandPCGState *pcg); | ||||||
| // Returns a random integer N between [min, max]
 | // Returns a random integer N between [min, max]
 | ||||||
| DQN_FILE_SCOPE i32  DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max); | DQN_FILE_SCOPE i32  DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max); | ||||||
| 
 |  | ||||||
| #endif  /* DQN_H */ | #endif  /* DQN_H */ | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////
 | ||||||
| @ -817,6 +816,7 @@ DQN_FILE_SCOPE i32  DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max); | |||||||
| 
 | 
 | ||||||
| #ifdef DQN_UNIX_PLATFORM | #ifdef DQN_UNIX_PLATFORM | ||||||
| 	#include <sys/stat.h> | 	#include <sys/stat.h> | ||||||
|  | 	#include <unistd.h>   // unlink() | ||||||
| 	#include <stdio.h>    // Basic File I/O | 	#include <stdio.h>    // Basic File I/O | ||||||
| 	#include <dirent.h>   // readdir()/opendir()/closedir() | 	#include <dirent.h>   // readdir()/opendir()/closedir() | ||||||
| #endif | #endif | ||||||
| @ -854,6 +854,7 @@ typedef struct DqnFile | |||||||
| 	u32     permissionFlags; | 	u32     permissionFlags; | ||||||
| } DqnFile; | } DqnFile; | ||||||
| 
 | 
 | ||||||
|  | // NOTE: W(ide) versions of functions only work on Win32, since Unix is UTF-8 compatible.
 | ||||||
| // Open a handle to the file
 | // 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_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); | 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 size_t DqnFile_Read (const DqnFile file, u8 *const buffer, const size_t numBytesToRead); | ||||||
| DQN_FILE_SCOPE void   DqnFile_Close(DqnFile *const file); | 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
 | // Return an array of strings of the files in the directory in UTF-8. numFiles
 | ||||||
| // returns the number of strings read.
 | // returns the number of strings read.
 | ||||||
| // This is allocated using malloc and MUST BE FREED! Can be done manually or
 | // 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")) | 	                   "'ptr' to pop does not belong to current memStack attached block")) | ||||||
| 	{ | 	{ | ||||||
| 		size_t calcSize = (size_t)currPtr - (size_t)ptr; | 		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; | 			return true; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -3878,7 +3884,7 @@ DQN_FILE_SCOPE size_t DqnFile_Write(const DqnFile *const file, | |||||||
| { | { | ||||||
| 	size_t numBytesWritten = 0; | 	size_t numBytesWritten = 0; | ||||||
| 	// TODO(doyle): Implement when it's needed
 | 	// 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 (!file || !buffer) return numBytesToWrite; | ||||||
| 
 | 
 | ||||||
| #if defined(DQN_WIN32_PLATFORM) | #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) | DQN_FILE_SCOPE char **DqnDir_Read(const char *const dir, u32 *const numFiles) | ||||||
| { | { | ||||||
| 	char **result = DqnDirInternal_PlatformRead(dir, numFiles); | 	char **result = DqnDirInternal_PlatformRead(dir, numFiles); | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #if (defined(_WIN32) || defined(_WIN64)) | #if (defined(_WIN32) || defined(_WIN64)) | ||||||
| 	#define DQN_WIN32_IMPLEMENTATION | 	#define DQN_WIN32_IMPLEMENTATION | ||||||
|  | 	#include <Windows.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if defined(__linux__) | #if defined(__linux__) | ||||||
| @ -1445,21 +1446,46 @@ void FileTest() | |||||||
| { | { | ||||||
| 	// File i/o
 | 	// 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 = {}; | 			DqnFile file = {}; | ||||||
| 	        DQN_ASSERT(DqnFile_Open( | 	        DQN_ASSERT(DqnFile_Open( | ||||||
| 	            ".clang-format", &file, | 	            ".clang-format", &file, | ||||||
| 	            (DqnFilePermissionFlag_Write | DqnFilePermissionFlag_Read), | 	            (DqnFilePermissionFlag_Write | DqnFilePermissionFlag_Read), | ||||||
| 	            DqnFileAction_OpenOnly)); | 	            DqnFileAction_OpenOnly)); | ||||||
| 
 | 
 | ||||||
| #if defined(DQN_UNIX_IMPLEMENTATION) | 	        DQN_ASSERT_MSG(file.size == expectedSize, | ||||||
| 			const u32 EXPECTED_SIZE = 1274; |  | ||||||
| #elif defined(DQN_WIN32_IMPLEMENTATION) |  | ||||||
| 			const u32 EXPECTED_SIZE = 1320; |  | ||||||
| #endif |  | ||||||
| 	        DQN_ASSERT_MSG(file.size == EXPECTED_SIZE, |  | ||||||
| 	                       "DqnFileOpen() failed: file.size: %d, expected:%d\n", | 	                       "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)); | 	        u8 *buffer = (u8 *)calloc(1, (size_t)file.size * sizeof(u8)); | ||||||
| 			DQN_ASSERT(DqnFile_Read(file, buffer, (u32)file.size) == file.size); | 			DQN_ASSERT(DqnFile_Read(file, buffer, (u32)file.size) == file.size); | ||||||
| @ -1470,6 +1496,7 @@ void FileTest() | |||||||
| 	                   file.permissionFlags == 0); | 	                   file.permissionFlags == 0); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | 		// Test invalid file
 | ||||||
| 		{ | 		{ | ||||||
| 			DqnFile file = {}; | 			DqnFile file = {}; | ||||||
| 			DQN_ASSERT(!DqnFile_Open( | 			DQN_ASSERT(!DqnFile_Open( | ||||||
| @ -1482,7 +1509,74 @@ void FileTest() | |||||||
| 			printf("FileTest(): FileIO: Completed successfully\n"); | 			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++) | 	for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++) | ||||||
| 		DQN_ASSERT(globalDebugCounterMemoize[i]); | 		DQN_ASSERT(globalDebugCounterMemoize[i]); | ||||||
| 
 | 
 | ||||||
|  | 	while (DqnJobQueue_TryExecuteNextJob(jobQueue) && | ||||||
|  | 	       !DqnJobQueue_AllJobsComplete(jobQueue)) | ||||||
|  | 		; | ||||||
|  | 
 | ||||||
| 	printf("\nJobQueueTest(): Final incremented value: %d\n", globalDebugCounter); | 	printf("\nJobQueueTest(): Final incremented value: %d\n", globalDebugCounter); | ||||||
| 	DQN_ASSERT(globalDebugCounter == DQN_ARRAY_COUNT(globalDebugCounterMemoize)); | 	DQN_ASSERT(globalDebugCounter == DQN_ARRAY_COUNT(globalDebugCounterMemoize)); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user