Add file write tests and delete functionality

This commit is contained in:
Doyle Thai 2017-06-22 01:26:08 +10:00
parent 93bbc25b11
commit 84149d0ad1
2 changed files with 136 additions and 15 deletions

31
dqn.h
View File

@ -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);

View File

@ -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));
} }