skia2/tests/Test.h
scroggo 0ee2627026 When running DM, write test failures to json.
Add skiatest::Failure to keep track of data about a test failure.

Reporter::reportFailed and ::onReportFailed now take Failure as a
parameter. This allows the implementation to treat the failure as it
wishes. Provide a helper to format the failure the same as prior to
the change.

Update the macros for calling reportFailed (REPORTER_ASSERT etc) to
create a Failure object.

Convert a direct call to reportFailed to the macro ERRORF.

Write Failures to Json.
Sample output when running dm on the dummy test crrev.com/705723004:
{
   "test_results" : {
      "failures" : [
         {
            "condition" : "0 > 3",
            "file_name" : "../../tests/DummyTest.cpp",
            "line_no" : 10,
            "message" : ""
         },
         {
            "condition" : "false",
            "file_name" : "../../tests/DummyTest.cpp",
            "line_no" : 4,
            "message" : ""
         },
         {
            "condition" : "1 == 3",
            "file_name" : "../../tests/DummyTest.cpp",
            "line_no" : 5,
            "message" : "I can too count!"
         },
         {
            "condition" : "",
            "file_name" : "../../tests/DummyTest.cpp",
            "line_no" : 6,
            "message" : "seven is 7"
         },
         {
            "condition" : "1 == 3",
            "file_name" : "../../tests/DummyTest.cpp",
            "line_no" : 14,
            "message" : "I can too count!"
         }
      ]
   }
}

Report all of the failures from one test.
Previously, if one test had multiple failures, only one was reportered.
e.g:

Failures:
  test Dummy: ../../tests/DummyTest.cpp:6   seven is 7
  test Dummy2: ../../tests/DummyTest.cpp:10 0 > 3
  test Dummy3: ../../tests/DummyTest.cpp:14 I can too count!: 1 == 3
3 failures.

Now, we get all the messages:

Failures:
  test Dummy: ../../tests/DummyTest.cpp:4   false
        ../../tests/DummyTest.cpp:5 I can too count!: 1 == 3
        ../../tests/DummyTest.cpp:6 seven is 7
  test Dummy2: ../../tests/DummyTest.cpp:10 0 > 3
  test Dummy3: ../../tests/DummyTest.cpp:14 I can too count!: 1 == 3
3 failures.

(Note that we still state "3 failures" because 3 DM::Tasks failed.)

BUG=skia:3082
BUG=skia:2454

Review URL: https://codereview.chromium.org/694703005
2014-11-07 06:07:32 -08:00

209 lines
7.4 KiB
C++

/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skiatest_Test_DEFINED
#define skiatest_Test_DEFINED
#include "SkRefCnt.h"
#include "SkString.h"
#include "SkTRegistry.h"
#include "SkThread.h"
#include "SkTypes.h"
class GrContextFactory;
namespace skiatest {
class Test;
/**
* Information about a single failure from a Test.
*
* Not intended to be created/modified directly. To create one, use one of
*
* REPORTER_ASSERT
* REPORTER_ASSERT_MESSAGE
* ERRORF
*
* described in more detail further down in this file.
*/
struct Failure {
const char* fileName;
int lineNo;
const char* condition;
SkString message;
// Helper to combine the failure info into one string.
void getFailureString(SkString* result) const {
if (!result) {
return;
}
result->printf("%s:%d\t", fileName, lineNo);
if (!message.isEmpty()) {
result->append(message);
if (strlen(condition) > 0) {
result->append(": ");
}
}
result->append(condition);
}
};
class Reporter : public SkRefCnt {
public:
SK_DECLARE_INST_COUNT(Reporter)
Reporter();
int countTests() const { return fTestCount; }
void startTest(Test*);
void reportFailed(const Failure&);
void endTest(Test*);
virtual bool allowExtendedTest() const { return false; }
virtual bool verbose() const { return false; }
virtual void bumpTestCount() { sk_atomic_inc(&fTestCount); }
protected:
virtual void onStart(Test*) {}
virtual void onReportFailed(const Failure&) {}
virtual void onEnd(Test*) {}
private:
int32_t fTestCount;
typedef SkRefCnt INHERITED;
};
class Test {
public:
Test();
virtual ~Test();
Reporter* getReporter() const { return fReporter; }
void setReporter(Reporter*);
const char* getName();
void run();
bool passed() const { return fPassed; }
SkMSec elapsedMs() const { return fElapsed; }
static SkString GetTmpDir();
virtual bool isGPUTest() const { return false; }
virtual void setGrContextFactory(GrContextFactory* factory) {}
protected:
virtual void onGetName(SkString*) = 0;
virtual void onRun(Reporter*) = 0;
private:
Reporter* fReporter;
SkString fName;
bool fPassed;
SkMSec fElapsed;
};
class GpuTest : public Test{
public:
GpuTest() : Test(), fGrContextFactory(NULL) {}
virtual bool isGPUTest() const { return true; }
virtual void setGrContextFactory(GrContextFactory* factory) {
fGrContextFactory = factory;
}
protected:
GrContextFactory* fGrContextFactory; // Unowned.
};
typedef SkTRegistry<Test*(*)(void*)> TestRegistry;
} // namespace skiatest
/*
Use the following macros to make use of the skiatest classes, e.g.
#include "Test.h"
DEF_TEST(TestName, reporter) {
...
REPORTER_ASSERT(reporter, x == 15);
...
REPORTER_ASSERT_MESSAGE(reporter, x == 15, "x should be 15");
...
if (x != 15) {
ERRORF(reporter, "x should be 15, but is %d", x);
return;
}
...
}
*/
#define REPORTER_ASSERT(r, cond) \
do { \
if (!(cond)) { \
skiatest::Failure failure = { __FILE__, __LINE__, \
#cond, SkString() }; \
r->reportFailed(failure); \
} \
} while(0)
#define REPORTER_ASSERT_MESSAGE(r, cond, message) \
do { \
if (!(cond)) { \
skiatest::Failure failure = { __FILE__, __LINE__, \
#cond, SkString(message) }; \
r->reportFailed(failure); \
} \
} while(0)
#define ERRORF(r, ...) \
do { \
SkString desc; \
desc.appendf(__VA_ARGS__) ; \
skiatest::Failure failure = { __FILE__, __LINE__, \
"", SkString(desc) }; \
r->reportFailed(failure); \
} while(0)
#define DEF_TEST(name, reporter) \
static void test_##name(skiatest::Reporter*); \
namespace skiatest { \
class name##Class : public Test { \
public: \
static Test* Factory(void*) { return SkNEW(name##Class); } \
protected: \
virtual void onGetName(SkString* name) SK_OVERRIDE { \
name->set(#name); \
} \
virtual void onRun(Reporter* r) SK_OVERRIDE { test_##name(r); } \
}; \
static TestRegistry gReg_##name##Class(name##Class::Factory); \
} \
static void test_##name(skiatest::Reporter* reporter)
#define DEF_GPUTEST(name, reporter, factory) \
static void test_##name(skiatest::Reporter*, GrContextFactory*); \
namespace skiatest { \
class name##Class : public GpuTest { \
public: \
static Test* Factory(void*) { return SkNEW(name##Class); } \
protected: \
virtual void onGetName(SkString* name) SK_OVERRIDE { \
name->set(#name); \
} \
virtual void onRun(Reporter* r) SK_OVERRIDE { \
test_##name(r, fGrContextFactory); \
} \
}; \
static TestRegistry gReg_##name##Class(name##Class::Factory); \
} \
static void test_##name(skiatest::Reporter* reporter, GrContextFactory* factory)
#endif