/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkTDPQueue.h" #include "SkRandom.h" #include "Test.h" namespace { bool intless(const int& a, const int& b) { return a < b; } } static void simple_test(skiatest::Reporter* reporter) { SkTDPQueue<int, intless> heap; REPORTER_ASSERT(reporter, 0 == heap.count()); heap.insert(0); REPORTER_ASSERT(reporter, 1 == heap.count()); REPORTER_ASSERT(reporter, 0 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 0 == heap.count()); heap.insert(0); heap.insert(1); REPORTER_ASSERT(reporter, 2 == heap.count()); REPORTER_ASSERT(reporter, 0 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 1 == heap.count()); REPORTER_ASSERT(reporter, 1 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 0 == heap.count()); heap.insert(2); heap.insert(1); heap.insert(0); REPORTER_ASSERT(reporter, 3 == heap.count()); REPORTER_ASSERT(reporter, 0 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 2 == heap.count()); REPORTER_ASSERT(reporter, 1 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 1 == heap.count()); REPORTER_ASSERT(reporter, 2 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 0 == heap.count()); heap.insert(2); heap.insert(3); heap.insert(0); heap.insert(1); REPORTER_ASSERT(reporter, 4 == heap.count()); REPORTER_ASSERT(reporter, 0 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 3 == heap.count()); REPORTER_ASSERT(reporter, 1 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 2 == heap.count()); REPORTER_ASSERT(reporter, 2 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 1 == heap.count()); REPORTER_ASSERT(reporter, 3 == heap.peek()); heap.pop(); REPORTER_ASSERT(reporter, 0 == heap.count()); } struct Dummy { int fValue; int fPriority; mutable int fIndex; static bool LessP(Dummy* const& a, Dummy* const& b) { return a->fPriority < b->fPriority; } static int* PQIndex(Dummy* const& dummy) { return &dummy->fIndex; } bool operator== (const Dummy& that) const { return fValue == that.fValue && fPriority == that.fPriority; } bool operator!= (const Dummy& that) const { return !(*this == that); } }; void random_test(skiatest::Reporter* reporter) { SkRandom random; static const Dummy kSentinel = {-1, -1, -1}; for (int i = 0; i < 100; ++i) { // Create a random set of Dummy objects. int count = random.nextULessThan(100); SkTDArray<Dummy> array; array.setReserve(count); for (int j = 0; j < count; ++j) { Dummy* dummy = array.append(); dummy->fPriority = random.nextS(); dummy->fValue = random.nextS(); dummy->fIndex = -1; if (*dummy == kSentinel) { array.pop(); --j; } } // Stick the dummy objects in the pqueue. SkTDPQueue<Dummy*, Dummy::LessP, Dummy::PQIndex> pq; for (int j = 0; j < count; ++j) { pq.insert(&array[j]); } REPORTER_ASSERT(reporter, pq.count() == array.count()); for (int j = 0; j < count; ++j) { // every item should have an entry in the queue. REPORTER_ASSERT(reporter, -1 != array[j].fIndex); } // Begin the test. while (pq.count()) { // Make sure the top of the queue is really the highest priority. Dummy* top = pq.peek(); for (int k = 0; k < count; ++k) { REPORTER_ASSERT(reporter, kSentinel == array[k] || array[k].fPriority >= top->fPriority); } // Do one of three random actions: unsigned action = random.nextULessThan(3); switch (action) { case 0: { // pop the top, Dummy* top = pq.peek(); REPORTER_ASSERT(reporter, array.begin() <= top && top < array.end()); pq.pop(); *top = kSentinel; break; } case 1: { // remove a random element, int item; do { item = random.nextULessThan(count); } while (array[item] == kSentinel); pq.remove(&array[item]); array[item] = kSentinel; break; } case 2: { // or change an element's priority. int item; do { item = random.nextULessThan(count); } while (array[item] == kSentinel); array[item].fPriority = random.nextS(); pq.priorityDidChange(&array[item]); break; } } } } } void sort_test(skiatest::Reporter* reporter) { SkRandom random; SkTDPQueue<Dummy *, Dummy::LessP, Dummy::PQIndex> pqTest; SkTDPQueue<Dummy *, Dummy::LessP, Dummy::PQIndex> pqControl; // Create a random set of Dummy objects and populate the test queue. int count = random.nextULessThan(100); SkTDArray<Dummy> testArray; testArray.setReserve(count); for (int i = 0; i < count; i++) { Dummy *dummy = testArray.append(); dummy->fPriority = random.nextS(); dummy->fValue = random.nextS(); dummy->fIndex = -1; pqTest.insert(&testArray[i]); } // Stick equivalent dummy objects into the control queue. SkTDArray<Dummy> controlArray; controlArray.setReserve(count); for (int i = 0; i < count; i++) { Dummy *dummy = controlArray.append(); dummy->fPriority = testArray[i].fPriority; dummy->fValue = testArray[i].fValue; dummy->fIndex = -1; pqControl.insert(&controlArray[i]); } // Sort the queue pqTest.sort(); // Compare elements in the queue to ensure they are in sorted order int prevPriority = pqTest.peek()->fPriority; for (int i = 0; i < count; i++) { REPORTER_ASSERT(reporter, i <= pqTest.at(i)->fIndex); REPORTER_ASSERT(reporter, prevPriority <= pqTest.at(i)->fPriority); prevPriority = pqTest.at(i)->fPriority; } // Verify that after sorting the queue still produces the same result as the control queue for (int i = 0; i < count; i++) { REPORTER_ASSERT(reporter, *pqControl.peek() == *pqTest.peek()); pqControl.pop(); pqTest.pop(); } } DEF_TEST(TDPQueueTest, reporter) { simple_test(reporter); random_test(reporter); sort_test(reporter); }