瀏覽代碼

Testing CodeDweller::Child.


git-svn-id: https://svn.microneil.com/svn/CodeDweller-Tests/trunk@42 b3372362-9eaa-4a85-aa2b-6faa1ab7c995
master
adeniz 9 年之前
父節點
當前提交
20a7ee7c51
共有 3 個文件被更改,包括 686 次插入56 次删除
  1. 2
    2
      TestChild/buildAndRun
  2. 14
    5
      TestChild/childProgram.cpp
  3. 670
    49
      TestChild/testChild.cpp

+ 2
- 2
TestChild/buildAndRun 查看文件

@@ -1,11 +1,11 @@
CFLAGS='-I.. -std=c++11 -g -O0'
CFLAGS='-I.. -std=c++11 -g -O0 -pthread'
g++ $CFLAGS childProgram.cpp -o childProgram
if [ $? -ne 0 ]
then
exit -1
fi

g++ $CFLAGS testChild.cpp ../CodeDweller/child.cpp -o testChild
g++ $CFLAGS testChild.cpp ../CodeDweller/child.cpp ../CodeDweller/timing.cpp -o testChild
if [ $? -ne 0 ]
then
exit -1

+ 14
- 5
TestChild/childProgram.cpp 查看文件

@@ -7,41 +7,50 @@
int
main(int argc, char *argv[]) {
std::ofstream log("childProgram.log");
// Output for read test.
if (argc == 2) {
// Write a single line and exit.
if (std::string(argv[1]) == "write") {
log << "Command is \"write\". Returning \"This is a test\"" << std::endl;
std::cout << "This is a test";
std::cout.flush();
return 25;
goto exit;
}
// Exit without writing anything.
if (std::string(argv[1]) == "quit") {
return 25;
log << "Command is \"quit\". Exiting" << std::endl;
goto exit;
}
}
std::ofstream log("childProgram.log");
char ch;
log << "Received \"";
while (std::cin >> ch) {
// Exit?
if ('q' == ch) {
log << ch << "\"" << std::endl;
break;
}
std::cout << (char) std::toupper(ch);
std::cout.flush();
log << (char) std::toupper(ch);
log << (char) ch;
log.flush();
}
exit:
log.close();
return 25;

+ 670
- 49
TestChild/testChild.cpp 查看文件

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

Loading…
取消
儲存