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.
This commit is contained in:
parent
606e6ff9cd
commit
9862f383d0
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
cmTest::cmTest()
|
||||
{
|
||||
this->Makefile = 0;
|
||||
this->OldStyle = true;
|
||||
}
|
||||
|
||||
cmTest::~cmTest()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,8 +95,69 @@ 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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue