|
|
@@ -4,6 +4,7 @@ |
|
|
|
#include <chrono>
|
|
|
|
#include <thread>
|
|
|
|
#include <sstream>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include "CodeDweller/child.hpp"
|
|
|
|
|
|
|
@@ -29,10 +30,9 @@ bool result; |
|
|
|
<< 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 EXCEPTION_TERM(msg) \
|
|
|
|
std::cout \
|
|
|
|
<< msg << " threw unexpected exception: " << e.what() << std::endl
|
|
|
|
|
|
|
|
#define RETURN_FALSE(msg) \
|
|
|
|
std::cout \
|
|
|
@@ -398,6 +398,257 @@ testReader() { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
testBinaryRead() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
|
|
|
|
cmd.push_back(childName);
|
|
|
|
|
|
|
|
size_t bufSize = 164;
|
|
|
|
CodeDweller::Child child(cmd, bufSize);
|
|
|
|
|
|
|
|
child.run();
|
|
|
|
|
|
|
|
// Write.
|
|
|
|
std::string childInput("abc");
|
|
|
|
#if 0
|
|
|
|
child.writer << childInput;
|
|
|
|
child.writer.flush();
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
|
|
|
|
// Read one character.
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
child.reader.read(&ch, 1);
|
|
|
|
|
|
|
|
if (ch != 'A') {
|
|
|
|
RETURN_FALSE(" reader.read() returned incorrect value");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read.
|
|
|
|
char buf[bufSize * 2];
|
|
|
|
|
|
|
|
child.reader.read(buf, 2);
|
|
|
|
buf[2] = '\0';
|
|
|
|
|
|
|
|
std::string input(buf);
|
|
|
|
|
|
|
|
if (input != "BC") {
|
|
|
|
RETURN_FALSE(" reader.read() returned incorrect value");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
char buf[bufSize * 2];
|
|
|
|
#endif
|
|
|
|
// Fill input buffer.
|
|
|
|
std::string output("abcdefghijklmnopprstuvwxyz");
|
|
|
|
std::string expectedInput(output);
|
|
|
|
|
|
|
|
for (int i = 0; i < output.size(); i++) {
|
|
|
|
expectedInput[i] = std::toupper(output[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "Writing '" << output << "', " << output.size()
|
|
|
|
<< " bytes" << std::endl;//debug
|
|
|
|
child.writer << output;
|
|
|
|
child.writer.flush();
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
#if 1
|
|
|
|
char ch;
|
|
|
|
child.reader.read(&ch, 1);
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
if (ch != expectedInput[index++]) {
|
|
|
|
RETURN_FALSE(" reader.read() returned incorrect value");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
size_t nBytesRead = expectedInput.size() - 1;
|
|
|
|
|
|
|
|
std::cout << "testChild. reading " << nBytesRead << " bytes..." << std::endl; // debug
|
|
|
|
child.reader.read(buf, nBytesRead);
|
|
|
|
std::cout << "done." << std::endl;
|
|
|
|
buf[nBytesRead] = '\0';
|
|
|
|
|
|
|
|
std::cout << "buf: '" << buf << "'" << std::endl; //debug
|
|
|
|
if (expectedInput.substr(index, nBytesRead) != std::string(buf)) {
|
|
|
|
RETURN_FALSE(" reader.read() failure");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send exit message.
|
|
|
|
child.writer << 'q';
|
|
|
|
child.writer.flush();
|
|
|
|
if (!child.writer) {
|
|
|
|
RETURN_FALSE(" Failure in testNonblockingReader: writer stream is bad");
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
EXCEPTION_TERM("Binary read test");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::cout << "success. returning." << std::endl;//debug
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
testNonBlockingRead() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
|
|
|
|
cmd.push_back(childName);
|
|
|
|
|
|
|
|
size_t bufSize = 16;
|
|
|
|
CodeDweller::Child child(cmd, bufSize);
|
|
|
|
|
|
|
|
child.run();
|
|
|
|
|
|
|
|
// Check for available input with no input.
|
|
|
|
if (child.numBytesAvailable() != 0) {
|
|
|
|
RETURN_FALSE(" numBytesAvailable() did not return expected 0");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for available input with input.
|
|
|
|
std::string childInput("abc");
|
|
|
|
|
|
|
|
child.writer << childInput;
|
|
|
|
child.writer.flush();
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
|
|
|
|
// Check that input is available.
|
|
|
|
if (child.numBytesAvailable() != 1) {
|
|
|
|
RETURN_FALSE(" numBytesAvailable() did not return expected 1");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read one character.
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
child.reader.read(&ch, 1);
|
|
|
|
|
|
|
|
if (ch != 'A') {
|
|
|
|
RETURN_FALSE(" reader.read() returned incorrect value");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that input is available.
|
|
|
|
if (child.numBytesAvailable() != 2) {
|
|
|
|
RETURN_FALSE(" numBytesAvailable() did not return expected 2");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read.
|
|
|
|
char buf[bufSize * 2];
|
|
|
|
|
|
|
|
child.reader.read(buf, 2);
|
|
|
|
buf[2] = '\0';
|
|
|
|
|
|
|
|
std::string input(buf);
|
|
|
|
|
|
|
|
if (input != "BC") {
|
|
|
|
RETURN_FALSE(" reader.read() returned incorrect value");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that no input is available.
|
|
|
|
if (child.numBytesAvailable() != 0) {
|
|
|
|
RETURN_FALSE(" numBytesAvailable() did not return expected 0 "
|
|
|
|
"after reading");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill input buffer.
|
|
|
|
std::string output("abcdefghijklmnopqrstuvwxyz");
|
|
|
|
std::string expectedInput(output);
|
|
|
|
|
|
|
|
for (int i = 0; i < output.size(); i++) {
|
|
|
|
expectedInput[i] = std::toupper(output[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
child.writer << output;
|
|
|
|
child.writer.flush();
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
|
|
|
|
if (child.numBytesAvailable() != 1) {
|
|
|
|
RETURN_FALSE(" numBytesAvailable() did not return expected 1");
|
|
|
|
}
|
|
|
|
|
|
|
|
child.reader.read(&ch, 1);
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
if (ch != expectedInput[index++]) {
|
|
|
|
RETURN_FALSE(" reader.read() returned incorrect value");
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t nBytesAvailable;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
nBytesAvailable = child.numBytesAvailable();
|
|
|
|
if (nBytesAvailable != bufSize) {
|
|
|
|
RETURN_FALSE(" numBytesAvailable() did not return expected value");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
nBytesAvailable = 16;
|
|
|
|
#endif
|
|
|
|
std::fill_n(buf, sizeof(buf), 0);
|
|
|
|
std::cout << "Reading " << nBytesAvailable << " bytes..." << std::endl; // DEBUG
|
|
|
|
child.reader.read(buf, nBytesAvailable);
|
|
|
|
std::cout << "Done" << std::endl; // DEBUG
|
|
|
|
|
|
|
|
if (expectedInput.substr(index, nBytesAvailable) != std::string(buf)) {
|
|
|
|
RETURN_FALSE(" reader.read() failure");
|
|
|
|
}
|
|
|
|
index += nBytesAvailable;
|
|
|
|
|
|
|
|
std::fill_n(buf, sizeof(buf), 0);
|
|
|
|
child.reader.read(buf, nBytesAvailable);
|
|
|
|
|
|
|
|
if (expectedInput.substr(index, nBytesAvailable) != std::string(buf)) {
|
|
|
|
RETURN_FALSE(" reader.read() failure");
|
|
|
|
}
|
|
|
|
|
|
|
|
index += nBytesAvailable;
|
|
|
|
if (expectedInput.size() != index) {
|
|
|
|
RETURN_FALSE(" not all data was read by reader.read()");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (child.numBytesAvailable() != 0) {
|
|
|
|
RETURN_FALSE(" numBytesAvailable() did not return expected 0");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send exit message.
|
|
|
|
child.writer << 'q';
|
|
|
|
child.writer.flush();
|
|
|
|
if (!child.writer) {
|
|
|
|
RETURN_FALSE(" Failure in testNonblockingReader: writer stream is bad");
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
EXCEPTION_TERM("Non-blocking reader test");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::cout << "success. returning." << std::endl;//debug
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// End of tests ////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
@@ -408,11 +659,13 @@ int main() |
|
|
|
|
|
|
|
CodeDweller::Child child(childName);
|
|
|
|
|
|
|
|
RUN_TEST(testIsDone);
|
|
|
|
RUN_TEST(testResult);
|
|
|
|
RUN_TEST(testTerminate);
|
|
|
|
RUN_TEST(testReader);
|
|
|
|
RUN_TEST(testReaderWriter);
|
|
|
|
//RUN_TEST(testIsDone);
|
|
|
|
//RUN_TEST(testResult);
|
|
|
|
//RUN_TEST(testTerminate);
|
|
|
|
//RUN_TEST(testReader);
|
|
|
|
//RUN_TEST(testReaderWriter);
|
|
|
|
RUN_TEST(testBinaryRead);
|
|
|
|
//RUN_TEST(testNonBlockingRead);
|
|
|
|
|
|
|
|
SUMMARY;
|
|
|
|
|