/*************************************************************************** copyright : (C) by 2003-2004 Stefano Barbato email : stefano@codesink.org $Id: cutee.cxx,v 1.1 2005/02/23 10:07:39 tat Exp $ ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include "cutee.h" #define DEFAULT_RUNNER_EXT __FILE__ #define RUNTEST_NAME "runtest" #define CPP_EXT " cc cxx cpp c++ CC CXX CPP C++ " using namespace std; // c++ unit testing easy environment const char* g_usage = "cutee, C++ Unit Testing Easy Environment, Ver. " CUTEE_VERSION "\n\ Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.\n\ Usage: cutee [options]... testfile(s)\n\ -m generates runtest source code\n\ -o specify the output filename\n\ -p generates autocutee.mk to include in your Makefile\n\ -k generates autocutee.mk to include in your Makefile.am\n\n"; typedef list StringList; #define die(msg) do { do_die_if(1, msg, __LINE__); } while(0); #define die_if(a, msg) do { do_die_if(a, msg, __LINE__); } while(0); void do_die_if(int b, const string& msg, int line) { if(!b) return; cerr << "(" << line << ") " << msg << endl; exit(1); } #define _( code ) of << code << endl enum { MODE_RUNTEST, MODE_MAIN, MODE_AUTOMAKEFILE, MODE_MAKEFILE }; struct CmdLineOpts { string ifile, ofile, ext; string class_name; StringList ifList; int mode; CmdLineOpts() : ext(DEFAULT_RUNNER_EXT),mode(MODE_RUNTEST) { } void parse(int argc, char **argv) { int ret, i; mode = MODE_RUNTEST; // default while((ret=getopt(argc, argv, "mo:pk")) != -1) { switch(ret) { case 'o': ofile = optarg; break; case 'm': mode = MODE_MAIN; break; case 'k': mode = MODE_AUTOMAKEFILE; break; case 'p': mode = MODE_MAKEFILE; break; default: die(g_usage); } } switch(mode) { case MODE_RUNTEST: die_if( (argc - optind) != 1 || ofile.empty(), g_usage); for(; optind < argc; optind++) ifile = argv[optind]; break; case MODE_MAIN: die_if( (argc - optind) != 0 || ofile.empty(), g_usage); break; case MODE_AUTOMAKEFILE: die_if( (argc - optind) < 1 || ofile.empty(), g_usage); for(i = 0; optind < argc; i++, optind++) ifList.push_back(argv[optind]); break; case MODE_MAKEFILE: die_if( (argc - optind) < 1 || ofile.empty(), g_usage); for(i = 0; optind < argc; i++, optind++) ifList.push_back(argv[optind]); break; }; } }; class String2WordList { list mList; string mS; public: typedef list WordList; typedef list::iterator iterator; typedef list::const_iterator const_iterator; String2WordList(const string& s) : mS(s) { if(mS.empty()) return; split(); } inline bool isWordChar(char c) const { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_'); } void split() { string word; string::const_iterator beg = mS.begin(), end = mS.end(); for( ; beg != end; ++beg) { if(isWordChar(*beg)) word += *beg; else { if(word.empty()) continue; mList.push_back(word); word.erase(word.begin(), word.end()); } } if(!word.empty()) mList.push_back(word); } iterator begin() { return mList.begin(); } iterator end() { return mList.end(); } const_iterator begin() const { return mList.begin(); } const_iterator end() const { return mList.end(); } }; struct GenMain { GenMain(const string& ofqn) : mFqn(ofqn) { } void writeMain() { ofstream of(mFqn.c_str()); die_if(!of.is_open(), string("Unable to open output file: ") + mFqn); _( "#include " ); _( "#include " ); _( "#include \"cutee.h\"" ); _( "using namespace std;" ); _( "using namespace cutee;" ); _( "" ); _( "// static vars initialization" ); _( "CuteeTest* TestList::list[MAX_TEST_COUNT];" ); _( "int TestList::list_idx = 0;" ); _( "" ); _( "int main(int argc, char **argv) " ); _( "{" ); _( "\tRunner r(argc, argv);" ); _( "\tr.run();" ); _( "}" ); } private: string mFqn; }; struct GenRunTest { GenRunTest(const string& ifqn, const string& ofqn) : m_ifqn(ifqn), mFqn(ofqn) { } void writeRunTestClass() { ofstream of(mFqn.c_str()); die_if(!of.is_open(), string("Unable to open output file: ") + mFqn); string cn = m_className, fqcn; if(m_nsList.empty()) fqcn = cn; else { StringList::const_iterator beg = m_nsList.begin(), end = m_nsList.end(); for(; beg != end; ++beg) fqcn += *beg + "::"; fqcn += cn; } _( "#include \"cutee.h\"" ); _( "#include \"" << m_ifqn << "\"" ); _( "using namespace cutee;" ); _( "struct run_" << cn << ": public " << fqcn); _( "{" ); _( " void run()" ); _( " {" ); of << " "; _( " setUp();" ); StringList::const_iterator beg = m_fnList.begin(), end = m_fnList.end(); for(; beg != end; ++beg) _( " run_" << *beg << "();" ); _( " tearDown();" ); _( " }" ); _( " uint count() { return " << m_fnList.size() << "; }" ); _( "};" ); _("static struct "<parseInputFile()) pGrt->writeRunTestClass(); delete pGrt; break; case MODE_MAIN: pGm = new GenMain(clo.ofile); pGm->writeMain(); delete pGm; break; case MODE_AUTOMAKEFILE: pGamk = new GenAutomakefile(clo.ifList, clo.ofile, clo.ext); pGamk->writeMakefile(); delete pGamk; break; case MODE_MAKEFILE: pGmk = new GenMakefile(clo.ifList, clo.ofile, clo.ext); pGmk->writeMakefile(); delete pGmk; break; default: die("UNKNOWN MODE"); break; } return 0; }