| 
				
			 | 
			
			 | 
			@@ -25,39 +25,39 @@ int nFail = 0; | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool result;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#define NO_EXCEPTION_TERM(msg)			                  \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout                                                       \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << msg << " failed to throw exception at line "		  \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#define NO_EXCEPTION_TERM(msg)                          \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout                                             \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << msg << " failed to throw exception at line "       \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << __LINE__ << "." << std::endl
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#define EXCEPTION_TERM(msg)			             	      \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout                                                  	      \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#define EXCEPTION_TERM(msg)                                             \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout                                                             \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << msg << " threw unexpected exception:  " << e.what() << std::endl
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#define RETURN_FALSE(msg)					\
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout							\
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << msg << " at line " << __LINE__ << 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++;							\
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#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 \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#define SUMMARY                                 \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout                                     \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << "\nPass:  " << nPass                       \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << ", Fail:  " << nFail                       \
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  << ", Total:  " << nTotalTests << std::endl
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			// Tests ///////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			// ChildStream Tests ///////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testIsDone() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamIsDone() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -99,7 +99,7 @@ bool testIsDone() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testIsRunning() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamIsRunning() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -133,6 +133,7 @@ bool testIsRunning() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("isRunning()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -142,7 +143,7 @@ bool testIsRunning() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testResult() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamResult() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<std::string> cmd;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -184,12 +185,12 @@ bool testResult() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testClose() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamClose() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test with no waiting.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      CodeDweller::ChildStream child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::ChildStream child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close() with no waiting");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -197,9 +198,9 @@ bool testClose() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test with waiting.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      CodeDweller::ChildStream child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::ChildStream child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close() with 100 ms waiting");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -212,10 +213,10 @@ bool testClose() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  cmd.push_back("quit");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      CodeDweller::ChildStream child(cmd);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::ChildStream child(cmd);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close() after child exits");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -224,19 +225,19 @@ bool testClose() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test exception thrown for out-of-order calling.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      CodeDweller::ChildStream child;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::ChildStream child;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      NO_EXCEPTION_TERM("close() called without run()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    NO_EXCEPTION_TERM("close() called without run()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testReaderWriter() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamReaderWriter() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    size_t bufSize = 15;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -352,7 +353,7 @@ bool testReaderWriter() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testReader() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamReader() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -440,7 +441,7 @@ bool testReader() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testBinaryRead() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamBinaryRead() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<std::string> cmd;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -534,7 +535,7 @@ bool testBinaryRead() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testNonBlockingRead() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildStreamNonBlockingRead() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<std::string> cmd;
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -679,24 +680,644 @@ bool testNonBlockingRead() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			// End of tests ////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			// Child Tests ///////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			int main()
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout << "CodeDweller::ChildStream unit tests" << std::endl << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildIsDone() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Test exception if called out-of-order.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      child.isDone();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      NO_EXCEPTION_TERM("isDone() called without run()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Start the child.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.open(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.isDone()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "isDone() failure; returned true." << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Command the child to exit.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.write("q")) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  Failure in testChildIsDone:  write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // 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;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("isDone()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildIsRunning() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.isRunning()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "isRunning() failure; returned true before starting."
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Start the child.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.open(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.isRunning()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "isRunning() failure; returned false." << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Command the child to exit.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.write("q")) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Sleep to let the child exit.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.isRunning()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "isRunning() failure; returned true after stopping."
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("isRunning()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildResult() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  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) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // 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 testChildClose() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test with no child process.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    NO_EXCEPTION_TERM("close() with no child process");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test with no waiting.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close() with no waiting");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test with waiting.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close() with 100 ms waiting");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test after the child exits.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::vector<std::string> cmd;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  cmd.push_back(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  cmd.push_back("quit");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  CodeDweller::ChildStream child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(cmd);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testIsDone);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testIsRunning);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testResult);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testClose);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testReader);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testReaderWriter);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testBinaryRead);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testNonBlockingRead);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close() after child exits");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test exception thrown for out-of-order calling.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    NO_EXCEPTION_TERM("close() called without open()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildOpen() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test with no waiting.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.open(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close()/open() with no waiting");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test with waiting.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.open(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("close()/open() with 100 ms waiting");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  // Test exception thrown for out-of-order calling.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    NO_EXCEPTION_TERM("close() called without open()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildReadWrite() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  size_t bufSize = 15;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  int nChar = bufSize - 1; // Size of each packet.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(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.write("Should Throw");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      NO_EXCEPTION_TERM("  writer called without run()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.open(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Write, read, put back, and reread each character.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int nLine = 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    for (std::string &line : expectedChildOutput) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      nLine++;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Try to queue.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      bool done;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      int nTries = 100;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      for (int i = 0; i < nTries; i++) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        done = child.write(line);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (done) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			          break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        std::this_thread::sleep_for(std::chrono::milliseconds(10));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      if (!done) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        std::ostringstream temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        temp << "  Failure from write(std::string const &) on line " << nLine;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        RETURN_FALSE(temp.str());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Wait for transmission.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      for (int i = 0; i < nTries; i++) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        done = child.isFinishedWriting();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (done) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			          break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        std::this_thread::sleep_for(std::chrono::milliseconds(10));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      if (!done) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        std::ostringstream temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        temp << "  Failure from isFinishedWriting() on line " << nLine;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        RETURN_FALSE(temp.str());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::this_thread::sleep_for(std::chrono::milliseconds(10));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Read one line.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::string readLine, temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      int nCharToRead, nCharRead;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      readLine.clear();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      nCharToRead = line.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      for (int i = 0; i < nTries; i++) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        nCharRead = child.read(temp, nCharToRead);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        nCharToRead -= nCharRead;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        if (nCharToRead <= 0) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			          break;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      if (0 != nCharToRead) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        std::ostringstream temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        temp << "  Failure from () on line " << nLine
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			             << ":  nCharRead:  " << nCharRead;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        RETURN_FALSE(temp.str());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Convert to upper case.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::string expectedLine;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      expectedLine = line;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      for (auto &c : expectedLine) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
				c = toupper(c);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Compare.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      if (expectedLine != readLine) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
				std::cout << "  Failure in testReadWrite." << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
				std::cout << "    Expected:  '" << expectedLine
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					  << "'\n    Received:  '" << readLine << "'" << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
				return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Send exit message.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.write("q")) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  Failure in testChildIsDone:  write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Verify exit.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.isDone()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "  Failure in testReadWrite:  Child program did not exit."
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("read()/write()/isFinishedWriting()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildRead() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    size_t bufSize = 32;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(bufSize);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Test exception.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::string temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      (void) child.read(temp);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      NO_EXCEPTION_TERM("  read() called without open()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::ostringstream childOutput;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string expectedChildOutput("This is a test");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string readBuf;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<std::string> cmd;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    cmd.push_back(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    cmd.push_back("write");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.open(cmd);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int nTries = 100;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    for (int i = 0; i < nTries; i++) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      if (child.read(readBuf) > 0) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        childOutput << readBuf;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      if (child.errorOccurred(readBuf)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        std::ostringstream temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        temp << "  Failure in testReader:  " << readBuf;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			        RETURN_FALSE(temp.str());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::this_thread::sleep_for(std::chrono::milliseconds(10));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (childOutput.str() != expectedChildOutput) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "  read() failure in testChildRead." << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "    Expected:  '" << expectedChildOutput
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					<< "'\n    Received:  '" << childOutput.str() << "'"
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					<< std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Sleep to let the child exit.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.isDone()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "first isDone() failure in testReader." << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.isDone()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "second isDone() failure in testReader." << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("reader()");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildNonBlockingReadWrite() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  try {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<std::string> cmd;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    cmd.push_back(childName);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    size_t bufSize = 16;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::uint16_t
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      nominalAboveMin_ms = 15,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      delta_ms = 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    CodeDweller::Child child(cmd,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                             bufSize,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                             nominalAboveMin_ms,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                             delta_ms);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check for available input with input.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string childInput("abc");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.write(childInput)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  first write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Read one character.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string readBuf;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf, 1) != 1) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if ("A" != readBuf) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Read.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf, 2) != 2) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if ("BC" != readBuf) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check that no input is available.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf) != 0) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!readBuf.empty()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Fill input buffer.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string output("abcdefghijklmnopprstuvwxyz");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string expectedInput(output);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string expectedOutputAfter1(output.substr(bufSize));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    for (int i = 0; i < output.size(); i++) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      expectedInput[i] = std::toupper(output[i]);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.writeAndShrink(output) != bufSize) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  writeAndShrink() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (output != expectedOutputAfter1) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  writeAndShrink() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(25));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int expectedLeftOver = output.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.writeAndShrink(output) != expectedLeftOver) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  writeAndShrink() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!output.empty()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  writeAndShrink() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(25));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf) != bufSize) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (readBuf != expectedInput.substr(0, bufSize)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure)");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf) != expectedLeftOver) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (expectedInput.substr(bufSize) != readBuf) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Send exit message.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.write("q")) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Verify exit.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.isDone()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::cout << "  Failure in testNonblockingReader:  "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					<< "Child program did not exit."  << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string errorDescription;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.errorOccurred(errorDescription)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::ostringstream temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      temp << "  Failure in: testChildNonBlockingReadWrite:  "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			           << errorDescription;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE(temp.str());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("Non-blocking reader test");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			// End of tests ////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			int main()
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			{
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#if 0
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout << "\nCodeDweller::ChildStream unit tests\n" << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamIsDone);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamIsRunning);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamResult);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamClose);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamReader);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamReaderWriter);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamBinaryRead);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildStreamNonBlockingRead);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::cout << "\nCodeDweller::Child unit tests\n" << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildIsDone);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildIsRunning);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildResult);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildClose);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildOpen);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#endif
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildRead);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#if 1
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildReadWrite);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildNonBlockingReadWrite);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#endif
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  SUMMARY;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return 0;
 |