| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 | 
							- #include <cstdlib>
 - 
 - #include <iostream>
 - #include <chrono>
 - #include <thread>
 - #include <sstream>
 - 
 - #include "CodeDweller/child.hpp"
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // Configuration ///////////////////////////////////////////////////////////////
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - /// Child program name.
 - const std::string childName("./childProgram");
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // End of configuration ////////////////////////////////////////////////////////
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - int nTotalTests = 0;
 - int nPass = 0;
 - int nFail = 0;
 - 
 - bool result;
 - 
 - #define NO_EXCEPTION_TERM(msg)			                  \
 -   std::cout                                                       \
 -   << msg << " failed to throw exception at line "		  \
 -   << __LINE__ << "." << std::endl
 - 
 - #define EXCEPTION_TERM(msg)			                  \
 -   std::cout                                                       \
 -   << msg << " threw unexpected exception at line "		  \
 -   << __LINE__ << ":  " << e.what() << std::endl
 - 
 - #define RETURN_FALSE(msg)					\
 -   std::cout							\
 -   << msg << " at line " << __LINE__ << std::endl;		\
 -   return false;
 - 
 - #define RUN_TEST(test)							\
 -   std::cout << "  " #test ":  ";					\
 -   std::cout.flush();							\
 -   result = test();							\
 -   std::cout << (result ? "ok" : "fail") << std::endl;			\
 -   nTotalTests++;							\
 -   if (result) nPass++; else nFail++;
 - 
 - #define SUMMARY \
 -   std::cout                                     \
 -   << "\nPass:  " << nPass                       \
 -   << ", Fail:  " << nFail                       \
 -   << ", Total:  " << nTotalTests << std::endl
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // Tests ///////////////////////////////////////////////////////////////////////
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - bool
 - testIsDone() {
 - 
 -   try {
 - 
 -     CodeDweller::Child child(childName);
 - 
 -     // Test exception if called out-of-order.
 -     try {
 -       child.isDone();
 -       NO_EXCEPTION_TERM("isDone() called without run()");
 -       return false;
 -     } catch (std::exception &e) {
 -     }
 - 
 -     child.run();
 -     if (child.isDone()) {
 -       std::cout << "isDone() failure; returned true." << std::endl;
 -       return false;
 -     }
 - 
 -     // Command the child to exit.
 -     child.writer << 'q';
 -     child.writer.flush();
 - 
 -     // Sleep to let the child exit.
 -     std::this_thread::sleep_for(std::chrono::milliseconds(100));
 - 
 -     if (!child.isDone()) {
 -       std::cout << "isDone() failure; returned false." << std::endl;
 -       return false;
 -     }
 -   } catch (std::exception &e) {
 -     EXCEPTION_TERM("isDone()");
 -     return false;
 -   }
 - 
 -   return true;
 - 
 - }
 - 
 - bool
 - testResult() {
 - 
 -   try {
 -     std::vector<std::string> cmd;
 - 
 -     cmd.push_back(childName);
 -     cmd.push_back("quit");
 - 
 -     CodeDweller::Child child(cmd);
 - 
 -     // Test exception if called out-of-order.
 -     try {
 -       (void) child.result();
 -       NO_EXCEPTION_TERM("  result() called without run()");
 -       return false;
 -     } catch (std::exception &e) {
 -     }
 - 
 -     child.run();
 - 
 -     // Test exception if called while child is running.
 -     try {
 -       (void) child.result();
 -       NO_EXCEPTION_TERM("  result() called before child exited");
 -       return false;
 -     } catch (std::exception &e) {
 -     }
 - 
 -     // Wait for the child to exit.
 -     std::this_thread::sleep_for(std::chrono::milliseconds(100));
 - 
 -     int32_t result = child.result();
 -     if (25 != result) {
 -       std::cout << "result() failure; returned " << result
 - 		<< " instead of 25." << std::endl;
 -       return false;
 -     }
 -   } catch (std::exception &e) {
 -     EXCEPTION_TERM("result()");
 -     return false;
 -   }
 -   return true;
 - }
 - 
 - bool
 - testTerminate() {
 - 
 -   // Test with no waiting.
 -   try {
 -       CodeDweller::Child child(childName);
 -       child.run();
 -       child.terminate();
 -   } catch (std::exception &e) {
 -     EXCEPTION_TERM("terminate() with no waiting");
 -     return false;
 -   }
 - 
 -   // Test with waiting.
 -   try {
 -       CodeDweller::Child child(childName);
 -       child.run();
 -       std::this_thread::sleep_for(std::chrono::milliseconds(100));
 -       child.terminate();
 -   } catch (std::exception &e) {
 -     EXCEPTION_TERM("terminate() with 100 ms waiting");
 -     return false;
 -   }
 - 
 -   // Test after the child exits.
 -   std::vector<std::string> cmd;
 - 
 -   cmd.push_back(childName);
 -   cmd.push_back("quit");
 - 
 -   try {
 -       CodeDweller::Child child(cmd);
 -       child.run();
 -       std::this_thread::sleep_for(std::chrono::milliseconds(100));
 -       child.terminate();
 -   } catch (std::exception &e) {
 -     EXCEPTION_TERM("terminate() after child exits");
 -     return false;
 -   }
 - 
 -   // Test exception thrown for out-of-order calling.
 -   try {
 -       CodeDweller::Child child(cmd);
 -       child.terminate();
 -       NO_EXCEPTION_TERM("terminate() called without run()");
 -       return false;
 -   } catch (std::exception &e) {
 -   }
 - 
 -   return true;
 - }
 - 
 - bool
 - testReaderWriter() {
 - 
 -   try {
 -     size_t bufSize = 15;
 -     CodeDweller::Child child(childName, bufSize);
 -     std::ostringstream childOutput;
 -     std::vector<std::string> expectedChildOutput;
 -     char readChar;
 - 
 -     // Generate input.
 -     char randomLetter[] = "abcdefghijklmnop#rstuvwxyz";
 -     int nChar = bufSize - 1;
 -     int nLines = 2;
 -     for (int iLine = 0; iLine < nLines; iLine++) {
 -       std::string line;
 -       line.erase();
 -       for (int iChar = 0; iChar < nChar; iChar++) {
 - 	line.push_back(randomLetter[std::rand() % 26]);
 -       }
 -       expectedChildOutput.push_back(line);
 -     }
 - 
 -     // Test exception.
 -     try {
 -       child.writer << bufSize;
 -       child.writer.flush();
 -       NO_EXCEPTION_TERM("  writer called without run()");
 -       return false;
 -     } catch (std::exception &e) {
 -     }
 - 
 -     // Clear the writer stream.
 -     try {
 -       child.writer.clear();
 -     } catch (std::exception &e) {
 -     }
 - 
 -     child.run();
 - 
 -     // Write, read, put back, and reread each character.
 -     for (std::string line : expectedChildOutput) {
 - 
 -       // Write one line.
 -       const char *ptr;
 - 
 -       ptr = line.data();
 -       for (std::string::size_type i = 0; i < line.length(); i++) {
 - 	child.writer << ptr[i];
 - 	if (!child.writer) {
 - 	  RETURN_FALSE("  Failure in testReaderWriter:  writer stream is bad");
 - 	}
 -       }
 -       child.writer.flush();
 -       if (!child.writer) {
 - 	RETURN_FALSE("  Failure in testReaderWriter:  writer stream is bad");
 -       }
 - 
 -       // Read one line.
 -       std::string readLine;
 - 
 -       readLine.erase();
 -       for (std::string::size_type i = 0; i < line.length(); i++) {
 - 	child.reader >> readChar;
 - 	if (!child.reader) {
 - 	  RETURN_FALSE("  Failure in testReaderWriter:  reader stream is bad");
 - 	}
 - 	readLine.push_back(readChar);
 -       }
 - 
 -       // Convert to upper case.
 -       std::string expectedLine;
 - 
 -       expectedLine = line;
 -       for (auto &c : expectedLine) {
 - 
 - 	c = toupper(c);
 - 
 -       }
 - 
 -       // Compare.
 -       if (expectedLine != readLine) {
 - 	std::cout << "  Failure in testReaderWriter." << std::endl;
 - 	std::cout << "    Expected:  '" << expectedLine
 - 		  << "'\n    Received:  '" << readLine << "'" << std::endl;
 - 	return false;
 - 
 -       }
 - 
 -     }
 - 
 -     // Send exit message.
 -     child.writer << 'q';
 -     child.writer.flush();
 -     if (!child.writer) {
 -       RETURN_FALSE("  Failure in testReaderWriter:  writer stream is bad");
 -     }
 - 
 -     // Verify exit.
 -     std::this_thread::sleep_for(std::chrono::milliseconds(100));
 - 
 -     if (!child.isDone()) {
 -       std::cout << "  Failure in testReaderWriter:  "
 - 		<< "Child program did not exit."  << std::endl;
 -       return false;
 -     }
 - 
 -   } catch (std::exception &e) {
 -     EXCEPTION_TERM("reader()/writer()");
 -     return false;
 -   }
 - 
 -   return true;
 - 
 - }
 - 
 - bool
 - testReader() {
 - 
 -   try {
 -     std::vector<std::string> cmd;
 - 
 -     cmd.push_back(childName);
 -     cmd.push_back("write");
 - 
 -     size_t bufSize = 32;
 -     CodeDweller::Child child(cmd, bufSize);
 - 
 -     // Test exception.
 -     try {
 -       int temp;
 -       child.reader >>  temp;
 -       NO_EXCEPTION_TERM("  reader called without run()");
 -       return false;
 -     } catch (std::exception &e) {
 -     }
 - 
 -     child.reader.clear();
 -     child.writer.clear();
 -     std::ostringstream childOutput;
 -     std::string expectedChildOutput("This is a test");
 -     char readChar;
 - 
 -     child.run();
 -     child.reader.exceptions(std::istream::badbit);
 -     child.reader >> std::noskipws;
 -     if (!child.reader) {
 -       RETURN_FALSE("  Failure in testReader:  reader stream is bad");
 -     }
 - 
 -     while (child.reader >> readChar) {
 - 
 -       if (!child.reader) {
 - 	RETURN_FALSE("  Failure in testReader:  reader stream is bad");
 -       }
 -       child.reader.putback(readChar);
 -       if (!child.reader) {
 - 	RETURN_FALSE("  Failure in testReader:  reader stream is bad");
 -       }
 -       child.reader >> readChar;
 -       if (!child.reader) {
 - 	RETURN_FALSE("  Failure in testReader:  reader stream is bad");
 -       }
 -       childOutput << readChar;
 - 
 -     }
 - 
 -     if (!child.reader.eof()) {
 -       RETURN_FALSE("  Failure in testReader:  Error occured before "
 - 		   "EOF was reached while reading");
 -     }
 - 
 -     // Check.
 -     if (childOutput.str() != expectedChildOutput) {
 -       std::cout << "  reader() failure in testReader." << std::endl;
 -       std::cout << "    Expected:  '" << expectedChildOutput
 - 		<< "'\n    Received:  '" << childOutput.str() << "'"
 - 		<< std::endl;
 -       return false;
 -     }
 -     if (!child.isDone()) {
 -       std::cout << "isDone() failure in testReader." << std::endl;
 -       return false;
 -     }
 - 
 -   } catch (std::exception &e) {
 -     EXCEPTION_TERM("reader()");
 -     return false;
 -   }
 - 
 -   return true;
 - 
 - }
 - 
 - ////////////////////////////////////////////////////////////////////////////////
 - // End of tests ////////////////////////////////////////////////////////////////
 - ////////////////////////////////////////////////////////////////////////////////
 - 
 - int main()
 - {
 -   std::cout << "CodeDweller::Child unit tests" << std::endl << std::endl;
 - 
 -   CodeDweller::Child child(childName);
 - 
 -   RUN_TEST(testIsDone);
 -   RUN_TEST(testResult);
 -   RUN_TEST(testTerminate);
 -   RUN_TEST(testReader);
 -   RUN_TEST(testReaderWriter);
 - 
 -   SUMMARY;
 - 
 -   return 0;
 - }
 
 
  |