Go to the documentation of this file.00001 #ifndef __HAYAI_TESTDESCRIPTOR
00002 #define __HAYAI_TESTDESCRIPTOR
00003 #include <cstring>
00004 #include <sstream>
00005 #include <string>
00006 #include <vector>
00007
00008 #include "hayai/hayai_test.hpp"
00009 #include "hayai/hayai_test_factory.hpp"
00010
00011
00012 namespace hayai
00013 {
00015
00017 class TestParameterDescriptor
00018 {
00019 public:
00020 TestParameterDescriptor(std::string declaration,
00021 std::string value)
00022 : Declaration(declaration),
00023 Value(value)
00024 {
00025
00026 }
00027
00028
00030 std::string Declaration;
00031
00032
00034 std::string Value;
00035 };
00036
00037
00039 class TestParametersDescriptor
00040 {
00041 private:
00043 enum QuotingState
00044 {
00046 Unquoted,
00047
00048
00050 SingleQuoted,
00051
00052
00054 DoubleQuoted
00055 };
00056
00057
00059
00062 inline static std::string TrimmedString(const char* start,
00063 const char* end)
00064 {
00065 while (start < end)
00066 {
00067 if ((*start == ' ') ||
00068 (*start == '\r') ||
00069 (*start == '\n') ||
00070 (*start == '\t'))
00071 {
00072 ++start;
00073 }
00074 else
00075 {
00076 break;
00077 }
00078 }
00079
00080 while (end > start)
00081 {
00082 const char c = *(end - 1);
00083
00084 if ((c != ' ') &&
00085 (c != '\r') &&
00086 (c != '\n') &&
00087 (c != '\t'))
00088 {
00089 break;
00090 }
00091
00092 --end;
00093 }
00094
00095 return std::string(start, std::string::size_type(end - start));
00096 }
00097
00098
00100
00103 static std::vector<std::string>
00104 ParseCommaSeparated(const char* separated)
00105 {
00106 std::vector<std::string> result;
00107
00108 if (*separated)
00109 {
00110 ++separated;
00111 }
00112
00113 while ((*separated) && (*separated != ')'))
00114 {
00115 std::size_t escapeCounter = 0;
00116 const char* start = separated;
00117 QuotingState state = Unquoted;
00118 bool escaped = false;
00119
00120 while (*separated)
00121 {
00122 const char c = *separated++;
00123
00124 if (state == Unquoted)
00125 {
00126 if ((c == '"') || (c == '\''))
00127 {
00128 state = (c == '"' ? DoubleQuoted : SingleQuoted);
00129 escaped = false;
00130 }
00131 else if ((c == '<') ||
00132 (c == '(') ||
00133 (c == '[') ||
00134 (c == '{'))
00135 {
00136 ++escapeCounter;
00137 }
00138 else if ((escapeCounter) &&
00139 ((c == '>') ||
00140 (c == ')') ||
00141 (c == ']') ||
00142 (c == '}')))
00143 {
00144 --escapeCounter;
00145 }
00146 else if ((!escapeCounter) &&
00147 ((c == ',') || (c == ')')))
00148 {
00149 result.push_back(TrimmedString(start,
00150 separated - 1));
00151 break;
00152 }
00153 }
00154 else
00155 {
00156 if (escaped)
00157 {
00158 escaped = false;
00159 }
00160 else if (c == '\\')
00161 {
00162 escaped = true;
00163 }
00164 else if (c == (state == DoubleQuoted ? '"' : '\''))
00165 {
00166 state = Unquoted;
00167 }
00168 }
00169 }
00170 }
00171
00172 return result;
00173 }
00174
00175
00177
00179 TestParameterDescriptor ParseDescriptor(const std::string& raw)
00180 {
00181 const char* position = raw.c_str();
00182
00183
00184
00185 const char* equalPosition = NULL;
00186 std::size_t escapeCounter = 0;
00187 QuotingState state = Unquoted;
00188 bool escaped = false;
00189
00190 while (*position)
00191 {
00192 const char c = *position++;
00193
00194 if (state == Unquoted)
00195 {
00196 if ((c == '"') || (c == '\''))
00197 {
00198 state = (c == '"' ? DoubleQuoted : SingleQuoted);
00199 escaped = false;
00200 }
00201 else if ((c == '<') ||
00202 (c == '(') ||
00203 (c == '[') ||
00204 (c == '{'))
00205 {
00206 ++escapeCounter;
00207 }
00208 else if ((escapeCounter) &&
00209 ((c == '>') ||
00210 (c == ')') ||
00211 (c == ']') ||
00212 (c == '}')))
00213 {
00214 --escapeCounter;
00215 }
00216 else if ((!escapeCounter) &&
00217 (c == '='))
00218 {
00219 equalPosition = position;
00220 break;
00221 }
00222 }
00223 else
00224 {
00225 if (escaped)
00226 {
00227 escaped = false;
00228 }
00229 else if (c == '\\')
00230 {
00231 escaped = true;
00232 }
00233 else if (c == (state == DoubleQuoted ? '"' : '\''))
00234 {
00235 state = Unquoted;
00236 }
00237 }
00238 }
00239
00240
00241 if (equalPosition)
00242 {
00243 const char* start = raw.c_str();
00244 const char* end = start + raw.length();
00245
00246 return TestParameterDescriptor(
00247 std::string(TrimmedString(start,
00248 equalPosition - 1)),
00249 std::string(TrimmedString(equalPosition,
00250 end))
00251 );
00252 }
00253 else
00254 {
00255 return TestParameterDescriptor(raw, std::string());
00256 }
00257 }
00258 public:
00259 TestParametersDescriptor()
00260 {
00261
00262 }
00263
00264
00265 TestParametersDescriptor(const char* rawDeclarations,
00266 const char* rawValues)
00267 {
00268
00269 std::vector<std::string> declarations =
00270 ParseCommaSeparated(rawDeclarations);
00271
00272 for (std::vector<std::string>::const_iterator it =
00273 declarations.begin();
00274 it != declarations.end();
00275 ++it)
00276 {
00277 _parameters.push_back(ParseDescriptor(*it));
00278 }
00279
00280
00281 std::vector<std::string> values = ParseCommaSeparated(rawValues);
00282
00283 std::size_t
00284 straightValues = (_parameters.size() > values.size() ?
00285 values.size() :
00286 _parameters.size()),
00287 variadicValues = 0;
00288
00289 if (values.size() > _parameters.size())
00290 {
00291 if (straightValues > 0)
00292 {
00293 --straightValues;
00294 }
00295
00296 variadicValues = values.size() - _parameters.size() + 1;
00297 }
00298
00299 for (std::size_t i = 0; i < straightValues; ++i)
00300 {
00301 _parameters[i].Value = values[i];
00302 }
00303
00304 if (variadicValues)
00305 {
00306 std::stringstream variadic;
00307
00308 for (std::size_t i = 0; i < variadicValues; ++i)
00309 {
00310 if (i)
00311 {
00312 variadic << ", ";
00313 }
00314
00315 variadic << values[straightValues + i];
00316 }
00317
00318 _parameters[_parameters.size() - 1].Value = variadic.str();
00319 }
00320 }
00321
00322
00323 inline const std::vector<TestParameterDescriptor>& Parameters() const
00324 {
00325 return _parameters;
00326 }
00327 private:
00328 std::vector<TestParameterDescriptor> _parameters;
00329 };
00330
00331
00333 class TestDescriptor
00334 {
00335 public:
00337
00344 TestDescriptor(const char* fixtureName,
00345 const char* testName,
00346 std::size_t runs,
00347 std::size_t iterations,
00348 TestFactory* testFactory,
00349 TestParametersDescriptor parameters,
00350 bool isDisabled = false)
00351 : FixtureName(fixtureName),
00352 TestName(testName),
00353 CanonicalName(std::string(fixtureName) + "." + testName),
00354 Runs(runs),
00355 Iterations(iterations),
00356 Factory(testFactory),
00357 Parameters(parameters),
00358 IsDisabled(isDisabled)
00359 {
00360
00361 }
00362
00363
00365 ~TestDescriptor()
00366 {
00367 delete this->Factory;
00368 }
00369
00370
00372 std::string FixtureName;
00373
00374
00376 std::string TestName;
00377
00378
00380
00382 std::string CanonicalName;
00383
00384
00386 std::size_t Runs;
00387
00388
00390 std::size_t Iterations;
00391
00392
00394 TestFactory* Factory;
00395
00396
00398 TestParametersDescriptor Parameters;
00399
00400
00402 bool IsDisabled;
00403 };
00404 }
00405 #endif