formalize host debugging

Pathops writes files, anticipating upcoming crashes,
and verifies the results against regions.

Formalize these debugging methods so that they
are more easily triggered by hosts outside of
skia unit tests.

TBR=reed@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2441763003

Review-Url: https://codereview.chromium.org/2441763003
This commit is contained in:
caryclark 2016-10-24 05:10:14 -07:00 committed by Commit bot
parent 826167111f
commit 1326068147
13 changed files with 312 additions and 187 deletions

View File

@ -8,10 +8,19 @@
#include "SkMutex.h"
#include "SkOpCoincidence.h"
#include "SkOpContour.h"
#include "SkOSFile.h"
#include "SkPath.h"
#include "SkPathOpsDebug.h"
#include "SkString.h"
#ifdef SK_DEBUG
bool SkPathOpsDebug::gDumpOp; // set to true to write op to file before a crash
bool SkPathOpsDebug::gVerifyOp; // set to true to compare result against regions
#endif
bool SkPathOpsDebug::gRunFail; // set to true to check for success on tests known to fail
bool SkPathOpsDebug::gVeryVerbose; // set to true to run extensive checking tests
#undef FAIL_IF
#define FAIL_IF(cond, coin) \
do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, coin); } while (false)
@ -27,10 +36,6 @@
class SkCoincidentSpans;
#if DEBUG_VALIDATE
extern bool FLAGS_runFail;
#endif
#if DEBUG_SORT
int SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
int SkPathOpsDebug::gSortCount;
@ -647,15 +652,9 @@ void SkOpGlobalState::debugResetLoopCounts() {
}
#endif
#ifdef SK_DEBUG
bool SkOpGlobalState::debugRunFail() const {
#if DEBUG_VALIDATE
return FLAGS_runFail;
#else
return false;
#endif
bool SkOpGlobalState::DebugRunFail() {
return SkPathOpsDebug::gRunFail;
}
#endif
// this is const so it can be called by const methods that overwise don't alter state
#if DEBUG_VALIDATE || DEBUG_COIN
@ -1362,8 +1361,8 @@ void SkOpAngle::debugValidate() const {
}
next = next->fNext;
} while (next && next != first);
SkASSERT(wind == 0 || !FLAGS_runFail);
SkASSERT(opp == 0 || !FLAGS_runFail);
SkASSERT(wind == 0 || !SkPathOpsDebug::gRunFail);
SkASSERT(opp == 0 || !SkPathOpsDebug::gRunFail);
#endif
}
@ -1390,8 +1389,8 @@ void SkOpAngle::debugValidateNext() const {
#ifdef SK_DEBUG
void SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over,
const SkOpGlobalState* debugState) const {
SkASSERT(coinPtTEnd()->span() == over || !debugState->debugRunFail());
SkASSERT(oppPtTEnd()->span() == outer || !debugState->debugRunFail());
SkASSERT(coinPtTEnd()->span() == over || !SkOpGlobalState::DebugRunFail());
SkASSERT(oppPtTEnd()->span() == outer || !SkOpGlobalState::DebugRunFail());
}
#endif
@ -2906,3 +2905,203 @@ void SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool incl
iter.setPath(path);
showPathContours(iter, name);
}
#ifdef SK_DEBUG
#include "SkData.h"
#include "SkStream.h"
static void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) {
SkDynamicMemoryWStream wStream;
path.dump(&wStream, force, dumpAsHex);
sk_sp<SkData> data(wStream.detachAsData());
fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data());
}
static int dumpID = 0;
void SkPathOpsDebug::DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName) {
FILE* file = sk_fopen("op_dump.txt", kWrite_SkFILE_Flag);
DumpOp(file, one, two, op, testName);
}
void SkPathOpsDebug::DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName) {
const char* name = testName ? testName : "op";
fprintf(file,
"\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
name, ++dumpID);
fprintf(file, " SkPath path;\n");
fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillType());
dump_path(file, one, false, true);
fprintf(file, " SkPath path1(path);\n");
fprintf(file, " path.reset();\n");
fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillType());
dump_path(file, two, false, true);
fprintf(file, " SkPath path2(path);\n");
fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op);
fprintf(file, "}\n\n");
fclose(file);
}
void SkPathOpsDebug::DumpSimplify(const SkPath& path, const char* testName) {
FILE* file = sk_fopen("simplify_dump.txt", kWrite_SkFILE_Flag);
DumpSimplify(file, path, testName);
}
void SkPathOpsDebug::DumpSimplify(FILE* file, const SkPath& path, const char* testName) {
const char* name = testName ? testName : "simplify";
fprintf(file,
"\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
name, ++dumpID);
fprintf(file, " SkPath path;\n");
fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", path.getFillType());
dump_path(file, path, false, true);
fprintf(file, " testSimplify(reporter, path, filename);\n");
fprintf(file, "}\n\n");
fclose(file);
}
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkPaint.h"
const int bitWidth = 64;
const int bitHeight = 64;
static void debug_scale_matrix(const SkPath& one, const SkPath* two, SkMatrix& scale) {
SkRect larger = one.getBounds();
if (two) {
larger.join(two->getBounds());
}
SkScalar largerWidth = larger.width();
if (largerWidth < 4) {
largerWidth = 4;
}
SkScalar largerHeight = larger.height();
if (largerHeight < 4) {
largerHeight = 4;
}
SkScalar hScale = (bitWidth - 2) / largerWidth;
SkScalar vScale = (bitHeight - 2) / largerHeight;
scale.reset();
scale.preScale(hScale, vScale);
larger.fLeft *= hScale;
larger.fRight *= hScale;
larger.fTop *= vScale;
larger.fBottom *= vScale;
SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
: 16000 < larger.fRight ? 16000 - larger.fRight : 0;
SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
: 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
scale.preTranslate(dx, dy);
}
static int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) {
if (bits.width() == 0) {
bits.allocN32Pixels(bitWidth * 2, bitHeight);
}
SkCanvas canvas(bits);
canvas.drawColor(SK_ColorWHITE);
SkPaint paint;
canvas.save();
const SkRect& bounds1 = one.getBounds();
canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
canvas.drawPath(one, paint);
canvas.restore();
canvas.save();
canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
canvas.drawPath(two, paint);
canvas.restore();
int errors = 0;
for (int y = 0; y < bitHeight - 1; ++y) {
uint32_t* addr1 = bits.getAddr32(0, y);
uint32_t* addr2 = bits.getAddr32(0, y + 1);
uint32_t* addr3 = bits.getAddr32(bitWidth, y);
uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
for (int x = 0; x < bitWidth - 1; ++x) {
// count 2x2 blocks
bool err = addr1[x] != addr3[x];
if (err) {
errors += addr1[x + 1] != addr3[x + 1]
&& addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
}
}
}
return errors;
}
void SkPathOpsDebug::ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op) {
SkDebugf("// Op did not expect failure\n");
DumpOp(stderr, one, two, op, "opTest");
fflush(stderr);
}
void SkPathOpsDebug::VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op,
const SkPath& result) {
SkPath pathOut, scaledPathOut;
SkRegion rgnA, rgnB, openClip, rgnOut;
openClip.setRect(-16000, -16000, 16000, 16000);
rgnA.setPath(one, openClip);
rgnB.setPath(two, openClip);
rgnOut.op(rgnA, rgnB, (SkRegion::Op) op);
rgnOut.getBoundaryPath(&pathOut);
SkMatrix scale;
debug_scale_matrix(one, &two, scale);
SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
SkPath scaledA, scaledB;
scaledA.addPath(one, scale);
scaledA.setFillType(one.getFillType());
scaledB.addPath(two, scale);
scaledB.setFillType(two.getFillType());
scaledRgnA.setPath(scaledA, openClip);
scaledRgnB.setPath(scaledB, openClip);
scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op);
scaledRgnOut.getBoundaryPath(&scaledPathOut);
SkBitmap bitmap;
SkPath scaledOut;
scaledOut.addPath(result, scale);
scaledOut.setFillType(result.getFillType());
int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
const int MAX_ERRORS = 9;
if (errors > MAX_ERRORS) {
fprintf(stderr, "// Op did not expect errors=%d\n", errors);
DumpOp(stderr, one, two, op, "opTest");
fflush(stderr);
}
}
void SkPathOpsDebug::ReportSimplifyFail(const SkPath& path) {
SkDebugf("// Simplify did not expect failure\n");
DumpSimplify(stderr, path, "simplifyTest");
fflush(stderr);
}
void SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) {
SkPath pathOut, scaledPathOut;
SkRegion rgnA, openClip, rgnOut;
openClip.setRect(-16000, -16000, 16000, 16000);
rgnA.setPath(path, openClip);
rgnOut.getBoundaryPath(&pathOut);
SkMatrix scale;
debug_scale_matrix(path, nullptr, scale);
SkRegion scaledRgnA;
SkPath scaledA;
scaledA.addPath(path, scale);
scaledA.setFillType(path.getFillType());
scaledRgnA.setPath(scaledA, openClip);
scaledRgnA.getBoundaryPath(&scaledPathOut);
SkBitmap bitmap;
SkPath scaledOut;
scaledOut.addPath(result, scale);
scaledOut.setFillType(result.getFillType());
int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
const int MAX_ERRORS = 9;
if (errors > MAX_ERRORS) {
fprintf(stderr, "// Simplify did not expect errors=%d\n", errors);
DumpSimplify(stderr, path, "simplifyTest");
fflush(stderr);
}
}
#endif

View File

@ -371,6 +371,27 @@ public:
static void DumpCoinDict();
static void DumpGlitchType(GlitchType );
#endif
static bool gRunFail;
static bool gVeryVerbose;
#ifdef SK_DEBUG
static bool gDumpOp;
static bool gVerifyOp;
static void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName);
static void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName);
static void DumpSimplify(const SkPath& path, const char* testName);
static void DumpSimplify(FILE* file, const SkPath& path, const char* testName);
static void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op);
static void ReportSimplifyFail(const SkPath& path);
static void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op,
const SkPath& result);
static void VerifySimplify(const SkPath& path, const SkPath& result);
#endif
};
struct SkDQuad;

View File

@ -198,44 +198,6 @@ static const bool gOutInverse[kReverseDifference_SkPathOp + 1][2][2] = {
{{ false, true }, { false, false }}, // rev diff
};
#define DEBUGGING_PATHOPS_FROM_HOST 0 // enable to debug svg in chrome -- note path hardcoded below
#if DEBUGGING_PATHOPS_FROM_HOST
#include "SkData.h"
#include "SkStream.h"
static void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) {
SkDynamicMemoryWStream wStream;
path.dump(&wStream, force, dumpAsHex);
sk_sp<SkData> data(wStream.detachAsData());
fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data());
}
static int dumpID = 0;
static void dump_op(const SkPath& one, const SkPath& two, SkPathOp op) {
#if SK_BUILD_FOR_MAC
FILE* file = fopen("/Users/caryclark/Documents/svgop.txt", "w");
#else
FILE* file = fopen("/usr/local/google/home/caryclark/Documents/svgop.txt", "w");
#endif
fprintf(file,
"\nstatic void fuzz763_%d(skiatest::Reporter* reporter, const char* filename) {\n",
++dumpID);
fprintf(file, " SkPath path;\n");
fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillType());
dump_path(file, one, false, true);
fprintf(file, " SkPath path1(path);\n");
fprintf(file, " path.reset();\n");
fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillType());
dump_path(file, two, false, true);
fprintf(file, " SkPath path2(path);\n");
fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op);
fprintf(file, "}\n");
fclose(file);
}
#endif
#if DEBUG_T_SECT_LOOP_COUNT
#include "SkMutex.h"
@ -261,8 +223,10 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
SkOpGlobalState globalState(contourList, &allocator
SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName));
SkOpCoincidence coincidence(&globalState);
#if DEBUGGING_PATHOPS_FROM_HOST
dump_op(one, two, op);
#ifdef SK_DEBUG
if (SkPathOpsDebug::gDumpOp) {
SkPathOpsDebug::DumpOp(one, two, op, testName);
}
#endif
op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()];
SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()]
@ -351,122 +315,16 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
return true;
}
#define DEBUG_VERIFY 0
#if DEBUG_VERIFY
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkPaint.h"
const int bitWidth = 64;
const int bitHeight = 64;
static void debug_scale_matrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
SkRect larger = one.getBounds();
larger.join(two.getBounds());
SkScalar largerWidth = larger.width();
if (largerWidth < 4) {
largerWidth = 4;
}
SkScalar largerHeight = larger.height();
if (largerHeight < 4) {
largerHeight = 4;
}
SkScalar hScale = (bitWidth - 2) / largerWidth;
SkScalar vScale = (bitHeight - 2) / largerHeight;
scale.reset();
scale.preScale(hScale, vScale);
larger.fLeft *= hScale;
larger.fRight *= hScale;
larger.fTop *= vScale;
larger.fBottom *= vScale;
SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
: 16000 < larger.fRight ? 16000 - larger.fRight : 0;
SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
: 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
scale.preTranslate(dx, dy);
}
static int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) {
if (bits.width() == 0) {
bits.allocN32Pixels(bitWidth * 2, bitHeight);
}
SkCanvas canvas(bits);
canvas.drawColor(SK_ColorWHITE);
SkPaint paint;
canvas.save();
const SkRect& bounds1 = one.getBounds();
canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
canvas.drawPath(one, paint);
canvas.restore();
canvas.save();
canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
canvas.drawPath(two, paint);
canvas.restore();
int errors = 0;
for (int y = 0; y < bitHeight - 1; ++y) {
uint32_t* addr1 = bits.getAddr32(0, y);
uint32_t* addr2 = bits.getAddr32(0, y + 1);
uint32_t* addr3 = bits.getAddr32(bitWidth, y);
uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
for (int x = 0; x < bitWidth - 1; ++x) {
// count 2x2 blocks
bool err = addr1[x] != addr3[x];
if (err) {
errors += addr1[x + 1] != addr3[x + 1]
&& addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
}
}
}
return errors;
}
#endif
bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
#if DEBUG_VERIFY
if (!OpDebug(one, two, op, result SkDEBUGPARAMS(nullptr))) {
SkDebugf("%s did not expect failure\none: fill=%d\n", __FUNCTION__, one.getFillType());
one.dumpHex();
SkDebugf("two: fill=%d\n", two.getFillType());
two.dumpHex();
SkASSERT(0);
return false;
#ifdef SK_DEBUG
if (SkPathOpsDebug::gVerifyOp) {
if (!OpDebug(one, two, op, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) {
SkPathOpsDebug::ReportOpFail(one, two, op);
return false;
}
SkPathOpsDebug::VerifyOp(one, two, op, *result);
return true;
}
SkPath pathOut, scaledPathOut;
SkRegion rgnA, rgnB, openClip, rgnOut;
openClip.setRect(-16000, -16000, 16000, 16000);
rgnA.setPath(one, openClip);
rgnB.setPath(two, openClip);
rgnOut.op(rgnA, rgnB, (SkRegion::Op) op);
rgnOut.getBoundaryPath(&pathOut);
SkMatrix scale;
debug_scale_matrix(one, two, scale);
SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
SkPath scaledA, scaledB;
scaledA.addPath(one, scale);
scaledA.setFillType(one.getFillType());
scaledB.addPath(two, scale);
scaledB.setFillType(two.getFillType());
scaledRgnA.setPath(scaledA, openClip);
scaledRgnB.setPath(scaledB, openClip);
scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op);
scaledRgnOut.getBoundaryPath(&scaledPathOut);
SkBitmap bitmap;
SkPath scaledOut;
scaledOut.addPath(*result, scale);
scaledOut.setFillType(result->getFillType());
int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
const int MAX_ERRORS = 9;
if (errors > MAX_ERRORS) {
SkDebugf("%s did not expect failure\none: fill=%d\n", __FUNCTION__, one.getFillType());
one.dumpHex();
SkDebugf("two: fill=%d\n", two.getFillType());
two.dumpHex();
SkASSERT(0);
}
return true;
#else
return OpDebug(one, two, op, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
#endif
return OpDebug(one, two, op, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
}

View File

@ -158,6 +158,11 @@ bool SimplifyDebug(const SkPath& path, SkPath* result
SkOpGlobalState globalState(contourList, &allocator
SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName));
SkOpCoincidence coincidence(&globalState);
#ifdef SK_DEBUG
if (SkPathOpsDebug::gDumpOp) {
SkPathOpsDebug::DumpSimplify(path, testName);
}
#endif
SkScalar scaleFactor = ScaleFactor(path);
SkPath scaledPath;
const SkPath* workingPath;
@ -218,5 +223,15 @@ bool SimplifyDebug(const SkPath& path, SkPath* result
}
bool Simplify(const SkPath& path, SkPath* result) {
#ifdef SK_DEBUG
if (SkPathOpsDebug::gVerifyOp) {
if (!SimplifyDebug(path, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) {
SkPathOpsDebug::ReportSimplifyFail(path);
return false;
}
SkPathOpsDebug::VerifySimplify(path, *result);
return true;
}
#endif
return SimplifyDebug(path, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
}

View File

@ -75,7 +75,11 @@ public:
const SkOpCoincidence* debugCoincidence() const;
SkOpContour* debugContour(int id) const;
const class SkOpPtT* debugPtT(int id) const;
bool debugRunFail() const;
#endif
static bool DebugRunFail();
#ifdef SK_DEBUG
const class SkOpSegment* debugSegment(int id) const;
bool debugSkipAssert() const { return fDebugSkipAssert; }
const class SkOpSpanBase* debugSpan(int id) const;

View File

@ -88,6 +88,8 @@ static void setupOne(skiatest::Reporter* reporter, int col, int row, int rot, in
testOne(reporter, set);
}
#include "SkCommandLineFlags.h"
DEFINE_int32(processOffset, 0, "Offset the test by this value. This permits multiple processes "
"to exercise the same test in parallel with different test values.");
DEFINE_int32(processCount, 1, "Test iteration count. This permits multiple "

View File

@ -13,8 +13,6 @@
#include "SkOpSegment.h"
#include "SkString.h"
extern bool FLAGS_runFail;
inline void DebugDumpDouble(double x) {
if (x == floor(x)) {
SkDebugf("%.0f", x);

View File

@ -32,9 +32,6 @@ bool SimplifyDebug(const SkPath& one, SkPath* result
__SK_FORCE_IMAGE_DECODER_LINKING;
DEFINE_bool2(runFail, f, false, "run tests known to fail.");
DEFINE_bool2(runBinary, f, false, "run tests known to fail binary sect.");
static const char marker[] =
"</div>\n"
"\n"

View File

@ -8,15 +8,11 @@
#define PathOpsExtendedTest_DEFINED
#include "SkBitmap.h"
#include "SkCommandLineFlags.h"
#include "SkPath.h"
#include "SkPathOpsTypes.h"
#include "SkStream.h"
#include "Test.h"
DECLARE_bool(runFail);
DECLARE_bool(runBinary);
struct PathOpsThreadState;
struct TestDesc {

View File

@ -2093,7 +2093,7 @@ path.close();
SkPath path2(path);
// DEBUG_UNDER_DEVELOPMENT fuzz763_1026368 disable expectation check for now
testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, !FLAGS_runFail);
testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, !SkOpGlobalState::DebugRunFail());
}
static void fuzz763_5485218(skiatest::Reporter* reporter, const char* filename) {

View File

@ -473,7 +473,8 @@ static void issue3651_1a(skiatest::Reporter* reporter, const char* filename) {
SkPath path = path1_a();
SkPath pathB = path2_a();
// DEBUG_UNDER_DEVELOPMENT issue3651_1a disable expectation check for now
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename, !FLAGS_runFail);
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename,
!SkOpGlobalState::DebugRunFail());
}
static SkPath path3() {
@ -1204,7 +1205,8 @@ static void issue3651_1(skiatest::Reporter* reporter, const char* filename) {
SkPath path = path1();
SkPath pathB = path2();
// DEBUG_UNDER_DEVELOPMENT issue3651_1 disable expectation check for now
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename, !FLAGS_runFail);
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename,
!SkOpGlobalState::DebugRunFail());
}
static void issue3651_2(skiatest::Reporter* reporter, const char* filename) {

View File

@ -524,10 +524,8 @@ DEF_TEST(PathOpsQuadIntersection, reporter) {
if (false) QuadraticIntersection_IntersectionFinder();
}
#include "SkCommonFlags.h"
DEF_TEST(PathOpsQuadBinaryProfile, reporter) {
if (!FLAGS_veryVerbose) {
if (!SkPathOpsDebug::gVeryVerbose) {
return;
}
SkIntersections intersections;

View File

@ -27,7 +27,11 @@
using namespace skiatest;
using namespace sk_gpu_test;
DEFINE_bool2(dumpOp, d, false, "dump the pathOps to a file to recover mid-crash.");
DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
DEFINE_bool2(runFail, f, false, "check for success on tests known to fail.");
DEFINE_bool2(verifyOp, y, false, "compare the pathOps result against a region.");
#if DEBUG_COIN
DEFINE_bool2(coinTest, c, false, "detect unused coincidence algorithms.");
#endif
@ -133,6 +137,12 @@ static bool should_run(const char* testName, bool isGPUTest) {
int test_main();
int test_main() {
#ifdef SK_DEBUG
SkPathOpsDebug::gDumpOp = FLAGS_dumpOp;
SkPathOpsDebug::gVerifyOp = FLAGS_verifyOp;
#endif
SkPathOpsDebug::gRunFail = FLAGS_runFail;
SkPathOpsDebug::gVeryVerbose = FLAGS_veryVerbose;
SetupCrashHandler();
SkAutoGraphics ag;
@ -153,6 +163,31 @@ int test_main() {
if (!resourcePath.isEmpty()) {
header.appendf(" --resourcePath %s", resourcePath.c_str());
}
#if DEBUG_COIN
if (FLAGS_coinTest) {
header.appendf(" -c");
}
#endif
if (FLAGS_dumpOp) {
header.appendf(" -d");
}
#if SK_DEBUG
if (FLAGS_runFail) {
header.appendf(" -f");
}
#endif
if (FLAGS_verbose) {
header.appendf(" -v");
}
if (FLAGS_veryVerbose) {
header.appendf(" -V");
}
if (FLAGS_extendedTest) {
header.appendf(" -x");
}
if (FLAGS_verifyOp) {
header.appendf(" -y");
}
#ifdef SK_DEBUG
header.append(" SK_DEBUG");
#else