diff --git a/tests/renderdot.py b/tests/renderdot.py new file mode 100644 index 0000000..597e68b --- /dev/null +++ b/tests/renderdot.py @@ -0,0 +1,73 @@ +import sys + +class Renderer(object): + + def __init__(self, getleft, getright, + getred, getstart, getend, nil): + self.getleft = getleft + self.getright = getright + self.getred = getred + self.getstart = getstart + self.getend = getend + self.nil = nil + + # Rendering + def __render_dot_node(self, node, max_depth = 20): + from nilmdb.printf import sprintf + """Render a single node and its children into a dot graph fragment""" + if max_depth == 0: + return "" + if node is self.nil: + return "" + def c(red): + if red: + return 'color="#ff0000", style=filled, fillcolor="#ffc0c0"' + else: + return 'color="#000000", style=filled, fillcolor="#c0c0c0"' + s = sprintf("%d [label=\"%g\\n%g\", %s];\n", + id(node), + self.getstart(node), self.getend(node), + c(self.getred(node))) + + if self.getleft(node) is self.nil: + s += sprintf("L%d [label=\"-\", %s];\n", id(node), c(False)) + s += sprintf("%d -> L%d [label=L];\n", id(node), id(node)) + else: + s += sprintf("%d -> %d [label=L];\n", + id(node),id(self.getleft(node))) + if self.getright(node) is self.nil: + s += sprintf("R%d [label=\"-\", %s];\n", id(node), c(False)) + s += sprintf("%d -> R%d [label=R];\n", id(node), id(node)) + else: + s += sprintf("%d -> %d [label=R];\n", + id(node), id(self.getright(node))) + s += self.__render_dot_node(self.getleft(node), max_depth-1) + s += self.__render_dot_node(self.getright(node), max_depth-1) + return s + + def render_dot(self, rootnode, title = "Tree"): + """Render the entire tree as a dot graph""" + return ("digraph rbtree {\n" + + self.__render_dot_node(rootnode) + + "}\n"); + + def render_dot_live(self, rootnode, title = "Tree"): + """Render the entiretree as a dot graph, live GTK view""" + import gtk + import gtk.gdk + sys.path.append("/usr/share/xdot") + import xdot + xdot.Pen.highlighted = lambda pen: pen + s = ("digraph rbtree {\n" + + self.__render_dot_node(rootnode) + + "}\n"); + window = xdot.DotWindow() + window.set_dotcode(s) + window.set_title(title + " - any key to close") + window.connect('destroy', gtk.main_quit) + def quit(widget, event): + if not event.is_modifier: + window.destroy() + gtk.main_quit() + window.widget.connect('key-press-event', quit) + gtk.main() diff --git a/tests/test_interval.py b/tests/test_interval.py index 839922d..7e06746 100644 --- a/tests/test_interval.py +++ b/tests/test_interval.py @@ -270,6 +270,7 @@ class TestIntervalDB: class TestIntervalTree: def test_interval_tree(self): + import renderdot import random random.seed(1234) @@ -280,6 +281,15 @@ class TestIntervalTree: interval = Interval(i, i+1) iset += interval + # Plot it + r = renderdot.Renderer(lambda node: node.cleft, + lambda node: node.cright, + lambda node: False, + lambda node: node.start, + lambda node: node.end, + iset.tree.emptynode()) + r.render_dot_live(iset.tree.rootnode(), "Random insertion") + # remove about half of them for i in random.sample(xrange(j),j): if random.randint(0,1): @@ -289,9 +299,32 @@ class TestIntervalTree: with assert_raises(IntervalError): iset -= Interval(1234,5678) - # show the graph - if False: - iset.tree.render_dot_live() + # Plot it + r = renderdot.Renderer(lambda node: node.cleft, + lambda node: node.cright, + lambda node: False, + lambda node: node.start, + lambda node: node.end, + iset.tree.emptynode()) + r.render_dot_live(iset.tree.rootnode(), "Random insertion, deletion") + + # make a set of 500 intervals, inserted in order + iset = IntervalSet() + j = 500 + for i in xrange(j): + interval = Interval(i, i+1) + iset += interval + + # Plot it + r = renderdot.Renderer(lambda node: node.cleft, + lambda node: node.cright, + lambda node: False, + lambda node: node.start, + lambda node: node.end, + iset.tree.emptynode()) + r.render_dot_live(iset.tree.rootnode(), "In-order insertion") + + assert(False) class TestIntervalSpeed: @unittest.skip("this is slow")