Commit bb4a1410 authored by Kyle Edwards's avatar Kyle Edwards Committed by Brad King

CTest: Add lexer for PROCESSES property

parent a1f78a48
......@@ -922,6 +922,7 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmCTestMemCheckCommand.cxx
CTest/cmCTestMemCheckHandler.cxx
CTest/cmCTestMultiProcessHandler.cxx
CTest/cmCTestProcessesLexerHelper.cxx
CTest/cmCTestReadCustomFilesCommand.cxx
CTest/cmCTestRunScriptCommand.cxx
CTest/cmCTestRunTest.cxx
......@@ -953,6 +954,10 @@ set(CTEST_SRCS cmCTest.cxx
CTest/cmCTestHG.h
CTest/cmCTestP4.cxx
CTest/cmCTestP4.h
LexerParser/cmCTestProcessesLexer.cxx
LexerParser/cmCTestProcessesLexer.h
LexerParser/cmCTestProcessesLexer.in.l
)
# Build CTestLib
......
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestProcessesLexerHelper.h"
#include "cmCTestProcessesLexer.h"
#include "cmCTestTestHandler.h"
cmCTestProcessesLexerHelper::cmCTestProcessesLexerHelper(
std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
output)
: Output(output)
{
}
bool cmCTestProcessesLexerHelper::ParseString(const std::string& value)
{
yyscan_t lexer;
cmCTestProcesses_yylex_init_extra(this, &lexer);
auto state = cmCTestProcesses_yy_scan_string(value.c_str(), lexer);
int retval = cmCTestProcesses_yylex(lexer);
cmCTestProcesses_yy_delete_buffer(state, lexer);
cmCTestProcesses_yylex_destroy(lexer);
return retval == 0;
}
void cmCTestProcessesLexerHelper::SetProcessCount(unsigned int count)
{
this->ProcessCount = count;
}
void cmCTestProcessesLexerHelper::SetResourceType(const std::string& type)
{
this->ResourceType = type;
}
void cmCTestProcessesLexerHelper::SetNeededSlots(int count)
{
this->NeededSlots = count;
}
void cmCTestProcessesLexerHelper::WriteRequirement()
{
this->Process.push_back({ this->ResourceType, this->NeededSlots, 1 });
}
void cmCTestProcessesLexerHelper::WriteProcess()
{
for (unsigned int i = 0; i < this->ProcessCount; ++i) {
this->Output.push_back(this->Process);
}
this->Process.clear();
this->ProcessCount = 1;
}
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmCTestProcessesLexerHelper_h
#define cmCTestProcessesLexerHelper_h
#include <string>
#include <vector>
#include "cmCTestTestHandler.h"
class cmCTestProcessesLexerHelper
{
public:
struct ParserType
{
};
cmCTestProcessesLexerHelper(
std::vector<
std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
output);
~cmCTestProcessesLexerHelper() = default;
bool ParseString(const std::string& value);
void SetProcessCount(unsigned int count);
void SetResourceType(const std::string& type);
void SetNeededSlots(int count);
void WriteRequirement();
void WriteProcess();
private:
std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>&
Output;
unsigned int ProcessCount = 1;
std::string ResourceType;
int NeededSlots;
std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement> Process;
};
#define YY_EXTRA_TYPE cmCTestProcessesLexerHelper*
#endif
......@@ -29,6 +29,7 @@
#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestMultiProcessHandler.h"
#include "cmCTestProcessesLexerHelper.h"
#include "cmDuration.h"
#include "cmExecutionStatus.h"
#include "cmGeneratedFileStream.h"
......@@ -1610,6 +1611,14 @@ std::string cmCTestTestHandler::FindExecutable(
return fullPath;
}
bool cmCTestTestHandler::ParseProcessesProperty(
const std::string& val,
std::vector<std::vector<cmCTestTestResourceRequirement>>& processes)
{
cmCTestProcessesLexerHelper lexer(processes);
return lexer.ParseString(val);
}
void cmCTestTestHandler::GetListOfTests()
{
if (!this->IncludeLabelRegExp.empty()) {
......@@ -2179,6 +2188,11 @@ bool cmCTestTestHandler::SetTestsProperties(
if (key == "PROCESSOR_AFFINITY") {
rt.WantAffinity = cmIsOn(val);
}
if (key == "PROCESSES") {
if (!ParseProcessesProperty(val, rt.Processes)) {
return false;
}
}
if (key == "SKIP_RETURN_CODE") {
rt.SkipReturnCode = atoi(val.c_str());
if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) {
......@@ -2356,3 +2370,17 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args)
this->TestList.push_back(test);
return true;
}
bool cmCTestTestHandler::cmCTestTestResourceRequirement::operator==(
const cmCTestTestResourceRequirement& other) const
{
return this->ResourceType == other.ResourceType &&
this->SlotsNeeded == other.SlotsNeeded &&
this->UnitsNeeded == other.UnitsNeeded;
}
bool cmCTestTestHandler::cmCTestTestResourceRequirement::operator!=(
const cmCTestTestResourceRequirement& other) const
{
return !(*this == other);
}
......@@ -102,6 +102,16 @@ public:
void Initialize() override;
struct cmCTestTestResourceRequirement
{
std::string ResourceType;
int SlotsNeeded;
int UnitsNeeded;
bool operator==(const cmCTestTestResourceRequirement& other) const;
bool operator!=(const cmCTestTestResourceRequirement& other) const;
};
// NOTE: This struct is Saved/Restored
// in cmCTestTestHandler, if you add to this class
// then you must add the new members to that code or
......@@ -147,6 +157,7 @@ public:
std::set<std::string> FixturesCleanup;
std::set<std::string> FixturesRequired;
std::set<std::string> RequireSuccessDepends;
std::vector<std::vector<cmCTestTestResourceRequirement>> Processes;
// Private test generator properties used to track backtraces
cmListFileBacktrace Backtrace;
};
......@@ -190,6 +201,10 @@ public:
std::vector<std::string>& extraPaths,
std::vector<std::string>& failed);
static bool ParseProcessesProperty(
const std::string& val,
std::vector<std::vector<cmCTestTestResourceRequirement>>& processes);
using ListOfTests = std::vector<cmCTestTestProperties>;
protected:
......
......@@ -2,6 +2,8 @@
/cmCommandArgumentLexer.h generated
/cmCommandArgumentParser.cxx generated
/cmCommandArgumentParserTokens.h generated
/cmCTestProcessesLexer.cxx generated
/cmCTestProcessesLexer.h generated
/cmDependsJavaLexer.cxx generated
/cmDependsJavaLexer.h generated
/cmDependsJavaParser.cxx generated
......
This diff is collapsed.
This diff is collapsed.
%{
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
/*
This file must be translated to C++ and modified to build everywhere.
Run flex >= 2.6 like this:
flex --nounistd -DFLEXINT_H --noline --header-file=cmCTestProcessesLexer.h -ocmCTestProcessesLexer.cxx cmCTestProcessesLexer.in.l
Modify cmCTestProcessesLexer.cxx:
- remove trailing whitespace: sed -i 's/\s*$//' cmCTestProcessesLexer.h cmCTestProcessesLexer.cxx
- remove blank lines at end of file: sed -i '${/^$/d;}' cmCTestProcessesLexer.h cmCTestProcessesLexer.cxx
- #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmCTestProcessesLexer.cxx
*/
/* IWYU pragma: no_forward_declare yyguts_t */
#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
#include "cmCTestProcessesLexerHelper.h"
#include <string>
#include <cstddef>
/*--------------------------------------------------------------------------*/
%}
%option prefix="cmCTestProcesses_yy"
%option reentrant
%option noyywrap
%option nodefault
%pointer
%s PROCESSES_START
%s PROCESSES_END
%s RESOURCE_START
%s RESOURCE_COUNT
%s RESOURCE_END
NUMBER [0-9]+
IDENTIFIER [a-z_][a-z0-9_]*
%%
<INITIAL,PROCESSES_START,RESOURCE_START>{IDENTIFIER}: {
BEGIN(RESOURCE_COUNT);
yyextra->SetResourceType(std::string(yytext, yyleng - 1));
}
<INITIAL,PROCESSES_START>{NUMBER} {
BEGIN(PROCESSES_END);
std::size_t len = yyleng;
yyextra->SetProcessCount(std::stoll(yytext, &len, 10));
}
<RESOURCE_COUNT>{NUMBER} {
BEGIN(RESOURCE_END);
std::size_t len = yyleng;
yyextra->SetNeededSlots(std::stoll(yytext, &len, 10));
yyextra->WriteRequirement();
}
<PROCESSES_END,RESOURCE_END>,+ {
BEGIN(RESOURCE_START);
}
<INITIAL,PROCESSES_START,RESOURCE_START>;+ {
BEGIN(PROCESSES_START);
}
<PROCESSES_END,RESOURCE_END>;+ {
BEGIN(PROCESSES_START);
yyextra->WriteProcess();
}
<RESOURCE_START,PROCESSES_END,RESOURCE_END><<EOF>> {
yyextra->WriteProcess();
return 0;
}
<INITIAL,PROCESSES_START><<EOF>> {
return 0;
}
<<EOF>> {
return 1;
}
.|\n {
return 1;
}
%%
/*--------------------------------------------------------------------------*/
#endif /* __clang_analyzer__ */
......@@ -2,10 +2,12 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMake_BINARY_DIR}/Source
${CMake_SOURCE_DIR}/Source
${CMake_SOURCE_DIR}/Source/CTest
)
set(CMakeLib_TESTS
testArgumentParser.cxx
testCTestProcesses.cxx
testGeneratedFileStream.cxx
testRST.cxx
testRange.cxx
......@@ -41,7 +43,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testXMLParser.h.in
create_test_sourcelist(CMakeLib_TEST_SRCS CMakeLibTests.cxx ${CMakeLib_TESTS})
add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS})
target_link_libraries(CMakeLibTests CMakeLib)
target_link_libraries(CMakeLibTests CMakeLib CTestLib)
set_property(TARGET CMakeLibTests PROPERTY C_CLANG_TIDY "")
set_property(TARGET CMakeLibTests PROPERTY CXX_CLANG_TIDY "")
......
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include <iostream>
#include <string>
#include <vector>
#include "cmCTestTestHandler.h"
struct ExpectedParseResult
{
std::string String;
bool ExpectedReturnValue;
std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>
ExpectedValue;
};
static const std::vector<ExpectedParseResult> expectedResults{
/* clang-format off */
{ "threads:2", true, {
{ { "threads", 2, 1 } },
} },
{ "3,threads:2", true, {
{ { "threads", 2, 1 } },
{ { "threads", 2, 1 } },
{ { "threads", 2, 1 } },
} },
{ "3,threads:2,gpus:4", true, {
{ { "threads", 2, 1 }, { "gpus", 4, 1 } },
{ { "threads", 2, 1 }, { "gpus", 4, 1 } },
{ { "threads", 2, 1 }, { "gpus", 4, 1 } },
} },
{ "2,threads:2;gpus:4", true, {
{ { "threads", 2, 1 } },
{ { "threads", 2, 1 } },
{ { "gpus", 4, 1 } },
} },
{ "threads:2;2,gpus:4", true, {
{ { "threads", 2, 1 } },
{ { "gpus", 4, 1 } },
{ { "gpus", 4, 1 } },
} },
{ "threads:2;gpus:4", true, {
{ { "threads", 2, 1 } },
{ { "gpus", 4, 1 } },
} },
{ "1,threads:2;0,gpus:4", true, {
{ { "threads", 2, 1 } },
} },
{ "1,_:1", true, {
{ { "_", 1, 1 } },
} },
{ "1,a:1", true, {
{ { "a", 1, 1 } },
} },
{ "2", true, {
{},
{},
} },
{ "1;2,threads:1", true, {
{},
{ { "threads", 1, 1 } },
{ { "threads", 1, 1 } },
} },
{ "1,,threads:1", true, {
{ { "threads", 1, 1 } },
} },
{ ";1,threads:1", true, {
{ { "threads", 1, 1 } },
} },
{ "1,threads:1;", true, {
{ { "threads", 1, 1 } },
} },
{ "1,threads:1,", true, {
{ { "threads", 1, 1 } },
} },
{ "threads:1;;threads:2", true, {
{ { "threads", 1, 1 } },
{ { "threads", 2, 1 } },
} },
{ "1,", true, {
{},
} },
{ ";", true, {} },
{ "", true, {} },
{ ",", false, {} },
{ "1,0:1", false, {} },
{ "1,A:1", false, {} },
{ "1,a-b:1", false, {} },
{ "invalid", false, {} },
{ ",1,invalid:1", false, {} },
{ "1,1", false, {} },
{ "-1,invalid:1", false, {} },
{ "1,invalid:*", false, {} },
{ "1,invalid:-1", false, {} },
{ "1,invalid:-", false, {} },
{ "1,invalid:ab2", false, {} },
{ "1,invalid :2", false, {} },
{ "1, invalid:2", false, {} },
{ "1,invalid:ab", false, {} },
/* clang-format on */
};
bool TestExpectedParseResult(const ExpectedParseResult& expected)
{
std::vector<std::vector<cmCTestTestHandler::cmCTestTestResourceRequirement>>
result;
bool retval;
if ((retval = cmCTestTestHandler::ParseProcessesProperty(
expected.String, result)) != expected.ExpectedReturnValue) {
std::cout << "ParseProcessesProperty(\"" << expected.String
<< "\") returned " << retval << ", should be "
<< expected.ExpectedReturnValue << std::endl;
return false;
}
if (result != expected.ExpectedValue) {
std::cout << "ParseProcessesProperty(\"" << expected.String
<< "\") did not yield expected set of processes" << std::endl;
return false;
}
return true;
}
int testCTestProcesses(int /*unused*/, char* /*unused*/ [])
{
int retval = 0;
for (auto const& expected : expectedResults) {
if (!TestExpectedParseResult(expected)) {
retval = 1;
}
}
return retval;
}
......@@ -11,6 +11,7 @@ pushd "${BASH_SOURCE%/*}/../../Source/LexerParser" > /dev/null
for lexer in \
CommandArgument \
CTestProcesses \
DependsJava \
Expr \
Fortran
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment