summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2009-03-16 14:51:30 (GMT)
committerBrad King <brad.king@kitware.com>2009-03-16 14:51:30 (GMT)
commit9862f383d09018cd9e14a6054c03b508c0ef3afa (patch)
treeb68b27adc864c2e0cfc5eab806b18b3ee223745c
parent606e6ff9cd2d1ab6a242a38e0c3f6df7167fdff8 (diff)
downloadCMake-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.cxx111
-rw-r--r--Source/cmAddTestCommand.h14
-rw-r--r--Source/cmTest.cxx1
-rw-r--r--Source/cmTest.h6
-rw-r--r--Source/cmTestGenerator.cxx68
-rw-r--r--Source/cmTestGenerator.h4
-rw-r--r--Tests/Testing/CMakeLists.txt8
-rw-r--r--Tests/Testing/perconfig.c4
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;
+}