From f4c20290509d7ed3a8fd5304577e7a4cc0b9d974 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 3 Apr 2007 03:49:53 +0000 Subject: Ok, no code is left in src, it's all in src/old. We'll gradually move code back into src as it's fixed and re-org'd. This includes tests, which, I may write a unit test system into libbu++ just to make my life easier. --- src/unit/hashtable/hashtable.cpp | 107 --------------------------------------- src/unit/xml/xml.cpp | 59 --------------------- 2 files changed, 166 deletions(-) delete mode 100644 src/unit/hashtable/hashtable.cpp delete mode 100644 src/unit/xml/xml.cpp (limited to 'src/unit') diff --git a/src/unit/hashtable/hashtable.cpp b/src/unit/hashtable/hashtable.cpp deleted file mode 100644 index b2e1cf5..0000000 --- a/src/unit/hashtable/hashtable.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "hashfunctionstring.h" -#include "hashfunctioncasestring.h" -#include "hashfunctionint.h" - -class HashFunctionSuite : public Test::Suite -{ -public: - HashFunctionSuite() - { - TEST_ADD( HashFunctionSuite::functionString ) - TEST_ADD( HashFunctionSuite::functionCaseString ) - TEST_ADD( HashFunctionSuite::functionInt ) - } - -private: - void functionStringWorker( HashFunction &hf, std::set &sCodes, char *str, int nLevel, int nMax ) - { - for( char let = 'A'; let <= 'z'; let += 3 ) - { - str[nLevel+1] = '\0'; - str[nLevel] = let; - unsigned long x = hf.hash( str ); - TEST_ASSERT( sCodes.find( x ) == sCodes.end() ); - TEST_ASSERT( hf.cmpIDs( str, str ) ); - sCodes.insert( x ); - - if( nLevel < nMax ) - functionStringWorker( hf, sCodes, str, nLevel+1, nMax ); - } - } - - void functionString() - { - HashFunctionString hf; - char str[10]; - - std::set sCodes; - - functionStringWorker( hf, sCodes, str, 0, 3 ); - } - - void functionCaseStringWorker( HashFunction &hf, std::map &sCodes, char *str, int nLevel, int nMax ) - { - for( char let = 'A'; let <= 'z'; let += 3 ) - { - str[nLevel+1] = '\0'; - str[nLevel] = let; - unsigned long x = hf.hash( str ); - std::map::iterator i = sCodes.find( x ); - if( i == sCodes.end() ) - { - sCodes[x] = strdup( str ); - } - else - { - TEST_ASSERT( strcasecmp( (*i).second, str ) == 0 ); - TEST_ASSERT( hf.cmpIDs( (*i).second, str ) == true ); - } - - if( nLevel < nMax ) - functionCaseStringWorker( hf, sCodes, str, nLevel+1, nMax ); - } - } - - void functionCaseString() - { - HashFunctionCaseString hf; - char str[10]; - - std::map sCodes; - - functionCaseStringWorker( hf, sCodes, str, 0, 3 ); - - std::map::iterator i; - for( i = sCodes.begin(); i != sCodes.end(); i++ ) - { - free( (*i).second ); - } - } - - void functionInt() - { - HashFunctionInt hf; - - for( long i = -100000; i <= 100000; i += 100 ) - { - TEST_ASSERT( ((long)hf.hash( (void *)i )) == i ); - TEST_ASSERT( ((long)hf.cmpIDs( (void *)i, (void *)i )) ); - } - } -}; - -int main( int argc, char *argv[] ) -{ - Test::TextOutput output( Test::TextOutput::Verbose ); - HashFunctionSuite ts; - return ts.run( output ) ? EXIT_SUCCESS : EXIT_FAILURE; -} - diff --git a/src/unit/xml/xml.cpp b/src/unit/xml/xml.cpp deleted file mode 100644 index e4d779c..0000000 --- a/src/unit/xml/xml.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include -#include -#include - -#include "xmlstringreader.h" -#include "xmlexception.h" - -class XmlCoreTestSuite : public Test::Suite -{ -public: - XmlCoreTestSuite() - { - TEST_ADD( XmlCoreTestSuite::badXml01 ) - TEST_ADD( XmlCoreTestSuite::badXml02 ) - TEST_ADD( XmlCoreTestSuite::badXml03 ) - - TEST_ADD( XmlCoreTestSuite::entityBuiltin01 ) - - TEST_ADD( XmlCoreTestSuite::entityDoc01 ) - } - -private: - void badXml01() - { - TEST_THROWS( XmlStringReader r(""), XmlException & ); - } - - void badXml02() - { - TEST_THROWS( XmlStringReader r(""), XmlException & ); - } - - void badXml03() - { - TEST_THROWS( XmlStringReader r("><&'""); - TEST_ASSERT( strcmp( r.getRoot()->getContent(), "><&\'\"" ) == 0 ); - } - - void entityDoc01() - { - XmlStringReader r(""&name;""); - TEST_ASSERT( strcmp( r.getRoot()->getContent(), "\"bob the man\"" ) == 0 ); - } -}; - -int main( int argc, char *argv[] ) -{ - Test::TextOutput output( Test::TextOutput::Verbose ); - XmlCoreTestSuite ts; - return ts.run( output ) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -- cgit v1.2.3 From b6e100b94b12f3f92ec025dc2363eaf7c0ee6662 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 10 Apr 2007 16:02:07 +0000 Subject: Well, we've got the basis of a workable unit test harness thing. There should be a few more add-ons to it, but it works just fine, and eventually it should cover command line options and creating logs, and possibly even provide output functionality so that output from tests can be logged and kept track of well. --- build.conf | 16 +++++++++++++ src/fstring.h | 24 +++++++++++++++++++ src/ssocket.cpp | 4 ++-- src/unit/fstring.cpp | 28 ++++++++++++++++++++++ src/unit/sfile.cpp | 27 +++++++++++++++++++++ src/unitsuite.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/unitsuite.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 src/unit/fstring.cpp create mode 100644 src/unit/sfile.cpp create mode 100644 src/unitsuite.cpp create mode 100644 src/unitsuite.h (limited to 'src/unit') diff --git a/build.conf b/build.conf index 5c4dbb6..bc186f9 100644 --- a/build.conf +++ b/build.conf @@ -30,6 +30,22 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): set "LDFLAGS" += "-L. -lbu++", input "src/{target}.cpp" +directoriesIn("src/unit","unit/"): + rule "exe", + target file, + requires "libbu++.a", + set "CXXFLAGS" += "-Isrc", + set "LDFLAGS" += "-L. -lbu++", + input filesIn("{fulldir}") filter regexp("^.*\\.cpp$") + +filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): + rule "exe", + target file, + requires "libbu++.a", + set "CXXFLAGS" += "-Isrc", + set "LDFLAGS" += "-L. -lbu++", + input "src/{target}.cpp" + "tests/plugin": set "LDFLAGS" += "-ldl" rule "exe": diff --git a/src/fstring.h b/src/fstring.h index 0184301..751beb8 100644 --- a/src/fstring.h +++ b/src/fstring.h @@ -364,6 +364,30 @@ namespace Bu } } + long find( const char *sText ) + { + long nTLen = strlen( sText ); + flatten(); + for( long j = 0; j < pFirst->nLength-nTLen; j++ ) + { + if( !strncmp( sText, pFirst->pData+j, nTLen ) ) + return j; + } + return -1; + } + + long rfind( const char *sText ) + { + long nTLen = strlen( sText ); + flatten(); + for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- ) + { + if( !strncmp( sText, pFirst->pData+j, nTLen ) ) + return j; + } + return -1; + } + void archive( class Archive &ar ) { if( ar.isLoading() ) diff --git a/src/ssocket.cpp b/src/ssocket.cpp index bdaac24..85a2da0 100644 --- a/src/ssocket.cpp +++ b/src/ssocket.cpp @@ -1,9 +1,9 @@ #include "ssocket.h" -SSocket::SSocket() +Bu::SSocket::SSocket() { } -SSocket::~SSocket() +Bu::SSocket::~SSocket() { } diff --git a/src/unit/fstring.cpp b/src/unit/fstring.cpp new file mode 100644 index 0000000..72755eb --- /dev/null +++ b/src/unit/fstring.cpp @@ -0,0 +1,28 @@ +#include "fstring.h" +#include "unitsuite.h" + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("FString"); + addTest( Unit::test1 ); + } + + virtual ~Unit() + { + } + + void test1() + { + unitTest( 1 == 1 ); + unitTest( 1 == 0 ); + } +}; + +int main( int argc, char *argv[] ) +{ + return Unit().run( argc, argv ); +} + diff --git a/src/unit/sfile.cpp b/src/unit/sfile.cpp new file mode 100644 index 0000000..7b19942 --- /dev/null +++ b/src/unit/sfile.cpp @@ -0,0 +1,27 @@ +#include "unitsuite.h" + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("SFile"); + addTest( Unit::test ); + } + + virtual ~Unit() { } + + // + // Tests go here + // + void test() + { + unitTest( 1 == 1 ); + } +}; + +int main( int argc, char *argv[] ) +{ + return Unit().run( argc, argv ); +} + diff --git a/src/unitsuite.cpp b/src/unitsuite.cpp new file mode 100644 index 0000000..2a28eb5 --- /dev/null +++ b/src/unitsuite.cpp @@ -0,0 +1,67 @@ +#include "unitsuite.h" + +Bu::UnitSuite::UnitSuite() +{ +} + +Bu::UnitSuite::~UnitSuite() +{ +} + +int Bu::UnitSuite::run( int argc, char *argv[] ) +{ + for( TestList::iterator i = lTests.begin(); i != lTests.end(); i++ ) + { + printf("%s: ", i->sName.getStr() ); + fflush( stdout ); + try + { + (this->*(i->fTest))(); + printf("passed.\n"); + } + catch( Failed &e ) + { + if( e.bFile ) + { + printf("unitTest(%s) failed. (%s:%d)\n", + e.str.getStr(), + e.sFile.getStr(), + e.nLine + ); + } + else + { + printf("unitTest(%s) failed.\n", + e.str.getStr() + ); + } + } + catch( ... ) + { + printf("failed with external exception.\n"); + } + } + + return 0; +} + +void Bu::UnitSuite::add( Test fTest, Bu::FString sName ) +{ + TestInfo ti; + ti.sName = sName; + long index = ti.sName.rfind("::"); + if( index != -1 ) + { + FString tmp = sSuiteName; + tmp += ti.sName.getStr()+index; + ti.sName = tmp; + } + ti.fTest = fTest; + lTests.push_back( ti ); +} + +void Bu::UnitSuite::setName( const FString &sName ) +{ + sSuiteName = sName; +} + diff --git a/src/unitsuite.h b/src/unitsuite.h new file mode 100644 index 0000000..3502a1b --- /dev/null +++ b/src/unitsuite.h @@ -0,0 +1,60 @@ +#ifndef UNIT_SUITE_H +#define UNIT_SUITE_H + +#include +#include +#include "fstring.h" + +namespace Bu +{ + /** + * + */ + class UnitSuite + { + public: + UnitSuite(); + virtual ~UnitSuite(); + + int run( int argc=0, char *argv[]=NULL ); + + typedef void (UnitSuite::*Test)(); + + class Failed + { + public: + Failed() : str(""), bFile( false ) { } + Failed( const FString &s ) : str( s ), bFile( false ) { } + Failed( const FString &s, const FString &sFile, int nLine ) : + str( s ), sFile( sFile ), nLine( nLine ), bFile( true ) { } + + FString str; + FString sFile; + int nLine; + bool bFile; + }; + + protected: + void add( Test fTest, Bu::FString sName ); + void setName( const FString &sName ); + + private: + typedef struct TestInfo + { + FString sName; + Test fTest; + } TestInfo; + + typedef std::list TestList; + TestList lTests; + FString sSuiteName; + }; +} + +#define addTest( fn ) add( static_cast(&fn), #fn ) +#define unitTest( tst ) if( !(tst) ) \ +{ \ + throw Bu::UnitSuite::Failed( #tst, __FILE__, __LINE__ ); \ +} + +#endif -- cgit v1.2.3 From 903e7a1e3d4fe99e9de7f4adc1e401ba871caec9 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 10 Apr 2007 17:23:35 +0000 Subject: Wrote some cute file unit tests, and added some more error reporting to SFile. Also fixed the stream system to use void * pointers instead of char *. --- src/sfile.cpp | 16 +++++++++-- src/sfile.h | 4 +-- src/stream.h | 4 +-- src/unit/sfile.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/unitsuite.h | 1 + 5 files changed, 99 insertions(+), 10 deletions(-) (limited to 'src/unit') diff --git a/src/sfile.cpp b/src/sfile.cpp index d7c5c83..529d8cd 100644 --- a/src/sfile.cpp +++ b/src/sfile.cpp @@ -1,9 +1,14 @@ #include "sfile.h" #include "exceptions.h" +#include Bu::SFile::SFile( const char *sName, const char *sFlags ) { fh = fopen( sName, sFlags ); + if( fh == NULL ) + { + throw Bu::FileException( errno, strerror(errno) ); + } } Bu::SFile::~SFile() @@ -20,15 +25,20 @@ void Bu::SFile::close() } } -size_t Bu::SFile::read( char *pBuf, size_t nBytes ) +size_t Bu::SFile::read( void *pBuf, size_t nBytes ) { if( !fh ) throw FileException("File not open."); - return fread( pBuf, 1, nBytes, fh ); + int nAmnt = fread( pBuf, 1, nBytes, fh ); + + if( nAmnt == 0 ) + throw FileException("End of file."); + + return nAmnt; } -size_t Bu::SFile::write( const char *pBuf, size_t nBytes ) +size_t Bu::SFile::write( const void *pBuf, size_t nBytes ) { if( !fh ) throw FileException("File not open."); diff --git a/src/sfile.h b/src/sfile.h index 304f6b7..f63b812 100644 --- a/src/sfile.h +++ b/src/sfile.h @@ -14,8 +14,8 @@ namespace Bu virtual ~SFile(); virtual void close(); - virtual size_t read( char *pBuf, size_t nBytes ); - virtual size_t write( const char *pBuf, size_t nBytes ); + virtual size_t read( void *pBuf, size_t nBytes ); + virtual size_t write( const void *pBuf, size_t nBytes ); virtual long tell(); virtual void seek( long offset ); diff --git a/src/stream.h b/src/stream.h index 274f4fd..ae94234 100644 --- a/src/stream.h +++ b/src/stream.h @@ -13,8 +13,8 @@ namespace Bu virtual ~Stream(); virtual void close() = 0; - virtual size_t read( char *pBuf, size_t nBytes ) = 0; - virtual size_t write( const char *pBuf, size_t nBytes ) = 0; + virtual size_t read( void *pBuf, size_t nBytes ) = 0; + virtual size_t write( const void *pBuf, size_t nBytes ) = 0; virtual long tell() = 0; virtual void seek( long offset ) = 0; diff --git a/src/unit/sfile.cpp b/src/unit/sfile.cpp index 7b19942..3f52272 100644 --- a/src/unit/sfile.cpp +++ b/src/unit/sfile.cpp @@ -1,4 +1,10 @@ #include "unitsuite.h" +#include "sfile.h" +#include "exceptions.h" + +#include +#include +#include class Unit : public Bu::UnitSuite { @@ -6,7 +12,10 @@ public: Unit() { setName("SFile"); - addTest( Unit::test ); + addTest( Unit::writeFull ); + addTest( Unit::readBlocks ); + addTest( Unit::readError1 ); + addTest( Unit::readError2 ); } virtual ~Unit() { } @@ -14,9 +23,78 @@ public: // // Tests go here // - void test() + void writeFull() + { + Bu::SFile sf("testfile1", "wb"); + for( int c = 0; c < 256; c++ ) + { + unsigned char ch = (unsigned char)c; + sf.write( &ch, 1 ); + unitTest( sf.tell() == c+1 ); + } + //unitTest( sf.canRead() == false ); + //unitTest( sf.canWrite() == true ); + //unitTest( sf.canSeek() == true ); + sf.close(); + struct stat sdat; + stat("testfile1", &sdat ); + unitTest( sdat.st_size == 256 ); + } + + void readBlocks() + { + Bu::SFile sf("testfile1", "rb"); + unsigned char buf[50]; + size_t total = 0; + for(;;) + { + size_t s = sf.read( buf, 50 ); + for( size_t c = 0; c < s; c++ ) + { + unitTest( buf[c] == (unsigned char)(c+total) ); + } + total += s; + if( s < 50 ) + { + unitTest( total == 256 ); + unitTest( sf.isEOS() == true ); + break; + } + } + sf.close(); + } + + void readError1() + { + try + { + Bu::SFile sf("doesn'texist", "rb"); + unitFailed("No exception thrown"); + } + catch( Bu::FileException &e ) + { + return; + } + } + + void readError2() { - unitTest( 1 == 1 ); + Bu::SFile sf("testfile1", "rb"); + char buf[256]; + int r = sf.read( buf, 256 ); + unitTest( r == 256 ); + // You have to read past the end to set the EOS flag. + unitTest( sf.isEOS() == false ); + try + { + int r = sf.read( buf, 5 ); + unitFailed("No exception thrown"); + } + catch( Bu::FileException &e ) + { + sf.close(); + return; + } } }; diff --git a/src/unitsuite.h b/src/unitsuite.h index 3502a1b..db249b2 100644 --- a/src/unitsuite.h +++ b/src/unitsuite.h @@ -56,5 +56,6 @@ namespace Bu { \ throw Bu::UnitSuite::Failed( #tst, __FILE__, __LINE__ ); \ } +#define unitFailed( msg ) throw Bu::UnitSuite::Failed(msg, __FILE__, __LINE__); #endif -- cgit v1.2.3 From e7ab7cb1604c04763bbdcece5885e6ce5aa100b4 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 10 Apr 2007 17:37:46 +0000 Subject: Fixed a warning in the SFile test, and added std::list support to the archive. I guess I should write a test for it too... I'm also thinking of removing the S from the front of the stream children. --- src/archive.cpp | 13 ------------- src/archive.h | 29 +++++++++++++++++++++++++++++ src/unit/sfile.cpp | 2 +- 3 files changed, 30 insertions(+), 14 deletions(-) (limited to 'src/unit') diff --git a/src/archive.cpp b/src/archive.cpp index edc8625..c759477 100644 --- a/src/archive.cpp +++ b/src/archive.cpp @@ -324,19 +324,6 @@ Bu::Archive &Bu::operator>>(Bu::Archive &s, Bu::Archival &p) return s; } -/* -Bu::Archive &Bu::operator&&(Bu::Archive &s, Bu::Archival &p) -{ - if (s.isLoading()) - { - return s >> p; - } - else - { - return s << p; - } -}*/ - Bu::Archive &Bu::operator<<( Bu::Archive &ar, std::string &s ) { ar << (uint32_t)s.length(); diff --git a/src/archive.h b/src/archive.h index a8ce53e..9ac3303 100644 --- a/src/archive.h +++ b/src/archive.h @@ -5,6 +5,7 @@ #include #include "archival.h" #include "stream.h" +#include namespace Bu { @@ -92,6 +93,34 @@ namespace Bu return ar << dat; } } + + template Archive &operator<<( Archive &ar, std::list &l ) + { + typename std::list::size_type num = l.size(); + ar << num; + for( typename std::list::const_iterator i = l.begin(); i != l.end(); + i++ ) + { + ar << *i; + } + + return ar; + } + + template Archive &operator>>( Archive &ar, std::list &l ) + { + typename std::list::size_type num; + ar >> num; + + l.resize( num ); + for( typename std::list::const_iterator i = l.begin(); + i != l.end(); i++ ) + { + ar >> *i; + } + + return ar; + } } #endif diff --git a/src/unit/sfile.cpp b/src/unit/sfile.cpp index 3f52272..2aff312 100644 --- a/src/unit/sfile.cpp +++ b/src/unit/sfile.cpp @@ -87,7 +87,7 @@ public: unitTest( sf.isEOS() == false ); try { - int r = sf.read( buf, 5 ); + sf.read( buf, 5 ); unitFailed("No exception thrown"); } catch( Bu::FileException &e ) -- cgit v1.2.3 From 070374dde0f53bff26078550997f7682e84412e5 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 10 Apr 2007 20:16:19 +0000 Subject: I did it, the streams don't start with an S now. --- src/file.cpp | 100 +++++++++++++++++++++++++++++++++++++++++++++++ src/file.h | 36 +++++++++++++++++ src/sfile.cpp | 100 ----------------------------------------------- src/sfile.h | 36 ----------------- src/socket.cpp | 10 +++++ src/socket.h | 24 ++++++++++++ src/ssocket.cpp | 9 ----- src/ssocket.h | 24 ------------ src/tests/archive.cpp | 4 +- src/unit/file.cpp | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/unit/sfile.cpp | 105 -------------------------------------------------- src/unitsuite.h | 35 +++++++++++++++++ 12 files changed, 312 insertions(+), 276 deletions(-) create mode 100644 src/file.cpp create mode 100644 src/file.h delete mode 100644 src/sfile.cpp delete mode 100644 src/sfile.h create mode 100644 src/socket.cpp create mode 100644 src/socket.h delete mode 100644 src/ssocket.cpp delete mode 100644 src/ssocket.h create mode 100644 src/unit/file.cpp delete mode 100644 src/unit/sfile.cpp (limited to 'src/unit') diff --git a/src/file.cpp b/src/file.cpp new file mode 100644 index 0000000..5de5f6c --- /dev/null +++ b/src/file.cpp @@ -0,0 +1,100 @@ +#include "file.h" +#include "exceptions.h" +#include + +Bu::File::File( const char *sName, const char *sFlags ) +{ + fh = fopen( sName, sFlags ); + if( fh == NULL ) + { + throw Bu::FileException( errno, strerror(errno) ); + } +} + +Bu::File::~File() +{ + close(); +} + +void Bu::File::close() +{ + if( fh ) + { + fclose( fh ); + fh = NULL; + } +} + +size_t Bu::File::read( void *pBuf, size_t nBytes ) +{ + if( !fh ) + throw FileException("File not open."); + + int nAmnt = fread( pBuf, 1, nBytes, fh ); + + if( nAmnt == 0 ) + throw FileException("End of file."); + + return nAmnt; +} + +size_t Bu::File::write( const void *pBuf, size_t nBytes ) +{ + if( !fh ) + throw FileException("File not open."); + + return fwrite( pBuf, 1, nBytes, fh ); +} + +long Bu::File::tell() +{ + if( !fh ) + throw FileException("File not open."); + + return ftell( fh ); +} + +void Bu::File::seek( long offset ) +{ + if( !fh ) + throw FileException("File not open."); + + fseek( fh, offset, SEEK_CUR ); +} + +void Bu::File::setPos( long pos ) +{ + if( !fh ) + throw FileException("File not open."); + + fseek( fh, pos, SEEK_SET ); +} + +void Bu::File::setPosEnd( long pos ) +{ + if( !fh ) + throw FileException("File not open."); + + fseek( fh, pos, SEEK_END ); +} + +bool Bu::File::isEOS() +{ + return feof( fh ); +} + +bool Bu::File::canRead() +{ + return true; +} + +bool Bu::File::canWrite() +{ + return true; +} + +bool Bu::File::canSeek() +{ + return true; +} + diff --git a/src/file.h b/src/file.h new file mode 100644 index 0000000..bbc620c --- /dev/null +++ b/src/file.h @@ -0,0 +1,36 @@ +#ifndef FILE_H +#define FILE_H + +#include + +#include "stream.h" + +namespace Bu +{ + class File : public Bu::Stream + { + public: + File( const char *sName, const char *sFlags ); + virtual ~File(); + + virtual void close(); + virtual size_t read( void *pBuf, size_t nBytes ); + virtual size_t write( const void *pBuf, size_t nBytes ); + + virtual long tell(); + virtual void seek( long offset ); + virtual void setPos( long pos ); + virtual void setPosEnd( long pos ); + virtual bool isEOS(); + + virtual bool canRead(); + virtual bool canWrite(); + virtual bool canSeek(); + + private: + FILE *fh; + + }; +} + +#endif diff --git a/src/sfile.cpp b/src/sfile.cpp deleted file mode 100644 index 529d8cd..0000000 --- a/src/sfile.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "sfile.h" -#include "exceptions.h" -#include - -Bu::SFile::SFile( const char *sName, const char *sFlags ) -{ - fh = fopen( sName, sFlags ); - if( fh == NULL ) - { - throw Bu::FileException( errno, strerror(errno) ); - } -} - -Bu::SFile::~SFile() -{ - close(); -} - -void Bu::SFile::close() -{ - if( fh ) - { - fclose( fh ); - fh = NULL; - } -} - -size_t Bu::SFile::read( void *pBuf, size_t nBytes ) -{ - if( !fh ) - throw FileException("File not open."); - - int nAmnt = fread( pBuf, 1, nBytes, fh ); - - if( nAmnt == 0 ) - throw FileException("End of file."); - - return nAmnt; -} - -size_t Bu::SFile::write( const void *pBuf, size_t nBytes ) -{ - if( !fh ) - throw FileException("File not open."); - - return fwrite( pBuf, 1, nBytes, fh ); -} - -long Bu::SFile::tell() -{ - if( !fh ) - throw FileException("File not open."); - - return ftell( fh ); -} - -void Bu::SFile::seek( long offset ) -{ - if( !fh ) - throw FileException("File not open."); - - fseek( fh, offset, SEEK_CUR ); -} - -void Bu::SFile::setPos( long pos ) -{ - if( !fh ) - throw FileException("File not open."); - - fseek( fh, pos, SEEK_SET ); -} - -void Bu::SFile::setPosEnd( long pos ) -{ - if( !fh ) - throw FileException("File not open."); - - fseek( fh, pos, SEEK_END ); -} - -bool Bu::SFile::isEOS() -{ - return feof( fh ); -} - -bool Bu::SFile::canRead() -{ - return true; -} - -bool Bu::SFile::canWrite() -{ - return true; -} - -bool Bu::SFile::canSeek() -{ - return true; -} - diff --git a/src/sfile.h b/src/sfile.h deleted file mode 100644 index f63b812..0000000 --- a/src/sfile.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SFILE_H -#define SFILE_H - -#include - -#include "stream.h" - -namespace Bu -{ - class SFile : public Bu::Stream - { - public: - SFile( const char *sName, const char *sFlags ); - virtual ~SFile(); - - virtual void close(); - virtual size_t read( void *pBuf, size_t nBytes ); - virtual size_t write( const void *pBuf, size_t nBytes ); - - virtual long tell(); - virtual void seek( long offset ); - virtual void setPos( long pos ); - virtual void setPosEnd( long pos ); - virtual bool isEOS(); - - virtual bool canRead(); - virtual bool canWrite(); - virtual bool canSeek(); - - private: - FILE *fh; - - }; -} - -#endif diff --git a/src/socket.cpp b/src/socket.cpp new file mode 100644 index 0000000..c5c592b --- /dev/null +++ b/src/socket.cpp @@ -0,0 +1,10 @@ +#include "socket.h" + +Bu::Socket::Socket() +{ +} + +Bu::Socket::~Socket() +{ +} + diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000..8ccde71 --- /dev/null +++ b/src/socket.h @@ -0,0 +1,24 @@ +#ifndef SOCKET_H +#define SOCKET_H + +#include + +#include "stream.h" + +namespace Bu +{ + /** + * + */ + class Socket : public Stream + { + public: + Socket(); + virtual ~Socket(); + + private: + + }; +} + +#endif diff --git a/src/ssocket.cpp b/src/ssocket.cpp deleted file mode 100644 index 85a2da0..0000000 --- a/src/ssocket.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "ssocket.h" - -Bu::SSocket::SSocket() -{ -} - -Bu::SSocket::~SSocket() -{ -} diff --git a/src/ssocket.h b/src/ssocket.h deleted file mode 100644 index ce02091..0000000 --- a/src/ssocket.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef S_SOCKET_H -#define S_SOCKET_H - -#include - -#include "stream.h" - -namespace Bu -{ - /** - * - */ - class SSocket : public Stream - { - public: - SSocket(); - virtual ~SSocket(); - - private: - - }; -} - -#endif diff --git a/src/tests/archive.cpp b/src/tests/archive.cpp index 5b7e285..2035aa6 100644 --- a/src/tests/archive.cpp +++ b/src/tests/archive.cpp @@ -1,11 +1,11 @@ #include "archive.h" -#include "sfile.h" +#include "file.h" using namespace Bu; int main() { - SFile f("test.dat", "wb"); + File f("test.dat", "wb"); Archive ar( f, Archive::save ); std::string s("Hello there"); diff --git a/src/unit/file.cpp b/src/unit/file.cpp new file mode 100644 index 0000000..a45b8d7 --- /dev/null +++ b/src/unit/file.cpp @@ -0,0 +1,105 @@ +#include "unitsuite.h" +#include "file.h" +#include "exceptions.h" + +#include +#include +#include + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("File"); + addTest( Unit::writeFull ); + addTest( Unit::readBlocks ); + addTest( Unit::readError1 ); + addTest( Unit::readError2 ); + } + + virtual ~Unit() { } + + // + // Tests go here + // + void writeFull() + { + Bu::File sf("testfile1", "wb"); + for( int c = 0; c < 256; c++ ) + { + unsigned char ch = (unsigned char)c; + sf.write( &ch, 1 ); + unitTest( sf.tell() == c+1 ); + } + //unitTest( sf.canRead() == false ); + //unitTest( sf.canWrite() == true ); + //unitTest( sf.canSeek() == true ); + sf.close(); + struct stat sdat; + stat("testfile1", &sdat ); + unitTest( sdat.st_size == 256 ); + } + + void readBlocks() + { + Bu::File sf("testfile1", "rb"); + unsigned char buf[50]; + size_t total = 0; + for(;;) + { + size_t s = sf.read( buf, 50 ); + for( size_t c = 0; c < s; c++ ) + { + unitTest( buf[c] == (unsigned char)(c+total) ); + } + total += s; + if( s < 50 ) + { + unitTest( total == 256 ); + unitTest( sf.isEOS() == true ); + break; + } + } + sf.close(); + } + + void readError1() + { + try + { + Bu::File sf("doesn'texist", "rb"); + unitFailed("No exception thrown"); + } + catch( Bu::FileException &e ) + { + return; + } + } + + void readError2() + { + Bu::File sf("testfile1", "rb"); + char buf[256]; + int r = sf.read( buf, 256 ); + unitTest( r == 256 ); + // You have to read past the end to set the EOS flag. + unitTest( sf.isEOS() == false ); + try + { + sf.read( buf, 5 ); + unitFailed("No exception thrown"); + } + catch( Bu::FileException &e ) + { + sf.close(); + return; + } + } +}; + +int main( int argc, char *argv[] ) +{ + return Unit().run( argc, argv ); +} + diff --git a/src/unit/sfile.cpp b/src/unit/sfile.cpp deleted file mode 100644 index 2aff312..0000000 --- a/src/unit/sfile.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "unitsuite.h" -#include "sfile.h" -#include "exceptions.h" - -#include -#include -#include - -class Unit : public Bu::UnitSuite -{ -public: - Unit() - { - setName("SFile"); - addTest( Unit::writeFull ); - addTest( Unit::readBlocks ); - addTest( Unit::readError1 ); - addTest( Unit::readError2 ); - } - - virtual ~Unit() { } - - // - // Tests go here - // - void writeFull() - { - Bu::SFile sf("testfile1", "wb"); - for( int c = 0; c < 256; c++ ) - { - unsigned char ch = (unsigned char)c; - sf.write( &ch, 1 ); - unitTest( sf.tell() == c+1 ); - } - //unitTest( sf.canRead() == false ); - //unitTest( sf.canWrite() == true ); - //unitTest( sf.canSeek() == true ); - sf.close(); - struct stat sdat; - stat("testfile1", &sdat ); - unitTest( sdat.st_size == 256 ); - } - - void readBlocks() - { - Bu::SFile sf("testfile1", "rb"); - unsigned char buf[50]; - size_t total = 0; - for(;;) - { - size_t s = sf.read( buf, 50 ); - for( size_t c = 0; c < s; c++ ) - { - unitTest( buf[c] == (unsigned char)(c+total) ); - } - total += s; - if( s < 50 ) - { - unitTest( total == 256 ); - unitTest( sf.isEOS() == true ); - break; - } - } - sf.close(); - } - - void readError1() - { - try - { - Bu::SFile sf("doesn'texist", "rb"); - unitFailed("No exception thrown"); - } - catch( Bu::FileException &e ) - { - return; - } - } - - void readError2() - { - Bu::SFile sf("testfile1", "rb"); - char buf[256]; - int r = sf.read( buf, 256 ); - unitTest( r == 256 ); - // You have to read past the end to set the EOS flag. - unitTest( sf.isEOS() == false ); - try - { - sf.read( buf, 5 ); - unitFailed("No exception thrown"); - } - catch( Bu::FileException &e ) - { - sf.close(); - return; - } - } -}; - -int main( int argc, char *argv[] ) -{ - return Unit().run( argc, argv ); -} - diff --git a/src/unitsuite.h b/src/unitsuite.h index db249b2..6e9270a 100644 --- a/src/unitsuite.h +++ b/src/unitsuite.h @@ -8,7 +8,42 @@ namespace Bu { /** + * Provides a unit testing framework. This is pretty easy to use, probably + * the best way to get started is to use ch to generate a template, or use + * the code below with appropriate tweaks: + *@code + * #include "unitsuite.h" + * + * class Unit : public Bu::UnitSuite + * { + * public: + * Unit() + * { + * setName("Example"); + * addTest( Unit::test ); + * } + * + * virtual ~Unit() { } + * + * // + * // Tests go here + * // + * void test() + * { + * unitTest( 1 == 1 ); + * } + * }; + * + * int main( int argc, char *argv[] ) + * { + * return Unit().run( argc, argv ); + * } * + @endcode + * The main function can contain other things, but using this one exactly + * makes all of the test suites work exactly the same. Using the optional + * setName at the top of the constructor replaces the class name with the + * chosen name when printing out stats and info. */ class UnitSuite { -- cgit v1.2.3 From 2b90449c30e4a420af4fff7e58588611d71f61fc Mon Sep 17 00:00:00 2001 From: David Date: Fri, 15 Jun 2007 18:54:59 +0000 Subject: david - wrote two silly unit tests... --- src/unit/hash.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/unit/taf.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/unit/hash.cpp create mode 100644 src/unit/taf.cpp (limited to 'src/unit') diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp new file mode 100644 index 0000000..588e687 --- /dev/null +++ b/src/unit/hash.cpp @@ -0,0 +1,40 @@ +#include "bu/fstring.h" +#include "bu/hash.h" +#include "unitsuite.h" + +#include + +class Unit : public Bu::UnitSuite +{ +private: + typedef Bu::Hash StrIntHash; +public: + Unit() + { + setName("Hash"); + addTest( Unit::test_probe ); + } + + virtual ~Unit() + { + } + + void test_probe() + { + StrIntHash h; + char buf[20]; + for(int i=0;i<10000;i++) + { + sprintf(buf,"%d",i); + Bu::FString sTmp(buf); + h[sTmp] = i; + unitTest( h.has(sTmp) ); + } + } +}; + +int main( int argc, char *argv[] ) +{ + return Unit().run( argc, argv ); +} + diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp new file mode 100644 index 0000000..ab485d0 --- /dev/null +++ b/src/unit/taf.cpp @@ -0,0 +1,48 @@ +#include "unitsuite.h" +#include "file.h" +#include "tafreader.h" + +#include +#include + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("taf"); + addTest( Unit::read1 ); + } + + virtual ~Unit() + { + } + + void read1() + { +#define FN_TMP ("/tmp/tmpXXXXXXXX") + Bu::FString sFnTmp(FN_TMP); + Bu::File fOut = Bu::File::tempFile( sFnTmp, "wb" ); + const char *data = +"{test: name=\"Bob\"}" +; + fOut.write(data,strlen(data)); + fOut.close(); + + Bu::File fIn(sFnTmp.c_str(), "rb"); + Bu::TafReader tr(fIn); + + Bu::TafNode *tn = tr.getNode(); + unitTest( !strcmp("Bob", tn->getProperty("name").c_str()) ); + delete tn; + + unlink(sFnTmp.c_str()); +#undef FN_TMP + } +}; + +int main( int argc, char *argv[] ) +{ + return Unit().run( argc, argv ); +} + -- cgit v1.2.3 From 5ec9a131e12d021c42b46b601f5e79502485bebb Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 27 Jun 2007 15:42:50 +0000 Subject: The MemBuf works just fine, although it still can't over-write data in the buffer. --- build.conf | 9 --------- src/membuf.cpp | 30 +++++++++++++++++++++++++++++- src/membuf.h | 7 +++++++ src/unit/entities/unit | 30 ++++++++++++++++++++++++++++++ src/unit/file.cpp | 10 ++++++++-- src/unit/hash.cpp | 4 ++-- src/unit/membuf.cpp | 37 +++++++++++++++++++++++++++++++++++++ 7 files changed, 113 insertions(+), 14 deletions(-) create mode 100644 src/unit/entities/unit create mode 100644 src/unit/membuf.cpp (limited to 'src/unit') diff --git a/build.conf b/build.conf index f493d67..d994977 100644 --- a/build.conf +++ b/build.conf @@ -41,15 +41,6 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): ["tests/itoqueue1", "tests/itoqueue2"]: set "LDFLAGS" += "-lpthread" -directoriesIn("src/unit","unit/"): - rule "exe", - target file, - group "tests", - requires "libbu++.a", - set "CXXFLAGS" += "-Isrc", - set "LDFLAGS" += "-L. -lbu++", - input filesIn("{fulldir}") filter regexp("^.*\\.cpp$") - filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): rule "exe", target file, diff --git a/src/membuf.cpp b/src/membuf.cpp index fdb4366..3c394b0 100644 --- a/src/membuf.cpp +++ b/src/membuf.cpp @@ -2,7 +2,8 @@ using namespace Bu; -Bu::MemBuf::MemBuf() +Bu::MemBuf::MemBuf() : + nPos( 0 ) { } @@ -16,35 +17,56 @@ void Bu::MemBuf::close() size_t Bu::MemBuf::read( void *pBuf, size_t nBytes ) { + if( (size_t)sBuf.getSize()-(size_t)nPos < nBytes ) + nBytes = sBuf.getSize()-nPos; + memcpy( pBuf, sBuf.getStr()+nPos, nBytes ); + nPos += nBytes; + + return nBytes; } size_t Bu::MemBuf::write( const void *pBuf, size_t nBytes ) { + sBuf.append( (const char *)pBuf, nBytes ); + nPos += nBytes; + return nBytes; } long Bu::MemBuf::tell() { + return nPos; } void Bu::MemBuf::seek( long offset ) { + nPos += offset; + if( nPos < 0 ) nPos = 0; + else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); } void Bu::MemBuf::setPos( long pos ) { + nPos = pos; + if( nPos < 0 ) nPos = 0; + else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); } void Bu::MemBuf::setPosEnd( long pos ) { + nPos = sBuf.getSize()-pos; + if( nPos < 0 ) nPos = 0; + else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize(); } bool Bu::MemBuf::isEOS() { + return (nPos == sBuf.getSize()); } bool Bu::MemBuf::isOpen() { + return true; } void Bu::MemBuf::flush() @@ -53,26 +75,32 @@ void Bu::MemBuf::flush() bool Bu::MemBuf::canRead() { + return !isEOS(); } bool Bu::MemBuf::canWrite() { + return isEOS(); } bool Bu::MemBuf::isReadable() { + return true; } bool Bu::MemBuf::isWritable() { + return true; } bool Bu::MemBuf::isSeekable() { + return true; } bool Bu::MemBuf::isBlocking() { + return true; } void Bu::MemBuf::setBlocking( bool bBlocking ) diff --git a/src/membuf.h b/src/membuf.h index 2cbbbdc..877b35e 100644 --- a/src/membuf.h +++ b/src/membuf.h @@ -4,6 +4,7 @@ #include #include "bu/stream.h" +#include "bu/fstring.h" namespace Bu { @@ -18,6 +19,12 @@ namespace Bu virtual void close(); virtual size_t read( void *pBuf, size_t nBytes ); + + /** + *@todo Allow writes at the current position, not just appending to + * the current buffer. This is a silly way to do it, but it covers all + * of our bases for now. + */ virtual size_t write( const void *pBuf, size_t nBytes ); virtual long tell(); virtual void seek( long offset ); diff --git a/src/unit/entities/unit b/src/unit/entities/unit new file mode 100644 index 0000000..28db45f --- /dev/null +++ b/src/unit/entities/unit @@ -0,0 +1,30 @@ + + + + #include "bu/unitsuite.h" + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("{=name}"); + addTest( Unit::test01 ); + } + + virtual ~Unit() + { + } + + void test01() + { + unitTest( 0 == 5 ); + } +}; + +int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); } + + diff --git a/src/unit/file.cpp b/src/unit/file.cpp index a45b8d7..1eaaf36 100644 --- a/src/unit/file.cpp +++ b/src/unit/file.cpp @@ -87,8 +87,14 @@ public: unitTest( sf.isEOS() == false ); try { - sf.read( buf, 5 ); - unitFailed("No exception thrown"); + if( sf.read( buf, 5 ) > 0 ) + { + unitFailed("Non-zero read result"); + } + else + { + sf.close(); + } } catch( Bu::FileException &e ) { diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp index 588e687..9ea933f 100644 --- a/src/unit/hash.cpp +++ b/src/unit/hash.cpp @@ -1,6 +1,6 @@ #include "bu/fstring.h" #include "bu/hash.h" -#include "unitsuite.h" +#include "bu/unitsuite.h" #include @@ -23,7 +23,7 @@ public: { StrIntHash h; char buf[20]; - for(int i=0;i<10000;i++) + for(int i=1;i<10000;i++) { sprintf(buf,"%d",i); Bu::FString sTmp(buf); diff --git a/src/unit/membuf.cpp b/src/unit/membuf.cpp new file mode 100644 index 0000000..65ba82a --- /dev/null +++ b/src/unit/membuf.cpp @@ -0,0 +1,37 @@ +#include "bu/unitsuite.h" +#include "bu/membuf.h" + +class Unit : public Bu::UnitSuite +{ +public: + Unit() + { + setName("MemBuf"); + addTest( Unit::testWriteRead01 ); + } + + virtual ~Unit() + { + } + + void testWriteRead01() + { + Bu::MemBuf mb; + unitTest( mb.write("ab", 2 ) == 2 ); + unitTest( mb.write("cde", 3 ) == 3 ); + unitTest( mb.write("FG", 2 ) == 2 ); + + mb.setPos( 0 ); + + char buf[8]; + buf[7] = '\0'; + unitTest( mb.read( buf, 7 ) == 7 ); + unitTest( !strncmp( buf, "abcdeFG", 7 ) ); + unitTest( mb.read( buf, 7 ) == 0 ); + mb.seek( -3 ); + unitTest( mb.read( buf, 7 ) == 3 ); + unitTest( !strncmp( buf, "eFG", 3 ) ); + } +}; + +int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); } -- cgit v1.2.3 From c86c0cf088492e02431dffb1f860ff2f6faa492d Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 27 Jun 2007 18:11:13 +0000 Subject: The taf system is new and improved. The writer works, we added C++ style comment blocks, and it retains the order of all nodes. --- src/tafnode.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++------------ src/tafnode.h | 68 +++++++++++++++++++++++---- src/tafreader.cpp | 44 +++++++++++------ src/tafreader.h | 9 ++-- src/tafwriter.cpp | 42 ++++++++++++++++- src/tafwriter.h | 4 +- src/tests/taf.cpp | 13 +++-- src/unit/taf.cpp | 2 +- test.taf | 31 +++--------- 9 files changed, 260 insertions(+), 91 deletions(-) (limited to 'src/unit') diff --git a/src/tafnode.cpp b/src/tafnode.cpp index b9a4a24..b7cf211 100644 --- a/src/tafnode.cpp +++ b/src/tafnode.cpp @@ -1,72 +1,148 @@ #include "tafnode.h" -Bu::TafNode::TafNode() +Bu::TafNode::TafNode( NodeType eType ) : + eType( eType ) { } Bu::TafNode::~TafNode() +{ +} + +const Bu::TafNode::NodeType Bu::TafNode::getType() const +{ + return eType; +} + +/* +const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const +{ + return hProp.get( sName ); +} + +const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const +{ + return hChildren.get( sName ); +} + +const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const +{ + return getProperties( sName ).first(); +} + +const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const +{ + return getChildren( sName ).first(); +} +*/ + +Bu::TafGroup::TafGroup( const Bu::FString &sName ) : + TafNode( typeGroup ), + sName( sName ) +{ +} + +Bu::TafGroup::~TafGroup() { //printf("Entering Bu::TafNode::~TafNode() \"%s\"\n", sName.getStr() ); - for( NodeHash::iterator i = hChildren.begin(); i != hChildren.end(); i++ ) + for( NodeList::iterator i = lChildren.begin(); i != lChildren.end(); i++ ) { - NodeList &l = i.getValue(); - for( NodeList::iterator k = l.begin(); k != l.end(); k++ ) - { - //printf("deleting: [%08X] %s\n", *k, "" );//(*k)->getName().getStr() ); - delete (*k); - } + delete (*i); } } -void Bu::TafNode::setProperty( Bu::FString sName, Bu::FString sValue ) +const Bu::FString &Bu::TafGroup::getName() const { - if( !hProp.has( sName ) ) + return sName; +} + +void Bu::TafGroup::addChild( Bu::TafNode *pNode ) +{ + switch( pNode->getType() ) { - hProp.insert( sName, PropList() ); + case typeGroup: + { + TafGroup *pGroup = (TafGroup *)pNode; + if( !hChildren.has( pGroup->getName() ) ) + hChildren.insert( pGroup->getName(), GroupList() ); + hChildren.get( pGroup->getName() ).append( pGroup ); + } + break; + + case typeProperty: + { + TafProperty *pProperty = (TafProperty *)pNode; + if( !hProp.has( pProperty->getName() ) ) + hProp.insert( pProperty->getName(), PropList() ); + hProp.get( pProperty->getName() ).append( pProperty->getValue() ); + } + break; + + case typeComment: + break; } - hProp.get( sName ).append( sValue ); + lChildren.append( pNode ); } -void Bu::TafNode::addChild( TafNode *pNode ) +const Bu::TafGroup::GroupList &Bu::TafGroup::getChildren( const Bu::FString &sName ) const { - if( !hChildren.has( pNode->getName() ) ) - { - hChildren.insert( pNode->getName(), NodeList() ); - } + return hChildren.get( sName ); +} - //printf("Appending \"%s\"\n", pNode->getName().getStr() ); - hChildren.get( pNode->getName() ).append( pNode ); - //printf("[%08X]\n", hChildren.get( pNode->getName() ).last() ); +const Bu::TafGroup::NodeList &Bu::TafGroup::getChildren() const +{ + return lChildren; } -const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const +const Bu::TafGroup *Bu::TafGroup::getChild( const Bu::FString &sName ) const { - return hProp.get( sName ); + return hChildren.get( sName ).first(); } -const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const +const Bu::TafGroup::PropList &Bu::TafGroup::getProperties( const Bu::FString &sName ) const { - return hChildren.get( sName ); + return hProp.get( sName ); } -const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const +const Bu::FString &Bu::TafGroup::getProperty( const Bu::FString &sName ) const { - return getProperties( sName ).first(); + return hProp.get( sName ).first(); } -const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const +Bu::TafProperty::TafProperty( const Bu::FString &sName, const Bu::FString &sValue ) : + TafNode( typeProperty ), + sName( sName ), + sValue( sValue ) { - return getChildren( sName ).first(); } -void Bu::TafNode::setName( const Bu::FString &sName ) +Bu::TafProperty::~TafProperty() { - this->sName = sName; } -const Bu::FString &Bu::TafNode::getName() const +const Bu::FString &Bu::TafProperty::getName() const { return sName; } +const Bu::FString &Bu::TafProperty::getValue() const +{ + return sValue; +} + +Bu::TafComment::TafComment( const Bu::FString &sText ) : + TafNode( typeComment ), + sText( sText ) +{ +} + +Bu::TafComment::~TafComment() +{ +} + +const Bu::FString &Bu::TafComment::getText() const +{ + return sText; +} + diff --git a/src/tafnode.h b/src/tafnode.h index 08f78e8..55a5123 100644 --- a/src/tafnode.h +++ b/src/tafnode.h @@ -14,29 +14,77 @@ namespace Bu class TafNode { public: - typedef Bu::List PropList; - typedef Bu::Hash PropHash; - typedef Bu::List NodeList; - typedef Bu::Hash NodeHash; + enum NodeType + { + typeGroup, + typeProperty, + typeComment + }; public: - TafNode(); + TafNode( NodeType eType ); virtual ~TafNode(); - void setName( const Bu::FString &sName ); + const NodeType getType() const; + + private: + NodeType eType; + }; + + class TafProperty; + class TafComment; + class TafGroup : public TafNode + { + public: + typedef Bu::List PropList; + typedef Bu::Hash PropHash; + typedef Bu::List GroupList; + typedef Bu::Hash GroupHash; + typedef Bu::List NodeList; + + TafGroup( const Bu::FString &sName ); + virtual ~TafGroup(); + const Bu::FString &getName() const; - void setProperty( Bu::FString sName, Bu::FString sValue ); const Bu::FString &getProperty( const Bu::FString &sName ) const; const PropList &getProperties( const Bu::FString &sName ) const; - const TafNode *getChild( const Bu::FString &sName ) const; - const NodeList &getChildren( const Bu::FString &sName ) const; + const TafGroup *getChild( const Bu::FString &sName ) const; + const GroupList &getChildren( const Bu::FString &sName ) const; void addChild( TafNode *pNode ); + const NodeList &getChildren() const; private: Bu::FString sName; PropHash hProp; - NodeHash hChildren; + GroupHash hChildren; + NodeList lChildren; + }; + + class TafProperty : public TafNode + { + public: + TafProperty( const Bu::FString &sName, const Bu::FString &sValue ); + virtual ~TafProperty(); + + const Bu::FString &getName() const; + const Bu::FString &getValue() const; + + private: + Bu::FString sName; + Bu::FString sValue; + }; + + class TafComment : public TafNode + { + public: + TafComment( const Bu::FString &sText ); + virtual ~TafComment(); + + const Bu::FString &getText() const; + + private: + Bu::FString sText; }; } diff --git a/src/tafreader.cpp b/src/tafreader.cpp index 1187176..db465e9 100644 --- a/src/tafreader.cpp +++ b/src/tafreader.cpp @@ -8,6 +8,7 @@ Bu::TafReader::TafReader( Bu::Stream &sIn ) : c( 0 ), sIn( sIn ) { + next(); next(); } Bu::TafReader::~TafReader() @@ -15,60 +16,74 @@ Bu::TafReader::~TafReader() } -Bu::TafNode *Bu::TafReader::getNode() +Bu::TafGroup *Bu::TafReader::readGroup() { - if( c == 0 ) next(); - TafNode *pNode = new TafNode(); ws(); if( c != '{' ) throw TafException("Expected '{'"); next(); ws(); FString sName = readStr(); - pNode->setName( sName ); + TafGroup *pGroup = new TafGroup( sName ); next(); //printf("Node[%s]:\n", sName.getStr() ); - nodeContent( pNode ); + groupContent( pGroup ); if( c != '}' ) throw TafException("Expected '}'"); next(); - return pNode; + return pGroup; } -void Bu::TafReader::nodeContent( Bu::TafNode *pNode ) +void Bu::TafReader::groupContent( Bu::TafGroup *pGroup ) { for(;;) { ws(); if( c == '{' ) - pNode->addChild( getNode() ); + pGroup->addChild( readGroup() ); else if( c == '}' ) return; + else if( c == '/' && la == '*' ) + pGroup->addChild( readComment() ); else - nodeProperty( pNode ); + pGroup->addChild( readProperty() ); } } -void Bu::TafReader::nodeProperty( Bu::TafNode *pNode ) +Bu::TafProperty *Bu::TafReader::readProperty() { FString sName = readStr(); ws(); if( c != '=' ) { //printf(" %s (true)\n", sName.getStr() ); - pNode->setProperty( sName, "" ); - return; + return new Bu::TafProperty( sName, "" ); } next(); FString sValue = readStr(); - pNode->setProperty( sName, sValue ); + return new Bu::TafProperty( sName, sValue ); //printf(" %s = %s\n", sName.getStr(), sValue.getStr() ); } +Bu::TafComment *Bu::TafReader::readComment() +{ + next(); + FString sCmnt; + for(;;) + { + next(); + if( c == '*' && la == '/' ) + break; + sCmnt += c; + } + + return new TafComment( sCmnt ); +} + Bu::FString Bu::TafReader::readStr() { ws(); @@ -134,6 +149,7 @@ bool Bu::TafReader::isws() void Bu::TafReader::next() { - sIn.read( &c, 1 ); + c = la; + sIn.read( &la, 1 ); } diff --git a/src/tafreader.h b/src/tafreader.h index 47ae187..eeaafb3 100644 --- a/src/tafreader.h +++ b/src/tafreader.h @@ -17,16 +17,17 @@ namespace Bu TafReader( Bu::Stream &sIn ); virtual ~TafReader(); - Bu::TafNode *getNode(); + Bu::TafGroup *readGroup(); private: - void nodeContent( Bu::TafNode *pNode ); - void nodeProperty( Bu::TafNode *pNode ); + void groupContent( Bu::TafGroup *pNode ); + Bu::TafProperty *readProperty(); + Bu::TafComment *readComment(); void ws(); bool isws(); void next(); Bu::FString readStr(); - char c; + char c, la; Bu::Stream &sIn; }; } diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp index ac42d3d..6b505ef 100644 --- a/src/tafwriter.cpp +++ b/src/tafwriter.cpp @@ -9,16 +9,54 @@ Bu::TafWriter::~TafWriter() { } -void Bu::TafWriter::writeNode( Bu::TafNode *pRoot ) +void Bu::TafWriter::writeGroup( const Bu::TafGroup *pRoot ) { sOut.write("{", 1 ); - writeString( pRoot->getName().getStr() ); + writeString( pRoot->getName() ); sOut.write(": ", 2 ); + const Bu::TafGroup::NodeList &nl = pRoot->getChildren(); + for( Bu::TafGroup::NodeList::const_iterator i = nl.begin(); i != nl.end(); i++ ) + { + switch( (*i)->getType() ) + { + case Bu::TafNode::typeGroup: + writeGroup( (Bu::TafGroup *)(*i) ); + break; + + case Bu::TafNode::typeProperty: + writeProperty( (Bu::TafProperty *)(*i) ); + break; + + case Bu::TafNode::typeComment: + writeComment( (Bu::TafComment *)(*i) ); + break; + } + } sOut.write("}", 1 ); } +void Bu::TafWriter::writeProperty( const Bu::TafProperty *pProp ) +{ + writeString( pProp->getName() ); + if( pProp->getValue().getStr() != NULL ) + { + sOut.write("=", 1 ); + writeString( pProp->getValue() ); + } + sOut.write(" ", 1 ); +} + +void Bu::TafWriter::writeComment( const Bu::TafComment *pComment ) +{ + sOut.write("/*", 2 ); + sOut.write( pComment->getText().getStr(), pComment->getText().getSize() ); + sOut.write("*/ ", 3 ); +} + void Bu::TafWriter::writeString( const Bu::FString &str ) { + if( str.getStr() == NULL ) + return; sOut.write("\"", 1 ); for( const char *s = str.getStr(); *s; s++ ) { diff --git a/src/tafwriter.h b/src/tafwriter.h index 4310e62..5f80504 100644 --- a/src/tafwriter.h +++ b/src/tafwriter.h @@ -17,9 +17,11 @@ namespace Bu TafWriter( Bu::Stream &sOut ); virtual ~TafWriter(); - void writeNode( Bu::TafNode *pRoot ); + void writeGroup( const Bu::TafGroup *pRoot ); private: + void writeProperty( const Bu::TafProperty *pProp ); + void writeComment( const Bu::TafComment *pComment ); void writeString( const Bu::FString &str ); Bu::Stream &sOut; }; diff --git a/src/tests/taf.cpp b/src/tests/taf.cpp index d135e78..e3da120 100644 --- a/src/tests/taf.cpp +++ b/src/tests/taf.cpp @@ -1,4 +1,5 @@ #include "bu/tafreader.h" +#include "bu/tafwriter.h" #include "bu/file.h" int main() @@ -6,12 +7,18 @@ int main() Bu::File f("test.taf", "rb"); Bu::TafReader tr( f ); - Bu::TafNode *pNode = tr.getNode(); + Bu::TafGroup *pGroup = tr.readGroup(); - const Bu::TafNode *pStats = pNode->getChild("stats"); + const Bu::TafGroup *pStats = pGroup->getChild("stats"); printf("%s\n", pStats->getName().getStr() ); printf(" str = %s\n", pStats->getProperty("str").getStr() ); - delete pNode; + { + Bu::File fo("out.taf", "wb"); + Bu::TafWriter tw( fo ); + tw.writeGroup( pGroup ); + } + + delete pGroup; } diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp index ab485d0..5e0e914 100644 --- a/src/unit/taf.cpp +++ b/src/unit/taf.cpp @@ -32,7 +32,7 @@ public: Bu::File fIn(sFnTmp.c_str(), "rb"); Bu::TafReader tr(fIn); - Bu::TafNode *tn = tr.getNode(); + Bu::TafGroup *tn = tr.readGroup(); unitTest( !strcmp("Bob", tn->getProperty("name").c_str()) ); delete tn; diff --git a/test.taf b/test.taf index 045b042..1d4e7d1 100644 --- a/test.taf +++ b/test.taf @@ -1,26 +1,7 @@ -{player: - password = "aoeuaoeuao" - userclass = "implementor" - species = "human" - sex = "male" - active - startroom = "Salourn::Xagafinelle's Room" - {stats: str=14 dex=12 spd=12 enr=7 rea=12 wil=10 int=13 cha=14} - {hp: cur = 100 max = 100} - {en: cur = 100 max = 100} - attackrate = 30 - gold = 0 - {inventory: - {: count=1 id="Salourn::Dark Blade"} - {: count=1 id="Salourn::Dark Suit"} - {: count=3 id="Salourn::Small Fig"} - } - {aliases: - {: key="." value="say"} - {: key="," value="yell"} - {: key="li" value="lightning"} - } - description = "They appear to be rather average looking, not particularly +{"player": "password"="aoeuaoeuao" "userclass"="implementor" "species"="human" "sex"="male" "active" "startroom"="Salourn::Xagafinelle's Room" {"stats": "str"="14" "dex"="12" "spd"="12" "enr"="7" "rea"="12" "wil"="10" "int"="13" "cha"="14" }{"hp": "cur"="100" "max"="100" }{"en": "cur"="100" "max"="100" }"attackrate"="30" "gold"="0" + + /* Hey, the inventory is next...isn't that cool? Oooooh yeah! */ + +{"inventory": {: "count"="1" "id"="Salourn::Dark Blade" }{: "count"="1" "id"="Salourn::Dark Suit" }{: "count"="3" "id"="Salourn::Small Fig" }}{"aliases": {: "key"="." "value"="say" }{: "key"="," "value"="yell" }{: "key"="li" "value"="lightning" }}"description"="They appear to be rather average looking, not particularly tall or short, with facial features that are difficult to remember even - seconds after witnessing them." -} + seconds after witnessing them." } -- cgit v1.2.3