diff options
author | Brad King <brad.king@kitware.com> | 2009-03-16 14:51:30 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2009-03-16 14:51:30 (GMT) |
commit | 9862f383d09018cd9e14a6054c03b508c0ef3afa (patch) | |
tree | b68b27adc864c2e0cfc5eab806b18b3ee223745c | |
parent | 606e6ff9cd2d1ab6a242a38e0c3f6df7167fdff8 (diff) | |
download | CMake-9862f383d09018cd9e14a6054c03b508c0ef3afa.zip CMake-9862f383d09018cd9e14a6054c03b508c0ef3afa.tar.gz CMake-9862f383d09018cd9e14a6054c03b508c0ef3afa.tar.bz2 |
ENH: Add NAME mode to ADD_TEST command
This creates command mode add_test(NAME ...). This signature is
extensible with more keyword arguments later. The main purpose is to
enable automatic replacement of target names with built target file
locations. A side effect of this feature is support for tests that only
run under specific configurations.
-rw-r--r-- | Source/cmAddTestCommand.cxx | 111 | ||||
-rw-r--r-- | Source/cmAddTestCommand.h | 14 | ||||
-rw-r--r-- | Source/cmTest.cxx | 1 | ||||
-rw-r--r-- | Source/cmTest.h | 6 | ||||
-rw-r--r-- | Source/cmTestGenerator.cxx | 68 | ||||
-rw-r--r-- | Source/cmTestGenerator.h | 4 | ||||
-rw-r--r-- | Tests/Testing/CMakeLists.txt | 8 | ||||
-rw-r--r-- | Tests/Testing/perconfig.c | 4 |
8 files changed, 210 insertions, 6 deletions
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx index e894bd8..3e735a1 100644 --- a/Source/cmAddTestCommand.cxx +++ b/Source/cmAddTestCommand.cxx @@ -25,6 +25,11 @@ bool cmAddTestCommand ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) { + if(!args.empty() && args[0] == "NAME") + { + return this->HandleNameMode(args); + } + // First argument is the name of the test Second argument is the name of // the executable to run (a target or external program) Remaining arguments // are the arguments to pass to the executable @@ -45,12 +50,116 @@ bool cmAddTestCommand // Create the test but add a generator only the first time it is // seen. This preserves behavior from before test generators. cmTest* test = this->Makefile->GetTest(args[0].c_str()); - if(!test) + if(test) + { + // If the test was already added by a new-style signature do not + // allow it to be duplicated. + if(!test->GetOldStyle()) + { + cmOStringStream e; + e << " given test name \"" << args[0] + << "\" which already exists in this directory."; + this->SetError(e.str().c_str()); + return false; + } + } + else { test = this->Makefile->CreateTest(args[0].c_str()); + test->SetOldStyle(true); this->Makefile->AddTestGenerator(new cmTestGenerator(test)); } test->SetCommand(command); return true; } + +//---------------------------------------------------------------------------- +bool cmAddTestCommand::HandleNameMode(std::vector<std::string> const& args) +{ + std::string name; + std::vector<std::string> configurations; + std::vector<std::string> command; + + // Read the arguments. + enum Doing { + DoingName, + DoingCommand, + DoingConfigs, + DoingNone + }; + Doing doing = DoingName; + for(unsigned int i=1; i < args.size(); ++i) + { + if(args[i] == "COMMAND") + { + if(!command.empty()) + { + this->SetError(" may be given at most one COMMAND."); + return false; + } + doing = DoingCommand; + } + else if(args[i] == "CONFIGURATIONS") + { + if(!configurations.empty()) + { + this->SetError(" may be given at most one set of CONFIGURATIONS."); + return false; + } + doing = DoingConfigs; + } + else if(doing == DoingName) + { + name = args[i]; + doing = DoingNone; + } + else if(doing == DoingCommand) + { + command.push_back(args[i]); + } + else if(doing == DoingConfigs) + { + configurations.push_back(args[i]); + } + else + { + cmOStringStream e; + e << " given unknown argument:\n " << args[i] << "\n"; + this->SetError(e.str().c_str()); + return false; + } + } + + // Require a test name. + if(name.empty()) + { + this->SetError(" must be given non-empty NAME."); + return false; + } + + // Require a command. + if(command.empty()) + { + this->SetError(" must be given non-empty COMMAND."); + return false; + } + + // Require a unique test name within the directory. + if(this->Makefile->GetTest(name.c_str())) + { + cmOStringStream e; + e << " given test NAME \"" << name + << "\" which already exists in this directory."; + this->SetError(e.str().c_str()); + return false; + } + + // Add the test. + cmTest* test = this->Makefile->CreateTest(name.c_str()); + test->SetOldStyle(false); + test->SetCommand(command); + this->Makefile->AddTestGenerator(new cmTestGenerator(test, configurations)); + + return true; +} diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h index 84e75d9..a971fd7 100644 --- a/Source/cmAddTestCommand.h +++ b/Source/cmAddTestCommand.h @@ -70,11 +70,21 @@ public: "built by this project or an arbitrary executable on the " "system (like tclsh). The test will be run with the current working " "directory set to the CMakeList.txt files corresponding directory " - "in the binary tree."; + "in the binary tree." + "\n" + " add_test(NAME <name> [CONFIGURATIONS [Debug|Release|...]]\n" + " COMMAND <command> [arg1 [arg2 ...]])\n" + "If COMMAND specifies an executable target (created by " + "add_executable) it will automatically be replaced by the location " + "of the executable created at build time. " + "If a CONFIGURATIONS option is given then the test will be executed " + "only when testing under one of the named configurations." + ; } cmTypeMacro(cmAddTestCommand, cmCommand); - +private: + bool HandleNameMode(std::vector<std::string> const& args); }; diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index ac61984..a4e8bf7 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -23,6 +23,7 @@ cmTest::cmTest() { this->Makefile = 0; + this->OldStyle = true; } cmTest::~cmTest() diff --git a/Source/cmTest.h b/Source/cmTest.h index 521981d..0d601ec 100644 --- a/Source/cmTest.h +++ b/Source/cmTest.h @@ -63,11 +63,17 @@ public: void SetMakefile(cmMakefile *mf); cmMakefile *GetMakefile() { return this->Makefile;}; + /** Get/Set whether this is an old-style test. */ + bool GetOldStyle() const { return this->OldStyle; } + void SetOldStyle(bool b) { this->OldStyle = b; } + private: cmPropertyMap Properties; cmStdString Name; std::vector<std::string> Command; + bool OldStyle; + // The cmMakefile instance that owns this target. This should // always be set. cmMakefile* Makefile; diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 8581c96..7f4c2d1 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -16,7 +16,10 @@ =========================================================================*/ #include "cmTestGenerator.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" #include "cmSystemTools.h" +#include "cmTarget.h" #include "cmTest.h" //---------------------------------------------------------------------------- @@ -26,7 +29,7 @@ cmTestGenerator cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations), Test(test) { - this->ActionsPerConfig = false; + this->ActionsPerConfig = !test->GetOldStyle(); this->TestGenerated = false; } @@ -92,9 +95,70 @@ void cmTestGenerator::GenerateScriptConfigs(std::ostream& os, } //---------------------------------------------------------------------------- -void cmTestGenerator::GenerateScriptActions(std::ostream& fout, +void cmTestGenerator::GenerateScriptActions(std::ostream& os, Indent const& indent) { + if(this->ActionsPerConfig) + { + // This is the per-config generation in a single-configuration + // build generator case. The superclass will call our per-config + // method. + this->cmScriptGenerator::GenerateScriptActions(os, indent); + } + else + { + // This is an old-style test, so there is only one config. + //assert(this->Test->GetOldStyle()); + this->GenerateOldStyle(os, indent); + } +} + +//---------------------------------------------------------------------------- +void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, + const char* config, + Indent const& indent) +{ + this->TestGenerated = true; + + // Start the test command. + os << indent << "ADD_TEST(" << this->Test->GetName() << " "; + + // Get the test command line to be executed. + std::vector<std::string> const& command = this->Test->GetCommand(); + + // Check whether the command executable is a target whose name is to + // be translated. + std::string exe = command[0]; + cmMakefile* mf = this->Test->GetMakefile(); + cmTarget* target = mf->FindTargetToUse(exe.c_str()); + if(target && target->GetType() == cmTarget::EXECUTABLE) + { + // Use the target file on disk. + exe = target->GetFullPath(config); + } + else + { + // Use the command name given. + cmSystemTools::ConvertToUnixSlashes(exe); + } + + // Generate the command line with full escapes. + cmLocalGenerator* lg = mf->GetLocalGenerator(); + os << lg->EscapeForCMake(exe.c_str()); + for(std::vector<std::string>::const_iterator ci = command.begin()+1; + ci != command.end(); ++ci) + { + os << " " << lg->EscapeForCMake(ci->c_str()); + } + + // Finish the test command. + os << ")\n"; +} + +//---------------------------------------------------------------------------- +void cmTestGenerator::GenerateOldStyle(std::ostream& fout, + Indent const& indent) +{ this->TestGenerated = true; // Get the test command line to be executed. diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h index 021be39..6f09b41 100644 --- a/Source/cmTestGenerator.h +++ b/Source/cmTestGenerator.h @@ -36,6 +36,10 @@ public: protected: virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent); virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); + virtual void GenerateScriptForConfig(std::ostream& os, + const char* config, + Indent const& indent); + void GenerateOldStyle(std::ostream& os, Indent const& indent); cmTest* Test; bool TestGenerated; diff --git a/Tests/Testing/CMakeLists.txt b/Tests/Testing/CMakeLists.txt index 5a15f11..462f20f 100644 --- a/Tests/Testing/CMakeLists.txt +++ b/Tests/Testing/CMakeLists.txt @@ -1,7 +1,7 @@ # # Testing # -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 2.7) PROJECT (Testing) # @@ -52,3 +52,9 @@ ADD_TEST(testing.1 ${Testing_BINARY_DIR}/bin/testing) # skip level test # ADD_SUBDIRECTORY(Sub/Sub2) + +# Per-config target name test. +ADD_EXECUTABLE(perconfig perconfig.c) +SET_PROPERTY(TARGET perconfig PROPERTY RELEASE_POSTFIX -opt) +SET_PROPERTY(TARGET perconfig PROPERTY DEBUG_POSTFIX -dbg) +ADD_TEST(NAME testing.perconfig COMMAND perconfig) diff --git a/Tests/Testing/perconfig.c b/Tests/Testing/perconfig.c new file mode 100644 index 0000000..f8b643a --- /dev/null +++ b/Tests/Testing/perconfig.c @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} |