mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
	
	
		
			302 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			302 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | """Tests for packaging.depgraph """ | ||
|  | import io | ||
|  | import os | ||
|  | import re | ||
|  | import sys | ||
|  | import packaging.database | ||
|  | from packaging import depgraph | ||
|  | 
 | ||
|  | from packaging.tests import unittest, support | ||
|  | 
 | ||
|  | 
 | ||
|  | class DepGraphTestCase(support.LoggingCatcher, | ||
|  |                        unittest.TestCase): | ||
|  | 
 | ||
|  |     DISTROS_DIST = ('choxie', 'grammar', 'towel-stuff') | ||
|  |     DISTROS_EGG = ('bacon', 'banana', 'strawberry', 'cheese') | ||
|  |     BAD_EGGS = ('nut',) | ||
|  | 
 | ||
|  |     EDGE = re.compile( | ||
|  |            r'"(?P<from>.*)" -> "(?P<to>.*)" \[label="(?P<label>.*)"\]') | ||
|  | 
 | ||
|  |     def checkLists(self, l1, l2): | ||
|  |         """ Compare two lists without taking the order into consideration """ | ||
|  |         self.assertListEqual(sorted(l1), sorted(l2)) | ||
|  | 
 | ||
|  |     def setUp(self): | ||
|  |         super(DepGraphTestCase, self).setUp() | ||
|  |         path = os.path.join(os.path.dirname(__file__), 'fake_dists') | ||
|  |         path = os.path.abspath(path) | ||
|  |         sys.path.insert(0, path) | ||
|  |         self.addCleanup(sys.path.remove, path) | ||
|  |         self.addCleanup(packaging.database.enable_cache) | ||
|  |         packaging.database.disable_cache() | ||
|  | 
 | ||
|  |     def test_generate_graph(self): | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST: | ||
|  |             dist = packaging.database.get_distribution(name) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         choxie, grammar, towel = dists | ||
|  | 
 | ||
|  |         graph = depgraph.generate_graph(dists) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[choxie]] | ||
|  |         self.checkLists([('towel-stuff', 'towel-stuff (0.1)')], deps) | ||
|  |         self.assertIn(choxie, graph.reverse_list[towel]) | ||
|  |         self.checkLists(graph.missing[choxie], ['nut']) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[grammar]] | ||
|  |         self.checkLists([], deps) | ||
|  |         self.checkLists(graph.missing[grammar], ['truffles (>=1.2)']) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[towel]] | ||
|  |         self.checkLists([], deps) | ||
|  |         self.checkLists(graph.missing[towel], ['bacon (<=0.2)']) | ||
|  | 
 | ||
|  |     def test_generate_graph_egg(self): | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST + self.DISTROS_EGG: | ||
|  |             dist = packaging.database.get_distribution(name, use_egg_info=True) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         choxie, grammar, towel, bacon, banana, strawberry, cheese = dists | ||
|  | 
 | ||
|  |         graph = depgraph.generate_graph(dists) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[choxie]] | ||
|  |         self.checkLists([('towel-stuff', 'towel-stuff (0.1)')], deps) | ||
|  |         self.assertIn(choxie, graph.reverse_list[towel]) | ||
|  |         self.checkLists(graph.missing[choxie], ['nut']) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[grammar]] | ||
|  |         self.checkLists([('bacon', 'truffles (>=1.2)')], deps) | ||
|  |         self.checkLists(graph.missing[grammar], []) | ||
|  |         self.assertIn(grammar, graph.reverse_list[bacon]) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[towel]] | ||
|  |         self.checkLists([('bacon', 'bacon (<=0.2)')], deps) | ||
|  |         self.checkLists(graph.missing[towel], []) | ||
|  |         self.assertIn(towel, graph.reverse_list[bacon]) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[bacon]] | ||
|  |         self.checkLists([], deps) | ||
|  |         self.checkLists(graph.missing[bacon], []) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[banana]] | ||
|  |         self.checkLists([('strawberry', 'strawberry (>=0.5)')], deps) | ||
|  |         self.checkLists(graph.missing[banana], []) | ||
|  |         self.assertIn(banana, graph.reverse_list[strawberry]) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[strawberry]] | ||
|  |         self.checkLists([], deps) | ||
|  |         self.checkLists(graph.missing[strawberry], []) | ||
|  | 
 | ||
|  |         deps = [(x.name, y) for x, y in graph.adjacency_list[cheese]] | ||
|  |         self.checkLists([], deps) | ||
|  |         self.checkLists(graph.missing[cheese], []) | ||
|  | 
 | ||
|  |     def test_dependent_dists(self): | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST: | ||
|  |             dist = packaging.database.get_distribution(name) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         choxie, grammar, towel = dists | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, choxie)] | ||
|  |         self.checkLists([], deps) | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, grammar)] | ||
|  |         self.checkLists([], deps) | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, towel)] | ||
|  |         self.checkLists(['choxie'], deps) | ||
|  | 
 | ||
|  |     def test_dependent_dists_egg(self): | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST + self.DISTROS_EGG: | ||
|  |             dist = packaging.database.get_distribution(name, use_egg_info=True) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         choxie, grammar, towel, bacon, banana, strawberry, cheese = dists | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, choxie)] | ||
|  |         self.checkLists([], deps) | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, grammar)] | ||
|  |         self.checkLists([], deps) | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, towel)] | ||
|  |         self.checkLists(['choxie'], deps) | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, bacon)] | ||
|  |         self.checkLists(['choxie', 'towel-stuff', 'grammar'], deps) | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, strawberry)] | ||
|  |         self.checkLists(['banana'], deps) | ||
|  | 
 | ||
|  |         deps = [d.name for d in depgraph.dependent_dists(dists, cheese)] | ||
|  |         self.checkLists([], deps) | ||
|  | 
 | ||
|  |     def test_graph_to_dot(self): | ||
|  |         expected = ( | ||
|  |             ('towel-stuff', 'bacon', 'bacon (<=0.2)'), | ||
|  |             ('grammar', 'bacon', 'truffles (>=1.2)'), | ||
|  |             ('choxie', 'towel-stuff', 'towel-stuff (0.1)'), | ||
|  |             ('banana', 'strawberry', 'strawberry (>=0.5)'), | ||
|  |         ) | ||
|  | 
 | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST + self.DISTROS_EGG: | ||
|  |             dist = packaging.database.get_distribution(name, use_egg_info=True) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         graph = depgraph.generate_graph(dists) | ||
|  |         buf = io.StringIO() | ||
|  |         depgraph.graph_to_dot(graph, buf) | ||
|  |         buf.seek(0) | ||
|  |         matches = [] | ||
|  |         lines = buf.readlines() | ||
|  |         for line in lines[1:-1]:  # skip the first and the last lines | ||
|  |             if line[-1] == '\n': | ||
|  |                 line = line[:-1] | ||
|  |             match = self.EDGE.match(line.strip()) | ||
|  |             self.assertIsNot(match, None) | ||
|  |             matches.append(match.groups()) | ||
|  | 
 | ||
|  |         self.checkLists(matches, expected) | ||
|  | 
 | ||
|  |     def test_graph_disconnected_to_dot(self): | ||
|  |         dependencies_expected = ( | ||
|  |             ('towel-stuff', 'bacon', 'bacon (<=0.2)'), | ||
|  |             ('grammar', 'bacon', 'truffles (>=1.2)'), | ||
|  |             ('choxie', 'towel-stuff', 'towel-stuff (0.1)'), | ||
|  |             ('banana', 'strawberry', 'strawberry (>=0.5)'), | ||
|  |         ) | ||
|  |         disconnected_expected = ('cheese', 'bacon', 'strawberry') | ||
|  | 
 | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST + self.DISTROS_EGG: | ||
|  |             dist = packaging.database.get_distribution(name, use_egg_info=True) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         graph = depgraph.generate_graph(dists) | ||
|  |         buf = io.StringIO() | ||
|  |         depgraph.graph_to_dot(graph, buf, skip_disconnected=False) | ||
|  |         buf.seek(0) | ||
|  |         lines = buf.readlines() | ||
|  | 
 | ||
|  |         dependencies_lines = [] | ||
|  |         disconnected_lines = [] | ||
|  | 
 | ||
|  |         # First sort output lines into dependencies and disconnected lines. | ||
|  |         # We also skip the attribute lines, and don't include the "{" and "}" | ||
|  |         # lines. | ||
|  |         disconnected_active = False | ||
|  |         for line in lines[1:-1]:  # Skip first and last line | ||
|  |             if line.startswith('subgraph disconnected'): | ||
|  |                 disconnected_active = True | ||
|  |                 continue | ||
|  |             if line.startswith('}') and disconnected_active: | ||
|  |                 disconnected_active = False | ||
|  |                 continue | ||
|  | 
 | ||
|  |             if disconnected_active: | ||
|  |                 # Skip the 'label = "Disconnected"', etc. attribute lines. | ||
|  |                 if ' = ' not in line: | ||
|  |                     disconnected_lines.append(line) | ||
|  |             else: | ||
|  |                 dependencies_lines.append(line) | ||
|  | 
 | ||
|  |         dependencies_matches = [] | ||
|  |         for line in dependencies_lines: | ||
|  |             if line[-1] == '\n': | ||
|  |                 line = line[:-1] | ||
|  |             match = self.EDGE.match(line.strip()) | ||
|  |             self.assertIsNot(match, None) | ||
|  |             dependencies_matches.append(match.groups()) | ||
|  | 
 | ||
|  |         disconnected_matches = [] | ||
|  |         for line in disconnected_lines: | ||
|  |             if line[-1] == '\n': | ||
|  |                 line = line[:-1] | ||
|  |             line = line.strip('"') | ||
|  |             disconnected_matches.append(line) | ||
|  | 
 | ||
|  |         self.checkLists(dependencies_matches, dependencies_expected) | ||
|  |         self.checkLists(disconnected_matches, disconnected_expected) | ||
|  | 
 | ||
|  |     def test_graph_bad_version_to_dot(self): | ||
|  |         expected = ( | ||
|  |             ('towel-stuff', 'bacon', 'bacon (<=0.2)'), | ||
|  |             ('grammar', 'bacon', 'truffles (>=1.2)'), | ||
|  |             ('choxie', 'towel-stuff', 'towel-stuff (0.1)'), | ||
|  |             ('banana', 'strawberry', 'strawberry (>=0.5)'), | ||
|  |         ) | ||
|  | 
 | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST + self.DISTROS_EGG + self.BAD_EGGS: | ||
|  |             dist = packaging.database.get_distribution(name, use_egg_info=True) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         graph = depgraph.generate_graph(dists) | ||
|  |         buf = io.StringIO() | ||
|  |         depgraph.graph_to_dot(graph, buf) | ||
|  |         buf.seek(0) | ||
|  |         matches = [] | ||
|  |         lines = buf.readlines() | ||
|  |         for line in lines[1:-1]:  # skip the first and the last lines | ||
|  |             if line[-1] == '\n': | ||
|  |                 line = line[:-1] | ||
|  |             match = self.EDGE.match(line.strip()) | ||
|  |             self.assertIsNot(match, None) | ||
|  |             matches.append(match.groups()) | ||
|  | 
 | ||
|  |         self.checkLists(matches, expected) | ||
|  | 
 | ||
|  |     def test_repr(self): | ||
|  |         dists = [] | ||
|  |         for name in self.DISTROS_DIST + self.DISTROS_EGG + self.BAD_EGGS: | ||
|  |             dist = packaging.database.get_distribution(name, use_egg_info=True) | ||
|  |             self.assertNotEqual(dist, None) | ||
|  |             dists.append(dist) | ||
|  | 
 | ||
|  |         graph = depgraph.generate_graph(dists) | ||
|  |         self.assertTrue(repr(graph)) | ||
|  | 
 | ||
|  |     def test_main(self): | ||
|  |         tempout = io.StringIO() | ||
|  |         old = sys.stdout | ||
|  |         sys.stdout = tempout | ||
|  |         oldargv = sys.argv[:] | ||
|  |         sys.argv[:] = ['script.py'] | ||
|  |         try: | ||
|  |             try: | ||
|  |                 depgraph.main() | ||
|  |             except SystemExit: | ||
|  |                 pass | ||
|  |         finally: | ||
|  |             sys.stdout = old | ||
|  |             sys.argv[:] = oldargv | ||
|  | 
 | ||
|  |         # checks what main did XXX could do more here | ||
|  |         tempout.seek(0) | ||
|  |         res = tempout.read() | ||
|  |         self.assertIn('towel', res) | ||
|  | 
 | ||
|  | 
 | ||
|  | def test_suite(): | ||
|  |     return unittest.makeSuite(DepGraphTestCase) | ||
|  | 
 | ||
|  | if __name__ == "__main__": | ||
|  |     unittest.main(defaultTest="test_suite") |