From d395b563ede173721c240df2daad23284f453c4a Mon Sep 17 00:00:00 2001 From: Andy Cedilnik Date: Sun, 24 Apr 2005 15:59:51 -0400 Subject: [PATCH] ENH: Improve internal test handling by creating a test class. Command cmEnableTesting now only sets CMAKE_TESTING_ENABLED and cmAddTest only adds a test to the list. The actual test files are written by local generator. This way we can at some point in the future replace DartTestfile with some XML file --- Source/CMakeLists.txt | 2 + Source/cmAddTestCommand.cxx | 72 ++++--------------------- Source/cmAddTestCommand.h | 8 +-- Source/cmEnableTestingCommand.cxx | 88 ------------------------------- Source/cmEnableTestingCommand.h | 8 --- Source/cmGlobalGenerator.cxx | 1 + Source/cmLocalGenerator.cxx | 85 ++++++++++++++++++++++++++++- Source/cmLocalGenerator.h | 8 ++- Source/cmMakefile.cxx | 46 ++++++++++++++++ Source/cmMakefile.h | 13 +++++ Source/cmTest.cxx | 51 ++++++++++++++++++ Source/cmTest.h | 64 ++++++++++++++++++++++ bootstrap | 1 + 13 files changed, 279 insertions(+), 168 deletions(-) create mode 100644 Source/cmTest.cxx create mode 100644 Source/cmTest.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 9edced400..393109c1d 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -71,6 +71,8 @@ SET(SRCS cmSystemTools.h cmTarget.cxx cmTarget.h + cmTest.cxx + cmTest.h cmVariableWatch.cxx cmVariableWatch.h cmVersion.cxx diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx index c5db5ef69..187a3adcc 100644 --- a/Source/cmAddTestCommand.cxx +++ b/Source/cmAddTestCommand.cxx @@ -16,6 +16,9 @@ =========================================================================*/ #include "cmAddTestCommand.h" +#include "cmTest.h" + + // cmExecutableCommand bool cmAddTestCommand::InitialPass(std::vector const& args) { @@ -32,67 +35,12 @@ bool cmAddTestCommand::InitialPass(std::vector const& args) // store the arguments for the final pass // also expand any CMake variables - m_Args = args; + std::vector arguments; + arguments.assign(args.begin() + 2, args.end()); + + cmTest* test = m_Makefile->CreateTest(args[0].c_str()); + test->SetCommand(args[1].c_str()); + test->SetArguments(arguments); + return true; } - -// we append to the file in the final pass because Enable Testing command -// creates the file in the final pass. -void cmAddTestCommand::FinalPass() -{ - // Create a full path filename for output Testfile - std::string fname; - fname = m_Makefile->GetStartOutputDirectory(); - fname += "/"; - if ( m_Makefile->IsSet("CTEST_NEW_FORMAT") ) - { - fname += "CTestTestfile.cmake"; - } - else - { - fname += "DartTestfile.txt"; - } - - - // If the file doesn't exist, then ENABLE_TESTING hasn't been run - if (cmSystemTools::FileExists(fname.c_str())) - { - // Open the output Testfile - std::ofstream fout(fname.c_str(), std::ios::app); - if (!fout) - { - cmSystemTools::Error("Error Writing ", fname.c_str()); - return; - } - - std::vector::iterator it; - - // for each arg in the test - fout << "ADD_TEST("; - it = m_Args.begin(); - fout << (*it).c_str(); - ++it; - for (; it != m_Args.end(); ++it) - { - // Just double-quote all arguments so they are re-parsed - // correctly by the test system. - fout << " \""; - for(std::string::iterator c = it->begin(); c != it->end(); ++c) - { - // Escape quotes within arguments. We should escape - // backslashes too but we cannot because it makes the result - // inconsistent with previous behavior of this command. - if((*c == '"')) - { - fout << '\\'; - } - fout << *c; - } - fout << "\""; - } - fout << ")" << std::endl; - fout.close(); - } - return; -} - diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h index b2bb5633f..1718547b0 100644 --- a/Source/cmAddTestCommand.h +++ b/Source/cmAddTestCommand.h @@ -41,12 +41,6 @@ public: */ virtual bool InitialPass(std::vector const& args); - /** - * This is called at the end after all the information - * specified by the command is accumulated. - */ - virtual void FinalPass(); - /** * The name of the command as specified in CMakeList.txt. */ @@ -79,7 +73,7 @@ public: cmTypeMacro(cmAddTestCommand, cmCommand); private: - std::vector m_Args; + std::string m_Test; }; diff --git a/Source/cmEnableTestingCommand.cxx b/Source/cmEnableTestingCommand.cxx index cc9c7cb7a..ce0b69ac4 100644 --- a/Source/cmEnableTestingCommand.cxx +++ b/Source/cmEnableTestingCommand.cxx @@ -24,91 +24,3 @@ bool cmEnableTestingCommand::InitialPass(std::vector const&) m_Makefile->AddDefinition("CMAKE_TESTING_ENABLED","1"); return true; } - -void cmEnableTestingCommand::FinalPass() -{ - // initialize the DartTestfile files for the tree - this->CreateDartTestfileForMakefile(m_Makefile); -} - -void cmEnableTestingCommand::CreateDartTestfileForMakefile(cmMakefile *mf) -{ - // Create a full path filename for output Testfile - std::string fname; - fname = mf->GetStartOutputDirectory(); - fname += "/"; - if ( m_Makefile->IsSet("CTEST_NEW_FORMAT") ) - { - fname += "CTestTestfile.cmake"; - } - else - { - fname += "DartTestfile.txt"; - } - - cmSystemTools::MakeDirectory(mf->GetStartOutputDirectory()); - - // Open the output Testfile - std::ofstream fout(fname.c_str()); - if (!fout) - { - cmSystemTools::Error("Error Writing ", fname.c_str()); - cmSystemTools::ReportLastSystemError(""); - return; - } - - fout << "# CMake generated Testfile for " << std::endl - << "#\tSource directory: " - << mf->GetStartDirectory() - << std::endl - << "#\tBuild directory: " << mf->GetStartOutputDirectory() - << std::endl - << "# " << std::endl - << "# This file replicates the SUBDIRS() and ADD_TEST() commands from the source" - << std::endl - << "# tree CMakeLists.txt file, skipping any SUBDIRS() or ADD_TEST() commands" - << std::endl - << "# that are excluded by CMake control structures, i.e. IF() commands." - << std::endl - << "#" << std::endl - << "# The next line is critical for Dart to work" << std::endl - << "# Duh :-)" << std::endl << std::endl; - - // get our output directory - std::string outDir = mf->GetStartOutputDirectory(); - outDir += "/"; - - // write out the subdirs for the current directory - std::vector& children = - mf->GetLocalGenerator()->GetChildren(); - - unsigned int i; - if (children.size()) - { - fout << "SUBDIRS("; - std::string binP = children[0]->GetMakefile()->GetStartOutputDirectory(); - cmSystemTools::ReplaceString(binP, outDir.c_str(), ""); - fout << binP.c_str(); - for(i = 1; i < children.size(); ++i) - { - binP = children[i]->GetMakefile()->GetStartOutputDirectory(); - cmSystemTools::ReplaceString(binP, outDir.c_str(), ""); - fout << " " << binP.c_str(); - } - fout << ")" << std::endl << std::endl;; - } - fout.close(); - - // then recurse - if (children.size()) - { - for(i = 0; i < children.size(); ++i) - { - this->CreateDartTestfileForMakefile(children[i]->GetMakefile()); - } - } - - - return; -} - diff --git a/Source/cmEnableTestingCommand.h b/Source/cmEnableTestingCommand.h index 3c5f01bc9..b5292886e 100644 --- a/Source/cmEnableTestingCommand.h +++ b/Source/cmEnableTestingCommand.h @@ -49,14 +49,6 @@ public: */ virtual bool InitialPass(std::vector const&); - /** - * This is called at the end after all the information - * specified by the command is accumulated. Most commands do - * not implement this method. At this point, reading and - * writing to the cache can be done. - */ - virtual void FinalPass(); - /** * The name of the command as specified in CMakeList.txt. */ diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 850ef170e..4e1934da7 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -607,6 +607,7 @@ void cmGlobalGenerator::Generate() { m_LocalGenerators[i]->Generate(); m_LocalGenerators[i]->GenerateInstallRules(); + m_LocalGenerators[i]->GenerateTestFiles(); m_CMakeInstance->UpdateProgress("Generating", (i+1.0f)/m_LocalGenerators.size()); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 259a1f591..8de4ad655 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -21,6 +21,7 @@ #include "cmGeneratedFileStream.h" #include "cmSourceFile.h" #include "cmOrderLinkDirectories.h" +#include "cmTest.h" #include // for isalpha cmLocalGenerator::cmLocalGenerator() @@ -83,15 +84,95 @@ void cmLocalGenerator::SetGlobalGenerator(cmGlobalGenerator *gg) gg->GetCMakeInstance()->GetHomeDirectory()); m_Makefile->SetHomeOutputDirectory( gg->GetCMakeInstance()->GetHomeOutputDirectory()); - } - void cmLocalGenerator::ConfigureFinalPass() { m_Makefile->ConfigureFinalPass(); } +void cmLocalGenerator::GenerateTestFiles() +{ + if ( !m_Makefile->IsOn("CMAKE_TESTING_ENABLED") ) + { + return; + } + std::string file = m_Makefile->GetStartOutputDirectory(); + file += "/"; + if ( m_Makefile->IsSet("CTEST_NEW_FORMAT") ) + { + file += "CTestTestfile.cmake"; + } + else + { + file += "DartTestfile.txt"; + } + cmGeneratedFileStream fout(file.c_str()); + fout.SetCopyIfDifferent(true); + + fout << "# CMake generated Testfile for " << std::endl + << "# Source directory: " << m_Makefile->GetStartDirectory() << std::endl + << "# Build directory: " << m_Makefile->GetStartOutputDirectory() << std::endl + << "# " << std::endl + << "# This file replicates the SUBDIRS() and ADD_TEST() commands from the source" << std::endl + << "# tree CMakeLists.txt file, skipping any SUBDIRS() or ADD_TEST() commands" << std::endl + << "# that are excluded by CMake control structures, i.e. IF() commands." << std::endl + << "#" << std::endl + << "# The next line is critical for Dart to work" << std::endl + << "# Duh :-)" << std::endl << std::endl; + + + const std::vector *tests = m_Makefile->GetTests(); + std::vector::const_iterator it; + for ( it = tests->begin(); it != tests->end(); ++ it ) + { + cmTest* test = *it; + fout << "ADD_TEST("; + fout << test->GetName() << " \"" << test->GetCommand() << "\""; + + std::vector::iterator it; + for (it = test->GetArguments().begin(); + it != test->GetArguments().end(); ++it) + { + // Just double-quote all arguments so they are re-parsed + // correctly by the test system. + fout << " \""; + for(std::string::iterator c = it->begin(); c != it->end(); ++c) + { + // Escape quotes within arguments. We should escape + // backslashes too but we cannot because it makes the result + // inconsistent with previous behavior of this command. + if((*c == '"')) + { + fout << '\\'; + } + fout << *c; + } + fout << "\""; + } + fout << ")" << std::endl; + + } + if ( this->Children.size()) + { + fout << "SUBDIRS("; + size_t i; + std::string outDir = m_Makefile->GetStartOutputDirectory(); + outDir += "/"; + for(i = 0; i < this->Children.size(); ++i) + { + std::string binP = this->Children[i]->GetMakefile()->GetStartOutputDirectory(); + cmSystemTools::ReplaceString(binP, outDir.c_str(), ""); + if ( i > 0 ) + { + fout << " "; + } + fout << binP.c_str(); + } + fout << ")" << std::endl << std::endl;; + } +} + void cmLocalGenerator::GenerateInstallRules() { const cmTargets &tgts = m_Makefile->GetTargets(); diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 4012cdfa6..989cc69d1 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -59,6 +59,12 @@ public: */ virtual void GenerateInstallRules(); + /** + * Generate the test files for tests. + */ + virtual void GenerateTestFiles(); + + ///! Get the makefile for this generator cmMakefile *GetMakefile() { return this->m_Makefile; }; @@ -188,7 +194,7 @@ protected: void CreateCustomTargetsAndCommands(std::set const&); virtual void AddInstallRule(std::ostream& fout, const char* dest, int type, const char* files, bool optional = false, const char* properties = 0); - + cmMakefile *m_Makefile; cmGlobalGenerator *m_GlobalGenerator; // members used for relative path function ConvertToMakefilePath diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 43964d74a..12c7c80a8 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -24,6 +24,7 @@ #include "cmCacheManager.h" #include "cmFunctionBlocker.h" #include "cmListFileCache.h" +#include "cmTest.h" #ifdef CMAKE_BUILD_WITH_CMAKE # include "cmVariableWatch.h" #endif @@ -126,6 +127,11 @@ cmMakefile::~cmMakefile() { delete *i; } + for(std::vector::iterator i = m_Tests.begin(); + i != m_Tests.end(); ++i) + { + delete *i; + } for(unsigned int i=0; i < m_UsedCommands.size(); i++) { delete m_UsedCommands[i]; @@ -2465,3 +2471,43 @@ cmTarget* cmMakefile::FindTarget(const char* name) } return 0; } + +cmTest* cmMakefile::CreateTest(const char* testName) +{ + if ( !testName ) + { + return 0; + } + cmTest* test = this->GetTest(testName); + if ( test ) + { + return test; + } + test = new cmTest; + test->SetName(testName); + m_Tests.push_back(test); + return test; +} + +cmTest* cmMakefile::GetTest(const char* testName) const +{ + if ( !testName ) + { + return 0; + } + std::vector::const_iterator it; + for ( it = m_Tests.begin(); it != m_Tests.end(); ++ it ) + { + if ( strcmp((*it)->GetName(), testName) == 0 ) + { + return *it; + } + } + return 0; +} + +const std::vector *cmMakefile::GetTests() const +{ + return &m_Tests; +} + diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 75dfb7ef4..27840fb93 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -31,6 +31,7 @@ class cmCommand; class cmLocalGenerator; class cmMakeDepend; class cmSourceFile; +class cmTest; class cmVariableWatch; class cmake; @@ -642,6 +643,15 @@ public: */ void AddMacro(const char* name, const char* signature); + ///! Add a new cmTest to the list of tests for this makefile. + cmTest* CreateTest(const char* testName); + + /** Get a cmTest pointer for a given test name, if the name is + * not found, then a null pointer is returned. + */ + cmTest* GetTest(const char* testName) const; + const std::vector *GetTests() const; + /** * Get a list of macros as a ; separated string */ @@ -686,6 +696,9 @@ protected: cmTargets m_Targets; std::vector m_SourceFiles; + // Tests + std::vector m_Tests; + // The include and link-library paths. These may have order // dependency, so they must be vectors (not set). std::vector m_IncludeDirectories; diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx new file mode 100644 index 000000000..bf999fef7 --- /dev/null +++ b/Source/cmTest.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "cmTest.h" +#include "cmSystemTools.h" + + +cmTest::cmTest() +{ +} + +cmTest::~cmTest() +{ +} + +void cmTest::SetName(const char* name) +{ + if ( !name ) + { + name = ""; + } + m_Name = name; +} + +void cmTest::SetCommand(const char* command) +{ + if ( !command ) + { + command = ""; + } + m_Command = command; +} + +void cmTest::SetArguments(const std::vector& args) +{ + m_Args = args; +} + diff --git a/Source/cmTest.h b/Source/cmTest.h new file mode 100644 index 000000000..e5dd1eded --- /dev/null +++ b/Source/cmTest.h @@ -0,0 +1,64 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef cmTest_h +#define cmTest_h + +#include "cmCustomCommand.h" + +/** \class cmTest + * \brief Represent a test + * + * cmTest is representation of a test. + */ +class cmTest +{ +public: + /** + */ + cmTest(); + ~cmTest(); + + ///! Set the test name + void SetName(const char* name); + const char* GetName() { return m_Name.c_str(); } + void SetCommand(const char* command); + const char* GetCommand() { return m_Command.c_str(); } + void SetArguments(const std::vector& args); + std::vector& GetArguments() + { + return m_Args; + } + + /** + * Print the structure to std::cout. + */ + void Print() const; + + ///! Set/Get a property of this source file + void SetProperty(const char *prop, const char *value); + const char *GetProperty(const char *prop) const; + bool GetPropertyAsBool(const char *prop) const; + +private: + std::map m_Properties; + cmStdString m_Name; + cmStdString m_Command; + std::vector m_Args; +}; + +#endif + diff --git a/bootstrap b/bootstrap index cb32a266e..6ac4fdcbf 100755 --- a/bootstrap +++ b/bootstrap @@ -53,6 +53,7 @@ CMAKE_CXX_SOURCES="\ cmBootstrapCommands \ cmCommands \ cmTarget \ + cmTest \ cmCustomCommand \ cmCacheManager \ cmListFileCache \