string TestApplication::readTestfilePathFromEnv() { const char *const testFilesPathEnv = getenv("TEST_FILE_PATH"); if (!testFilesPathEnv || !*testFilesPathEnv) { return string(); } return argsToString(testFilesPathEnv, '/'); }
/*! * \brief Executes the application to be tested with the specified \a args and stores the standard output and * errors in \a stdout and \a stderr. * \throws Throws std::runtime_error when the application can not be executed. * \remarks * - The specified \a args must be 0 terminated. The first argument is the application name. * - Currently only supported under UNIX. * - \a stdout and \a stderr are cleared before. */ int TestApplication::execApp(const char *const *args, string &output, string &errors, bool suppressLogging, int timeout) const { // increase counter used for giving profiling files unique names static unsigned int invocationCount = 0; ++invocationCount; // determine the path of the application to be tested const char *appPath = m_applicationPathArg.firstValue(); string fallbackAppPath; if (!appPath || !*appPath) { // try to find the path by removing "_tests"-suffix from own executable path // (the own executable path is the path of the test application and its name is usually the name of the application // to be tested with "_tests"-suffix) const char *const testAppPath = m_parser.executable(); const size_t testAppPathLength = strlen(testAppPath); if (testAppPathLength > 6 && !strcmp(testAppPath + testAppPathLength - 6, "_tests")) { fallbackAppPath.assign(testAppPath, testAppPathLength - 6); appPath = fallbackAppPath.data(); // TODO: it would not hurt to verify whether "fallbackAppPath" actually exists and is executalbe } else { throw runtime_error("Unable to execute application to be tested: no application path specified"); } } // determine new path for profiling output (to not override profiling output of parent and previous invocations) string newProfilingPath; if (const char *llvmProfileFile = getenv("LLVM_PROFILE_FILE")) { // replace eg. "/some/path/tageditor_tests.profraw" with "/some/path/tageditor0.profraw" if (const char *llvmProfileFileEnd = strstr(llvmProfileFile, ".profraw")) { const string llvmProfileFileWithoutExtension(llvmProfileFile, llvmProfileFileEnd); // extract application name from path const char *appName = strrchr(appPath, '/'); appName = appName ? appName + 1 : appPath; // concat new path newProfilingPath = argsToString(llvmProfileFileWithoutExtension, '_', appName, invocationCount, ".profraw"); // append path to profiling list file if (const char *profrawListFile = getenv("LLVM_PROFILE_LIST_FILE")) { ofstream(profrawListFile, ios_base::app) << newProfilingPath << endl; } } } return execAppInternal(appPath, args, output, errors, suppressLogging, timeout, newProfilingPath); }
/* * The real main function. * Make all instead of us. * Gets equation string, prepare it, and solve. * * @param argc - the int number of parameters passed to the main function. * @param argv - the array of pointers to parameters strings. */ void makeAll(int argc, char** argv) { do { // in configuration.h // show input rules if (USAGE) showUsage(); //String of equation. string equation = ""; if (argc > 1) { equation = argsToString(argc, argv); } else { equation = getUserString(); } cout << equation << " = " << calculate(equation) << endl; } while (repeat()); closeProgramManually(); //system("pause"); }
/*! * \brief Internally called to make the entry's label unique within the parent. * \sa setLabel() */ void Entry::makeLabelUnique() { if (!m_parent) { return; } string newLabel(label()); for (unsigned int index = 2;; ++index) { bool needsNewLabel = false; for (Entry *const sibling : m_parent->children()) { if (sibling == this || newLabel != sibling->label()) { continue; } needsNewLabel = true; newLabel = argsToString(label(), ' ', index); break; } if (!needsNewLabel) { break; } } m_label.swap(newLabel); }
/*! * \brief Parses field information from the specified EbmlElement. * * The specified atom should be a simple tag element. These elements * represents the fields of a MatroskaTag. * * \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws TagParser::Failure or a derived exception when a parsing * error occurs. */ void MatroskaTagField::reparse(EbmlElement &simpleTagElement, Diagnostics &diag, bool parseNestedFields) { string context("parsing Matroska tag field"); simpleTagElement.parse(diag); bool tagDefaultFound = false; for (EbmlElement *child = simpleTagElement.firstChild(); child; child = child->nextSibling()) { try { child->parse(diag); } catch (const Failure &) { diag.emplace_back(DiagLevel::Critical, "Unable to parse children of \"SimpleTag\"-element.", context); break; } switch (child->id()) { case MatroskaIds::TagName: if (id().empty()) { setId(child->readString()); context = "parsing Matroska tag field " + id(); } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagName\"-elements. Surplus TagName elements will be ignored.", context); } break; case MatroskaIds::TagString: case MatroskaIds::TagBinary: if (value().isEmpty()) { unique_ptr<char[]> buffer = make_unique<char[]>(child->dataSize()); child->stream().seekg(static_cast<streamoff>(child->dataOffset())); child->stream().read(buffer.get(), static_cast<streamoff>(child->dataSize())); switch (child->id()) { case MatroskaIds::TagString: value().assignData(move(buffer), child->dataSize(), TagDataType::Text, TagTextEncoding::Utf8); break; case MatroskaIds::TagBinary: value().assignData(move(buffer), child->dataSize(), TagDataType::Undefined); break; } } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagString\"/\"TagBinary\"-elements. Surplus \"TagName\"/\"TagBinary\"-elements will " "be ignored.", context); } break; case MatroskaIds::TagLanguage: if (value().language().empty() || value().language() == "und") { string lng = child->readString(); if (lng != "und") { value().setLanguage(lng); } } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagLanguage\"-elements. Surplus \"TagLanguage\"-elements will be ignored.", context); } break; case MatroskaIds::TagDefault: if (!tagDefaultFound) { setDefault(child->readUInteger() > 0); tagDefaultFound = true; } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagDefault\" elements. Surplus \"TagDefault\"-elements will be ignored.", context); } break; case MatroskaIds::SimpleTag: if (parseNestedFields) { nestedFields().emplace_back(); nestedFields().back().reparse(*child, diag, true); } else { diag.emplace_back(DiagLevel::Warning, "Nested fields are currently not supported. Nested tags can not be displayed and will be discarded when rewriting the file.", context); } break; case EbmlIds::Crc32: case EbmlIds::Void: break; default: diag.emplace_back(DiagLevel::Warning, argsToString( "\"SimpleTag\"-element contains unknown element ", child->idToString(), " at ", child->startOffset(), ". It will be ignored."), context); } } }
/*! * \brief Returns a label for the entry. */ string MatroskaEditionEntry::label() const { return argsToString("ID: ", id()); }
/*! * \brief Returns the full path to a working copy of the test file with the specified \a relativeTestFilePath. * * The specified \a mode controls whether a working copy is actually created or whether just the path is returned. If only the * path is returned, the \a relativeTestFilePath is ignored. * * In contrast to workingCopyPath(), this method allows to adjust the relative path of the working copy within the working copy * directory via \a relativeWorkingCopyPath. * * \remarks * - The test file specified via \a relativeTestFilePath is located using testFilePath(). * - The name of the working copy file specified via \a relativeWorkingCopyPath will be adjusted if it already exists in the file * system and can not be truncated. */ string TestApplication::workingCopyPathAs( const std::string &relativeTestFilePath, const std::string &relativeWorkingCopyPath, WorkingCopyMode mode) const { // ensure working directory is present if (!dirExists(m_workingDir) && !makeDir(m_workingDir)) { cerr << Phrases::Error << "Unable to create working copy for \"" << relativeTestFilePath << "\": can't create working directory \"" << m_workingDir << "\"." << Phrases::EndFlush; return string(); } // ensure subdirectory exists const auto parts = splitString<vector<string>>(relativeWorkingCopyPath, "/", EmptyPartsTreat::Omit); if (!parts.empty()) { // create subdirectory level by level string currentLevel; currentLevel.reserve(m_workingDir.size() + relativeWorkingCopyPath.size() + 1); currentLevel.assign(m_workingDir); for (auto i = parts.cbegin(), end = parts.end() - 1; i != end; ++i) { if (currentLevel.back() != '/') { currentLevel += '/'; } currentLevel += *i; // continue if subdirectory level already exists or we can successfully create the directory if (dirExists(currentLevel) || makeDir(currentLevel)) { continue; } // fail otherwise cerr << Phrases::Error << "Unable to create working copy for \"" << relativeWorkingCopyPath << "\": can't create directory \"" << currentLevel << "\" (inside working directory)." << Phrases::EndFlush; return string(); } } // just return the path if we don't want to actually create a copy if (mode == WorkingCopyMode::NoCopy) { return m_workingDir + relativeWorkingCopyPath; } // copy the file const auto origFilePath(testFilePath(relativeTestFilePath)); auto workingCopyPath(m_workingDir + relativeWorkingCopyPath); size_t workingCopyPathAttempt = 0; NativeFileStream origFile, workingCopy; origFile.open(origFilePath, ios_base::in | ios_base::binary); if (origFile.fail()) { cerr << Phrases::Error << "Unable to create working copy for \"" << relativeTestFilePath << "\": an IO error occurred when opening original file \"" << origFilePath << "\"." << Phrases::EndFlush; cerr << "error: " << strerror(errno) << endl; return string(); } workingCopy.open(workingCopyPath, ios_base::out | ios_base::binary | ios_base::trunc); while (workingCopy.fail() && fileSystemItemExists(workingCopyPath)) { // adjust the working copy path if the target file already exists and can not be truncated workingCopyPath = argsToString(m_workingDir, relativeWorkingCopyPath, '.', ++workingCopyPathAttempt); workingCopy.clear(); workingCopy.open(workingCopyPath, ios_base::out | ios_base::binary | ios_base::trunc); } if (workingCopy.fail()) { cerr << Phrases::Error << "Unable to create working copy for \"" << relativeTestFilePath << "\": an IO error occurred when opening target file \"" << workingCopyPath << "\"." << Phrases::EndFlush; cerr << "error: " << strerror(errno) << endl; return string(); } workingCopy << origFile.rdbuf(); if (!origFile.fail() && !workingCopy.fail()) { return workingCopyPath; } cerr << Phrases::Error << "Unable to create working copy for \"" << relativeTestFilePath << "\": "; if (origFile.fail()) { cerr << "an IO error occurred when reading original file \"" << origFilePath << "\""; return string(); } if (workingCopy.fail()) { if (origFile.fail()) { cerr << " and "; } cerr << " an IO error occurred when writing to target file \"" << workingCopyPath << "\"."; } cerr << "error: " << strerror(errno) << endl; return string(); }
/*! * \brief Constructs a TestApplication instance. * \throws Throws std::runtime_error if an instance has already been created. */ TestApplication::TestApplication(int argc, char **argv) : m_helpArg(m_parser) , m_testFilesPathArg("test-files-path", 'p', "specifies the path of the directory with test files") , m_applicationPathArg("app-path", 'a', "specifies the path of the application to be tested") , m_workingDirArg("working-dir", 'w', "specifies the directory to store working copies of test files") , m_unitsArg("units", 'u', "specifies the units to test; omit to test all units") { // check whether there is already an instance if (m_instance) { throw runtime_error("only one TestApplication instance allowed at a time"); } m_instance = this; // determine fallback path for testfiles which is used when --test-files-path/-p not present // -> read TEST_FILE_PATH environment variable m_fallbackTestFilesPath = readTestfilePathFromEnv(); // -> find source directory if TEST_FILE_PATH not present bool fallbackIsSourceDir = m_fallbackTestFilesPath.empty(); if (fallbackIsSourceDir) { m_fallbackTestFilesPath = readTestfilePathFromSrcRef(); } // handle specified arguments (if present) if (argc && argv) { // setup argument parser for (Argument *arg : initializer_list<Argument *>{ &m_testFilesPathArg, &m_applicationPathArg, &m_workingDirArg }) { arg->setRequiredValueCount(1); arg->setValueNames({ "path" }); arg->setCombinable(true); } m_unitsArg.setRequiredValueCount(Argument::varValueCount); m_unitsArg.setValueNames({ "unit1", "unit2", "unit3" }); m_unitsArg.setCombinable(true); m_parser.setMainArguments({ &m_testFilesPathArg, &m_applicationPathArg, &m_workingDirArg, &m_unitsArg, &m_helpArg }); // parse arguments try { m_parser.parseArgs(argc, argv); } catch (const Failure &failure) { cerr << failure; m_valid = false; return; } // print help if (m_helpArg.isPresent()) { exit(0); } } // handle path for testfiles and working-copy cerr << "Directories used to search for testfiles:" << endl; if (m_testFilesPathArg.isPresent()) { if (*m_testFilesPathArg.values().front()) { cerr << ((m_testFilesPath = m_testFilesPathArg.values().front()) += '/') << endl; } else { cerr << (m_testFilesPath = "./") << endl; } } else { // use fallback path if --test-files-path/-p not present m_testFilesPath.swap(m_fallbackTestFilesPath); cerr << m_testFilesPath << endl; } // if it wasn't already the case, use the source directory as fallback dir if (m_fallbackTestFilesPath.empty() && !fallbackIsSourceDir) { m_fallbackTestFilesPath = readTestfilePathFromSrcRef(); fallbackIsSourceDir = true; } if (!m_fallbackTestFilesPath.empty() && m_testFilesPath != m_fallbackTestFilesPath) { cerr << m_fallbackTestFilesPath << endl; } cerr << "./testfiles/" << endl << endl; cerr << "Directory used to store working copies:" << endl; if (m_workingDirArg.isPresent()) { if (*m_workingDirArg.values().front()) { (m_workingDir = m_workingDirArg.values().front()) += '/'; } else { m_workingDir = "./"; } } else if (const char *workingDirEnv = getenv("WORKING_DIR")) { if (*workingDirEnv) { m_workingDir = argsToString(workingDirEnv, '/'); } } else { if (m_testFilesPathArg.isPresent()) { m_workingDir = m_testFilesPath + "workingdir/"; } else if (!m_fallbackTestFilesPath.empty() && !fallbackIsSourceDir) { m_workingDir = m_fallbackTestFilesPath + "workingdir/"; } else { m_workingDir = "./testfiles/workingdir/"; } } cerr << m_workingDir << endl << endl; // clear list of all additional profiling files created when forking the test application if (const char *profrawListFile = getenv("LLVM_PROFILE_LIST_FILE")) { ofstream(profrawListFile, ios_base::trunc); } m_valid = true; cerr << TextAttribute::Bold << "Executing test cases ..." << Phrases::EndFlush; }