gecko-dev/ef/Tools/UtilityTest/TreeTest.cpp

409 строки
8.8 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
//
// A test program for the Tree classes
//
#include <stdio.h>
#include "TreeTest.h"
#include "DebugUtils.h"
//
// Return a pseudo-random number between 0 and range-1, inclusive.
// This is not a good pseudo-random number generator (it has biases),
// but it will do fine for generating tests.
// range should be relatively small -- less than 1000 or so.
//
Uint32 random(Uint16 range)
{
static Uint32 seed = 1;
seed *= 0x10003;
return (seed>>16) % range;
}
// ----------------------------------------------------------------------------
// TreeHarness
//
// Initialize the TreeHarness, which contains both a SortedTree and a
// rep value that is a bitmap that is supposed to match the contents of
// the tree.
//
TreeHarness::TreeHarness(): rep(0)
{
for (Uint32 i = nNodes; i--;)
nodes[i].key.n = i;
}
//
// Return a random node number of a node present in the tree or nNodes
// if the tree is empty.
//
Uint32 TreeHarness::randomPresent() const
{
Uint32 limit = tree.getNNodes();
if (limit) {
Uint32 i = random(limit);
for (Uint32 j = 0; j != nNodes; j++)
if (present(j))
if (i)
i--;
else
return j;
trespass("Error in randomPresent");
}
return nNodes;
}
//
// Remove all elements from the tree.
//
void TreeHarness::testClear()
{
Uint32 n;
while ((n = randomPresent()) != nNodes)
testRemove(n);
assert(rep == 0);
}
//
// Test the find method on element n, which may or may not be in the tree.
//
void TreeHarness::testFind(Uint32 n) const
{
TestNode *node = tree.find(TestKey(n));
if (present(n))
assert(node == nodes + n);
else
assert(!node);
}
//
// Test the findAfter method on element n, which may or may not be in the tree.
// Return the number of the lowest element in the set that is greater than or
// equal to n, or nNodes if there is no such element.
//
Uint32 TreeHarness::testFindAfter(Uint32 n) const
{
TestNode *node = tree.findAfter(TestKey(n));
Uint32 i = n;
while (i != nNodes && !present(i))
i++;
if (i != nNodes)
assert(node == nodes + i);
else
assert(!node);
return i;
}
//
// Test the findBefore method on element n, which may or may not be in the tree.
// Return the number of the greatest element in the set that is less than or
// equal to n, or nNodes if there is no such element.
//
Uint32 TreeHarness::testFindBefore(Uint32 n) const
{
TestNode *node = tree.findBefore(TestKey(n));
Uint32 i = n;
while (i != 0 && !present(i))
i--;
if (present(i)) {
assert(node == nodes + i);
return i;
} else {
assert(!node);
return nNodes;
}
}
//
// Test the three-argument find method on element n, which may or may not be
// in the tree. If element n is not in the tree, add it.
//
void TreeHarness::testFindAttach(Uint32 n)
{
TestNode *where;
bool right;
TestNode *node = tree.find(TestKey(n), where, right);
if (!node)
tree.attach(nodes[n], where, right);
if (present(n))
assert(node == nodes + n);
else {
assert(!node);
add(n);
}
}
//
// Test the insert method on element n, which is not currently in the tree.
//
void TreeHarness::testInsert(Uint32 n)
{
assert(!present(n));
tree.insert(nodes[n]);
add(n);
}
//
// Test the insertAfter method on element n, which is not currently in the tree,
// and location where, which is a valid argument to insertAfter for this n.
// If where==nNodes, then insertAfter's where is set to nil.
//
void TreeHarness::testInsertAfter(Uint32 n, Uint32 where)
{
assert(!present(n) && (where == nNodes || present(where)));
tree.insertAfter(nodes[n], where == nNodes ? 0 : nodes + where);
add(n);
}
//
// Test the insertBefore method on element n, which is not currently in the tree,
// and location where, which is a valid argument to insertBefore for this n.
// If where==nNodes, then insertBefore's where is set to nil.
//
void TreeHarness::testInsertBefore(Uint32 n, Uint32 where)
{
assert(!present(n) && (where == nNodes || present(where)));
tree.insertBefore(nodes[n], where == nNodes ? 0 : nodes + where);
add(n);
}
//
// Test the remove method on element n, which is currently in the tree.
//
void TreeHarness::testRemove(Uint32 n)
{
assert(present(n));
tree.remove(nodes[n]);
remove(n);
}
//
// Test the remove substitute on element newN, which is not currently in the tree
// (unless newN==oldN) and element oldN, which is currently in the tree. The caller
// guarantees that the combination of newN and oldN is legal.
//
void TreeHarness::testSubstitute(Uint32 newN, Uint32 oldN)
{
assert(newN == oldN || !present(newN) && present(oldN));
tree.substitute(nodes[newN], nodes[oldN]);
remove(oldN);
add(newN);
}
//
// Make sure that the contents of the tree and rep match.
//
void TreeHarness::verify() const
{
tree.verify();
// Make sure that there is a one-to-one correspondence between the tree nodes
// and the bits set in rep.
Uint32 r = rep;
for (TestNode *p = tree.firstNode(); p; p = p->next()) {
Uint32 n = p->key.n;
assert(r & 1<<n);
assert(p == nodes + n);
r &= ~(1<<n);
}
assert(r == 0);
}
//
// Print the subtree with the given root.
//
void TreeHarness::printSubtree(TestNode *node)
{
if (node) {
printf(node->isRed() ? "(" : "[");
printSubtree(node->getChild(false));
printf(" %d ", node->key.n);
printSubtree(node->getChild(true));
printf(node->isRed() ? ")" : "]");
} else
printf("-");
}
//
// Print the current state of the TreeHarness.
//
void TreeHarness::print() const
{
printSubtree(tree.getRoot());
printf("\n");
}
// ----------------------------------------------------------------------------
//
// Test the implementation of SortedTree. Assert if problems are found.
//
void testTrees()
{
printf("Testing SortedTree...\n");
TreeHarness h;
for (Uint32 i = 0; i != 10000; i++) {
Uint32 n = h.randomNode();
Uint32 m;
Uint32 c = 0;
switch (random(21)) {
case 0: // Clear the tree (but do it infrequently)
if (random(5) != 2)
continue;
if (printProgress)
c = printf("Clear");
h.testClear();
break;
case 1: // Test finding an element
case 2:
if (printProgress)
c = printf("Find %d", n);
h.testFind(n);
break;
case 3: // Test findAfter
case 4:
if (printProgress)
c = printf("FindAfter %d", n);
h.testFindAfter(n);
break;
case 5: // Test findBefore
case 6:
if (printProgress)
c = printf("FindBefore %d", n);
h.testFindBefore(n);
break;
case 7: // Test findAttach
case 8:
if (printProgress)
c = printf("Find+Attach %d", n);
h.testFindAttach(n);
break;
case 9: // Test insert
case 10:
if (h.present(n))
continue;
if (printProgress)
c = printf("Insert %d", n);
h.testInsert(n);
break;
case 11: // Test insertAfter
case 12:
if (h.present(n))
continue;
m = h.testFindBefore(n);
if (printProgress)
if (m == h.nNodes)
c = printf("Insert %d after nil", n);
else
c = printf("Insert %d after %d", n, m);
h.testInsertAfter(n, m);
break;
case 13: // Test insertBefore
case 14:
if (h.present(n))
continue;
m = h.testFindAfter(n);
if (printProgress)
if (m == h.nNodes)
c = printf("Insert %d before nil", n);
else
c = printf("Insert %d before %d", n, m);
h.testInsertBefore(n, m);
break;
case 15: // Test remove
case 16:
case 17:
n = h.randomPresent();
if (n == h.nNodes)
continue;
if (printProgress)
c = printf("Remove %d", n);
h.testRemove(n);
break;
case 18: // Test substitute
case 19:
n = h.randomPresent();
m = n^1;
if (n == h.nNodes || m >= h.nNodes || h.present(m))
continue;
if (printProgress)
c = printf("Substitute %d for %d", m, n);
h.testSubstitute(m, n);
break;
case 20: // Test self-substitute
n = h.randomPresent();
if (n == h.nNodes)
continue;
if (printProgress)
c = printf("Substitute %d for %d", n, n);
h.testSubstitute(n, n);
break;
default:
trespass("Bad case");
}
h.verify();
if (printProgress) {
printSpaces(stdout, 32 - c);
h.print();
}
}
h.testClear();
h.verify();
printf("Done testing SortedTree.\n");
}