mirror of
https://github.com/pantor/inja.git
synced 2026-02-17 09:03:58 +00:00
366 lines
10 KiB
C++
Executable File
366 lines
10 KiB
C++
Executable File
#ifndef __HAYAI_TESTDESCRIPTOR
|
|
#define __HAYAI_TESTDESCRIPTOR
|
|
#include <cstring>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "hayai_test.hpp"
|
|
#include "hayai_test_factory.hpp"
|
|
|
|
|
|
namespace hayai
|
|
{
|
|
/// Parameter declaration.
|
|
|
|
/// Describes parameter type and name.
|
|
class TestParameterDescriptor
|
|
{
|
|
public:
|
|
TestParameterDescriptor(std::string declaration,
|
|
std::string value)
|
|
: Declaration(declaration),
|
|
Value(value)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
/// Declaration.
|
|
std::string Declaration;
|
|
|
|
|
|
/// Value.
|
|
std::string Value;
|
|
};
|
|
|
|
|
|
/// Test parameters descriptor.
|
|
class TestParametersDescriptor
|
|
{
|
|
private:
|
|
/// Quoting state.
|
|
enum QuotingState
|
|
{
|
|
/// Unquoted.
|
|
Unquoted,
|
|
|
|
|
|
/// Single quoted.
|
|
SingleQuoted,
|
|
|
|
|
|
/// Double quoted.
|
|
DoubleQuoted
|
|
};
|
|
|
|
|
|
/// Trimmed string.
|
|
|
|
/// @param start Start character.
|
|
/// @param end Character one position beyond end.
|
|
inline static std::string TrimmedString(const char* start,
|
|
const char* end)
|
|
{
|
|
while (start < end)
|
|
{
|
|
if ((*start == ' ') ||
|
|
(*start == '\r') ||
|
|
(*start == '\n') ||
|
|
(*start == '\t'))
|
|
++start;
|
|
else
|
|
break;
|
|
}
|
|
|
|
while (end > start)
|
|
{
|
|
const char c = *(end - 1);
|
|
|
|
if ((c != ' ') &&
|
|
(c != '\r') &&
|
|
(c != '\n') &&
|
|
(c != '\t'))
|
|
break;
|
|
|
|
--end;
|
|
}
|
|
|
|
return std::string(start, std::string::size_type(end - start));
|
|
}
|
|
|
|
|
|
/// Parse comma separated parentherized value.
|
|
|
|
/// @param separated Separated values as "(..[, ..])".
|
|
/// @returns the individual values with white space trimmed.
|
|
static std::vector<std::string>
|
|
ParseCommaSeparated(const char* separated)
|
|
{
|
|
std::vector<std::string> result;
|
|
|
|
if (*separated)
|
|
++separated;
|
|
|
|
while ((*separated) && (*separated != ')'))
|
|
{
|
|
std::size_t escapeCounter = 0;
|
|
const char* start = separated;
|
|
QuotingState state = Unquoted;
|
|
bool escaped = false;
|
|
|
|
while (*separated)
|
|
{
|
|
const char c = *separated++;
|
|
|
|
if (state == Unquoted)
|
|
{
|
|
if ((c == '"') || (c == '\''))
|
|
{
|
|
state = (c == '"' ? DoubleQuoted : SingleQuoted);
|
|
escaped = false;
|
|
}
|
|
else if ((c == '<') ||
|
|
(c == '(') ||
|
|
(c == '[') ||
|
|
(c == '{'))
|
|
++escapeCounter;
|
|
else if ((escapeCounter) &&
|
|
((c == '>') ||
|
|
(c == ')') ||
|
|
(c == ']') ||
|
|
(c == '}')))
|
|
--escapeCounter;
|
|
else if ((!escapeCounter) &&
|
|
((c == ',') || (c == ')')))
|
|
{
|
|
result.push_back(TrimmedString(start,
|
|
separated - 1));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (escaped)
|
|
escaped = false;
|
|
else if (c == '\\')
|
|
escaped = true;
|
|
else if (c == (state == DoubleQuoted ? '"' : '\''))
|
|
state = Unquoted;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/// Parse parameter declaration.
|
|
|
|
/// @param raw Raw declaration.
|
|
TestParameterDescriptor ParseDescriptor(const std::string& raw)
|
|
{
|
|
const char* position = raw.c_str();
|
|
|
|
// Split the declaration into its declaration and its default
|
|
// type.
|
|
const char* equalPosition = NULL;
|
|
std::size_t escapeCounter = 0;
|
|
QuotingState state = Unquoted;
|
|
bool escaped = false;
|
|
|
|
while (*position)
|
|
{
|
|
const char c = *position++;
|
|
|
|
if (state == Unquoted)
|
|
{
|
|
if ((c == '"') || (c == '\''))
|
|
{
|
|
state = (c == '"' ? DoubleQuoted : SingleQuoted);
|
|
escaped = false;
|
|
}
|
|
else if ((c == '<') ||
|
|
(c == '(') ||
|
|
(c == '[') ||
|
|
(c == '{'))
|
|
++escapeCounter;
|
|
else if ((escapeCounter) &&
|
|
((c == '>') ||
|
|
(c == ')') ||
|
|
(c == ']') ||
|
|
(c == '}')))
|
|
--escapeCounter;
|
|
else if ((!escapeCounter) &&
|
|
(c == '='))
|
|
{
|
|
equalPosition = position;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (escaped)
|
|
escaped = false;
|
|
else if (c == '\\')
|
|
escaped = true;
|
|
else if (c == (state == DoubleQuoted ? '"' : '\''))
|
|
state = Unquoted;
|
|
}
|
|
}
|
|
|
|
// Construct the parameter descriptor.
|
|
if (equalPosition)
|
|
{
|
|
const char* start = raw.c_str();
|
|
const char* end = start + raw.length();
|
|
|
|
return TestParameterDescriptor(
|
|
std::string(TrimmedString(start,
|
|
equalPosition - 1)),
|
|
std::string(TrimmedString(equalPosition,
|
|
end))
|
|
);
|
|
}
|
|
else
|
|
return TestParameterDescriptor(raw, std::string());
|
|
}
|
|
public:
|
|
TestParametersDescriptor()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
TestParametersDescriptor(const char* rawDeclarations,
|
|
const char* rawValues)
|
|
{
|
|
// Parse the declarations.
|
|
std::vector<std::string> declarations =
|
|
ParseCommaSeparated(rawDeclarations);
|
|
|
|
for (std::vector<std::string>::const_iterator it =
|
|
declarations.begin();
|
|
it != declarations.end();
|
|
++it)
|
|
_parameters.push_back(ParseDescriptor(*it));
|
|
|
|
// Parse the values.
|
|
std::vector<std::string> values = ParseCommaSeparated(rawValues);
|
|
|
|
std::size_t
|
|
straightValues = (_parameters.size() > values.size() ?
|
|
values.size() :
|
|
_parameters.size()),
|
|
variadicValues = 0;
|
|
|
|
if (values.size() > _parameters.size())
|
|
{
|
|
if (straightValues > 0)
|
|
--straightValues;
|
|
variadicValues = values.size() - _parameters.size() + 1;
|
|
}
|
|
|
|
for (std::size_t i = 0; i < straightValues; ++i)
|
|
_parameters[i].Value = values[i];
|
|
|
|
if (variadicValues)
|
|
{
|
|
std::stringstream variadic;
|
|
|
|
for (std::size_t i = 0; i < variadicValues; ++i)
|
|
{
|
|
if (i)
|
|
variadic << ", ";
|
|
variadic << values[straightValues + i];
|
|
}
|
|
|
|
_parameters[_parameters.size() - 1].Value = variadic.str();
|
|
}
|
|
}
|
|
|
|
|
|
inline const std::vector<TestParameterDescriptor>& Parameters() const
|
|
{
|
|
return _parameters;
|
|
}
|
|
private:
|
|
std::vector<TestParameterDescriptor> _parameters;
|
|
};
|
|
|
|
|
|
/// Test descriptor.
|
|
class TestDescriptor
|
|
{
|
|
public:
|
|
/// Initialize a new test descriptor.
|
|
|
|
/// @param fixtureName Name of the fixture.
|
|
/// @param testName Name of the test.
|
|
/// @param runs Number of runs for the test.
|
|
/// @param iterations Number of iterations per run.
|
|
/// @param testFactory Test factory implementation for the test.
|
|
/// @param parameters Parametrized test parameters.
|
|
TestDescriptor(const char* fixtureName,
|
|
const char* testName,
|
|
std::size_t runs,
|
|
std::size_t iterations,
|
|
TestFactory* testFactory,
|
|
TestParametersDescriptor parameters,
|
|
bool isDisabled = false)
|
|
: FixtureName(fixtureName),
|
|
TestName(testName),
|
|
CanonicalName(std::string(fixtureName) + "." + testName),
|
|
Runs(runs),
|
|
Iterations(iterations),
|
|
Factory(testFactory),
|
|
Parameters(parameters),
|
|
IsDisabled(isDisabled)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
/// Dispose of a test descriptor.
|
|
~TestDescriptor()
|
|
{
|
|
delete this->Factory;
|
|
}
|
|
|
|
|
|
/// Fixture name.
|
|
std::string FixtureName;
|
|
|
|
|
|
/// Test name.
|
|
std::string TestName;
|
|
|
|
|
|
/// Canonical name.
|
|
|
|
/// As: <FixtureName>.<TestName>.
|
|
std::string CanonicalName;
|
|
|
|
|
|
/// Test runs.
|
|
std::size_t Runs;
|
|
|
|
|
|
/// Iterations per test run.
|
|
std::size_t Iterations;
|
|
|
|
|
|
/// Test factory.
|
|
TestFactory* Factory;
|
|
|
|
|
|
/// Parameters for parametrized tests
|
|
TestParametersDescriptor Parameters;
|
|
|
|
|
|
/// Disabled.
|
|
bool IsDisabled;
|
|
};
|
|
}
|
|
#endif
|