diff --git a/tests/testutils.cpp b/tests/testutils.cpp index 140086e..4488739 100644 --- a/tests/testutils.cpp +++ b/tests/testutils.cpp @@ -211,18 +211,19 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode { // ensure working directory is present struct stat currentStat; - if (stat(m_workingDir.c_str(), ¤tStat) || !S_ISDIR(currentStat.st_mode)) { - if (mkdir(m_workingDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) { - cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": can't create working directory." << Phrases::EndFlush; - return string(); - } + if ((stat(m_workingDir.c_str(), ¤tStat) || !S_ISDIR(currentStat.st_mode)) + && mkdir(m_workingDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) { + cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": can't create working directory." << Phrases::EndFlush; + return string(); } // ensure subdirectory exists - const auto parts = splitString>(name, string("/"), EmptyPartsTreat::Omit); + const auto parts = splitString>(name, "/", EmptyPartsTreat::Omit); if (!parts.empty()) { - string currentLevel = m_workingDir; // create subdirectory level by level + string currentLevel; + currentLevel.reserve(m_workingDir.size() + name.size() + 1); + currentLevel.assign(m_workingDir); for (auto i = parts.cbegin(), end = parts.end() - 1; i != end; ++i) { if (currentLevel.back() != '/') { currentLevel += '/'; @@ -238,8 +239,7 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode continue; } // fail otherwise - cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": can't create working directory." - << Phrases::EndFlush; + cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": can't create working directory." << Phrases::EndFlush; return string(); } } @@ -255,12 +255,14 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode fstream origFile, workingCopy; origFile.open(origFilePath, ios_base::in | ios_base::binary); if (origFile.fail()) { - cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": an IO error occurred when opening original file \"" << origFilePath << "\"." << Phrases::EndFlush; + cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": an IO error occurred when opening original file \"" + << origFilePath << "\"." << Phrases::EndFlush; return string(); } workingCopy.open(workingCopyPath, ios_base::out | ios_base::binary | ios_base::trunc); if (workingCopy.fail()) { - cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": an IO error occurred when opening target file \"" << workingCopyPath << "\"." << Phrases::EndFlush; + cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": an IO error occurred when opening target file \"" + << workingCopyPath << "\"." << Phrases::EndFlush; return string(); } workingCopy << origFile.rdbuf(); @@ -270,7 +272,7 @@ string TestApplication::workingCopyPathMode(const string &name, WorkingCopyMode cerr << Phrases::Error << "Unable to create working copy for \"" << name << "\": "; if (origFile.fail()) { - cerr << "an IO error occurred when reading original file \"" << origFilePath << "\""; + cerr << "an IO error occurred when reading original file \"" << origFilePath << "\""; return string(); } if (workingCopy.fail()) { @@ -312,14 +314,16 @@ int execAppInternal(const char *appPath, const char *const *args, std::string &o // create pipes int coutPipes[2], cerrPipes[2]; - pipe(coutPipes), pipe(cerrPipes); - int readCoutPipe = coutPipes[0], writeCoutPipe = coutPipes[1]; - int readCerrPipe = cerrPipes[0], writeCerrPipe = cerrPipes[1]; + pipe(coutPipes); + pipe(cerrPipes); + const auto readCoutPipe = coutPipes[0], writeCoutPipe = coutPipes[1]; + const auto readCerrPipe = cerrPipes[0], writeCerrPipe = cerrPipes[1]; // create child process - if (int child = fork()) { + if (const auto child = fork()) { // parent process: read stdout and stderr from child - close(writeCoutPipe), close(writeCerrPipe); + close(writeCoutPipe); + close(writeCerrPipe); try { if (child == -1) { @@ -334,41 +338,41 @@ int execAppInternal(const char *appPath, const char *const *args, std::string &o // init variables for reading char buffer[512]; - ssize_t count; - output.clear(), errors.clear(); + output.clear(); + errors.clear(); // poll as long as at least one pipe is open do { - int retpoll = poll(fileDescriptorSet, 2, timeout); - if (retpoll > 0) { - // poll succeeds - if (fileDescriptorSet[0].revents & POLLIN) { - if ((count = read(readCoutPipe, buffer, sizeof(buffer))) > 0) { - output.append(buffer, static_cast(count)); - } - } else if (fileDescriptorSet[0].revents & POLLHUP) { - close(readCoutPipe); - fileDescriptorSet[0].fd = -1; - } - if (fileDescriptorSet[1].revents & POLLIN) { - if ((count = read(readCerrPipe, buffer, sizeof(buffer))) > 0) { - errors.append(buffer, static_cast(count)); - } - } else if (fileDescriptorSet[1].revents & POLLHUP) { - close(readCerrPipe); - fileDescriptorSet[1].fd = -1; - } - } else if (retpoll == 0) { - // timeout + const auto retpoll = poll(fileDescriptorSet, 2, timeout); + if (retpoll == 0) { throw runtime_error("Poll time-out"); - } else { - // fail + } + if (retpoll < 0) { throw runtime_error("Poll failed"); } + if (fileDescriptorSet[0].revents & POLLIN) { + const auto count = read(readCoutPipe, buffer, sizeof(buffer)); + if (count > 0) { + output.append(buffer, static_cast(count)); + } + } else if (fileDescriptorSet[0].revents & POLLHUP) { + close(readCoutPipe); + fileDescriptorSet[0].fd = -1; + } + if (fileDescriptorSet[1].revents & POLLIN) { + const auto count = read(readCerrPipe, buffer, sizeof(buffer)); + if (count > 0) { + errors.append(buffer, static_cast(count)); + } + } else if (fileDescriptorSet[1].revents & POLLHUP) { + close(readCerrPipe); + fileDescriptorSet[1].fd = -1; + } } while (fileDescriptorSet[0].fd >= 0 || fileDescriptorSet[1].fd >= 0); } catch (...) { - // ensure all pipes are close in the error case - close(readCoutPipe), close(readCerrPipe); + // ensure all pipes are closed in the error case + close(readCoutPipe); + close(readCerrPipe); throw; } @@ -379,8 +383,12 @@ int execAppInternal(const char *appPath, const char *const *args, std::string &o } else { // child process // -> set pipes to be used for stdout/stderr - dup2(writeCoutPipe, STDOUT_FILENO), dup2(writeCerrPipe, STDERR_FILENO); - close(readCoutPipe), close(writeCoutPipe), close(readCerrPipe), close(writeCerrPipe); + dup2(writeCoutPipe, STDOUT_FILENO); + dup2(writeCerrPipe, STDERR_FILENO); + close(readCoutPipe); + close(writeCoutPipe); + close(readCerrPipe); + close(writeCerrPipe); // -> modify environment variable LLVM_PROFILE_FILE to apply new path for profiling output if (!newProfilingPath.empty()) { @@ -475,7 +483,7 @@ string TestApplication::readTestfilePathFromSrcRef() try { // read "srcdirref" file which should contain the path of the source directory; this file should have been // create by the CMake module "TestTarget.cmake" - string srcDirContent(readFile("srcdirref", 2 * 1024)); + auto srcDirContent(readFile("srcdirref", 2 * 1024)); if (srcDirContent.empty()) { cerr << Phrases::Warning << "The file \"srcdirref\" is empty." << Phrases::EndFlush; return string();