diff --git a/python/samba/graph_utils.py b/python/samba/graph_utils.py index a8c727f682e..a01e068a17a 100644 --- a/python/samba/graph_utils.py +++ b/python/samba/graph_utils.py @@ -117,15 +117,17 @@ def verify_graph_connected(edges, vertices, edge_vertices): for i in reversed(doomed): del remaining_edges[i] - if remaining_edges or reached != vertices: - raise GraphError("graph is not connected:\nvertices: %s\n edges: %s" % - (sorted(vertices), sorted(edges))) + if remaining_edges or reached != set(vertices): + raise GraphError("graph is not connected:\n vertices: %s\n edges: %s\n" + " reached: %s\n remaining edges: %s" % + (sorted(vertices), sorted(edges), + sorted(reached), sorted(remaining_edges))) def verify_graph_connected_under_edge_failures(edges, vertices, edge_vertices): """The graph stays connected when any single edge is removed.""" for subset in itertools.combinations(edges, len(edges) - 1): - verify_graph_connected(edges, vertices, edge_vertices) + verify_graph_connected(subset, vertices, edge_vertices) def verify_graph_connected_under_vertex_failures(edges, vertices, @@ -150,7 +152,10 @@ def verify_graph_forest(edges, vertices, edge_vertices): trees.remove(b) break else: - raise GraphError("there is a loop in the graph") + raise GraphError("there is a loop in the graph\n" + " vertices %s\n edges %s\n" + " intersection %s" % + (vertices, edges, intersection)) else: # no break in itertools.combinations loop means no # further mergers, so we're done. @@ -195,7 +200,7 @@ def verify_graph_forest_of_rings(edges, vertices, edge_vertices): def verify_graph_no_lonely_vertices(edges, vertices, edge_vertices): """There are no vertices without edges.""" - lonely = vertices - edge_vertices + lonely = set(vertices) - set(edge_vertices) if lonely: raise GraphError("some vertices are not connected:\n%s" % '\n'.join(sorted(lonely))) @@ -203,7 +208,7 @@ def verify_graph_no_lonely_vertices(edges, vertices, edge_vertices): def verify_graph_no_unknown_vertices(edges, vertices, edge_vertices): """The edge endpoints contain no vertices that are otherwise unknown.""" - unknown = edge_vertices - vertices + unknown = set(edge_vertices) - set(vertices) if unknown: raise GraphError("some edge vertices are seemingly unknown:\n%s" % '\n'.join(sorted(unknown))) diff --git a/python/samba/tests/graph_utils.py b/python/samba/tests/graph_utils.py new file mode 100644 index 00000000000..be76b89ad0b --- /dev/null +++ b/python/samba/tests/graph_utils.py @@ -0,0 +1,162 @@ +# Unix SMB/CIFS implementation. Tests for graph_utils.py routines +# Copyright (C) Andrew Bartlett 2015 +# +# Written by Douglas Bagnall +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +"""Tests for samba.graph_utils""" + +import samba +import samba.tests +from samba.graph_utils import * + +import itertools + + +def make_tree(vertices): + if len(vertices) < 2: + return () + remaining = set(vertices) + used = set() + edges = set() + used.add(remaining.pop()) + used.add(remaining.pop()) + edges.add(tuple(used)) + while remaining: + v = remaining.pop() + w = used.pop() + e = (w, v) + edges.add(e) + used.update(e) + return tuple(edges) + +# TODO: test directed graphs + + +class UndirectedGraphTests(samba.tests.TestCase): + + def setUp(self): + super(UndirectedGraphTests, self).setUp() + vertices = tuple('abcdefgh') + vertices2 = tuple('ijk') + edges = tuple(itertools.combinations(vertices, 2)) + edges2 = tuple(itertools.combinations(vertices2, 2)) + line_edges = zip(vertices[1:], vertices[:-1]) + ring_edges = line_edges + [(vertices[0], vertices[-1])] + + tree = make_tree(vertices) + tree2 = make_tree(vertices2) + + self.complete_graph = [edges, vertices, vertices] + + self.disconnected_clusters = [edges + edges2, + vertices + vertices2, + vertices + vertices2] + + self.graph_with_unreachables = [edges, + vertices + vertices2, + vertices] + + self.ring = [ring_edges, vertices, vertices] + self.line = [line_edges, vertices, vertices] + + self.tree = [tree, vertices, vertices] + self.forest = [tree + tree2, + vertices + vertices2, + vertices + vertices2] + + self.unconnected_graph = ((), vertices, ()) + + def assertGraphError(self, fn, *args): + return self.assertRaises(GraphError, fn, *args) + + def test_graph_complete(self): + fn = verify_graph_complete + + self.assertGraphError(fn, *self.disconnected_clusters) + self.assertGraphError(fn, *self.graph_with_unreachables) + self.assertGraphError(fn, *self.ring) + self.assertGraphError(fn, *self.tree) + + self.assertIsNone(fn(*self.complete_graph)) + + def test_graph_connected(self): + fn = verify_graph_connected + + self.assertGraphError(fn, *self.disconnected_clusters) + self.assertGraphError(fn, *self.graph_with_unreachables) + self.assertGraphError(fn, *self.forest) + self.assertGraphError(fn, *self.unconnected_graph) + + self.assertIsNone(fn(*self.line)) + self.assertIsNone(fn(*self.ring)) + self.assertIsNone(fn(*self.complete_graph)) + self.assertIsNone(fn(*self.tree)) + + def test_graph_forest(self): + fn = verify_graph_forest + + self.assertGraphError(fn, *self.disconnected_clusters) + self.assertGraphError(fn, *self.graph_with_unreachables) + self.assertGraphError(fn, *self.ring) + + self.assertIsNone(fn(*self.line)) + self.assertIsNone(fn(*self.tree)) + self.assertIsNone(fn(*self.forest)) + self.assertIsNone(fn(*self.unconnected_graph)) + + def test_graph_connected_under_edge_failures(self): + fn = verify_graph_connected_under_edge_failures + + self.assertGraphError(fn, *self.line) + self.assertGraphError(fn, *self.tree) + self.assertGraphError(fn, *self.forest) + self.assertGraphError(fn, *self.disconnected_clusters) + + self.assertIsNone(fn(*self.ring)) + self.assertIsNone(fn(*self.complete_graph)) + + def test_graph_connected_under_vertex_failures(self): + #XXX no tests to distinguish this from the edge_failures case + fn = verify_graph_connected_under_vertex_failures + + self.assertGraphError(fn, *self.line) + self.assertGraphError(fn, *self.tree) + self.assertGraphError(fn, *self.forest) + self.assertGraphError(fn, *self.disconnected_clusters) + + self.assertIsNone(fn(*self.ring)) + self.assertIsNone(fn(*self.complete_graph)) + + def test_graph_multi_edge_forest(self): + pass + + def test_graph_forest_of_rings(self): + pass + + def test_graph_no_lonely_vertices(self): + fn = verify_graph_no_lonely_vertices + self.assertGraphError(fn, *self.unconnected_graph) + self.assertGraphError(fn, *self.graph_with_unreachables) + + self.assertIsNone(fn(*self.ring)) + self.assertIsNone(fn(*self.complete_graph)) + self.assertIsNone(fn(*self.line)) + self.assertIsNone(fn(*self.tree)) + self.assertIsNone(fn(*self.forest)) + + def test_graph_no_unknown_vertices(self): + pass diff --git a/selftest/tests.py b/selftest/tests.py index 1185142afc5..8cf35aca20a 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -96,4 +96,5 @@ planpythontestsuite("none", "samba.tests.upgradeprovision") planpythontestsuite("none", "samba.tests.xattr") planpythontestsuite("none", "samba.tests.ntacls") planpythontestsuite("none", "samba.tests.policy") +planpythontestsuite("none", "samba.tests.graph_utils") plantestsuite("wafsamba.duplicate_symbols", "none", [os.path.join(srcdir(), "buildtools/wafsamba/test_duplicate_symbol.sh")])