| /*============================================================================ |
| CMake - Cross Platform Makefile Generator |
| Copyright 2000-2009 Kitware, Inc., Insight Software Consortium |
| |
| Distributed under the OSI-approved BSD License (the "License"); |
| see accompanying file Copyright.txt for details. |
| |
| This software is distributed WITHOUT ANY WARRANTY; without even the |
| implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the License for more information. |
| ============================================================================*/ |
| |
| #ifndef cmCTest_h |
| #define cmCTest_h |
| |
| #include "cmStandardIncludes.h" |
| #include "cmListFileCache.h" |
| #include <time.h> |
| |
| class cmake; |
| class cmMakefile; |
| class cmCTestGenericHandler; |
| class cmGeneratedFileStream; |
| class cmCTestCommand; |
| class cmCTestScriptHandler; |
| class cmCTestStartCommand; |
| |
| #define cmCTestLog(ctSelf, logType, msg) \ |
| do { \ |
| std::ostringstream cmCTestLog_msg; \ |
| cmCTestLog_msg << msg; \ |
| (ctSelf)->Log(cmCTest::logType, __FILE__, __LINE__,\ |
| cmCTestLog_msg.str().c_str());\ |
| } while ( 0 ) |
| |
| #ifdef cerr |
| # undef cerr |
| #endif |
| #define cerr no_cerr_use_cmCTestLog |
| |
| #ifdef cout |
| # undef cout |
| #endif |
| #define cout no_cout_use_cmCTestLog |
| |
| class cmCTest |
| { |
| friend class cmCTestRunTest; |
| friend class cmCTestMultiProcessHandler; |
| public: |
| /** Enumerate parts of the testing and submission process. */ |
| enum Part |
| { |
| PartStart, |
| PartUpdate, |
| PartConfigure, |
| PartBuild, |
| PartTest, |
| PartCoverage, |
| PartMemCheck, |
| PartSubmit, |
| PartNotes, |
| PartExtraFiles, |
| PartUpload, |
| PartCount // Update names in constructor when adding a part |
| }; |
| |
| /** Representation of one part. */ |
| struct PartInfo |
| { |
| PartInfo(): Enabled(false) {} |
| |
| void SetName(const std::string& name) { this->Name = name; } |
| const std::string& GetName() const { return this->Name; } |
| |
| void Enable() { this->Enabled = true; } |
| operator bool() const { return this->Enabled; } |
| |
| std::vector<std::string> SubmitFiles; |
| private: |
| bool Enabled; |
| std::string Name; |
| }; |
| #ifdef CMAKE_BUILD_WITH_CMAKE |
| enum HTTPMethod { |
| HTTP_GET, |
| HTTP_POST, |
| HTTP_PUT |
| }; |
| |
| /** |
| * Perform an HTTP request. |
| */ |
| static int HTTPRequest(std::string url, HTTPMethod method, |
| std::string& response, |
| std::string fields = "", |
| std::string putFile = "", int timeout = 0); |
| #endif |
| |
| /** Get a testing part id from its string name. Returns PartCount |
| if the string does not name a valid part. */ |
| Part GetPartFromName(const char* name); |
| |
| typedef std::vector<cmsys::String> VectorOfStrings; |
| typedef std::set<std::string> SetOfStrings; |
| |
| ///! Process Command line arguments |
| int Run(std::vector<std::string> &, std::string* output = 0); |
| |
| /** |
| * Initialize and finalize testing |
| */ |
| bool InitializeFromCommand(cmCTestStartCommand* command); |
| void Finalize(); |
| |
| /** |
| * Process the tests. This is the main routine. The execution of the |
| * tests should look like this: |
| * |
| * ctest foo; |
| * foo.Initialize(); |
| * // Set some things on foo |
| * foo.ProcessTests(); |
| * foo.Finalize(); |
| */ |
| int ProcessTests(); |
| |
| /* |
| * A utility function that returns the nightly time |
| */ |
| struct tm* GetNightlyTime(std::string str, |
| bool tomorrowtag); |
| |
| /* |
| * Is the tomorrow tag set? |
| */ |
| bool GetTomorrowTag() { return this->TomorrowTag; } |
| |
| /** |
| * Try to run tests of the project |
| */ |
| int TestDirectory(bool memcheck); |
| |
| ///! what is the configuraiton type, e.g. Debug, Release etc. |
| std::string const& GetConfigType(); |
| double GetTimeOut() { return this->TimeOut; } |
| void SetTimeOut(double t) { this->TimeOut = t; } |
| |
| double GetGlobalTimeout() { return this->GlobalTimeout; } |
| |
| // how many test to run at the same time |
| int GetParallelLevel() { return this->ParallelLevel; } |
| void SetParallelLevel(int); |
| |
| /** |
| * Check if CTest file exists |
| */ |
| bool CTestFileExists(const std::string& filename); |
| bool AddIfExists(Part part, const char* file); |
| |
| /** |
| * Set the cmake test |
| */ |
| bool SetTest(const char*, bool report = true); |
| |
| /** |
| * Set the cmake test mode (experimental, nightly, continuous). |
| */ |
| void SetTestModel(int mode); |
| int GetTestModel() { return this->TestModel; } |
| |
| std::string GetTestModelString(); |
| static int GetTestModelFromString(const char* str); |
| static std::string CleanString(const std::string& str); |
| std::string GetCTestConfiguration(const std::string& name); |
| void SetCTestConfiguration(const char *name, const char* value); |
| void EmptyCTestConfiguration(); |
| |
| /** |
| * constructor and destructor |
| */ |
| cmCTest(); |
| ~cmCTest(); |
| |
| //! Set the notes files to be created. |
| void SetNotesFiles(const char* notes); |
| |
| void PopulateCustomVector(cmMakefile* mf, const std::string& definition, |
| std::vector<std::string>& vec); |
| void PopulateCustomInteger(cmMakefile* mf, const std::string& def, |
| int& val); |
| |
| ///! Get the current time as string |
| std::string CurrentTime(); |
| |
| //! tar/gzip and then base 64 encode a file |
| std::string Base64GzipEncodeFile(std::string file); |
| //! base64 encode a file |
| std::string Base64EncodeFile(std::string file); |
| |
| /** |
| * Return the time remaining that the script is allowed to run in |
| * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has |
| * not been set it returns 1e7 seconds |
| */ |
| double GetRemainingTimeAllowed(); |
| |
| ///! Open file in the output directory and set the stream |
| bool OpenOutputFile(const std::string& path, |
| const std::string& name, |
| cmGeneratedFileStream& stream, |
| bool compress = false); |
| |
| ///! Should we only show what we would do? |
| bool GetShowOnly(); |
| |
| bool ShouldUseHTTP10() { return this->UseHTTP10; } |
| |
| bool ShouldPrintLabels() { return this->PrintLabels; } |
| |
| bool ShouldCompressTestOutput(); |
| bool ShouldCompressMemCheckOutput(); |
| bool CompressString(std::string& str); |
| |
| std::string GetCDashVersion(); |
| |
| std::string GetStopTime() { return this->StopTime; } |
| void SetStopTime(std::string time); |
| |
| //Used for parallel ctest job scheduling |
| std::string GetScheduleType() { return this->ScheduleType; } |
| void SetScheduleType(std::string type) { this->ScheduleType = type; } |
| |
| ///! The max output width |
| int GetMaxTestNameWidth() const; |
| void SetMaxTestNameWidth(int w) { this->MaxTestNameWidth = w;} |
| |
| /** |
| * Run a single executable command and put the stdout and stderr |
| * in output. |
| * |
| * If verbose is false, no user-viewable output from the program |
| * being run will be generated. |
| * |
| * If timeout is specified, the command will be terminated after |
| * timeout expires. Timeout is specified in seconds. |
| * |
| * Argument retVal should be a pointer to the location where the |
| * exit code will be stored. If the retVal is not specified and |
| * the program exits with a code other than 0, then the this |
| * function will return false. |
| * |
| * If the command has spaces in the path the caller MUST call |
| * cmSystemTools::ConvertToRunCommandPath on the command before passing |
| * it into this function or it will not work. The command must be correctly |
| * escaped for this to with spaces. |
| */ |
| bool RunCommand(const char* command, |
| std::string* stdOut, std::string* stdErr, |
| int* retVal = 0, const char* dir = 0, double timeout = 0.0); |
| |
| //! Clean/make safe for xml the given value such that it may be used as |
| // one of the key fields by CDash when computing the buildid. |
| static std::string SafeBuildIdField(const std::string& value); |
| |
| //! Start CTest XML output file |
| void StartXML(std::ostream& ostr, bool append); |
| |
| //! End CTest XML output file |
| void EndXML(std::ostream& ostr); |
| |
| //! Run command specialized for make and configure. Returns process status |
| // and retVal is return value or exception. |
| int RunMakeCommand(const char* command, std::string& output, |
| int* retVal, const char* dir, int timeout, |
| std::ostream& ofs); |
| |
| /* |
| * return the current tag |
| */ |
| std::string GetCurrentTag(); |
| |
| //! Get the path to the build tree |
| std::string GetBinaryDir(); |
| |
| //! Get the short path to the file. This means if the file is in binary or |
| //source directory, it will become /.../relative/path/to/file |
| std::string GetShortPathToFile(const char* fname); |
| |
| enum { |
| EXPERIMENTAL, |
| NIGHTLY, |
| CONTINUOUS |
| }; |
| |
| // provide some more detailed info on the return code for ctest |
| enum { |
| UPDATE_ERRORS = 0x01, |
| CONFIGURE_ERRORS = 0x02, |
| BUILD_ERRORS = 0x04, |
| TEST_ERRORS = 0x08, |
| MEMORY_ERRORS = 0x10, |
| COVERAGE_ERRORS = 0x20, |
| SUBMIT_ERRORS = 0x40 |
| }; |
| |
| ///! Are we producing XML |
| bool GetProduceXML(); |
| void SetProduceXML(bool v); |
| |
| //! Run command specialized for tests. Returns process status and retVal is |
| // return value or exception. If environment is non-null, it is used to set |
| // environment variables prior to running the test. After running the test, |
| // environment variables are restored to their previous values. |
| int RunTest(std::vector<const char*> args, std::string* output, int *retVal, |
| std::ostream* logfile, double testTimeOut, |
| std::vector<std::string>* environment); |
| |
| /** |
| * Execute handler and return its result. If the handler fails, it returns |
| * negative value. |
| */ |
| int ExecuteHandler(const char* handler); |
| |
| /* |
| * Get the handler object |
| */ |
| cmCTestGenericHandler* GetHandler(const char* handler); |
| cmCTestGenericHandler* GetInitializedHandler(const char* handler); |
| |
| /* |
| * Set the CTest variable from CMake variable |
| */ |
| bool SetCTestConfigurationFromCMakeVariable(cmMakefile* mf, |
| const char* dconfig, const std::string& cmake_var); |
| |
| //! Make string safe to be send as an URL |
| static std::string MakeURLSafe(const std::string&); |
| |
| /** Decode a URL to the original string. */ |
| static std::string DecodeURL(const std::string&); |
| |
| //! Should ctect configuration be updated. When using new style ctest |
| // script, this should be true. |
| void SetSuppressUpdatingCTestConfiguration(bool val) |
| { |
| this->SuppressUpdatingCTestConfiguration = val; |
| } |
| |
| //! Add overwrite to ctest configuration. |
| // The format is key=value |
| void AddCTestConfigurationOverwrite(const std::string& encstr); |
| |
| //! Create XML file that contains all the notes specified |
| int GenerateNotesFile(const VectorOfStrings &files); |
| |
| //! Submit extra files to the server |
| bool SubmitExtraFiles(const char* files); |
| bool SubmitExtraFiles(const VectorOfStrings &files); |
| |
| //! Set the output log file name |
| void SetOutputLogFileName(const char* name); |
| |
| //! Set the visual studio or Xcode config type |
| void SetConfigType(const char* ct); |
| |
| //! Various log types |
| enum { |
| DEBUG = 0, |
| OUTPUT, |
| HANDLER_OUTPUT, |
| HANDLER_VERBOSE_OUTPUT, |
| WARNING, |
| ERROR_MESSAGE, |
| OTHER |
| }; |
| |
| //! Add log to the output |
| void Log(int logType, const char* file, int line, const char* msg); |
| |
| //! Get the version of dart server |
| int GetDartVersion() { return this->DartVersion; } |
| int GetDropSiteCDash() { return this->DropSiteCDash; } |
| |
| //! Add file to be submitted |
| void AddSubmitFile(Part part, const char* name); |
| std::vector<std::string> const& GetSubmitFiles(Part part) |
| { return this->Parts[part].SubmitFiles; } |
| void ClearSubmitFiles(Part part) { this->Parts[part].SubmitFiles.clear(); } |
| |
| //! Read the custom configuration files and apply them to the current ctest |
| int ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf); |
| |
| std::vector<std::string> &GetInitialCommandLineArguments() |
| { return this->InitialCommandLineArguments; } |
| |
| //! Set the track to submit to |
| void SetSpecificTrack(const char* track); |
| const char* GetSpecificTrack(); |
| |
| void SetFailover(bool failover) { this->Failover = failover; } |
| bool GetFailover() { return this->Failover; } |
| |
| void SetBatchJobs(bool batch = true) { this->BatchJobs = batch; } |
| bool GetBatchJobs() { return this->BatchJobs; } |
| |
| bool GetVerbose() { return this->Verbose;} |
| bool GetExtraVerbose() { return this->ExtraVerbose;} |
| |
| /** Direct process output to given streams. */ |
| void SetStreams(std::ostream* out, std::ostream* err) |
| { this->StreamOut = out; this->StreamErr = err; } |
| void AddSiteProperties(std::ostream& ); |
| bool GetLabelSummary() { return this->LabelSummary;} |
| |
| std::string GetCostDataFile(); |
| |
| const std::map<std::string, std::string> &GetDefinitions() |
| { |
| return this->Definitions; |
| } |
| |
| private: |
| std::string ConfigType; |
| std::string ScheduleType; |
| std::string StopTime; |
| bool NextDayStopTime; |
| bool Verbose; |
| bool ExtraVerbose; |
| bool ProduceXML; |
| bool LabelSummary; |
| bool UseHTTP10; |
| bool PrintLabels; |
| bool Failover; |
| bool BatchJobs; |
| |
| bool ForceNewCTestProcess; |
| |
| bool RunConfigurationScript; |
| |
| //flag for lazy getter (optimization) |
| bool ComputedCompressTestOutput; |
| bool ComputedCompressMemCheckOutput; |
| |
| int GenerateNotesFile(const char* files); |
| |
| void DetermineNextDayStop(); |
| |
| // these are helper classes |
| typedef std::map<std::string,cmCTestGenericHandler*> t_TestingHandlers; |
| t_TestingHandlers TestingHandlers; |
| |
| bool ShowOnly; |
| |
| //! Map of configuration properties |
| typedef std::map<std::string, std::string> CTestConfigurationMap; |
| |
| std::string CTestConfigFile; |
| // TODO: The ctest configuration should be a hierarchy of |
| // configuration option sources: command-line, script, ini file. |
| // Then the ini file can get re-loaded whenever it changes without |
| // affecting any higher-precedence settings. |
| CTestConfigurationMap CTestConfiguration; |
| CTestConfigurationMap CTestConfigurationOverwrites; |
| PartInfo Parts[PartCount]; |
| typedef std::map<std::string, Part> PartMapType; |
| PartMapType PartMap; |
| |
| std::string CurrentTag; |
| bool TomorrowTag; |
| |
| int TestModel; |
| std::string SpecificTrack; |
| |
| double TimeOut; |
| |
| double GlobalTimeout; |
| |
| int LastStopTimeout; |
| |
| int MaxTestNameWidth; |
| |
| int ParallelLevel; |
| bool ParallelLevelSetInCli; |
| |
| int CompatibilityMode; |
| |
| // information for the --build-and-test options |
| std::string BinaryDir; |
| |
| std::string NotesFiles; |
| |
| |
| bool InteractiveDebugMode; |
| |
| bool ShortDateFormat; |
| |
| bool CompressXMLFiles; |
| bool CompressTestOutput; |
| bool CompressMemCheckOutput; |
| |
| void InitStreams(); |
| std::ostream* StreamOut; |
| std::ostream* StreamErr; |
| |
| void BlockTestErrorDiagnostics(); |
| |
| /** |
| * Initialize a dashboard run in the given build tree. The "command" |
| * argument is non-NULL when running from a command-driven (ctest_start) |
| * dashboard script, and NULL when running from the CTest command |
| * line. Note that a declarative dashboard script does not actually |
| * call this method because it sets CTEST_COMMAND to drive a build |
| * through the ctest command line. |
| */ |
| int Initialize(const char* binary_dir, cmCTestStartCommand* command); |
| |
| //! parse the option after -D and convert it into the appropriate steps |
| bool AddTestsForDashboardType(std::string &targ); |
| |
| //! read as "emit an error message for an unknown -D value" |
| void ErrorMessageUnknownDashDValue(std::string &val); |
| |
| //! add a variable definition from a command line -D value |
| bool AddVariableDefinition(const std::string &arg); |
| |
| //! parse and process most common command line arguments |
| void HandleCommandLineArguments(size_t &i, |
| std::vector<std::string> &args); |
| |
| //! hande the -S -SP and -SR arguments |
| void HandleScriptArguments(size_t &i, |
| std::vector<std::string> &args, |
| bool &SRArgumentSpecified); |
| |
| //! Reread the configuration file |
| bool UpdateCTestConfiguration(); |
| |
| //! Create note from files. |
| int GenerateCTestNotesOutput(std::ostream& os, |
| const VectorOfStrings& files); |
| |
| //! Check if the argument is the one specified |
| bool CheckArgument(const std::string& arg, const char* varg1, |
| const char* varg2 = 0); |
| |
| //! Output errors from a test |
| void OutputTestErrors(std::vector<char> const &process_output); |
| |
| bool SuppressUpdatingCTestConfiguration; |
| |
| bool Debug; |
| bool ShowLineNumbers; |
| bool Quiet; |
| |
| int DartVersion; |
| bool DropSiteCDash; |
| |
| std::vector<std::string> InitialCommandLineArguments; |
| |
| int SubmitIndex; |
| |
| cmGeneratedFileStream* OutputLogFile; |
| int OutputLogFileLastTag; |
| |
| bool OutputTestOutputOnTestFailure; |
| |
| std::map<std::string, std::string> Definitions; |
| }; |
| |
| class cmCTestLogWrite |
| { |
| public: |
| cmCTestLogWrite(const char* data, size_t length) |
| : Data(data), Length(length) {} |
| |
| const char* Data; |
| size_t Length; |
| }; |
| |
| inline std::ostream& operator<< (std::ostream& os, const cmCTestLogWrite& c) |
| { |
| if (!c.Length) |
| { |
| return os; |
| } |
| os.write(c.Data, c.Length); |
| os.flush(); |
| return os; |
| } |
| |
| #endif |