///////////////////////////////////////////////////////////////////////////// // unitTest_CppSemiExp.cpp - CppSemiExp Unit Tests // // ver 2.1 Uses testHarness module // // // // Language: Visual C++, ver 7.0 // // Platform: Dell Dimension 8300, Windows XP Prof, SP 1 // // Application: CSE687 prototype for project #1, Spring 2004 // // Author: Jim Fawcett, CST 2-187, Syracuse University // // (315) 443-3948, jfawcett@twcny.rr.com // ///////////////////////////////////////////////////////////////////////////// /* * Module Operations: * ================== * Provides a set of unit tests to validate CppSemiExp, using the * TestHarness module. * * Maintenance History: * ==================== * ver 2.0 : 29 Feb 04 * - made significant changes to CSemiExp interface, filtering, and tests * for many of the new and original CSemiExp functions. * ver 1.0 : 21 Feb 04 * - first release * * Build Process: * ============== * Required Files: * CppSemiExp.h, CppSemiExp.cpp, CppToker.h, CppToker.cpp, * TestHarness.h, TestHarness.cpp, UnitTest_CppSemiExp.cpp * * Building in IDE: * set working directory to folder with project source code files * (will be .. if you copy directory structure from cse687\code\Pr2HelpSp04.V2.0) * To see unit test for CppSemiExp include UNITTEST_CPPSEMIEXP in preprocessor * definitions in C\C++ properties * * Compiler Command: * cl /DUNITTEST_CPPSEMIEXP /EHsc \ * CppSemiExp.cpp CppToker.cpp TestHarness.cpp UnitTest_CppSemiExp.cpp */ #ifdef UNITTEST_CPPSEMIEXP #include #include #include #include "CppSemiExp.h" #include "testharness.h" using namespace TestHarness; using namespace Scanner; // /////////////////////////////////////////////////////////////////////// // test showToString() // class showToString : public test { public: showToString(output& out) : test(out) {} bool operator()() { title("showToString() function"); std::istringstream one("one\ntwo\nthree;"); CToker toker(&one); CSemiExp semi(&toker); while(semi.get()) tout << semi.showToString("",true); semi.get(); tout << semi.showToString("",true); return passed("show"); } }; // /////////////////////////////////////////////////////////////////////// // test CppSemiExp construction, copy, assignment, destruction // class construction : public test { public: construction(output& out) : test(out) {} bool operator()() { title("CppSemiExp construction:"); try { bool ok1, ok2, ok3, ok4; CSemiExp orig; // default construction orig.push_back("one"); tout << " " << orig.showToString("orig: "); orig.push_back("two"); tout << " " << orig.showToString("orig: "); orig.insert(1,"three"); tout << " " << orig.showToString("orig: "); orig.push_back(";"); tout << " " << orig.showToString("orig: "); int i = static_cast(orig.find("three")); tout << " The index of token \"three\" is " << i << std::endl; ok1 = check(i==1,"construction"); // same as: // if(i==1) // ok1 = passed("construction"); // else // ok1 = failed("construction"); orig.get(); // does nothing since it has no CToker instance CSemiExp copy = orig; // copy construction tout << " " << copy.showToString("copy: "); ok2 = check(copy==orig,"copy construction"); std::istringstream in("this is a semi-expression;"); CToker toker(&in); CSemiExp semi1(&toker); CSemiExp semi2(&toker); { semi1.get(); tout << " " << semi1.showToString(); semi2 = semi1; tout << " " << semi2.showToString(); ok3 = check(semi2 == semi1, "assignment"); } in.clear(); in.seekg(0); semi1.get(); // if this doesn't crash, nested test passed tout << " " << semi1.showToString(); ok4 = passed("destruction"); return (ok1 && ok2 && ok3 & ok4); } catch(exception e) { return false; } } }; // /////////////////////////////////////////////////////////////////////// // test extraction of double quotes as a single token // class doubleQuotes : public test { public: doubleQuotes(output& out) : test(out) {} bool operator()() { std::istringstream inStream( "before \"this is a \\\"double\\\" quote\" after;" ); CToker testTok(&inStream); CDoubleQuoteFilter dqf(&testTok); testTok.registerFilter(&dqf); CSemiExp testSE(&testTok); testSE.get(); title("extract double quotes as tokens"); tout << testSE.showToString(); if(testSE.length() != 4) return failed("doubleQuotes"); testSE.get(); tout << testSE.showToString("get from bad stream: "); return passed("doubleQuotes"); } }; /////////////////////////////////////////////////////////////////////// // test extraction of double quotes as a single token // class doubleQuotesAgain : public test { public: doubleQuotesAgain(output& out) : test(out) {} bool operator()() { std::istringstream inStream("before \"\\\"\\n\" after;"); // std::ifstream inStream("testDoubleQuote.txt"); CToker testTok(&inStream); CDoubleQuoteFilter dqf(&testTok); testTok.registerFilter(&dqf); CSemiExp testSE(&testTok); testSE.get(); title("extract double quotes as tokens again"); tout << testSE.showToString(); if(testSE.length() != 4) return failed("doubleQuotesAgain"); testSE.get(); tout << testSE.showToString("get from bad stream: "); return passed("doubleQuotesAgain"); } }; /////////////////////////////////////////////////////////////////////// // test extraction of quoted character as a single token // class singleQuotes : public test { public: singleQuotes(output& out) : test(out) {} bool operator()() { std::istringstream inStream("before '\\\"' after;"); CToker testTok(&inStream); CSingleQuoteFilter sqf(&testTok); testTok.registerFilter(&sqf); CSemiExp testSE(&testTok); title("extract single quotes as tokens"); testSE.get(); tout << testSE.showToString(); if(testSE.length() != 4) return failed("singleQuotes"); testSE.get(); tout << testSE.showToString("get from bad stream: "); return passed("singleQuotes"); } }; /////////////////////////////////////////////////////////////////////// // test extraction of quoted character as a single token // class singleQuotesAgain : public test { public: singleQuotesAgain(output& out) : test(out) {} bool operator()() { // std::istringstream inStream("before '\\\'' '\\\"' '\\\'' after;"); std::ifstream inStream("..\\testSingleQuote.txt"); CToker testTok(&inStream); CSingleQuoteFilter sqf(&testTok); testTok.registerFilter(&sqf); CSemiExp testSE(&testTok); title("extract single quotes as tokens again"); testSE.get(); tout << testSE.showToString(); if(testSE.length() != 9) return failed("singleQuotesAgain"); testSE.get(); tout << testSE.showToString("get from bad stream: "); return passed("singleQuotesAgain"); } }; // /////////////////////////////////////////////////////////////////////// // test extraction of C Lanaguage comments as a single token // class keepCComments : public test { public: keepCComments(output& out) : test(out) {} bool operator()() { bool Keep = true; std::string comment; comment = "before\n"; comment += "/* this is a multi-line C Language Comment\n"; comment += " * a second line here\n"; comment += " * and a last line */ "; comment += "\nafter;"; std::istringstream inStream(comment); CToker testTok(&inStream); CCCommentFilter ccf(&testTok); if(Keep) ccf.keep(); testTok.registerFilter(&ccf); CSemiExp testSE(&testTok); title("extract C Language Comments as tokens"); if(Keep) { tout << " returning comments as single tokens\n"; testSE.get(); tout << testSE.showToString("",true); tout << " #tokens = " << (unsigned)testSE.length() << std::endl; if(testSE.length() != 6) return failed("keep C comments"); } else { tout << " discarding comment tokens\n"; testSE.get(); tout << testSE.showToString("",true); tout << " #tokens = " << (unsigned)testSE.length() << std::endl; if(testSE.length() != 5) return failed("discard C comments");; } testSE.get(); tout << testSE.showToString("get from bad stream: ") << std::endl; return passed("keep C comments"); } }; // /////////////////////////////////////////////////////////////////////// // test discarding of C Lanaguage comments as a single token // class discardCComments : public test { public: discardCComments(output& out) : test(out) {} bool operator()() { bool Keep = false; std::string comment; comment = "before\n"; comment += "/* this is a multi-line C Language Comment\n"; comment += " * a second line here\n"; comment += " * and a last line */ "; comment += "\nafter;"; std::istringstream inStream(comment); CToker testTok(&inStream); CCCommentFilter ccf(&testTok); if(Keep) ccf.keep(); testTok.registerFilter(&ccf); CSemiExp testSE(&testTok); title("extract C Language Comments as tokens"); if(Keep) { tout << " returning comments as single tokens\n"; testSE.get(); tout << testSE.showToString("",true); tout << " #tokens = " << (unsigned)testSE.length() << std::endl; if(testSE.length() != 6) return failed("keep C comments"); } else { tout << " discarding comment tokens\n"; testSE.get(); tout << testSE.showToString("",true); tout << " #tokens = " << (unsigned)testSE.length() << std::endl; if(testSE.length() != 5) return failed("discard C comments");; } testSE.get(); tout << testSE.showToString("get from bad stream: ") << std::endl; return passed("discard C comments"); } }; // /////////////////////////////////////////////////////////////////////// // test extraction of C++ Language Comments as single token class keepCppComments : public test { public: keepCppComments(output &out) : test(out) {} bool operator()() { bool Keep = true; std::string comment; // comment = "before\n"; comment += "// this first line of C++ Language Comment\n"; comment += "// plus a second line\n"; comment += "// and a last and very final line"; // comment += "\nafter;"; std::istringstream inStream(comment); CToker testTok(&inStream); CCppCommentFilter cppcf(&testTok); if(Keep) cppcf.keep(); testTok.registerFilter(&cppcf); CSemiExp testSE(&testTok); title("extract C++ Language Comments as tokens"); if(Keep) { int count=0; tout << " returning comments as single tokens\n"; while(testSE.get()) { tout << testSE.showToString("",true); tout << " #tokens (comments, newlines, and other tokens) = " << (unsigned)testSE.length() << "\n"; if(testSE.length() != 5) return failed("keep C++ comments"); } } else { tout << " discarding comment tokens\n"; while(testSE.get()) { tout << testSE.showToString("",true); tout << " #tokens (comments, newlines, and other tokens) = " << (unsigned)testSE.length() << "\n"; if(testSE.length() != 5) return failed("keep C++ comments"); } } testSE.get(); tout << testSE.showToString("get from bad stream: ") << std::endl; return passed("keep C++ comments"); } }; // ///////////////////////////////////////////////////////////////////////// // test discarding C++ Lanaguage comments class discardCppComments : public test { public: discardCppComments(output &out) : test(out) {} bool operator()() { bool Keep = false; std::string comment; // comment = "before\n"; comment += "// this first line of C++ Language Comment\n"; comment += "// plus a second line\n"; comment += "// and a last and very final line"; // comment += "\nafter;"; std::istringstream inStream(comment); CToker testTok(&inStream); CCppCommentFilter cppcf(&testTok); if(Keep) cppcf.keep(); testTok.registerFilter(&cppcf); CSemiExp testSE(&testTok); title("extract C++ Language Comments as tokens"); if(Keep) { int count=0; tout << " returning comments as single tokens\n"; while(testSE.get()) { tout << testSE.showToString("",true); tout << " #tokens (comments, newlines, and other tokens) = " << (unsigned)testSE.length() << "\n"; if(testSE.length() != 5) return failed("keep C++ comments"); } } else { tout << " discarding comment tokens\n"; while(testSE.get()) { tout << testSE.showToString("",true); tout << " #tokens (comments, newlines, and other tokens) = " << (unsigned)testSE.length() << "\n"; if(testSE.length() != 0) return failed("keep C++ comments"); } } testSE.get(); tout << testSE.showToString("get from bad stream: ") << std::endl; return passed("discard C++ comments"); } }; // /////////////////////////////////////////////////////////////////////// // test extracting comments from production code // class keepSourceCodeComments : public test { public: keepSourceCodeComments(output& out) : test(out) {} bool operator()() { bool Keep = true; std::string file = "..\\CppSemiExp.h"; std::ostringstream temp; temp << "extracting comments in CppToker while processing " << file; title(temp.str()); if(Keep) tout << " returning comments as single tokens\n"; else tout << " discarding comment tokens\n"; std::ifstream in(file.c_str()); if(in.good()) { try { CToker toker(&in); CCCommentFilter filter1(&toker); if(Keep) filter1.keep(); toker.registerFilter(&filter1); CCppCommentFilter filter2(&toker); if(Keep) filter2.keep(); toker.registerFilter(&filter2); bool ok1 = false, ok2 = false; CSemiExp semi(&toker); while(semi.get()) { if(semi.findStringInTokens("//") != semi.length()) ok1 = true; if(semi.findStringInTokens("/*") != semi.length()) ok2 = true; tout << semi.showToString("",true); } tout << semi.showToString("",true) << std::endl; return check(ok1 && ok2, "keep comments in production code"); } catch(std::exception e) { tout << "\n\n " << e.what() << "\n\n"; } } return failed("keep comments - can't open test file"); } }; // /////////////////////////////////////////////////////////////////////// // test discarding comments from production code // class discardSourceCodeComments : public test { public: discardSourceCodeComments(output& out) : test(out) {} bool operator()() { bool Keep = false; std::string file = "..\\CppSemiExp.h"; std::ostringstream temp; temp << "extracting comments in CppToker while processing " << file; title(temp.str()); if(Keep) tout << " returning comments as single tokens\n"; else tout << " discarding comment tokens\n"; std::ifstream in(file.c_str()); if(in.good()) { try { CToker toker(&in); CCCommentFilter filter1(&toker); if(Keep) filter1.keep(); toker.registerFilter(&filter1); CCppCommentFilter filter2(&toker); if(Keep) filter2.keep(); toker.registerFilter(&filter2); bool ok1 = false, ok2 = false; CSemiExp semi(&toker); while(semi.get()) { if(semi.findStringInTokens("//") != semi.length()) ok1 = true; if(semi.findStringInTokens("/*") != semi.length()) ok2 = true; tout << semi.showToString("",true); } tout << semi.showToString("",true) << std::endl; return check(!(ok1 || ok2), "discard comments in production code"); } catch(std::exception e) { tout << "\n\n " << e.what() << "\n\n"; } } return failed("discard comments - can't open test file"); } }; // /////////////////////////////////////////////////////////////////////// // test copy constructing CppSemiExp instances in more than one scope // class nestedScope : public test { public: nestedScope(output& out) : test(out) {} bool operator()() { title("Nested Scope Fix"); std::istringstream inStr("int x; double y; char z;"); CToker tokA(&inStr); CSemiExp testA(&tokA); testA.registerDefaultFilters(); testA.get(); tout << " " << testA.showToString(); { CSemiExp testB(&tokA); testB.registerDefaultFilters(); testB = testA; testB.get(); tout << " " << testB.showToString(); } testA.get(); tout << " " << testA.showToString() << std::endl; return passed("nestedScopeFix"); // if we get here test passed } }; /////////////////////////////////////////////////////////////////////// // Test CppSemiExp comment filter at end of file with no newline // - should return with no token // class commentAtEndOfStream : public test { public: commentAtEndOfStream(output& out) : test(out) {} bool operator()() { title("Comment at end of Stream Fix"); std::istringstream inStr1("/* a comment */"); CToker tok1(&inStr1); tok1.registerDefaultFilters(true); // return comments CSemiExp test1(&tok1); test1.registerDefaultFilters(); test1.get(); tout << test1.showToString(); std::istringstream inStr2("// a comment "); CToker tok2(&inStr2); tok2.registerDefaultFilters(true); // return comments CSemiExp test2(&tok2); test2.registerDefaultFilters(); test2.get(); tout << " " << test2.showToString() << std::endl; return passed("commentAtEndOfStream"); // if we get here test passed } }; // /////////////////////////////////////////////////////////////////////// // CppSemiExp Filters test // should remove C and C++ comments class filterSourceCode : public test { public: filterSourceCode(output& out) : test(out) {} bool findComment(const CSemiExp &semi) { bool ok1 = false, ok2 = false; if(semi.findStringInTokens("//") < semi.length()) ok1 = true; if(semi.findStringInTokens("/*") < semi.length()) ok2 = true; return (ok1 || ok2); } bool operator()() { title("source code comment stripping in CppSemiExp"); std::string file = "..\\CppSemiExp.h"; std::ifstream in(file.c_str()); if(in.good()) { try { CToker toker(&in); toker.registerDefaultFilters(); CSemiExp semi(&toker); semi.registerDefaultFilters(); while(semi.get()) { tout << semi.showToString(); if(findComment(semi)) { tout << std::endl; return failed("filterSourceCode"); } } tout << semi.showToString() << std::endl; tout.write(); return passed("filterSourceCode"); } catch(exception e) { return false; } } return failed("filterSourceCode - can't open test file"); } }; // /////////////////////////////////////////////////////////////////////// // CppSemiExp construction and programmatic insertion of elements // class building : public test { public: building(output& out) : test(out) {} bool operator()() { title("manual construction of semi-expression"); CSemiExp test1; // default construction test1.push_back("one"); tout << " " << test1.showToString(); test1.push_back("two"); tout << " " << test1.showToString(); test1.insert(1,"three"); tout << " " << test1.showToString(); test1.push_back(";"); tout << " " << test1.showToString(); int i = static_cast(test1.find("three")); tout << " The index of token \"three\" is " << i << std::endl; test1.get(); // does nothing since it has no CToker instance tout << " " << test1.showToString() << std::endl; tout.write(); return check(i==1,"building"); } }; /////////////////////////////////////////////////////////////////////// // test CppSemiExp copy construction // class copy : public test { public: copy(output& out) : test(out) {} bool operator()() { title("copy construction"); CSemiExp test1; // default construction test1.push_back("one"); test1.push_back("two"); test1.insert(1,"three"); test1.push_back(";"); tout << " " << test1.showToString(); CSemiExp test2 = test1; // compiler generated copy construction tout << " " << test2.showToString(); return check(test2 == test1,"copy"); } }; // /////////////////////////////////////////////////////////////////////// // test CppSemiExp assignment // class assign : public test { public: assign(output& out) : test(out) {} bool operator()() { title("assignment"); CSemiExp test1; // default construction test1.push_back("one"); test1.push_back("two"); test1.insert(1,"three"); test1.push_back(";"); tout << " " << test1.showToString(); CSemiExp test2; test2 = test1; // compiler generated assignment tout << " " << test2.showToString(); return check(test2 == test1,"assign"); } }; /////////////////////////////////////////////////////////////////////// // test CForFilter // class forFilter : public test { public: forFilter(output& out) : test(out) {} bool operator()() { title("For Filter"); std::string temp = "void main() { "; temp += "for(int i=0; i<5; ++i) "; temp += "std::cout << i << \" \"; cout << \"\n\n\"; "; std::istringstream source(temp); CToker toker(&source); CSemiExp test(&toker); CForFilter forFilter; test.registerFilter(&forFilter); unsigned int count = 0; while(test.get()) { ++count; tout << test.showToString(); } tout << std::endl; return check(count == 3, "forFilter"); } }; // /////////////////////////////////////////////////////////////////////// // test operator filter // class operFilter : public test { public: operFilter(output& out) : test(out) {} bool operator()() { title("operator filter"); std::string temp = "void main() { "; temp += "X x; "; temp += "x.operator[](3) = 5; "; temp += "x.operator()(3); "; temp += "}"; std::istringstream source(temp); CToker toker(&source); CSemiExp test(&toker); COperatorFilter operFilter; test.registerFilter(&operFilter); unsigned int count = 0; bool found1 = false, found2 = false; while(test.get()) { if(test.find("operator[]")) found1 = true; if(test.find("operator()")) found2 = true; tout << test.showToString(); } tout << std::endl; return check(found1 && found2, "operFilter"); } }; // ///////////////////////////////////////////////////////////////////////// // test: size_t len = se.find("operator"); statement class findStatement : public test { public: findStatement(output& out) : test(out) {} bool operator()() { title("find Statement"); std::string temp = "size_t len = se.find(\"operator\"); "; temp += "if(len < se.length()-1)"; std::istringstream source(temp); CToker toker(&source); toker.registerDefaultFilters(); CSemiExp test(&toker); test.registerDefaultFilters(); bool ok = false; while(test.get()) { tout << test.showToString(); if(test.find("operator")) ok = true; } tout << std::endl; return check(ok,"findStatement"); } }; ///////////////////////////////////////////////////////////////////////// // test: "----" class punctuatorDoubleQuote : public test { public: punctuatorDoubleQuote(output& out) : test(out) {} bool operator()() { title("punctuator double quote"); std::string temp = "myfun(\"----\");"; temp += "// void myfun();"; std::istringstream source(temp); CToker toker(&source); toker.registerDefaultFilters(true); CSemiExp test(&toker); test.registerDefaultFilters(); bool ok = false; while(test.get()) { tout << test.showToString("",true); if(test.find("\"----\"") < test.length()) ok = true; } tout << std::endl; return check(ok,"punctuator double quote"); } }; // ///////////////////////////////////////////////////////////////////////// // test: '-' class punctuatorSingleQuote : public test { public: punctuatorSingleQuote(output& out) : test(out) {} bool operator()() { title("punctuator single quote"); std::string temp = "myfun(\'-\');"; temp += " void myfun();"; std::istringstream source(temp); CToker toker(&source); toker.registerDefaultFilters(true); CSemiExp test(&toker); test.registerDefaultFilters(); bool ok = false; while(test.get()) { tout << test.showToString("",true); if(test.find("\'-\'") < test.length()) ok = true; } tout << std::endl; return check(ok,"punctuator single quote"); } }; ///////////////////////////////////////////////////////////////////////// // test: //----< a brief statement >------------------ class punctuatorCppComment : public test { public: punctuatorCppComment(output& out) : test(out) {} bool operator()() { title("punctuator C++ comment"); std::string temp = "//----< a brief statement >----\n"; temp += "//\n void myfun() {}"; std::istringstream source(temp); CToker toker(&source); toker.registerDefaultFilters(true); CSemiExp test(&toker); test.registerDefaultFilters(); bool ok = false; while(test.get()) { tout << test.showToString("",true); if(test.find("//----< a brief statement >----") < test.length()) ok = true; } tout << std::endl; return check(ok,"punctuator C++ Comment"); } }; // ///////////////////////////////////////////////////////////////////////// // test: /*----< a brief statement >----*/ class punctuatorCComment : public test { public: punctuatorCComment(output& out) : test(out) {} bool operator()() { title("punctuator C comment"); std::string temp = "/*----< a brief statement >----*/\n"; temp += "/* void myfun() {} */"; std::istringstream source(temp); CToker toker(&source); toker.registerDefaultFilters(true); CSemiExp test(&toker); test.registerDefaultFilters(); bool ok = false; while(test.get()) { tout << test.showToString("",true); if(test.find("/*----< a brief statement >----*/") < test.length()) ok = true; } tout << std::endl; return check(ok,"punctuator C comment"); } }; // int main() { stdOutput out; tester t(out, "Testing CSemiExp Class"); nullOutput null; null.showAll(true); // comment this out to show just the outs t.registerTest(new showToString(null)); t.registerTest(new construction(null)); t.registerTest(new doubleQuotes(null)); t.registerTest(new doubleQuotesAgain(null)); t.registerTest(new singleQuotes(null)); t.registerTest(new singleQuotesAgain(null)); t.registerTest(new keepCComments(null)); t.registerTest(new discardCComments(null)); t.registerTest(new keepCppComments(null)); t.registerTest(new discardCppComments(null)); t.registerTest(new keepSourceCodeComments(null)); t.registerTest(new discardSourceCodeComments(null)); t.registerTest(new nestedScope(null)); t.registerTest(new commentAtEndOfStream(null)); t.registerTest(new filterSourceCode(null)); t.registerTest(new building(null)); t.registerTest(new copy(null)); t.registerTest(new assign(null)); t.registerTest(new forFilter(out)); t.registerTest(new operFilter(out)); t.registerTest(new findStatement(out)); t.registerTest(new punctuatorDoubleQuote(out)); t.registerTest(new punctuatorSingleQuote(out)); t.registerTest(new punctuatorCppComment(out)); t.registerTest(new punctuatorCComment(out)); t.execute(out); std::cout << "\n\n"; } #endif