/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "Test.h" #include "SkChecksum.h" // Word size that is large enough to hold results of any checksum type. typedef uint64_t checksum_result; namespace skiatest { class ChecksumTestClass : public Test { public: static Test* Factory(void*) {return SkNEW(ChecksumTestClass); } protected: virtual void onGetName(SkString* name) { name->set("Checksum"); } virtual void onRun(Reporter* reporter) { this->fReporter = reporter; RunTest(); } private: enum Algorithm { kSkChecksum }; // Call Compute(data, size) on the appropriate checksum algorithm, // depending on this->fWhichAlgorithm. checksum_result ComputeChecksum(const char *data, size_t size) { switch(fWhichAlgorithm) { case kSkChecksum: REPORTER_ASSERT_MESSAGE(fReporter, reinterpret_cast(data) % 4 == 0, "test data pointer is not 32-bit aligned"); REPORTER_ASSERT_MESSAGE(fReporter, SkIsAlign4(size), "test data size is not 32-bit aligned"); return SkChecksum::Compute(reinterpret_cast(data), size); default: SkString message("fWhichAlgorithm has unknown value "); message.appendf("%d", fWhichAlgorithm); fReporter->reportFailed(message); } // we never get here return 0; } // Confirm that the checksum algorithm (specified by fWhichAlgorithm) // generates the same results if called twice over the same data. void TestChecksumSelfConsistency(size_t buf_size) { SkAutoMalloc storage(buf_size); char* ptr = reinterpret_cast(storage.get()); REPORTER_ASSERT(fReporter, GetTestDataChecksum(8, 0) == GetTestDataChecksum(8, 0)); REPORTER_ASSERT(fReporter, GetTestDataChecksum(8, 0) != GetTestDataChecksum(8, 1)); sk_bzero(ptr, buf_size); checksum_result prev = 0; // assert that as we change values (from 0 to non-zero) in // our buffer, we get a different value for (size_t i = 0; i < buf_size; ++i) { ptr[i] = (i & 0x7f) + 1; // need some non-zero value here // Try checksums of different-sized chunks, but always // 32-bit aligned and big enough to contain all the // nonzero bytes. (Remaining bytes will still be zero // from the initial sk_bzero() call.) size_t checksum_size = (((i/4)+1)*4); REPORTER_ASSERT(fReporter, checksum_size <= buf_size); checksum_result curr = ComputeChecksum(ptr, checksum_size); REPORTER_ASSERT(fReporter, prev != curr); checksum_result again = ComputeChecksum(ptr, checksum_size); REPORTER_ASSERT(fReporter, again == curr); prev = curr; } } // Return the checksum of a buffer of bytes 'len' long. // The pattern of values within the buffer will be consistent // for every call, based on 'seed'. checksum_result GetTestDataChecksum(size_t len, char seed=0) { SkAutoMalloc storage(len); char* start = reinterpret_cast(storage.get()); char* ptr = start; for (size_t i = 0; i < len; ++i) { *ptr++ = ((seed+i) & 0x7f); } checksum_result result = ComputeChecksum(start, len); return result; } void RunTest() { // Test self-consistency of checksum algorithms. fWhichAlgorithm = kSkChecksum; TestChecksumSelfConsistency(128); // Test checksum results that should be consistent across // versions and platforms. fWhichAlgorithm = kSkChecksum; REPORTER_ASSERT(fReporter, ComputeChecksum(NULL, 0) == 0); // TODO: note the weakness exposed by these collisions... // We need to improve the SkChecksum algorithm. // We would prefer that these asserts FAIL! // Filed as https://code.google.com/p/skia/issues/detail?id=981 // ('SkChecksum algorithm allows for way too many collisions') fWhichAlgorithm = kSkChecksum; REPORTER_ASSERT(fReporter, GetTestDataChecksum(128) == GetTestDataChecksum(256)); REPORTER_ASSERT(fReporter, GetTestDataChecksum(132) == GetTestDataChecksum(260)); } Reporter* fReporter; Algorithm fWhichAlgorithm; }; static TestRegistry gReg(ChecksumTestClass::Factory); }