| 
				
			 | 
			
			 | 
			@@ -1589,6 +1589,163 @@ bool testChildNonBlockingReadWrite2() { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			bool testChildVectorReadWrite() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  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 that write fails.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<char> badVector(bufSize + 1);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.write(badVector)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check write().
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<char> childInput = {'a', 'b', 'c'};
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!child.write(childInput)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(50));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Read one character.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<char> readBuf;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf, 1) != 1) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if ('A' != readBuf[0]) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Read.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf, 2) != 2) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (std::vector<char>({'B', 'C'}) != 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::vector<char> output = {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      'n', 'o', 'p', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    };
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::vector<char> expectedInput(output);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    for (int i = 0; i < output.size(); i++) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      expectedInput[i] = std::toupper(output[i]);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.write(output, bufSize) != bufSize) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  write() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(50));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    size_t nRequested = bufSize / 2;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check partial read.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    size_t nRead = child.read(readBuf, nRequested);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (nRead != nRequested) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (readBuf != std::vector<char>(expectedInput.begin(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                     expectedInput.begin() + nRead)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure)");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check remainder.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    readBuf.resize(bufSize * 2);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    nRead = child.read(readBuf);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if ( (bufSize - nRequested) != nRead) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (readBuf != std::vector<char>(expectedInput.begin() + nRequested,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                                     expectedInput.begin() + bufSize)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure)");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Write remainder.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    output.erase(output.begin(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                 output.begin() + bufSize);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    expectedInput.erase(expectedInput.begin(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			                        expectedInput.begin() + bufSize);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    size_t nExpectedBytes = output.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.writeAndShrink(output) != nExpectedBytes) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  writeAndShrink() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::this_thread::sleep_for(std::chrono::milliseconds(50));
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.read(readBuf) != nExpectedBytes) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE("  read() failure");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (readBuf != expectedInput) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      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 testChildVectorReadWrite:  "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					<< "Child program did not exit."  << std::endl;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::string errorDescription;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (child.errorOccurred(errorDescription)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      std::ostringstream temp;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      temp << "  Failure in: testChildVectorReadWrite:  "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			           << errorDescription;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      RETURN_FALSE(temp.str());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    child.close();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  } catch (std::exception &e) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    EXCEPTION_TERM("testChildVectorReadWrite");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			// End of tests ////////////////////////////////////////////////////////////////
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			////////////////////////////////////////////////////////////////////////////////
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -1619,6 +1776,7 @@ int main() | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildReadWrite);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildNonBlockingReadWrite1);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildNonBlockingReadWrite2);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  RUN_TEST(testChildVectorReadWrite);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  SUMMARY;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 |