Relevant code, this is from UnitTest++/TestRunner.h:
class TestRunner
{
public:
explicit TestRunner(TestReporter& reporter);
~TestRunner();
template <class Predicate>
int RunTestsIf(TestList const& list, char const* suiteName,
const Predicate& predicate, int maxTestTimeInMs) const
{
Test* curTest = list.GetHead();
while (curTest != 0)
{
if (IsTestInSuite(curTest,suiteName) && predicate(curTest))
{
RunTest(m_result, curTest, maxTestTimeInMs);
}
curTest = curTest->next;
}
return Finish();
}
private:
TestReporter* m_reporter;
TestResults* m_result;
Timer* m_timer;
int Finish() const;
bool IsTestInSuite(const Test* const curTest, char const* suiteName) const;
void RunTest(TestResults* const result, Test* const curTest, int const maxTestTimeInMs) const;
};
Here is my predicate class I am trying to modify to let it do what I want:
class ListFilterRemember {
char **list;
int n;
Test **testsAlreadyRun;
int index_tar;
int max_allocd;
public:
ListFilterRemember(char **list_, int count) {
int testCount = 0;
Test* curTest = Test::GetTestList().GetHead();
while (curTest != 0) {
testCount++;
}
list = list_; n = count; max_allocd = testCount;
testsAlreadyRun = new Test *[max_allocd];
index_tar = 0;
}
bool operator()(const Test* const t) const {
for (int i=0;i<index_tar;++i) {
if (testsAlreadyRun[i] == t) { return false; }
}
for (int i=0;i<n;++i) {
std::string dot_cpp_appended = std::string(list[i]) + ".cpp";
if (!strcasecmp(t->m_details.testName, list[i]) ||
!strcasecmp(t->m_details.suiteName, list[i]) ||
!strcasecmp(t->m_details.filename, list[i]) ||
!strcasecmp(t->m_details.filename, dot_cpp_appended.c_str()) || (
filename_dir_prefix_len < (int)strlen(t->m_details.filename) && ( // ensure the ptr arith in next 2 lines doesn't go out of bounds
!strcasecmp(t->m_details.filename+filename_dir_prefix_len, list[i]) ||
!strcasecmp(t->m_details.filename+filename_dir_prefix_len, dot_cpp_appended.c_str())
)
) || (
std::string::npos != findCaseInsensitive(t->m_details.testName,list[i])
)
) {
// erring on the side of matching more tests
//printf(" running\n");
if (index_tar >= max_allocd) throw std::runtime_error("Did not allocate! Segfault here.");
testsAlreadyRun[index_tar] = (Test *)t;
index_tar += 1;
return true;
}
}
//printf(" not running\n");
return false;
}
~ListFilterRemember() {
delete[] testsAlreadyRun;
}
};
You see the way that it’s defined in TestRunner.h attaches a const qualifier which makes it impossible for my operator () function to make changes to member variables. I need to make those changes so I can remember which tests I’ve already run so I don’t run them again. The reason why there might be risk of them running again is that I intend to run RunTestsIf() multiple times.
I enter a list of tests at the command line to specify which tests I want to run based on their names. That is what all of the string matching code is for. I still want to use those, but this time I want to improve it so that the tests I specify will run in the order that i specify them in. In order to do this I have to move the test runner so that I loop over my specified test list and match based on them one by one.
Ideas? I’d go nuke the const in the UnitTest++ code but I don’t want to break things if I don’t have to.
You could use the
mutablekeyword, but the way the test is structured suggests that the test runner might not reuse the same instance of the predicate, so your changes might be lost between tests. Of course, if the posted code is the entire test runner, then it looks like it does call the samePredicateinstance every time.