|
|
@@ -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;
|