From e72ad7404ef431c283fa3195fd53a294788b377b Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Sun, 24 May 2026 11:59:49 +0200 Subject: [PATCH] Add unit tests for file I/O Also use PF_FAM_ constants in place of "wb" and other strings when opening files. Cleanup use of PF_DEBUG. Debug print lines read from readLineFromStream. --- csrc/paging/qadmpage.c | 8 ++--- csrc/pf_core.c | 15 +++++---- csrc/pf_inner.c | 6 +--- csrc/pf_io.c | 76 +++++++++++++++++++++++++++++++++++++++++- csrc/pf_io.h | 5 +++ csrc/pf_save.c | 4 +-- csrc/pfcompil.c | 52 ++++++++++++++++++++++++++--- csrc/pfcompil.h | 2 ++ 8 files changed, 145 insertions(+), 23 deletions(-) diff --git a/csrc/paging/qadmpage.c b/csrc/paging/qadmpage.c index 170551b..860f0bc 100644 --- a/csrc/paging/qadmpage.c +++ b/csrc/paging/qadmpage.c @@ -157,7 +157,7 @@ static int pfQaTestRegionLock(void) { static cell_t pfQaTestCreateFile(size_t numBytes) { uint8_t buffer[100]; int i; - FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, "wb"); + FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, PF_FAM_BIN_CREATE_WO); if (fid == NULL) { printf("ERROR: Could not open file %s\n",PF_DP_TEST_PATHNAME); return -1; @@ -183,7 +183,7 @@ static int pfQaTestReadFileStandard(size_t numBytes) { uint8_t buffer[100]; int i; printf("pfQaDemandPaging : pfQaCheckReadFile\n"); - FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, "rb"); + FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, PF_FAM_BIN_OPEN_RO); ASSERT_NE(PF_VM_NULL, PTR_TO_VMA(fid)); while (numBytes > 0) { size_t bytesToRead = (numBytes < sizeof(buffer)) ? numBytes : sizeof(buffer); @@ -209,7 +209,7 @@ static int pfQaTestReadFilePaging(void) { ASSERT_EQ(0, result); vm_address_t vm1 = pfAllocatePagedMemory(kBytesToRead); ASSERT_NE(PF_VM_NULL, vm1); - FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, "rb"); + FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, PF_FAM_BIN_OPEN_RO); ASSERT_NE(PF_VM_NULL, PTR_TO_VMA(fid)); result = ffReadFile(vm1, 1, kBytesToRead, fid); /* use demand paging */ ASSERT_EQ(kBytesToRead, result); @@ -234,7 +234,7 @@ static int pfQaTestWriteFilePaging(void) { for (i = 0; i < kBytesToWrite; i++) { DP_STORE_U8((vm1 + i), (i % 100)); } - FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, "wb"); + FileStream *fid = sdOpenFile(PF_DP_TEST_PATHNAME, PF_FAM_BIN_CREATE_WO); ASSERT_NE(PF_VM_NULL, PTR_TO_VMA(fid)); result = ffWriteFile(vm1, 1, kBytesToWrite, fid); /* use demand paging */ ASSERT_EQ(kBytesToWrite, result); diff --git a/csrc/pf_core.c b/csrc/pf_core.c index 55ebfc1..1382410 100644 --- a/csrc/pf_core.c +++ b/csrc/pf_core.c @@ -393,7 +393,7 @@ cell_t pfIncludeFile( const char *FileName ) cell_t numChars, len; /* Open file. */ - fid = sdOpenFile( FileName, "r" ); + fid = sdOpenFile( FileName, PF_FAM_OPEN_RO ); if( fid == NULL ) { ERR("pfIncludeFile could not open "); @@ -423,7 +423,7 @@ cell_t pfIncludeFile( const char *FileName ) ***************************************************************/ void pfDebugMessage( const char *CString ) { -#if 0 +#ifdef PF_DEBUG while( *CString ) { char c = *CString++; @@ -438,9 +438,9 @@ void pfDebugMessage( const char *CString ) sdTerminalOut( c ); } } -#else +#else /* PF_DEBUG */ (void)CString; -#endif +#endif /* PF_DEBUG */ } /*************************************************************** @@ -462,7 +462,6 @@ void pfMessage( const char *CString ) ioType( CString, (cell_t) pfCStringLength(CString) ); } - /** * Interprets the Forth in the text. * The text length cannot exceed TIB_SIZE. @@ -703,7 +702,7 @@ ThrowCode pfDoForth(const char *DicFileName, #ifdef PF_UNIT_TEST error: #endif - + pfTerminate(); return Result ? Result : gVarByeCode; @@ -719,6 +718,10 @@ cell_t pfUnitTest( void ) #if PF_DEMAND_PAGING numErrors += pfQaDemandPaging(); #endif + + numErrors += pfQaFileIO(); + numErrors += pfQaCompile(); + return numErrors; } #endif diff --git a/csrc/pf_inner.c b/csrc/pf_inner.c index 4a65b9c..931bf22 100644 --- a/csrc/pf_inner.c +++ b/csrc/pf_inner.c @@ -1434,7 +1434,7 @@ DBUG(("XX ah,m,l = 0x%8x,%8x,%8x - qh,l = 0x%8x,%8x\n", ah,am,al, qh,ql )); #ifndef PF_NO_SHELL case ID_LOADSYS: MSG("Load "); MSG(SYSTEM_LOAD_FILE); EMIT_CR; - FileID = sdOpenFile(SYSTEM_LOAD_FILE, "r"); + FileID = sdOpenFile(SYSTEM_LOAD_FILE, PF_FAM_OPEN_RO); if( FileID ) { SAVE_REGISTERS; @@ -1979,10 +1979,6 @@ DBUGX(("After 0Branch: IP = 0x%x\n", InsPtr )); InsPtr += PF_CELL_SIZE; } -#ifdef PF_DEBUG - M_DOTS; -#endif - #if 0 if( _CrtCheckMemory() == 0 ) { diff --git a/csrc/pf_io.c b/csrc/pf_io.c index c4cd62f..8491771 100644 --- a/csrc/pf_io.c +++ b/csrc/pf_io.c @@ -22,7 +22,9 @@ ***************************************************************/ #include "pf_all.h" - +#ifdef PF_UNIT_TEST +#include "paging/unittest.h" +#endif /*************************************************************** ** Initialize I/O system. @@ -241,3 +243,75 @@ ThrowCode sdResizeFile( FileStream * File, uint64_t NewSize ) #endif +#ifdef PF_UNIT_TEST +int pfQaFileIO(void) { + int savedNumFailed = pfQaNumFailed; + cell_t numWritten, numRead, c, result; + char buffer[128]; + const char kTestFileName[] = "pf_qa_fileio_test.txt"; + const char kTextNumbers[] = "0123456789"; + const int kTextNumbersSize = sizeof(kTextNumbers) - 1; /* skip NUL */ + const char kTextLines[] = "pumpkin\npie"; + const int kTextLinesSize = sizeof(kTextLines) - 1; /* skip NUL */ + + printf("pfQaFileIO() called\n"); + + /* Create a test file. */ + FileStream *fid = sdOpenFile(kTestFileName, PF_FAM_CREATE_WO); + ASSERT_NE(NULL, fid); + numWritten = sdWriteFile(kTextNumbers, 1, kTextNumbersSize, fid); + ASSERT_EQ(kTextNumbersSize, numWritten); + sdCloseFile(fid); + + /* Test repositioning within a file. */ + fid = sdOpenFile(kTestFileName, PF_FAM_OPEN_RO); + ASSERT_NE(NULL, fid); + ASSERT_EQ(0, sdTellFile(fid)); + ASSERT_EQ(0, sdSeekFile(fid, 5, PF_SEEK_SET)); + ASSERT_EQ(5, sdTellFile(fid)); + c = sdInputChar(fid); + ASSERT_EQ(kTextNumbers[5], c); + ASSERT_EQ(6, sdTellFile(fid)); + ASSERT_EQ(0, sdSeekFile(fid, 0, PF_SEEK_END)); + ASSERT_EQ(kTextNumbersSize, sdTellFile(fid)); + ASSERT_EQ(0, sdSeekFile(fid, -6, PF_SEEK_END)); + ASSERT_EQ(kTextNumbersSize - 6, sdTellFile(fid)); + c = sdInputChar(fid); + ASSERT_EQ(kTextNumbers[4], c); + ASSERT_EQ(5, sdTellFile(fid)); + ASSERT_EQ(0, sdSeekFile(fid, 2, PF_SEEK_CUR)); + ASSERT_EQ(7, sdTellFile(fid)); + ASSERT_EQ(0, sdSeekFile(fid, -4, PF_SEEK_CUR)); + ASSERT_EQ(3, sdTellFile(fid)); + + /* Test repositioning past the end of the file. + * fseek() behaves this way! */ + ASSERT_EQ(0, sdSeekFile(fid, 5, PF_SEEK_END)); + ASSERT_EQ(kTextNumbersSize + 5, sdTellFile(fid)); + + + /* Test repositioning past the beginning of the file. + * fseek() behaves this way! */ + ASSERT_EQ(0, sdSeekFile(fid, 3, PF_SEEK_SET)); + ASSERT_EQ(3, sdTellFile(fid)); + ASSERT_EQ(-1, sdSeekFile(fid, -5, PF_SEEK_SET)); + ASSERT_EQ(3, sdTellFile(fid)); + + sdCloseFile(fid); + + /* Cleanup */ + result = sdDeleteFile(kTestFileName); + ASSERT_EQ(0, result); + result = sdDeleteFile(kTestFileName); /* should fail */ + ASSERT_NE(0, result); + fid = sdOpenFile(kTestFileName, PF_FAM_OPEN_RO); /* should fail */ + ASSERT_EQ(NULL, fid); + + printf("pfQaFileIO() finished\n"); + +error: + PFQA_PRINT_RESULT; + return pfQaNumFailed - savedNumFailed; +} +#endif + diff --git a/csrc/pf_io.h b/csrc/pf_io.h index 667f5f2..242e9e6 100644 --- a/csrc/pf_io.h +++ b/csrc/pf_io.h @@ -177,6 +177,11 @@ cell_t ioKey( void); void ioEmit( char c ); void ioType( const char *s, cell_t n); + +#ifdef PF_UNIT_TEST +int pfQaFileIO(void); +#endif + #ifdef __cplusplus } #endif diff --git a/csrc/pf_save.c b/csrc/pf_save.c index 1e1c079..8919af4 100644 --- a/csrc/pf_save.c +++ b/csrc/pf_save.c @@ -389,7 +389,7 @@ cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, uint32_t CodeChunkSize; uint32_t relativeCodePtr; - fid = sdOpenFile( FileName, "wb" ); + fid = sdOpenFile( FileName, PF_FAM_BIN_CREATE_WO ); if( fid == NULL ) { pfReportError("pfSaveDictionary", PF_ERR_OPEN_FILE); @@ -542,7 +542,7 @@ PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPt DBUG(("pfLoadDictionary( %s )\n", FileName )); /* Open file. */ - fid = sdOpenFile( FileName, "rb" ); + fid = sdOpenFile( FileName, PF_FAM_BIN_OPEN_RO ); if( fid == NULL ) { pfReportError("pfLoadDictionary", PF_ERR_OPEN_FILE); diff --git a/csrc/pfcompil.c b/csrc/pfcompil.c index 4975662..8bda2f8 100644 --- a/csrc/pfcompil.c +++ b/csrc/pfcompil.c @@ -27,6 +27,10 @@ #include "pf_all.h" #include "pfcompil.h" +#ifdef PF_UNIT_TEST +#include "paging/unittest.h" +#endif + #define ABORT_RETURN_CODE (10) #define UCELL_MASK (((ucell_t)PF_CELL_SIZE) - 1) @@ -566,11 +570,9 @@ static cell_t ffCheckDicRoom( void ) */ void ffCreateSecondaryHeader( const ForthStringPtr FName) { - pfDebugMessage("ffCreateSecondaryHeader()\n"); /* Check for dictionary overflow. */ if( ffCheckDicRoom() ) return; - pfDebugMessage("ffCreateSecondaryHeader: CheckRedefinition()\n"); CheckRedefinition( FName ); /* Align CODE_HERE */ CODE_HERE = (CODE_HERE + UCELL_MASK) & ~UCELL_MASK; @@ -842,7 +844,6 @@ ThrowCode ffInterpret( void ) /* Is there any text left in Source ? */ while( gCurrentTask->td_IN < (gCurrentTask->td_SourceNum) ) { - pfDebugMessage("ffInterpret: calling ffWord(()\n"); theWord = ffLWord( BLANK ); DBUG(("ffInterpret: theWord = 0x%x, Len = %d\n", theWord, *theWord )); @@ -1101,7 +1102,6 @@ FileStream * ffConvertSourceIDToStream( cell_t id ) ** Receive line from input stream. ** Return length, or -1 for EOF. */ -#define BACKSPACE (8) static cell_t readLineFromStream( char *buffer, cell_t maxChars, FileStream *stream ) { int c; @@ -1143,7 +1143,11 @@ DBUGX(("readLineFromStream(0x%x, 0x%x, 0x%x)\n", buffer, len, stream )); } /* NUL terminate line to simplify printing when debugging. */ - if( (len >= 0) && (len < maxChars) ) *p = '\0'; + if( (len >= 0) && (len < maxChars) ) { + *p = '\0'; + pfDebugMessage(buffer); + pfDebugMessage("\n"); + } return len; } @@ -1208,3 +1212,41 @@ cell_t ffRefill( void ) error: return Result; } + + +#ifdef PF_UNIT_TEST +int pfQaCompile(void) { + int savedNumFailed = pfQaNumFailed; + cell_t numWritten, numRead, result; + char buffer[128]; + const char kTestFileName[] = "pf_qa_fileio_test.txt"; + const char kTextLines[] = "pumpkin\r\npie"; + const int kTextLinesSize = sizeof(kTextLines) - 1; /* skip NUL */ + + printf("pfQaCompile() called\n"); + + /* Create a test file with lines. */ + FileStream *fid = sdOpenFile(kTestFileName, PF_FAM_CREATE_WO); + ASSERT_NE(NULL, fid); + numWritten = sdWriteFile(kTextLines, 1, kTextLinesSize, fid); + ASSERT_EQ(kTextLinesSize, numWritten); + sdCloseFile(fid); + + fid = sdOpenFile(kTestFileName, PF_FAM_OPEN_RO); + numRead = readLineFromStream(buffer, sizeof(buffer), fid); + ASSERT_EQ(7, numRead); /* pumpkin */ + numRead = readLineFromStream(buffer, sizeof(buffer), fid); + ASSERT_EQ(3, numRead); /* pie */ + sdCloseFile(fid); + + /* Cleanup */ + result = sdDeleteFile(kTestFileName); + ASSERT_EQ(0, result); + + printf("pfQaCompile() finished\n"); + +error: + PFQA_PRINT_RESULT; + return pfQaNumFailed - savedNumFailed; +} +#endif diff --git a/csrc/pfcompil.h b/csrc/pfcompil.h index a94522e..df9ba91 100644 --- a/csrc/pfcompil.h +++ b/csrc/pfcompil.h @@ -70,6 +70,8 @@ ThrowCode ffIncludeFile( FileStream *InputFile ); void ffFPLiteral( PF_FLOAT fnum ); #endif +int pfQaCompile(void); + #ifdef __cplusplus } #endif