add initial unittest framework (tests)

move some previous unittests out of core classes and into tests



git-svn-id: http://skia.googlecode.com/svn/trunk@96 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-02-27 16:24:51 +00:00
parent 3469c76c40
commit ed673310e2
17 changed files with 1352 additions and 753 deletions

View File

@ -217,14 +217,5 @@ static inline unsigned SkMul16ShiftRound(unsigned a, unsigned b, int shift) {
return (prod + (prod >> shift)) >> shift;
}
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
class SkMath {
public:
static void UnitTest();
};
#endif
#endif

View File

@ -403,13 +403,6 @@ public:
void dump() const;
void toDumpString(SkString*) const;
#ifdef SK_DEBUG
/** @cond UNIT_TEST */
static void UnitTest();
/** @endcond */
#endif
private:
enum {
/** Set if the matrix will map a rectangle to another rectangle. This

View File

@ -118,7 +118,7 @@
so this flag is optional.
*/
#ifdef SK_DEBUG
//#define SK_SUPPORT_UNITTEST
#define SK_SUPPORT_UNITTEST
#endif
#endif

View File

@ -96,13 +96,6 @@ size_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t utf16[] = NULL);
size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues,
char utf8[] = NULL);
class SkUtils {
public:
#ifdef SK_DEBUG
static void UnitTest();
#endif
};
///////////////////////////////////////////////////////////////////////////////
class SkAutoTrace {

View File

@ -304,137 +304,9 @@ private:
typedef SkView INHERITED;
};
static const uint16_t gTest0[] = { 0, 0, 1, 1 };
static const uint16_t gTest1[] = { 1, 2, 3, 4, 5, 6 };
static const uint16_t gTest2[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
static const uint16_t gTest3[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
#include "SkRandom.h"
static SkRandom gRand;
static void rand_fill(uint16_t buffer[], int count) {
for (int i = 0; i < count; i++)
buffer[i] = (uint16_t)gRand.nextU();
}
static void test_pack16() {
static const struct {
const uint16_t* fSrc;
int fCount;
} gTests[] = {
{ gTest0, SK_ARRAY_COUNT(gTest0) },
{ gTest1, SK_ARRAY_COUNT(gTest1) },
{ gTest2, SK_ARRAY_COUNT(gTest2) },
{ gTest3, SK_ARRAY_COUNT(gTest3) }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); i++) {
uint8_t dst[100];
size_t dstSize = SkPackBits::Pack16(gTests[i].fSrc,
gTests[i].fCount, dst);
printf("Test[%d] orig size = %d, dst size = %d",
i, gTests[i].fCount, (int)dstSize);
uint16_t src[100];
int srcCount = SkPackBits::Unpack16(dst, dstSize, src);
printf(", src size = %d", srcCount);
bool match = gTests[i].fCount == srcCount && memcmp(gTests[i].fSrc, src,
gTests[i].fCount * sizeof(uint16_t)) == 0;
printf(", match = %d\n", match);
}
for (int n = 1000; n; n--) {
size_t size = 50;
uint16_t src[100], src2[100];
uint8_t dst[200];
rand_fill(src, size);
size_t dstSize = SkPackBits::Pack16(src, size, dst);
size_t maxSize = SkPackBits::ComputeMaxSize16(size);
SkASSERT(maxSize >= dstSize);
int srcCount = SkPackBits::Unpack16(dst, dstSize, src2);
SkASSERT(size == srcCount);
bool match = memcmp(src, src2, size * sizeof(uint16_t)) == 0;
SkASSERT(match);
}
}
static const uint8_t gTest80[] = { 0, 0, 1, 1 };
static const uint8_t gTest81[] = { 1, 2, 3, 4, 5, 6 };
static const uint8_t gTest82[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
static const uint8_t gTest83[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
static const uint8_t gTest84[] = { 1, 0, 3, 0, 0, 0, 2, 1, 1, 2 };
static void rand_fill(uint8_t buffer[], int count) {
for (int i = 0; i < count; i++)
buffer[i] = (uint8_t)((gRand.nextU() >> 8) & 0x3);
}
static void test_pack8() {
static const struct {
const uint8_t* fSrc;
int fCount;
} gTests[] = {
{ gTest80, SK_ARRAY_COUNT(gTest80) },
{ gTest81, SK_ARRAY_COUNT(gTest81) },
{ gTest82, SK_ARRAY_COUNT(gTest82) },
{ gTest83, SK_ARRAY_COUNT(gTest83) },
{ gTest84, SK_ARRAY_COUNT(gTest84) }
};
for (size_t i = 4; i < SK_ARRAY_COUNT(gTests); i++) {
uint8_t dst[100];
size_t maxSize = SkPackBits::ComputeMaxSize8(gTests[i].fCount);
size_t dstSize = SkPackBits::Pack8(gTests[i].fSrc,
gTests[i].fCount, dst);
SkASSERT(dstSize <= maxSize);
printf("Test[%d] orig size = %d, dst size = %d", i,
gTests[i].fCount, (int)dstSize);
uint8_t src[100];
int srcCount = SkPackBits::Unpack8(dst, dstSize, src);
printf(", src size = %d", srcCount);
bool match = gTests[i].fCount == srcCount &&
memcmp(gTests[i].fSrc, src,
gTests[i].fCount * sizeof(uint8_t)) == 0;
printf(", match = %d\n", match);
}
for (size_t size = 1; size <= 512; size += 1) {
for (int n = 200; n; n--) {
uint8_t src[600], src2[600];
uint8_t dst[600];
rand_fill(src, size);
size_t dstSize = SkPackBits::Pack8(src, size, dst);
size_t maxSize = SkPackBits::ComputeMaxSize8(size);
SkASSERT(maxSize >= dstSize);
int srcCount = SkPackBits::Unpack8(dst, dstSize, src2);
SkASSERT(size == srcCount);
bool match = memcmp(src, src2, size * sizeof(uint8_t)) == 0;
SkASSERT(match);
for (int j = 0; j < 200; j++) {
size_t skip = gRand.nextU() % size;
size_t write = gRand.nextU() % size;
if (skip + write > size) {
write = size - skip;
}
SkPackBits::Unpack8(src, skip, write, dst);
bool match = memcmp(src, src2 + skip, write) == 0;
SkASSERT(match);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() {
static bool gOnce;
if (!gOnce) {
// test_pack8();
gOnce = true;
}
return new TextOnPathView;
}

View File

@ -345,10 +345,7 @@ void SkGraphics::Init(bool runUnitTests)
void (*fUnitTest)();
} gUnitTests[] = {
unittestline(Sk64),
unittestline(SkMath),
unittestline(SkUtils),
unittestline(SkString),
unittestline(SkMatrix),
unittestline(SkGeometry),
unittestline(SkPath),
unittestline(SkPathMeasure),

View File

@ -543,396 +543,3 @@ SkFixed SkFixedATan2(SkFixed y, SkFixed x) { return SkCordicATan2(y, x); }
SkFixed SkFixedExp(SkFixed x) { return SkCordicExp(x); }
SkFixed SkFixedLog(SkFixed x) { return SkCordicLog(x); }
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
#include "SkRandom.h"
#if defined(SkLONGLONG) && defined(SK_SUPPORT_UNITTEST)
static int symmetric_fixmul(int a, int b) {
int sa = SkExtractSign(a);
int sb = SkExtractSign(b);
a = SkApplySign(a, sa);
b = SkApplySign(b, sb);
#if 1
int c = (int)(((SkLONGLONG)a * b) >> 16);
return SkApplySign(c, sa ^ sb);
#else
SkLONGLONG ab = (SkLONGLONG)a * b;
if (sa ^ sb) {
ab = -ab;
}
return ab >> 16;
#endif
}
#endif
#include "SkPoint.h"
#ifdef SK_SUPPORT_UNITTEST
static void check_length(const SkPoint& p, SkScalar targetLen) {
#ifdef SK_CAN_USE_FLOAT
float x = SkScalarToFloat(p.fX);
float y = SkScalarToFloat(p.fY);
float len = sk_float_sqrt(x*x + y*y);
len /= SkScalarToFloat(targetLen);
SkASSERT(len > 0.999f && len < 1.001f);
#endif
}
#endif
#if defined(SK_CAN_USE_FLOAT) && defined(SK_SUPPORT_UNITTEST)
static float nextFloat(SkRandom& rand) {
SkFloatIntUnion data;
data.fSignBitInt = rand.nextU();
return data.fFloat;
}
/* returns true if a == b as resulting from (int)x. Since it is undefined
what to do if the float exceeds 2^32-1, we check for that explicitly.
*/
static bool equal_float_native_skia(float x, uint32_t ni, uint32_t si) {
if (!(x == x)) { // NAN
return si == SK_MaxS32 || si == SK_MinS32;
}
// for out of range, C is undefined, but skia always should return NaN32
if (x > SK_MaxS32) {
return si == SK_MaxS32;
}
if (x < -SK_MaxS32) {
return si == SK_MinS32;
}
return si == ni;
}
static void assert_float_equal(const char op[], float x, uint32_t ni,
uint32_t si) {
if (!equal_float_native_skia(x, ni, si)) {
SkDebugf("-- %s float %g bits %x native %x skia %x\n", op, x, ni, si);
SkASSERT(!"oops");
}
}
static void test_float_cast(float x) {
int ix = (int)x;
int iix = SkFloatToIntCast(x);
assert_float_equal("cast", x, ix, iix);
}
static void test_float_floor(float x) {
int ix = (int)floor(x);
int iix = SkFloatToIntFloor(x);
assert_float_equal("floor", x, ix, iix);
}
static void test_float_round(float x) {
double xx = x + 0.5; // need intermediate double to avoid temp loss
int ix = (int)floor(xx);
int iix = SkFloatToIntRound(x);
assert_float_equal("round", x, ix, iix);
}
static void test_float_ceil(float x) {
int ix = (int)ceil(x);
int iix = SkFloatToIntCeil(x);
assert_float_equal("ceil", x, ix, iix);
}
static void test_float_conversions(float x) {
test_float_cast(x);
test_float_floor(x);
test_float_round(x);
test_float_ceil(x);
}
static void test_int2float(int ival) {
float x0 = (float)ival;
float x1 = SkIntToFloatCast(ival);
float x2 = SkIntToFloatCast_NoOverflowCheck(ival);
SkASSERT(x0 == x1);
SkASSERT(x0 == x2);
}
static void unittest_fastfloat() {
SkRandom rand;
size_t i;
static const float gFloats[] = {
0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3,
0.000000001f, 1000000000.f, // doesn't overflow
0.0000000001f, 10000000000.f // does overflow
};
for (i = 0; i < SK_ARRAY_COUNT(gFloats); i++) {
// SkDebugf("---- test floats %g %d\n", gFloats[i], (int)gFloats[i]);
test_float_conversions(gFloats[i]);
test_float_conversions(-gFloats[i]);
}
for (int outer = 0; outer < 100; outer++) {
rand.setSeed(outer);
for (i = 0; i < 100000; i++) {
float x = nextFloat(rand);
test_float_conversions(x);
}
test_int2float(0);
test_int2float(1);
test_int2float(-1);
for (i = 0; i < 100000; i++) {
// for now only test ints that are 24bits or less, since we don't
// round (down) large ints the same as IEEE...
int ival = rand.nextU() & 0xFFFFFF;
test_int2float(ival);
test_int2float(-ival);
}
}
}
#endif
#ifdef SK_SUPPORT_UNITTEST
static void test_muldiv255() {
#ifdef SK_CAN_USE_FLOAT
for (int a = 0; a <= 255; a++) {
for (int b = 0; b <= 255; b++) {
int ab = a * b;
float s = ab / 255.0f;
int round = (int)floorf(s + 0.5f);
int trunc = (int)floorf(s);
int iround = SkMulDiv255Round(a, b);
int itrunc = SkMulDiv255Trunc(a, b);
SkASSERT(iround == round);
SkASSERT(itrunc == trunc);
SkASSERT(itrunc <= iround);
SkASSERT(iround <= a);
SkASSERT(iround <= b);
}
}
#endif
}
#endif
void SkMath::UnitTest() {
#ifdef SK_SUPPORT_UNITTEST
int i;
int32_t x;
SkRandom rand;
SkToS8(127); SkToS8(-128); SkToU8(255);
SkToS16(32767); SkToS16(-32768); SkToU16(65535);
SkToS32(2*1024*1024); SkToS32(-2*1024*1024); SkToU32(4*1024*1024);
SkCordic_UnitTest();
// these should assert
#if 0
SkToS8(128);
SkToS8(-129);
SkToU8(256);
SkToU8(-5);
SkToS16(32768);
SkToS16(-32769);
SkToU16(65536);
SkToU16(-5);
if (sizeof(size_t) > 4) {
SkToS32(4*1024*1024);
SkToS32(-4*1024*1024);
SkToU32(5*1024*1024);
SkToU32(-5);
}
#endif
test_muldiv255();
#ifdef SK_DEBUG
{
SkScalar x = SK_ScalarNaN;
SkASSERT(SkScalarIsNaN(x));
}
#endif
for (i = 1; i <= 10; i++) {
x = SkCubeRootBits(i*i*i, 11);
SkASSERT(x == i);
}
x = SkFixedSqrt(SK_Fixed1);
SkASSERT(x == SK_Fixed1);
x = SkFixedSqrt(SK_Fixed1/4);
SkASSERT(x == SK_Fixed1/2);
x = SkFixedSqrt(SK_Fixed1*4);
SkASSERT(x == SK_Fixed1*2);
x = SkFractSqrt(SK_Fract1);
SkASSERT(x == SK_Fract1);
x = SkFractSqrt(SK_Fract1/4);
SkASSERT(x == SK_Fract1/2);
x = SkFractSqrt(SK_Fract1/16);
SkASSERT(x == SK_Fract1/4);
for (i = 1; i < 100; i++) {
x = SkFixedSqrt(SK_Fixed1 * i * i);
SkASSERT(x == SK_Fixed1 * i);
}
for (i = 0; i < 1000; i++) {
int value = rand.nextS16();
int max = rand.nextU16();
int clamp = SkClampMax(value, max);
int clamp2 = value < 0 ? 0 : (value > max ? max : value);
SkASSERT(clamp == clamp2);
}
for (i = 0; i < 100000; i++) {
SkPoint p;
p.setLength(rand.nextS(), rand.nextS(), SK_Scalar1);
check_length(p, SK_Scalar1);
p.setLength(rand.nextS() >> 13, rand.nextS() >> 13, SK_Scalar1);
check_length(p, SK_Scalar1);
}
{
SkFixed result = SkFixedDiv(100, 100);
SkASSERT(result == SK_Fixed1);
result = SkFixedDiv(1, SK_Fixed1);
SkASSERT(result == 1);
}
#ifdef SK_CAN_USE_FLOAT
unittest_fastfloat();
#endif
#ifdef SkLONGLONG
for (i = 0; i < 100000; i++) {
SkFixed numer = rand.nextS();
SkFixed denom = rand.nextS();
SkFixed result = SkFixedDiv(numer, denom);
SkLONGLONG check = ((SkLONGLONG)numer << 16) / denom;
(void)SkCLZ(numer);
(void)SkCLZ(denom);
SkASSERT(result != (SkFixed)SK_NaN32);
if (check > SK_MaxS32) {
check = SK_MaxS32;
} else if (check < -SK_MaxS32) {
check = SK_MinS32;
}
SkASSERT(result == (int32_t)check);
result = SkFractDiv(numer, denom);
check = ((SkLONGLONG)numer << 30) / denom;
SkASSERT(result != (SkFixed)SK_NaN32);
if (check > SK_MaxS32) {
check = SK_MaxS32;
} else if (check < -SK_MaxS32) {
check = SK_MinS32;
}
SkASSERT(result == (int32_t)check);
// make them <= 2^24, so we don't overflow in fixmul
numer = numer << 8 >> 8;
denom = denom << 8 >> 8;
result = SkFixedMul(numer, denom);
SkFixed r2 = symmetric_fixmul(numer, denom);
// SkASSERT(result == r2);
result = SkFixedMul(numer, numer);
r2 = SkFixedSquare(numer);
SkASSERT(result == r2);
#ifdef SK_CAN_USE_FLOAT
if (numer >= 0 && denom >= 0) {
SkFixed mean = SkFixedMean(numer, denom);
float fm = sk_float_sqrt(sk_float_abs(SkFixedToFloat(numer) * SkFixedToFloat(denom)));
SkFixed mean2 = SkFloatToFixed(fm);
int diff = SkAbs32(mean - mean2);
SkASSERT(diff <= 1);
}
{
SkFixed mod = SkFixedMod(numer, denom);
float n = SkFixedToFloat(numer);
float d = SkFixedToFloat(denom);
float m = sk_float_mod(n, d);
#if 0
SkDebugf("%g mod %g = %g [%g]\n",
SkFixedToFloat(numer), SkFixedToFloat(denom),
SkFixedToFloat(mod), m);
#endif
SkASSERT(mod == 0 || (mod < 0) == (m < 0)); // ensure the same sign
int diff = SkAbs32(mod - SkFloatToFixed(m));
SkASSERT((diff >> 7) == 0);
}
#endif
}
#endif
#ifdef SK_CAN_USE_FLOAT
for (i = 0; i < 100000; i++) {
SkFract x = rand.nextU() >> 1;
double xx = (double)x / SK_Fract1;
SkFract xr = SkFractSqrt(x);
SkFract check = SkFloatToFract(sqrt(xx));
SkASSERT(xr == check || xr == check-1 || xr == check+1);
xr = SkFixedSqrt(x);
xx = (double)x / SK_Fixed1;
check = SkFloatToFixed(sqrt(xx));
SkASSERT(xr == check || xr == check-1);
xr = SkSqrt32(x);
xx = (double)x;
check = (int32_t)sqrt(xx);
SkASSERT(xr == check || xr == check-1);
}
#endif
#if !defined(SK_SCALAR_IS_FLOAT) && defined(SK_CAN_USE_FLOAT)
{
SkFixed s, c;
s = SkFixedSinCos(0, &c);
SkASSERT(s == 0);
SkASSERT(c == SK_Fixed1);
}
int maxDiff = 0;
for (i = 0; i < 10000; i++) {
SkFixed rads = rand.nextS() >> 10;
double frads = SkFixedToFloat(rads);
SkFixed s, c;
s = SkScalarSinCos(rads, &c);
double fs = sin(frads);
double fc = cos(frads);
SkFixed is = SkFloatToFixed(fs);
SkFixed ic = SkFloatToFixed(fc);
maxDiff = SkMax32(maxDiff, SkAbs32(is - s));
maxDiff = SkMax32(maxDiff, SkAbs32(ic - c));
}
SkDebugf("SinCos: maximum error = %d\n", maxDiff);
#endif
#endif
}
#endif

View File

@ -1606,85 +1606,3 @@ void SkMatrix::toDumpString(SkString* str) const {
#endif
}
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
void SkMatrix::UnitTest() {
#ifdef SK_SUPPORT_UNITTEST
SkMatrix mat, inverse, iden1, iden2;
mat.reset();
mat.setTranslate(SK_Scalar1, SK_Scalar1);
mat.invert(&inverse);
inverse.dump();
iden1.setConcat(mat, inverse);
iden1.dump();
mat.setScale(SkIntToScalar(2), SkIntToScalar(2));
mat.invert(&inverse);
inverse.dump();
iden1.setConcat(mat, inverse);
iden1.dump();
mat.setScale(SK_Scalar1/2, SK_Scalar1/2);
mat.invert(&inverse);
inverse.dump();
iden1.setConcat(mat, inverse);
iden1.dump();
SkASSERT(iden1.isIdentity());
mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
mat.postRotate(SkIntToScalar(25));
SkASSERT(mat.invert(NULL));
mat.invert(&inverse);
iden1.setConcat(mat, inverse);
iden2.setConcat(inverse, mat);
iden1.dump();
// SkASSERT(iden1.isIdentity());
iden2.dump();
// SkASSERT(iden2.isIdentity());
// rectStaysRect test
{
static const struct {
SkScalar m00, m01, m10, m11;
bool mStaysRect;
}
gRectStaysRectSamples[] = {
{ 0, 0, 0, 0, false },
{ 0, 0, 0, SK_Scalar1, false },
{ 0, 0, SK_Scalar1, 0, false },
{ 0, 0, SK_Scalar1, SK_Scalar1, false },
{ 0, SK_Scalar1, 0, 0, false },
{ 0, SK_Scalar1, 0, SK_Scalar1, false },
{ 0, SK_Scalar1, SK_Scalar1, 0, true },
{ 0, SK_Scalar1, SK_Scalar1, SK_Scalar1, false },
{ SK_Scalar1, 0, 0, 0, false },
{ SK_Scalar1, 0, 0, SK_Scalar1, true },
{ SK_Scalar1, 0, SK_Scalar1, 0, false },
{ SK_Scalar1, 0, SK_Scalar1, SK_Scalar1, false },
{ SK_Scalar1, SK_Scalar1, 0, 0, false },
{ SK_Scalar1, SK_Scalar1, 0, SK_Scalar1, false },
{ SK_Scalar1, SK_Scalar1, SK_Scalar1, 0, false },
{ SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, false }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
SkMatrix m;
m.reset();
m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
m.set(SkMatrix::kMSkewX, gRectStaysRectSamples[i].m01);
m.set(SkMatrix::kMSkewY, gRectStaysRectSamples[i].m10);
m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
SkASSERT(m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
}
}
#endif
}
#endif

View File

@ -458,126 +458,3 @@ SkAutoMemoryUsageProbe::~SkAutoMemoryUsageProbe()
#endif
}
////////////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
#include "SkRandom.h"
#include "SkTSearch.h"
#include "SkTSort.h"
#define kSEARCH_COUNT 91
#ifdef SK_SUPPORT_UNITTEST
static void test_search()
{
int i, array[kSEARCH_COUNT];
SkRandom rand;
for (i = 0; i < kSEARCH_COUNT; i++)
array[i] = rand.nextS();
SkTHeapSort<int>(array, kSEARCH_COUNT);
// make sure we got sorted properly
for (i = 1; i < kSEARCH_COUNT; i++)
SkASSERT(array[i-1] <= array[i]);
// make sure we can find all of our values
for (i = 0; i < kSEARCH_COUNT; i++)
{
int index = SkTSearch<int>(array, kSEARCH_COUNT, array[i], sizeof(int));
SkASSERT(index == i);
}
// make sure that random values are either found, or the correct
// insertion index is returned
for (i = 0; i < 10000; i++)
{
int value = rand.nextS();
int index = SkTSearch<int>(array, kSEARCH_COUNT, value, sizeof(int));
if (index >= 0)
SkASSERT(index < kSEARCH_COUNT && array[index] == value);
else
{
index = ~index;
SkASSERT(index <= kSEARCH_COUNT);
if (index < kSEARCH_COUNT)
{
SkASSERT(value < array[index]);
if (index > 0)
SkASSERT(value > array[index - 1]);
}
else // we should append the new value
{
SkASSERT(value > array[kSEARCH_COUNT - 1]);
}
}
}
}
static void test_utf16()
{
static const SkUnichar gUni[] = {
0x10000, 0x18080, 0x20202, 0xFFFFF, 0x101234
};
uint16_t buf[2];
for (unsigned i = 0; i < SK_ARRAY_COUNT(gUni); i++)
{
size_t count = SkUTF16_FromUnichar(gUni[i], buf);
SkASSERT(count == 2);
size_t count2 = SkUTF16_CountUnichars(buf, 2);
SkASSERT(count2 == 1);
const uint16_t* ptr = buf;
SkUnichar c = SkUTF16_NextUnichar(&ptr);
SkASSERT(c == gUni[i]);
SkASSERT(ptr - buf == 2);
}
}
#endif
void SkUtils::UnitTest()
{
#ifdef SK_SUPPORT_UNITTEST
static const struct {
const char* fUtf8;
SkUnichar fUni;
} gTest[] = {
{ "a", 'a' },
{ "\x7f", 0x7f },
{ "\xC2\x80", 0x80 },
{ "\xC3\x83", (3 << 6) | 3 },
{ "\xDF\xBF", 0x7ff },
{ "\xE0\xA0\x80", 0x800 },
{ "\xE0\xB0\xB8", 0xC38 },
{ "\xE3\x83\x83", (3 << 12) | (3 << 6) | 3 },
{ "\xEF\xBF\xBF", 0xFFFF },
{ "\xF0\x90\x80\x80", 0x10000 },
{ "\xF3\x83\x83\x83", (3 << 18) | (3 << 12) | (3 << 6) | 3 }
};
for (unsigned i = 0; i < SK_ARRAY_COUNT(gTest); i++)
{
const char* p = gTest[i].fUtf8;
int n = SkUTF8_CountUnichars(p);
SkUnichar u0 = SkUTF8_ToUnichar(gTest[i].fUtf8);
SkUnichar u1 = SkUTF8_NextUnichar(&p);
SkASSERT(n == 1);
SkASSERT(u0 == u1);
SkASSERT(u0 == gTest[i].fUni);
SkASSERT(p - gTest[i].fUtf8 == (int)strlen(gTest[i].fUtf8));
}
test_utf16();
test_search();
#endif
}
#endif

400
tests/MathTest.cpp Normal file
View File

@ -0,0 +1,400 @@
#include "Test.h"
#include "SkPoint.h"
#include "SkRandom.h"
#if defined(SkLONGLONG)
static int symmetric_fixmul(int a, int b) {
int sa = SkExtractSign(a);
int sb = SkExtractSign(b);
a = SkApplySign(a, sa);
b = SkApplySign(b, sb);
#if 1
int c = (int)(((SkLONGLONG)a * b) >> 16);
return SkApplySign(c, sa ^ sb);
#else
SkLONGLONG ab = (SkLONGLONG)a * b;
if (sa ^ sb) {
ab = -ab;
}
return ab >> 16;
#endif
}
#endif
static void check_length(skiatest::Reporter* reporter,
const SkPoint& p, SkScalar targetLen) {
#ifdef SK_CAN_USE_FLOAT
float x = SkScalarToFloat(p.fX);
float y = SkScalarToFloat(p.fY);
float len = sk_float_sqrt(x*x + y*y);
len /= SkScalarToFloat(targetLen);
REPORTER_ASSERT(reporter, len > 0.999f && len < 1.001f);
#endif
}
#if defined(SK_CAN_USE_FLOAT)
static float nextFloat(SkRandom& rand) {
SkFloatIntUnion data;
data.fSignBitInt = rand.nextU();
return data.fFloat;
}
/* returns true if a == b as resulting from (int)x. Since it is undefined
what to do if the float exceeds 2^32-1, we check for that explicitly.
*/
static bool equal_float_native_skia(float x, uint32_t ni, uint32_t si) {
if (!(x == x)) { // NAN
return si == SK_MaxS32 || si == SK_MinS32;
}
// for out of range, C is undefined, but skia always should return NaN32
if (x > SK_MaxS32) {
return si == SK_MaxS32;
}
if (x < -SK_MaxS32) {
return si == SK_MinS32;
}
return si == ni;
}
static void assert_float_equal(skiatest::Reporter* reporter, const char op[],
float x, uint32_t ni, uint32_t si) {
if (!equal_float_native_skia(x, ni, si)) {
SkString desc;
desc.printf("%s float %g bits %x native %x skia %x\n", op, x, ni, si);
reporter->reportFailed(desc);
}
}
static void test_float_cast(skiatest::Reporter* reporter, float x) {
int ix = (int)x;
int iix = SkFloatToIntCast(x);
assert_float_equal(reporter, "cast", x, ix, iix);
}
static void test_float_floor(skiatest::Reporter* reporter, float x) {
int ix = (int)floor(x);
int iix = SkFloatToIntFloor(x);
assert_float_equal(reporter, "floor", x, ix, iix);
}
static void test_float_round(skiatest::Reporter* reporter, float x) {
double xx = x + 0.5; // need intermediate double to avoid temp loss
int ix = (int)floor(xx);
int iix = SkFloatToIntRound(x);
assert_float_equal(reporter, "round", x, ix, iix);
}
static void test_float_ceil(skiatest::Reporter* reporter, float x) {
int ix = (int)ceil(x);
int iix = SkFloatToIntCeil(x);
assert_float_equal(reporter, "ceil", x, ix, iix);
}
static void test_float_conversions(skiatest::Reporter* reporter, float x) {
test_float_cast(reporter, x);
test_float_floor(reporter, x);
test_float_round(reporter, x);
test_float_ceil(reporter, x);
}
static void test_int2float(skiatest::Reporter* reporter, int ival) {
float x0 = (float)ival;
float x1 = SkIntToFloatCast(ival);
float x2 = SkIntToFloatCast_NoOverflowCheck(ival);
REPORTER_ASSERT(reporter, x0 == x1);
REPORTER_ASSERT(reporter, x0 == x2);
}
static void unittest_fastfloat(skiatest::Reporter* reporter) {
SkRandom rand;
size_t i;
static const float gFloats[] = {
0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3,
0.000000001f, 1000000000.f, // doesn't overflow
0.0000000001f, 10000000000.f // does overflow
};
for (i = 0; i < SK_ARRAY_COUNT(gFloats); i++) {
// SkDebugf("---- test floats %g %d\n", gFloats[i], (int)gFloats[i]);
test_float_conversions(reporter, gFloats[i]);
test_float_conversions(reporter, -gFloats[i]);
}
for (int outer = 0; outer < 100; outer++) {
rand.setSeed(outer);
for (i = 0; i < 100000; i++) {
float x = nextFloat(rand);
test_float_conversions(reporter, x);
}
test_int2float(reporter, 0);
test_int2float(reporter, 1);
test_int2float(reporter, -1);
for (i = 0; i < 100000; i++) {
// for now only test ints that are 24bits or less, since we don't
// round (down) large ints the same as IEEE...
int ival = rand.nextU() & 0xFFFFFF;
test_int2float(reporter, ival);
test_int2float(reporter, -ival);
}
}
}
#endif
static void test_muldiv255(skiatest::Reporter* reporter) {
#ifdef SK_CAN_USE_FLOAT
for (int a = 0; a <= 255; a++) {
for (int b = 0; b <= 255; b++) {
int ab = a * b;
float s = ab / 255.0f;
int round = (int)floorf(s + 0.5f);
int trunc = (int)floorf(s);
int iround = SkMulDiv255Round(a, b);
int itrunc = SkMulDiv255Trunc(a, b);
REPORTER_ASSERT(reporter, iround == round);
REPORTER_ASSERT(reporter, itrunc == trunc);
REPORTER_ASSERT(reporter, itrunc <= iround);
REPORTER_ASSERT(reporter, iround <= a);
REPORTER_ASSERT(reporter, iround <= b);
}
}
#endif
}
static void TestMath(skiatest::Reporter* reporter) {
int i;
int32_t x;
SkRandom rand;
// these should not assert
SkToS8(127); SkToS8(-128); SkToU8(255);
SkToS16(32767); SkToS16(-32768); SkToU16(65535);
SkToS32(2*1024*1024); SkToS32(-2*1024*1024); SkToU32(4*1024*1024);
// these should assert
#if 0
SkToS8(128);
SkToS8(-129);
SkToU8(256);
SkToU8(-5);
SkToS16(32768);
SkToS16(-32769);
SkToU16(65536);
SkToU16(-5);
if (sizeof(size_t) > 4) {
SkToS32(4*1024*1024);
SkToS32(-4*1024*1024);
SkToU32(5*1024*1024);
SkToU32(-5);
}
#endif
test_muldiv255(reporter);
{
SkScalar x = SK_ScalarNaN;
REPORTER_ASSERT(reporter, SkScalarIsNaN(x));
}
for (i = 1; i <= 10; i++) {
x = SkCubeRootBits(i*i*i, 11);
REPORTER_ASSERT(reporter, x == i);
}
REPORTER_ASSERT(reporter, !"test the reporter");
x = SkFixedSqrt(SK_Fixed1);
REPORTER_ASSERT(reporter, x == SK_Fixed1);
x = SkFixedSqrt(SK_Fixed1/4);
REPORTER_ASSERT(reporter, x == SK_Fixed1/2);
x = SkFixedSqrt(SK_Fixed1*4);
REPORTER_ASSERT(reporter, x == SK_Fixed1*2);
x = SkFractSqrt(SK_Fract1);
REPORTER_ASSERT(reporter, x == SK_Fract1);
x = SkFractSqrt(SK_Fract1/4);
REPORTER_ASSERT(reporter, x == SK_Fract1/2);
x = SkFractSqrt(SK_Fract1/16);
REPORTER_ASSERT(reporter, x == SK_Fract1/4);
for (i = 1; i < 100; i++) {
x = SkFixedSqrt(SK_Fixed1 * i * i);
REPORTER_ASSERT(reporter, x == SK_Fixed1 * i);
}
for (i = 0; i < 1000; i++) {
int value = rand.nextS16();
int max = rand.nextU16();
int clamp = SkClampMax(value, max);
int clamp2 = value < 0 ? 0 : (value > max ? max : value);
REPORTER_ASSERT(reporter, clamp == clamp2);
}
for (i = 0; i < 100000; i++) {
SkPoint p;
p.setLength(rand.nextS(), rand.nextS(), SK_Scalar1);
check_length(reporter, p, SK_Scalar1);
p.setLength(rand.nextS() >> 13, rand.nextS() >> 13, SK_Scalar1);
check_length(reporter, p, SK_Scalar1);
}
{
SkFixed result = SkFixedDiv(100, 100);
REPORTER_ASSERT(reporter, result == SK_Fixed1);
result = SkFixedDiv(1, SK_Fixed1);
REPORTER_ASSERT(reporter, result == 1);
}
#ifdef SK_CAN_USE_FLOAT
unittest_fastfloat(reporter);
#endif
#ifdef SkLONGLONG
for (i = 0; i < 100000; i++) {
SkFixed numer = rand.nextS();
SkFixed denom = rand.nextS();
SkFixed result = SkFixedDiv(numer, denom);
SkLONGLONG check = ((SkLONGLONG)numer << 16) / denom;
(void)SkCLZ(numer);
(void)SkCLZ(denom);
REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
if (check > SK_MaxS32) {
check = SK_MaxS32;
} else if (check < -SK_MaxS32) {
check = SK_MinS32;
}
REPORTER_ASSERT(reporter, result == (int32_t)check);
result = SkFractDiv(numer, denom);
check = ((SkLONGLONG)numer << 30) / denom;
REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
if (check > SK_MaxS32) {
check = SK_MaxS32;
} else if (check < -SK_MaxS32) {
check = SK_MinS32;
}
REPORTER_ASSERT(reporter, result == (int32_t)check);
// make them <= 2^24, so we don't overflow in fixmul
numer = numer << 8 >> 8;
denom = denom << 8 >> 8;
result = SkFixedMul(numer, denom);
SkFixed r2 = symmetric_fixmul(numer, denom);
// SkASSERT(result == r2);
result = SkFixedMul(numer, numer);
r2 = SkFixedSquare(numer);
REPORTER_ASSERT(reporter, result == r2);
#ifdef SK_CAN_USE_FLOAT
if (numer >= 0 && denom >= 0) {
SkFixed mean = SkFixedMean(numer, denom);
float fm = sk_float_sqrt(sk_float_abs(SkFixedToFloat(numer) * SkFixedToFloat(denom)));
SkFixed mean2 = SkFloatToFixed(fm);
int diff = SkAbs32(mean - mean2);
REPORTER_ASSERT(reporter, diff <= 1);
}
{
SkFixed mod = SkFixedMod(numer, denom);
float n = SkFixedToFloat(numer);
float d = SkFixedToFloat(denom);
float m = sk_float_mod(n, d);
REPORTER_ASSERT(reporter, mod == 0 || (mod < 0) == (m < 0)); // ensure the same sign
int diff = SkAbs32(mod - SkFloatToFixed(m));
REPORTER_ASSERT(reporter, (diff >> 7) == 0);
}
#endif
}
#endif
#ifdef SK_CAN_USE_FLOAT
for (i = 0; i < 100000; i++) {
SkFract x = rand.nextU() >> 1;
double xx = (double)x / SK_Fract1;
SkFract xr = SkFractSqrt(x);
SkFract check = SkFloatToFract(sqrt(xx));
REPORTER_ASSERT(reporter, xr == check || xr == check-1 || xr == check+1);
xr = SkFixedSqrt(x);
xx = (double)x / SK_Fixed1;
check = SkFloatToFixed(sqrt(xx));
REPORTER_ASSERT(reporter, xr == check || xr == check-1);
xr = SkSqrt32(x);
xx = (double)x;
check = (int32_t)sqrt(xx);
REPORTER_ASSERT(reporter, xr == check || xr == check-1);
}
#endif
#if !defined(SK_SCALAR_IS_FLOAT) && defined(SK_CAN_USE_FLOAT)
{
SkFixed s, c;
s = SkFixedSinCos(0, &c);
REPORTER_ASSERT(reporter, s == 0);
REPORTER_ASSERT(reporter, c == SK_Fixed1);
}
int maxDiff = 0;
for (i = 0; i < 10000; i++) {
SkFixed rads = rand.nextS() >> 10;
double frads = SkFixedToFloat(rads);
SkFixed s, c;
s = SkScalarSinCos(rads, &c);
double fs = sin(frads);
double fc = cos(frads);
SkFixed is = SkFloatToFixed(fs);
SkFixed ic = SkFloatToFixed(fc);
maxDiff = SkMax32(maxDiff, SkAbs32(is - s));
maxDiff = SkMax32(maxDiff, SkAbs32(ic - c));
}
SkDebugf("SinCos: maximum error = %d\n", maxDiff);
#endif
}
///////////////////////////////////////////////////////////////////////////////
namespace skiatest {
class MathTest : public Test {
public:
static Test* Factory(void*) {
return SkNEW(MathTest);
}
protected:
virtual void onGetName(SkString* name) {
name->set("Math");
}
virtual void onRun(Reporter* reporter) {
TestMath(reporter);
}
};
static TestRegistry gReg(MathTest::Factory);
}

119
tests/MatrixTest.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "Test.h"
#include "SkMatrix.h"
static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
#ifdef SK_SCALAR_IS_FLOAT
const float tolerance = 0.000005f;
#else
const int32_t tolerance = 3;
#endif
return SkScalarAbs(a - b) <= tolerance;
}
static bool nearly_equal(const SkMatrix& a, const SkMatrix& b) {
for (int i = 0; i < 9; i++) {
if (!nearly_equal_scalar(a[i], b[i])) {
printf("not equal %g %g\n", a[i], b[i]);
return false;
}
}
return true;
}
static bool is_identity(const SkMatrix& m) {
SkMatrix identity;
identity.reset();
return nearly_equal(m, identity);
}
void TestMatrix(skiatest::Reporter* reporter) {
SkMatrix mat, inverse, iden1, iden2;
mat.reset();
mat.setTranslate(SK_Scalar1, SK_Scalar1);
mat.invert(&inverse);
iden1.setConcat(mat, inverse);
REPORTER_ASSERT(reporter, is_identity(iden1));
mat.setScale(SkIntToScalar(2), SkIntToScalar(2));
mat.invert(&inverse);
iden1.setConcat(mat, inverse);
REPORTER_ASSERT(reporter, is_identity(iden1));
mat.setScale(SK_Scalar1/2, SK_Scalar1/2);
mat.invert(&inverse);
iden1.setConcat(mat, inverse);
REPORTER_ASSERT(reporter, is_identity(iden1));
mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
mat.postRotate(SkIntToScalar(25));
REPORTER_ASSERT(reporter, mat.invert(NULL));
mat.invert(&inverse);
iden1.setConcat(mat, inverse);
REPORTER_ASSERT(reporter, is_identity(iden1));
iden2.setConcat(inverse, mat);
REPORTER_ASSERT(reporter, is_identity(iden2));
// rectStaysRect test
{
static const struct {
SkScalar m00, m01, m10, m11;
bool mStaysRect;
}
gRectStaysRectSamples[] = {
{ 0, 0, 0, 0, false },
{ 0, 0, 0, SK_Scalar1, false },
{ 0, 0, SK_Scalar1, 0, false },
{ 0, 0, SK_Scalar1, SK_Scalar1, false },
{ 0, SK_Scalar1, 0, 0, false },
{ 0, SK_Scalar1, 0, SK_Scalar1, false },
{ 0, SK_Scalar1, SK_Scalar1, 0, true },
{ 0, SK_Scalar1, SK_Scalar1, SK_Scalar1, false },
{ SK_Scalar1, 0, 0, 0, false },
{ SK_Scalar1, 0, 0, SK_Scalar1, true },
{ SK_Scalar1, 0, SK_Scalar1, 0, false },
{ SK_Scalar1, 0, SK_Scalar1, SK_Scalar1, false },
{ SK_Scalar1, SK_Scalar1, 0, 0, false },
{ SK_Scalar1, SK_Scalar1, 0, SK_Scalar1, false },
{ SK_Scalar1, SK_Scalar1, SK_Scalar1, 0, false },
{ SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, false }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
SkMatrix m;
m.reset();
m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
m.set(SkMatrix::kMSkewX, gRectStaysRectSamples[i].m01);
m.set(SkMatrix::kMSkewY, gRectStaysRectSamples[i].m10);
m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
REPORTER_ASSERT(reporter,
m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
}
}
}
///////////////////////////////////////////////////////////////////////////////
namespace skiatest {
class MatrixTest : public Test {
public:
static Test* Factory(void*) {
return SkNEW(MatrixTest);
}
protected:
virtual void onGetName(SkString* name) {
name->set("Matrix");
}
virtual void onRun(Reporter* reporter) {
TestMatrix(reporter);
}
};
static TestRegistry gReg(MatrixTest::Factory);
}

144
tests/PackBitsTest.cpp Normal file
View File

@ -0,0 +1,144 @@
#include "Test.h"
#include "SkPackBits.h"
static const uint16_t gTest0[] = { 0, 0, 1, 1 };
static const uint16_t gTest1[] = { 1, 2, 3, 4, 5, 6 };
static const uint16_t gTest2[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
static const uint16_t gTest3[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
#include "SkRandom.h"
static SkRandom gRand;
static void rand_fill(uint16_t buffer[], int count) {
for (int i = 0; i < count; i++)
buffer[i] = (uint16_t)gRand.nextU();
}
static void test_pack16(skiatest::Reporter* reporter) {
static const struct {
const uint16_t* fSrc;
int fCount;
} gTests[] = {
{ gTest0, SK_ARRAY_COUNT(gTest0) },
{ gTest1, SK_ARRAY_COUNT(gTest1) },
{ gTest2, SK_ARRAY_COUNT(gTest2) },
{ gTest3, SK_ARRAY_COUNT(gTest3) }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); i++) {
uint8_t dst[100];
size_t dstSize = SkPackBits::Pack16(gTests[i].fSrc,
gTests[i].fCount, dst);
uint16_t src[100];
int srcCount = SkPackBits::Unpack16(dst, dstSize, src);
bool match = gTests[i].fCount == srcCount && memcmp(gTests[i].fSrc, src,
gTests[i].fCount * sizeof(uint16_t)) == 0;
REPORTER_ASSERT(reporter, match);
}
for (int n = 1000; n; n--) {
size_t size = 50;
uint16_t src[100], src2[100];
uint8_t dst[200];
rand_fill(src, size);
size_t dstSize = SkPackBits::Pack16(src, size, dst);
size_t maxSize = SkPackBits::ComputeMaxSize16(size);
REPORTER_ASSERT(reporter, maxSize >= dstSize);
int srcCount = SkPackBits::Unpack16(dst, dstSize, src2);
REPORTER_ASSERT(reporter, size == srcCount);
bool match = memcmp(src, src2, size * sizeof(uint16_t)) == 0;
REPORTER_ASSERT(reporter, match);
}
}
static const uint8_t gTest80[] = { 0, 0, 1, 1 };
static const uint8_t gTest81[] = { 1, 2, 3, 4, 5, 6 };
static const uint8_t gTest82[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
static const uint8_t gTest83[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
static const uint8_t gTest84[] = { 1, 0, 3, 0, 0, 0, 2, 1, 1, 2 };
static void rand_fill(uint8_t buffer[], int count) {
for (int i = 0; i < count; i++)
buffer[i] = (uint8_t)((gRand.nextU() >> 8) & 0x3);
}
static void test_pack8(skiatest::Reporter* reporter) {
static const struct {
const uint8_t* fSrc;
int fCount;
} gTests[] = {
{ gTest80, SK_ARRAY_COUNT(gTest80) },
{ gTest81, SK_ARRAY_COUNT(gTest81) },
{ gTest82, SK_ARRAY_COUNT(gTest82) },
{ gTest83, SK_ARRAY_COUNT(gTest83) },
{ gTest84, SK_ARRAY_COUNT(gTest84) }
};
for (size_t i = 4; i < SK_ARRAY_COUNT(gTests); i++) {
uint8_t dst[100];
size_t maxSize = SkPackBits::ComputeMaxSize8(gTests[i].fCount);
size_t dstSize = SkPackBits::Pack8(gTests[i].fSrc,
gTests[i].fCount, dst);
REPORTER_ASSERT(reporter, dstSize <= maxSize);
uint8_t src[100];
int srcCount = SkPackBits::Unpack8(dst, dstSize, src);
bool match = gTests[i].fCount == srcCount &&
memcmp(gTests[i].fSrc, src,
gTests[i].fCount * sizeof(uint8_t)) == 0;
REPORTER_ASSERT(reporter, match);
}
for (size_t size = 1; size <= 512; size += 1) {
for (int n = 200; n; n--) {
uint8_t src[600], src2[600];
uint8_t dst[600];
rand_fill(src, size);
size_t dstSize = SkPackBits::Pack8(src, size, dst);
size_t maxSize = SkPackBits::ComputeMaxSize8(size);
REPORTER_ASSERT(reporter, maxSize >= dstSize);
int srcCount = SkPackBits::Unpack8(dst, dstSize, src2);
REPORTER_ASSERT(reporter, size == srcCount);
bool match = memcmp(src, src2, size * sizeof(uint8_t)) == 0;
REPORTER_ASSERT(reporter, match);
for (int j = 0; j < 200; j++) {
size_t skip = gRand.nextU() % size;
size_t write = gRand.nextU() % size;
if (skip + write > size) {
write = size - skip;
}
SkPackBits::Unpack8(src, skip, write, dst);
bool match = memcmp(src, src2 + skip, write) == 0;
REPORTER_ASSERT(reporter, match);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
namespace skiatest {
class PackBitsTest : public Test {
public:
static Test* Factory(void*) {
return SkNEW(PackBitsTest);
}
protected:
virtual void onGetName(SkString* name) {
name->set("PackBits");
}
virtual void onRun(Reporter* reporter) {
test_pack8(reporter);
test_pack16(reporter);
}
};
static TestRegistry gReg(PackBitsTest::Factory);
}

60
tests/Test.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "Test.h"
using namespace skiatest;
Reporter::Reporter() {
this->resetReporting();
}
void Reporter::resetReporting() {
fCurrTest = NULL;
fTestCount = 0;
bzero(fResultCount, sizeof(fResultCount));
}
void Reporter::startTest(Test* test) {
SkASSERT(NULL == fCurrTest);
fCurrTest = test;
this->onStart(test);
fTestCount += 1;
}
void Reporter::report(const char desc[], Result result) {
if (NULL == desc) {
desc = "<no description>";
}
this->onReport(desc, result);
fResultCount[result] += 1;
}
void Reporter::endTest(Test* test) {
SkASSERT(test == fCurrTest);
this->onEnd(test);
fCurrTest = NULL;
}
///////////////////////////////////////////////////////////////////////////////
Test::Test() : fReporter(NULL) {}
Test::~Test() {
fReporter->safeUnref();
}
void Test::setReporter(Reporter* r) {
SkRefCnt_SafeAssign(fReporter, r);
}
const char* Test::getName() {
if (fName.size() == 0) {
this->onGetName(&fName);
}
return fName.c_str();
}
void Test::run() {
fReporter->startTest(this);
this->onRun(fReporter);
fReporter->endTest(this);
}

98
tests/Test.h Normal file
View File

@ -0,0 +1,98 @@
#ifndef skiatest_Test_DEFINED
#define skiatest_Test_DEFINED
#include "SkRefCnt.h"
#include "SkString.h"
#include "SkTRegistry.h"
namespace skiatest {
class Test;
class Reporter : public SkRefCnt {
public:
Reporter();
enum Result {
kPassed, // must begin with 0
kFailed,
/////
kLastResult = kFailed
};
void resetReporting();
int countTests() const { return fTestCount; }
int countResults(Result r) {
SkASSERT((unsigned)r <= kLastResult);
return fResultCount[r];
}
void startTest(Test*);
void report(const char testDesc[], Result);
void endTest(Test*);
// helpers for tests
void assertTrue(bool cond, const char desc[]) {
if (!cond) {
this->report(desc, kFailed);
}
}
void assertFalse(bool cond, const char desc[]) {
if (cond) {
this->report(desc, kFailed);
}
}
void reportFailed(const char desc[]) {
this->report(desc, kFailed);
}
void reportFailed(const SkString& desc) {
this->report(desc.c_str(), kFailed);
}
protected:
virtual void onStart(Test*) {}
virtual void onReport(const char desc[], Result) {}
virtual void onEnd(Test*) {}
private:
Test* fCurrTest;
int fTestCount;
int fResultCount[kLastResult+1];
typedef SkRefCnt INHERITED;
};
class Test {
public:
Test();
virtual ~Test();
Reporter* getReporter() const { return fReporter; }
void setReporter(Reporter*);
const char* getName();
void run();
protected:
virtual void onGetName(SkString*) = 0;
virtual void onRun(Reporter*) = 0;
private:
Reporter* fReporter;
SkString fName;
};
typedef SkTRegistry<Test*, void*> TestRegistry;
}
#define REPORTER_ASSERT(r, cond) \
do { \
if (!(cond)) { \
SkString desc; \
desc.printf("%s:%d: %s", __FILE__, __LINE__, #cond); \
r->reportFailed(desc); \
} \
} while(0)
#endif

View File

@ -0,0 +1,333 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 44;
objects = {
/* Begin PBXBuildFile section */
00857F860F56F8EE0078BE26 /* libcore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00857F730F56F71B0078BE26 /* libcore.a */; };
00857F920F56F9170078BE26 /* libmaccore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00857F910F56F9150078BE26 /* libmaccore.a */; };
00857FAA0F56F9620078BE26 /* Test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00857FA80F56F9620078BE26 /* Test.cpp */; };
00857FAB0F56F9620078BE26 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00857FA90F56F9620078BE26 /* main.cpp */; };
00857FB70F56FD340078BE26 /* MathTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00857FB60F56FD340078BE26 /* MathTest.cpp */; };
008634DC0F579B7A0044DA64 /* PackBitsTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 008634DB0F579B7A0044DA64 /* PackBitsTest.cpp */; };
008634F10F579E410044DA64 /* MatrixTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 008634F00F579E410044DA64 /* MatrixTest.cpp */; };
0086350F0F57A3140044DA64 /* UtilsTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0086350E0F57A3140044DA64 /* UtilsTest.cpp */; };
8DD76F6A0486A84900D96B5E /* Tests.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859E8B029090EE04C91782 /* Tests.1 */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
00857F720F56F71B0078BE26 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00857F6B0F56F71B0078BE26 /* core.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = D2AAC046055464E500DB518D;
remoteInfo = core;
};
00857F900F56F9150078BE26 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00857F890F56F9150078BE26 /* maccore.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = D2AAC046055464E500DB518D;
remoteInfo = maccore;
};
0086351C0F57A51A0044DA64 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00857F6B0F56F71B0078BE26 /* core.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = D2AAC045055464E500DB518D /* core */;
remoteInfo = core;
};
0086351E0F57A5200044DA64 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00857F890F56F9150078BE26 /* maccore.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = D2AAC045055464E500DB518D /* maccore */;
remoteInfo = maccore;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
8DD76F690486A84900D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
8DD76F6A0486A84900D96B5E /* Tests.1 in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
00857F630F56F4220078BE26 /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Test.h; path = ../Test.h; sourceTree = SOURCE_ROOT; };
00857F6B0F56F71B0078BE26 /* core.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = core.xcodeproj; path = ../../xcode/core/core.xcodeproj; sourceTree = SOURCE_ROOT; };
00857F890F56F9150078BE26 /* maccore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = maccore.xcodeproj; path = ../../xcode/maccore/maccore.xcodeproj; sourceTree = SOURCE_ROOT; };
00857FA80F56F9620078BE26 /* Test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Test.cpp; path = ../Test.cpp; sourceTree = SOURCE_ROOT; };
00857FA90F56F9620078BE26 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../main.cpp; sourceTree = SOURCE_ROOT; };
00857FB60F56FD340078BE26 /* MathTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MathTest.cpp; path = ../MathTest.cpp; sourceTree = SOURCE_ROOT; };
008634DB0F579B7A0044DA64 /* PackBitsTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PackBitsTest.cpp; path = ../PackBitsTest.cpp; sourceTree = SOURCE_ROOT; };
008634F00F579E410044DA64 /* MatrixTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MatrixTest.cpp; path = ../MatrixTest.cpp; sourceTree = SOURCE_ROOT; };
0086350E0F57A3140044DA64 /* UtilsTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UtilsTest.cpp; path = ../UtilsTest.cpp; sourceTree = SOURCE_ROOT; };
8DD76F6C0486A84900D96B5E /* Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Tests; sourceTree = BUILT_PRODUCTS_DIR; };
C6859E8B029090EE04C91782 /* Tests.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = Tests.1; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8DD76F660486A84900D96B5E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
00857F860F56F8EE0078BE26 /* libcore.a in Frameworks */,
00857F920F56F9170078BE26 /* libmaccore.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00857F6C0F56F71B0078BE26 /* Products */ = {
isa = PBXGroup;
children = (
00857F730F56F71B0078BE26 /* libcore.a */,
);
name = Products;
sourceTree = "<group>";
};
00857F8A0F56F9150078BE26 /* Products */ = {
isa = PBXGroup;
children = (
00857F910F56F9150078BE26 /* libmaccore.a */,
);
name = Products;
sourceTree = "<group>";
};
08FB7794FE84155DC02AAC07 /* Tests */ = {
isa = PBXGroup;
children = (
00857F890F56F9150078BE26 /* maccore.xcodeproj */,
00857F6B0F56F71B0078BE26 /* core.xcodeproj */,
08FB7795FE84155DC02AAC07 /* Source */,
C6859E8C029090F304C91782 /* Documentation */,
1AB674ADFE9D54B511CA2CBB /* Products */,
);
name = Tests;
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
00857FA80F56F9620078BE26 /* Test.cpp */,
00857FA90F56F9620078BE26 /* main.cpp */,
00857F630F56F4220078BE26 /* Test.h */,
00857FB60F56FD340078BE26 /* MathTest.cpp */,
0086350E0F57A3140044DA64 /* UtilsTest.cpp */,
008634F00F579E410044DA64 /* MatrixTest.cpp */,
008634DB0F579B7A0044DA64 /* PackBitsTest.cpp */,
);
name = Source;
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8DD76F6C0486A84900D96B5E /* Tests */,
);
name = Products;
sourceTree = "<group>";
};
C6859E8C029090F304C91782 /* Documentation */ = {
isa = PBXGroup;
children = (
C6859E8B029090EE04C91782 /* Tests.1 */,
);
name = Documentation;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8DD76F620486A84900D96B5E /* Tests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "Tests" */;
buildPhases = (
8DD76F640486A84900D96B5E /* Sources */,
8DD76F660486A84900D96B5E /* Frameworks */,
8DD76F690486A84900D96B5E /* CopyFiles */,
);
buildRules = (
);
dependencies = (
0086351D0F57A51A0044DA64 /* PBXTargetDependency */,
0086351F0F57A5200044DA64 /* PBXTargetDependency */,
);
name = Tests;
productInstallPath = "$(HOME)/bin";
productName = Tests;
productReference = 8DD76F6C0486A84900D96B5E /* Tests */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "Tests" */;
compatibilityVersion = "Xcode 3.0";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* Tests */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 00857F6C0F56F71B0078BE26 /* Products */;
ProjectRef = 00857F6B0F56F71B0078BE26 /* core.xcodeproj */;
},
{
ProductGroup = 00857F8A0F56F9150078BE26 /* Products */;
ProjectRef = 00857F890F56F9150078BE26 /* maccore.xcodeproj */;
},
);
projectRoot = "";
targets = (
8DD76F620486A84900D96B5E /* Tests */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
00857F730F56F71B0078BE26 /* libcore.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libcore.a;
remoteRef = 00857F720F56F71B0078BE26 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
00857F910F56F9150078BE26 /* libmaccore.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libmaccore.a;
remoteRef = 00857F900F56F9150078BE26 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXSourcesBuildPhase section */
8DD76F640486A84900D96B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00857FAA0F56F9620078BE26 /* Test.cpp in Sources */,
00857FAB0F56F9620078BE26 /* main.cpp in Sources */,
00857FB70F56FD340078BE26 /* MathTest.cpp in Sources */,
008634DC0F579B7A0044DA64 /* PackBitsTest.cpp in Sources */,
008634F10F579E410044DA64 /* MatrixTest.cpp in Sources */,
0086350F0F57A3140044DA64 /* UtilsTest.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
0086351D0F57A51A0044DA64 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = core;
targetProxy = 0086351C0F57A51A0044DA64 /* PBXContainerItemProxy */;
};
0086351F0F57A5200044DA64 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = maccore;
targetProxy = 0086351E0F57A5200044DA64 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
1DEB923208733DC60010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"_GLIBCXX_DEBUG=1",
"_GLIBCXX_DEBUG_PEDANTIC=1",
);
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = Tests;
};
name = Debug;
};
1DEB923308733DC60010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = Tests;
};
name = Release;
};
1DEB923608733DC60010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "../../../**";
ONLY_ACTIVE_ARCH = NO;
PREBINDING = NO;
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk";
VALID_ARCHS = "i386 x86_64";
};
name = Debug;
};
1DEB923708733DC60010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH)";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "../../../**";
ONLY_ACTIVE_ARCH = NO;
PREBINDING = NO;
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk";
VALID_ARCHS = "i386 x86_64";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB923208733DC60010E9CD /* Debug */,
1DEB923308733DC60010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB923608733DC60010E9CD /* Debug */,
1DEB923708733DC60010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}

130
tests/UtilsTest.cpp Normal file
View File

@ -0,0 +1,130 @@
#include "Test.h"
#include "SkRandom.h"
#include "SkTSearch.h"
#include "SkTSort.h"
#include "SkUtils.h"
#define kSEARCH_COUNT 91
static void test_search(skiatest::Reporter* reporter) {
int i, array[kSEARCH_COUNT];
SkRandom rand;
for (i = 0; i < kSEARCH_COUNT; i++) {
array[i] = rand.nextS();
}
SkTHeapSort<int>(array, kSEARCH_COUNT);
// make sure we got sorted properly
for (i = 1; i < kSEARCH_COUNT; i++) {
REPORTER_ASSERT(reporter, array[i-1] <= array[i]);
}
// make sure we can find all of our values
for (i = 0; i < kSEARCH_COUNT; i++) {
int index = SkTSearch<int>(array, kSEARCH_COUNT, array[i], sizeof(int));
REPORTER_ASSERT(reporter, index == i);
}
// make sure that random values are either found, or the correct
// insertion index is returned
for (i = 0; i < 10000; i++) {
int value = rand.nextS();
int index = SkTSearch<int>(array, kSEARCH_COUNT, value, sizeof(int));
if (index >= 0) {
REPORTER_ASSERT(reporter,
index < kSEARCH_COUNT && array[index] == value);
} else {
index = ~index;
REPORTER_ASSERT(reporter, index <= kSEARCH_COUNT);
if (index < kSEARCH_COUNT) {
REPORTER_ASSERT(reporter, value < array[index]);
if (index > 0) {
REPORTER_ASSERT(reporter, value > array[index - 1]);
}
} else {
// we should append the new value
REPORTER_ASSERT(reporter, value > array[kSEARCH_COUNT - 1]);
}
}
}
}
static void test_utf16(skiatest::Reporter* reporter) {
static const SkUnichar gUni[] = {
0x10000, 0x18080, 0x20202, 0xFFFFF, 0x101234
};
uint16_t buf[2];
for (size_t i = 0; i < SK_ARRAY_COUNT(gUni); i++) {
size_t count = SkUTF16_FromUnichar(gUni[i], buf);
REPORTER_ASSERT(reporter, count == 2);
size_t count2 = SkUTF16_CountUnichars(buf, 2);
REPORTER_ASSERT(reporter, count2 == 1);
const uint16_t* ptr = buf;
SkUnichar c = SkUTF16_NextUnichar(&ptr);
REPORTER_ASSERT(reporter, c == gUni[i]);
REPORTER_ASSERT(reporter, ptr - buf == 2);
}
}
static void TestUTF(skiatest::Reporter* reporter) {
static const struct {
const char* fUtf8;
SkUnichar fUni;
} gTest[] = {
{ "a", 'a' },
{ "\x7f", 0x7f },
{ "\xC2\x80", 0x80 },
{ "\xC3\x83", (3 << 6) | 3 },
{ "\xDF\xBF", 0x7ff },
{ "\xE0\xA0\x80", 0x800 },
{ "\xE0\xB0\xB8", 0xC38 },
{ "\xE3\x83\x83", (3 << 12) | (3 << 6) | 3 },
{ "\xEF\xBF\xBF", 0xFFFF },
{ "\xF0\x90\x80\x80", 0x10000 },
{ "\xF3\x83\x83\x83", (3 << 18) | (3 << 12) | (3 << 6) | 3 }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gTest); i++) {
const char* p = gTest[i].fUtf8;
int n = SkUTF8_CountUnichars(p);
SkUnichar u0 = SkUTF8_ToUnichar(gTest[i].fUtf8);
SkUnichar u1 = SkUTF8_NextUnichar(&p);
REPORTER_ASSERT(reporter, n == 1);
REPORTER_ASSERT(reporter, u0 == u1);
REPORTER_ASSERT(reporter, u0 == gTest[i].fUni);
REPORTER_ASSERT(reporter,
p - gTest[i].fUtf8 == (int)strlen(gTest[i].fUtf8));
}
test_utf16(reporter);
test_search(reporter);
}
///////////////////////////////////////////////////////////////////////////////
namespace skiatest {
class UtfTest : public Test {
public:
static Test* Factory(void*) {
return SkNEW(UtfTest);
}
protected:
virtual void onGetName(SkString* name) {
name->set("UTF");
}
virtual void onRun(Reporter* reporter) {
TestUTF(reporter);
}
};
static TestRegistry gReg(UtfTest::Factory);
}

67
tests/main.cpp Normal file
View File

@ -0,0 +1,67 @@
#include <iostream>
#include "Test.h"
using namespace skiatest;
class Iter {
public:
Iter(Reporter* r) : fReporter(r) {
r->ref();
fReg = TestRegistry::Head();
}
~Iter() {
fReporter->unref();
}
Test* next() {
if (fReg) {
TestRegistry::Factory fact = fReg->factory();
fReg = fReg->next();
Test* test = fact(NULL);
test->setReporter(fReporter);
return test;
}
return NULL;
}
private:
Reporter* fReporter;
const TestRegistry* fReg;
};
static const char* result2string(Reporter::Result result) {
return result == Reporter::kPassed ? "passed" : "FAILED";
}
class PrintfReporter : public Reporter {
protected:
virtual void onStart(Test* test) {
printf("Running %s...\n", test->getName());
}
virtual void onReport(const char desc[], Reporter::Result result) {
printf("\t%s: %s\n", result2string(result), desc);
}
virtual void onEnd(Test* test) {}
};
int main (int argc, char * const argv[]) {
PrintfReporter reporter;
Iter iter(&reporter);
Test* test;
while ((test = iter.next()) != NULL) {
test->run();
SkDELETE(test);
}
int total = reporter.countTests();
int passed = reporter.countResults(Reporter::kPassed);
int failed = reporter.countResults(Reporter::kFailed);
printf("Tests=%d Passed=%d (%g%%) Failed=%d (%g%%)\n", total,
passed, passed * 100.f / total,
failed, failed * 100.f / total);
return 0;
}