Home | History | Annotate | Download | only in tests
      1 
      2 /*
      3  * Copyright 2012 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "Test.h"
      9 
     10 #include "SkBitmap.h"
     11 #include "SkBitmapChecksummer.h"
     12 #include "SkChecksum.h"
     13 #include "SkCityHash.h"
     14 #include "SkColor.h"
     15 
     16 // Word size that is large enough to hold results of any checksum type.
     17 typedef uint64_t checksum_result;
     18 
     19 namespace skiatest {
     20     class ChecksumTestClass : public Test {
     21     public:
     22         static Test* Factory(void*) {return SkNEW(ChecksumTestClass); }
     23     protected:
     24         virtual void onGetName(SkString* name) { name->set("Checksum"); }
     25         virtual void onRun(Reporter* reporter) {
     26             this->fReporter = reporter;
     27             RunTest();
     28         }
     29     private:
     30         enum Algorithm {
     31             kSkChecksum,
     32             kSkCityHash32,
     33             kSkCityHash64
     34         };
     35 
     36         // Call Compute(data, size) on the appropriate checksum algorithm,
     37         // depending on this->fWhichAlgorithm.
     38         checksum_result ComputeChecksum(const char *data, size_t size) {
     39             switch(fWhichAlgorithm) {
     40             case kSkChecksum:
     41                 REPORTER_ASSERT_MESSAGE(fReporter,
     42                                         reinterpret_cast<uintptr_t>(data) % 4 == 0,
     43                                         "test data pointer is not 32-bit aligned");
     44                 REPORTER_ASSERT_MESSAGE(fReporter, SkIsAlign4(size),
     45                                         "test data size is not 32-bit aligned");
     46                 return SkChecksum::Compute(reinterpret_cast<const uint32_t *>(data), size);
     47             case kSkCityHash32:
     48                 return SkCityHash::Compute32(data, size);
     49             case kSkCityHash64:
     50                 return SkCityHash::Compute64(data, size);
     51             default:
     52                 SkString message("fWhichAlgorithm has unknown value ");
     53                 message.appendf("%d", fWhichAlgorithm);
     54                 fReporter->reportFailed(message);
     55             }
     56             // we never get here
     57             return 0;
     58         }
     59 
     60         // Confirm that the checksum algorithm (specified by fWhichAlgorithm)
     61         // generates the same results if called twice over the same data.
     62         void TestChecksumSelfConsistency(size_t buf_size) {
     63             SkAutoMalloc storage(buf_size);
     64             char* ptr = reinterpret_cast<char *>(storage.get());
     65 
     66             REPORTER_ASSERT(fReporter,
     67                             GetTestDataChecksum(8, 0) ==
     68                             GetTestDataChecksum(8, 0));
     69             REPORTER_ASSERT(fReporter,
     70                             GetTestDataChecksum(8, 0) !=
     71                             GetTestDataChecksum(8, 1));
     72 
     73             sk_bzero(ptr, buf_size);
     74             checksum_result prev = 0;
     75 
     76             // assert that as we change values (from 0 to non-zero) in
     77             // our buffer, we get a different value
     78             for (size_t i = 0; i < buf_size; ++i) {
     79                 ptr[i] = (i & 0x7f) + 1; // need some non-zero value here
     80 
     81                 // Try checksums of different-sized chunks, but always
     82                 // 32-bit aligned and big enough to contain all the
     83                 // nonzero bytes.  (Remaining bytes will still be zero
     84                 // from the initial sk_bzero() call.)
     85                 size_t checksum_size = (((i/4)+1)*4);
     86                 REPORTER_ASSERT(fReporter, checksum_size <= buf_size);
     87 
     88                 checksum_result curr = ComputeChecksum(ptr, checksum_size);
     89                 REPORTER_ASSERT(fReporter, prev != curr);
     90                 checksum_result again = ComputeChecksum(ptr, checksum_size);
     91                 REPORTER_ASSERT(fReporter, again == curr);
     92                 prev = curr;
     93             }
     94         }
     95 
     96         // Return the checksum of a buffer of bytes 'len' long.
     97         // The pattern of values within the buffer will be consistent
     98         // for every call, based on 'seed'.
     99         checksum_result GetTestDataChecksum(size_t len, char seed=0) {
    100             SkAutoMalloc storage(len);
    101             char* start = reinterpret_cast<char *>(storage.get());
    102             char* ptr = start;
    103             for (size_t i = 0; i < len; ++i) {
    104                 *ptr++ = ((seed+i) & 0x7f);
    105             }
    106             checksum_result result = ComputeChecksum(start, len);
    107             return result;
    108         }
    109 
    110         // Fill in bitmap with test data.
    111         void CreateTestBitmap(SkBitmap &bitmap, SkBitmap::Config config, int width, int height,
    112                               SkColor color) {
    113             bitmap.setConfig(config, width, height);
    114             REPORTER_ASSERT(fReporter, bitmap.allocPixels());
    115             bitmap.setIsOpaque(true);
    116             bitmap.eraseColor(color);
    117         }
    118 
    119         void RunTest() {
    120             // Test self-consistency of checksum algorithms.
    121             fWhichAlgorithm = kSkChecksum;
    122             TestChecksumSelfConsistency(128);
    123             fWhichAlgorithm = kSkCityHash32;
    124             TestChecksumSelfConsistency(128);
    125             fWhichAlgorithm = kSkCityHash64;
    126             TestChecksumSelfConsistency(128);
    127 
    128             // Test checksum results that should be consistent across
    129             // versions and platforms.
    130             fWhichAlgorithm = kSkChecksum;
    131             REPORTER_ASSERT(fReporter, ComputeChecksum(NULL, 0) == 0);
    132             fWhichAlgorithm = kSkCityHash32;
    133             REPORTER_ASSERT(fReporter, ComputeChecksum(NULL, 0) == 0xdc56d17a);
    134             REPORTER_ASSERT(fReporter, GetTestDataChecksum(4)   == 0x616e1132);
    135             REPORTER_ASSERT(fReporter, GetTestDataChecksum(8)   == 0xeb0fd2d6);
    136             REPORTER_ASSERT(fReporter, GetTestDataChecksum(128) == 0x5321e430);
    137             REPORTER_ASSERT(fReporter, GetTestDataChecksum(132) == 0x924a10e4);
    138             REPORTER_ASSERT(fReporter, GetTestDataChecksum(256) == 0xd4de9dc9);
    139             REPORTER_ASSERT(fReporter, GetTestDataChecksum(260) == 0xecf0325d);
    140             fWhichAlgorithm = kSkCityHash64;
    141             REPORTER_ASSERT(fReporter, ComputeChecksum(NULL, 0) == 0x9ae16a3b2f90404fULL);
    142             REPORTER_ASSERT(fReporter, GetTestDataChecksum(4)   == 0x82bffd898958e540ULL);
    143             REPORTER_ASSERT(fReporter, GetTestDataChecksum(8)   == 0xad5a13e1e8e93b98ULL);
    144             REPORTER_ASSERT(fReporter, GetTestDataChecksum(128) == 0x10b153630af1f395ULL);
    145             REPORTER_ASSERT(fReporter, GetTestDataChecksum(132) == 0x7db71dc4adcc6647ULL);
    146             REPORTER_ASSERT(fReporter, GetTestDataChecksum(256) == 0xeee763519b91b010ULL);
    147             REPORTER_ASSERT(fReporter, GetTestDataChecksum(260) == 0x2fe19e0b2239bc23ULL);
    148 
    149             // TODO: note the weakness exposed by these collisions...
    150             // We need to improve the SkChecksum algorithm.
    151             // We would prefer that these asserts FAIL!
    152             // Filed as https://code.google.com/p/skia/issues/detail?id=981
    153             // ('SkChecksum algorithm allows for way too many collisions')
    154             fWhichAlgorithm = kSkChecksum;
    155             REPORTER_ASSERT(fReporter,
    156                 GetTestDataChecksum(128) == GetTestDataChecksum(256));
    157             REPORTER_ASSERT(fReporter,
    158                 GetTestDataChecksum(132) == GetTestDataChecksum(260));
    159 
    160             // Test SkBitmapChecksummer
    161             SkBitmap bitmap;
    162             // initial test case
    163             CreateTestBitmap(bitmap, SkBitmap::kARGB_8888_Config, 333, 555, SK_ColorBLUE);
    164             REPORTER_ASSERT(fReporter,
    165                             SkBitmapChecksummer::Compute64(bitmap) == 0x18f9df68b1b02f38ULL);
    166             // same pixel data but different dimensions should yield a different checksum
    167             CreateTestBitmap(bitmap, SkBitmap::kARGB_8888_Config, 555, 333, SK_ColorBLUE);
    168             REPORTER_ASSERT(fReporter,
    169                             SkBitmapChecksummer::Compute64(bitmap) == 0x6b0298183f786c8eULL);
    170             // same dimensions but different color should yield a different checksum
    171             CreateTestBitmap(bitmap, SkBitmap::kARGB_8888_Config, 555, 333, SK_ColorGREEN);
    172             REPORTER_ASSERT(fReporter,
    173                             SkBitmapChecksummer::Compute64(bitmap) == 0xc6b4b3f6fadaaf37ULL);
    174             // same pixel colors in a different config should yield the same checksum
    175             CreateTestBitmap(bitmap, SkBitmap::kARGB_4444_Config, 555, 333, SK_ColorGREEN);
    176             REPORTER_ASSERT(fReporter,
    177                             SkBitmapChecksummer::Compute64(bitmap) == 0xc6b4b3f6fadaaf37ULL);
    178         }
    179 
    180         Reporter* fReporter;
    181         Algorithm fWhichAlgorithm;
    182     };
    183 
    184     static TestRegistry gReg(ChecksumTestClass::Factory);
    185 }
    186