diff options
author | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-02-27 16:24:51 +0000 |
---|---|---|
committer | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-02-27 16:24:51 +0000 |
commit | ed673310e2551e64d8196f7776d7d4c92085f8c2 (patch) | |
tree | ac5a737aaaf66c97be7109eb980beadd35e30e25 | |
parent | 3469c76c40790b409621fd7eff34f56240718549 (diff) |
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
-rw-r--r-- | include/core/SkMath.h | 9 | ||||
-rw-r--r-- | include/core/SkMatrix.h | 7 | ||||
-rw-r--r-- | include/core/SkUserConfig.h | 2 | ||||
-rw-r--r-- | include/core/SkUtils.h | 7 | ||||
-rw-r--r-- | samplecode/SampleTextOnPath.cpp | 128 | ||||
-rw-r--r-- | src/core/SkGraphics.cpp | 3 | ||||
-rw-r--r-- | src/core/SkMath.cpp | 393 | ||||
-rw-r--r-- | src/core/SkMatrix.cpp | 82 | ||||
-rw-r--r-- | src/core/SkUtils.cpp | 123 | ||||
-rw-r--r-- | tests/MathTest.cpp | 400 | ||||
-rw-r--r-- | tests/MatrixTest.cpp | 119 | ||||
-rw-r--r-- | tests/PackBitsTest.cpp | 144 | ||||
-rw-r--r-- | tests/Test.cpp | 60 | ||||
-rw-r--r-- | tests/Test.h | 98 | ||||
-rw-r--r-- | tests/TestXCode/Tests.xcodeproj/project.pbxproj | 333 | ||||
-rw-r--r-- | tests/UtilsTest.cpp | 130 | ||||
-rw-r--r-- | tests/main.cpp | 67 |
17 files changed, 1352 insertions, 753 deletions
diff --git a/include/core/SkMath.h b/include/core/SkMath.h index 5c2b475ef9..683a1ac303 100644 --- a/include/core/SkMath.h +++ b/include/core/SkMath.h @@ -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 diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index 2b25dcada3..aa008cb2d9 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -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 diff --git a/include/core/SkUserConfig.h b/include/core/SkUserConfig.h index a3c34a3ba7..498eb8f62b 100644 --- a/include/core/SkUserConfig.h +++ b/include/core/SkUserConfig.h @@ -118,7 +118,7 @@ so this flag is optional. */ #ifdef SK_DEBUG -//#define SK_SUPPORT_UNITTEST +#define SK_SUPPORT_UNITTEST #endif #endif diff --git a/include/core/SkUtils.h b/include/core/SkUtils.h index f3e33417f1..9f3b1d6f36 100644 --- a/include/core/SkUtils.h +++ b/include/core/SkUtils.h @@ -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 { diff --git a/samplecode/SampleTextOnPath.cpp b/samplecode/SampleTextOnPath.cpp index 97b4e8e340..aec8fd6360 100644 --- a/samplecode/SampleTextOnPath.cpp +++ b/samplecode/SampleTextOnPath.cpp @@ -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; } diff --git a/src/core/SkGraphics.cpp b/src/core/SkGraphics.cpp index 7536ca8edc..053d9f0ec6 100644 --- a/src/core/SkGraphics.cpp +++ b/src/core/SkGraphics.cpp @@ -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), diff --git a/src/core/SkMath.cpp b/src/core/SkMath.cpp index e0babeb5e7..649b51890a 100644 --- a/src/core/SkMath.cpp +++ b/src/core/SkMath.cpp @@ -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 diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index 893aea17d4..ac5ae926e0 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -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 diff --git a/src/core/SkUtils.cpp b/src/core/SkUtils.cpp index a4c6c16cd1..edc5b74954 100644 --- a/src/core/SkUtils.cpp +++ b/src/core/SkUtils.cpp @@ -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 - - diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp new file mode 100644 index 0000000000..a759ab19a1 --- /dev/null +++ b/tests/MathTest.cpp @@ -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); +} + diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp new file mode 100644 index 0000000000..1e4e341f2b --- /dev/null +++ b/tests/MatrixTest.cpp @@ -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); +} + diff --git a/tests/PackBitsTest.cpp b/tests/PackBitsTest.cpp new file mode 100644 index 0000000000..6e69f825a4 --- /dev/null +++ b/tests/PackBitsTest.cpp @@ -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); +} + diff --git a/tests/Test.cpp b/tests/Test.cpp new file mode 100644 index 0000000000..5b8d439e2f --- /dev/null +++ b/tests/Test.cpp @@ -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); +} + diff --git a/tests/Test.h b/tests/Test.h new file mode 100644 index 0000000000..8d2eb87468 --- /dev/null +++ b/tests/Test.h @@ -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 diff --git a/tests/TestXCode/Tests.xcodeproj/project.pbxproj b/tests/TestXCode/Tests.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..004fb2247e --- /dev/null +++ b/tests/TestXCode/Tests.xcodeproj/project.pbxproj @@ -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 */; +} diff --git a/tests/UtilsTest.cpp b/tests/UtilsTest.cpp new file mode 100644 index 0000000000..810cb51650 --- /dev/null +++ b/tests/UtilsTest.cpp @@ -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); +} + diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000000..0b82af4c0f --- /dev/null +++ b/tests/main.cpp @@ -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; +} |