1#!/usr/bin/env python
2#
3# Copyright 2009 The Closure Library Authors. All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS-IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17
18"""Unit test for depstree."""
19
20__author__ = 'nnaze@google.com (Nathan Naze)'
21
22
23import unittest
24
25import depstree
26
27
28def _GetProvides(sources):
29  """Get all namespaces provided by a collection of sources."""
30
31  provides = set()
32  for source in sources:
33    provides.update(source.provides)
34  return provides
35
36
37class MockSource(object):
38  """Mock Source file."""
39
40  def __init__(self, provides, requires):
41    self.provides = set(provides)
42    self.requires = set(requires)
43
44  def __repr__(self):
45    return 'MockSource %s' % self.provides
46
47
48class DepsTreeTestCase(unittest.TestCase):
49  """Unit test for DepsTree.  Tests several common situations and errors."""
50
51  def AssertValidDependencies(self, deps_list):
52    """Validates a dependency list.
53
54    Asserts that a dependency list is valid: For every source in the list,
55    ensure that every require is provided by a source earlier in the list.
56
57    Args:
58      deps_list: A list of sources that should be in dependency order.
59    """
60
61    for i in range(len(deps_list)):
62      source = deps_list[i]
63      previous_provides = _GetProvides(deps_list[:i])
64      for require in source.requires:
65        self.assertTrue(
66            require in previous_provides,
67            'Namespace "%s" not provided before required by %s' % (
68                require, source))
69
70  def testSimpleDepsTree(self):
71    a = MockSource(['A'], ['B', 'C'])
72    b = MockSource(['B'], [])
73    c = MockSource(['C'], ['D'])
74    d = MockSource(['D'], ['E'])
75    e = MockSource(['E'], [])
76
77    tree = depstree.DepsTree([a, b, c, d, e])
78
79    self.AssertValidDependencies(tree.GetDependencies('A'))
80    self.AssertValidDependencies(tree.GetDependencies('B'))
81    self.AssertValidDependencies(tree.GetDependencies('C'))
82    self.AssertValidDependencies(tree.GetDependencies('D'))
83    self.AssertValidDependencies(tree.GetDependencies('E'))
84
85  def testCircularDependency(self):
86    # Circular deps
87    a = MockSource(['A'], ['B'])
88    b = MockSource(['B'], ['C'])
89    c = MockSource(['C'], ['A'])
90
91    tree = depstree.DepsTree([a, b, c])
92
93    self.assertRaises(depstree.CircularDependencyError,
94                      tree.GetDependencies, 'A')
95
96  def testRequiresUndefinedNamespace(self):
97    a = MockSource(['A'], ['B'])
98    b = MockSource(['B'], ['C'])
99    c = MockSource(['C'], ['D'])  # But there is no D.
100
101    def MakeDepsTree():
102      return depstree.DepsTree([a, b, c])
103
104    self.assertRaises(depstree.NamespaceNotFoundError, MakeDepsTree)
105
106  def testDepsForMissingNamespace(self):
107    a = MockSource(['A'], ['B'])
108    b = MockSource(['B'], [])
109
110    tree = depstree.DepsTree([a, b])
111
112    # There is no C.
113    self.assertRaises(depstree.NamespaceNotFoundError,
114                      tree.GetDependencies, 'C')
115
116  def testMultipleRequires(self):
117    a = MockSource(['A'], ['B'])
118    b = MockSource(['B'], ['C'])
119    c = MockSource(['C'], [])
120    d = MockSource(['D'], ['B'])
121
122    tree = depstree.DepsTree([a, b, c, d])
123    self.AssertValidDependencies(tree.GetDependencies(['D', 'A']))
124
125
126if __name__ == '__main__':
127  unittest.main()
128