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 "SkChecksum.h"
     11 
     12 // Word size that is large enough to hold results of any checksum type.
     13 typedef uint64_t checksum_result;
     14 
     15 namespace skiatest {
     16     class ChecksumTestClass : public Test {
     17     public:
     18         static Test* Factory(void*) {return SkNEW(ChecksumTestClass); }
     19     protected:
     20         virtual void onGetName(SkString* name) { name->set("Checksum"); }
     21         virtual void onRun(Reporter* reporter) {
     22             this->fReporter = reporter;
     23             RunTest();
     24         }
     25     private:
     26         enum Algorithm {
     27             kSkChecksum,
     28             kMurmur3,
     29         };
     30 
     31         // Call Compute(data, size) on the appropriate checksum algorithm,
     32         // depending on this->fWhichAlgorithm.
     33         checksum_result ComputeChecksum(const char *data, size_t size) {
     34             switch(fWhichAlgorithm) {
     35             case kSkChecksum:
     36                 REPORTER_ASSERT_MESSAGE(fReporter,
     37                                         reinterpret_cast<uintptr_t>(data) % 4 == 0,
     38                                         "test data pointer is not 32-bit aligned");
     39                 REPORTER_ASSERT_MESSAGE(fReporter, SkIsAlign4(size),
     40                                         "test data size is not 32-bit aligned");
     41                 return SkChecksum::Compute(reinterpret_cast<const uint32_t *>(data), size);
     42             case kMurmur3:
     43                 REPORTER_ASSERT_MESSAGE(fReporter,
     44                                         reinterpret_cast<uintptr_t>(data) % 4 == 0,
     45                                         "test data pointer is not 32-bit aligned");
     46                 REPORTER_ASSERT_MESSAGE(fReporter, SkIsAlign4(size),
     47                                         "test data size is not 32-bit aligned");
     48                 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t *>(data), size);
     49             default:
     50                 SkString message("fWhichAlgorithm has unknown value ");
     51                 message.appendf("%d", fWhichAlgorithm);
     52                 fReporter->reportFailed(message);
     53             }
     54             // we never get here
     55             return 0;
     56         }
     57 
     58         // Confirm that the checksum algorithm (specified by fWhichAlgorithm)
     59         // generates the same results if called twice over the same data.
     60         void TestChecksumSelfConsistency(size_t buf_size) {
     61             SkAutoMalloc storage(buf_size);
     62             char* ptr = reinterpret_cast<char *>(storage.get());
     63 
     64             REPORTER_ASSERT(fReporter,
     65                             GetTestDataChecksum(8, 0) ==
     66                             GetTestDataChecksum(8, 0));
     67             REPORTER_ASSERT(fReporter,
     68                             GetTestDataChecksum(8, 0) !=
     69                             GetTestDataChecksum(8, 1));
     70 
     71             sk_bzero(ptr, buf_size);
     72             checksum_result prev = 0;
     73 
     74             // assert that as we change values (from 0 to non-zero) in
     75             // our buffer, we get a different value
     76             for (size_t i = 0; i < buf_size; ++i) {
     77                 ptr[i] = (i & 0x7f) + 1; // need some non-zero value here
     78 
     79                 // Try checksums of different-sized chunks, but always
     80                 // 32-bit aligned and big enough to contain all the
     81                 // nonzero bytes.  (Remaining bytes will still be zero
     82                 // from the initial sk_bzero() call.)
     83                 size_t checksum_size = (((i/4)+1)*4);
     84                 REPORTER_ASSERT(fReporter, checksum_size <= buf_size);
     85 
     86                 checksum_result curr = ComputeChecksum(ptr, checksum_size);
     87                 REPORTER_ASSERT(fReporter, prev != curr);
     88                 checksum_result again = ComputeChecksum(ptr, checksum_size);
     89                 REPORTER_ASSERT(fReporter, again == curr);
     90                 prev = curr;
     91             }
     92         }
     93 
     94         // Return the checksum of a buffer of bytes 'len' long.
     95         // The pattern of values within the buffer will be consistent
     96         // for every call, based on 'seed'.
     97         checksum_result GetTestDataChecksum(size_t len, char seed=0) {
     98             SkAutoMalloc storage(len);
     99             char* start = reinterpret_cast<char *>(storage.get());
    100             char* ptr = start;
    101             for (size_t i = 0; i < len; ++i) {
    102                 *ptr++ = ((seed+i) & 0x7f);
    103             }
    104             checksum_result result = ComputeChecksum(start, len);
    105             return result;
    106         }
    107 
    108         void RunTest() {
    109             const Algorithm algorithms[] = { kSkChecksum, kMurmur3 };
    110             for (size_t i = 0; i < SK_ARRAY_COUNT(algorithms); i++) {
    111                 fWhichAlgorithm = algorithms[i];
    112 
    113                 // Test self-consistency of checksum algorithms.
    114                 TestChecksumSelfConsistency(128);
    115 
    116                 // Test checksum results that should be consistent across
    117                 // versions and platforms.
    118                 REPORTER_ASSERT(fReporter, ComputeChecksum(NULL, 0) == 0);
    119 
    120                 const bool colision1 = GetTestDataChecksum(128) == GetTestDataChecksum(256);
    121                 const bool colision2 = GetTestDataChecksum(132) == GetTestDataChecksum(260);
    122                 if (fWhichAlgorithm == kSkChecksum) {
    123                     // TODO: note the weakness exposed by these collisions...
    124                     // We need to improve the SkChecksum algorithm.
    125                     // We would prefer that these asserts FAIL!
    126                     // Filed as https://code.google.com/p/skia/issues/detail?id=981
    127                     // ('SkChecksum algorithm allows for way too many collisions')
    128                     REPORTER_ASSERT(fReporter, colision1);
    129                     REPORTER_ASSERT(fReporter, colision2);
    130                 } else {
    131                     REPORTER_ASSERT(fReporter, !colision1);
    132                     REPORTER_ASSERT(fReporter, !colision2);
    133                 }
    134             }
    135         }
    136 
    137         Reporter* fReporter;
    138         Algorithm fWhichAlgorithm;
    139     };
    140 
    141     static TestRegistry gReg(ChecksumTestClass::Factory);
    142 }
    143