/***
This file is part of systemd. See COPYING for details.
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/*
* Tests for RB-Tree
*/
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "c-rbtree.h"
/* verify that all API calls are exported */
static void test_api(void) {
CRBTree t = {};
CRBNode n = C_RBNODE_INIT(n);
assert(!c_rbnode_is_linked(&n));
/* init, is_linked, add, remove, remove_init */
assert(c_rbnode_is_linked(&n));
c_rbtree_remove_init(&t, &n);
assert(!c_rbnode_is_linked(&n));
assert(c_rbnode_is_linked(&n));
c_rbtree_remove(&t, &n);
c_rbnode_init(&n);
assert(!c_rbnode_is_linked(&n));
/* first, last, leftmost, rightmost, next, prev */
assert(!c_rbtree_first(&t));
assert(!c_rbtree_last(&t));
assert(&n == c_rbnode_leftmost(&n));
assert(&n == c_rbnode_rightmost(&n));
assert(!c_rbnode_next(&n));
assert(!c_rbnode_prev(&n));
}
/* copied from c-rbtree.c, relies on internal representation */
return !((unsigned long)n->__parent_and_color & 1UL);
}
/* copied from c-rbtree.c, relies on internal representation */
return !!((unsigned long)n->__parent_and_color & 1UL);
}
CRBNode *n, *p, *o;
assert(t);
/* traverse to left-most child, count black nodes */
i_black = 0;
n = t->root;
while (n && n->left) {
if (c_rbnode_is_black(n))
++i_black;
n = n->left;
}
/*
* Traverse tree and verify correctness:
* 1) A node is either red or black
* 2) The root is black
* 3) All leaves are black
* 4) Every red node must have two black child nodes
* 5) Every path to a leaf contains the same number of black nodes
*
* Note that NULL nodes are considered black, which is why we don't
* check for 3).
*/
o = NULL;
while (n) {
++count;
/* verify natural order */
assert(n > o);
o = n;
/* verify consistency */
/* verify 2) */
if (!c_rbnode_parent(n))
assert(c_rbnode_is_black(n));
if (c_rbnode_is_red(n)) {
/* verify 4) */
} else {
/* verify 1) */
assert(c_rbnode_is_black(n));
}
/* verify 5) */
/* get next node */
if (n->right) {
n = n->right;
if (c_rbnode_is_black(n))
++i_black;
while (n->left) {
n = n->left;
if (c_rbnode_is_black(n))
++i_black;
}
} else {
while ((p = c_rbnode_parent(n)) && n == p->right) {
n = p;
if (c_rbnode_is_black(p->right))
--i_black;
}
n = p;
if (p && c_rbnode_is_black(p->left))
--i_black;
}
}
return count;
}
CRBNode **i, *p;
assert(t);
assert(n);
assert(!c_rbnode_is_linked(n));
i = &t->root;
p = NULL;
while (*i) {
p = *i;
if (n < *i) {
i = &(*i)->left;
} else {
assert(n > *i);
i = &(*i)->right;
}
}
c_rbtree_add(t, p, i, n);
}
unsigned int i, j;
void *t;
for (i = 0; i < n_memb; ++i) {
t = nodes[j];
nodes[i] = t;
}
}
/* run some pseudo-random tests on the tree */
static void test_shuffle(void) {
CRBTree t = {};
unsigned int i, j;
size_t n;
/* allocate and initialize all nodes */
c_rbnode_init(nodes[i]);
}
/* shuffle nodes and validate *empty* tree */
n = validate(&t);
assert(n == 0);
/* add all nodes and validate after each insertion */
n = validate(&t);
assert(n == i + 1);
}
/* shuffle nodes again */
/* remove all nodes (in different order) and validate on each round */
c_rbtree_remove(&t, nodes[i]);
n = validate(&t);
c_rbnode_init(nodes[i]);
}
/* shuffle nodes and validate *empty* tree again */
n = validate(&t);
assert(n == 0);
/* add all nodes again */
n = validate(&t);
assert(n == i + 1);
}
/* 4 times, remove half of the nodes and add them again */
for (j = 0; j < 4; ++j) {
/* shuffle nodes again */
/* remove half of the nodes */
c_rbtree_remove(&t, nodes[i]);
n = validate(&t);
c_rbnode_init(nodes[i]);
}
/* shuffle the removed half */
/* add the removed half again */
n = validate(&t);
}
}
/* shuffle nodes again */
/* remove all */
c_rbtree_remove(&t, nodes[i]);
n = validate(&t);
c_rbnode_init(nodes[i]);
}
/* free nodes again */
}
typedef struct {
unsigned long key;
} Node;
unsigned long key = (unsigned long)k;
}
/* run tests against the c_rbtree_find*() helpers */
static void test_map(void) {
CRBTree t = {};
unsigned long i;
/* allocate and initialize all nodes */
}
/* shuffle nodes */
/* add all nodes, and verify that each node is linked */
}
/* shuffle nodes again */
/* remove all nodes (in different order) */
}
/* free nodes again */
}
unsigned int i;
/* we want stable tests, so use fixed seed */
srand(0xdeadbeef);
test_api();
/*
* The tests are pseudo random; run them multiple times, each run will
* have different orders and thus different results.
*/
for (i = 0; i < 4; ++i) {
test_shuffle();
test_map();
}
return 0;
}