2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
9 This file defines the behavior of the AST namespace which allows for resolving
10 a symbol as one or more AST nodes given a release or range of releases.
15 from idl_option
import GetOption
, Option
, ParseOptions
16 from idl_log
import ErrOut
, InfoOut
, WarnOut
17 from idl_release
import IDLRelease
, IDLReleaseList
19 Option('label', 'Use the specifed label blocks.', default
='Chrome')
20 Option('namespace_debug', 'Use the specified release')
26 # IDLNamespace provides a mapping between a symbol name and an IDLReleaseList
27 # which contains IDLRelease objects. It provides an interface for fetching
28 # one or more IDLNodes based on a release or range of releases.
30 class IDLNamespace(object):
31 def __init__(self
, parent
):
32 self
._name
_to
_releases
= {}
36 for name
in self
._name
_to
_releases
:
37 InfoOut
.Log('NAME=%s' % name
)
38 for cver
in self
._name
_to
_releases
[name
].GetReleases():
39 InfoOut
.Log(' %s' % cver
)
42 def FindRelease(self
, name
, release
):
43 verlist
= self
._name
_to
_releases
.get(name
, None)
46 return self
._parent
.FindRelease(name
, release
)
49 return verlist
.FindRelease(release
)
51 def FindRange(self
, name
, rmin
, rmax
):
52 verlist
= self
._name
_to
_releases
.get(name
, None)
55 return self
._parent
.FindRange(name
, rmin
, rmax
)
58 return verlist
.FindRange(rmin
, rmax
)
60 def FindList(self
, name
):
61 verlist
= self
._name
_to
_releases
.get(name
, None)
64 return self
._parent
.FindList(name
)
67 def AddNode(self
, node
):
69 verlist
= self
._name
_to
_releases
.setdefault(name
,IDLReleaseList())
70 if GetOption('namespace_debug'):
71 print "Adding to namespace: %s" % node
72 return verlist
.AddNode(node
)
82 # Mocks the IDLNode to support error, warning handling, and string functions.
84 class MockNode(IDLRelease
):
85 def __init__(self
, name
, rmin
, rmax
):
98 return '%s (%s : %s)' % (self
.name
, self
.rmin
, self
.rmax
)
103 def Error(self
, msg
):
104 if GetOption('release_debug'): print 'Error: %s' % msg
105 self
.errors
.append(msg
)
108 if GetOption('release_debug'): print 'Warn: %s' % msg
109 self
.warns
.append(msg
)
111 def GetProperty(self
, name
):
112 return self
.properties
.get(name
, None)
118 # Dumps all the information relevant to an add failure.
119 def DumpFailure(namespace
, node
, msg
):
121 print '\n******************************'
122 print 'Failure: %s %s' % (node
, msg
)
123 for warn
in node
.warns
:
124 print ' WARN: %s' % warn
125 for err
in node
.errors
:
126 print ' ERROR: %s' % err
129 print '******************************\n'
132 # Add expecting no errors or warnings
133 def AddOkay(namespace
, node
):
134 okay
= namespace
.AddNode(node
)
135 if not okay
or node
.errors
or node
.warns
:
136 DumpFailure(namespace
, node
, 'Expected success')
138 # Add expecting a specific warning
139 def AddWarn(namespace
, node
, msg
):
140 okay
= namespace
.AddNode(node
)
141 if not okay
or node
.errors
or not node
.warns
:
142 DumpFailure(namespace
, node
, 'Expected warnings')
143 if msg
not in node
.warns
:
144 DumpFailure(namespace
, node
, 'Expected warning: %s' % msg
)
146 # Add expecting a specific error any any number of warnings
147 def AddError(namespace
, node
, msg
):
148 okay
= namespace
.AddNode(node
)
149 if okay
or not node
.errors
:
150 DumpFailure(namespace
, node
, 'Expected errors')
151 if msg
not in node
.errors
:
152 DumpFailure(namespace
, node
, 'Expected error: %s' % msg
)
153 print ">>%s<<\n>>%s<<\n" % (node
.errors
[0], msg
)
155 # Verify that a FindRelease call on the namespace returns the expected node.
156 def VerifyFindOne(namespace
, name
, release
, node
):
158 if (namespace
.FindRelease(name
, release
) != node
):
159 print "Failed to find %s as release %f of %s" % (node
, release
, name
)
164 # Verify that a FindRage call on the namespace returns a set of expected nodes.
165 def VerifyFindAll(namespace
, name
, rmin
, rmax
, nodes
):
167 out
= namespace
.FindRange(name
, rmin
, rmax
)
169 print "Found [%s] instead of[%s] for releases %f to %f of %s" % (
170 ' '.join([str(x
) for x
in out
]),
171 ' '.join([str(x
) for x
in nodes
]),
183 InfoOut
.SetConsole(True)
185 namespace
= IDLNamespace(None)
187 FooXX
= MockNode('foo', None, None)
188 Foo1X
= MockNode('foo', 1.0, None)
189 Foo2X
= MockNode('foo', 2.0, None)
190 Foo3X
= MockNode('foo', 3.0, None)
192 # Verify we succeed with undeprecated adds
193 AddOkay(namespace
, FooXX
)
194 AddOkay(namespace
, Foo1X
)
195 AddOkay(namespace
, Foo3X
)
196 # Verify we fail to add a node between undeprecated releases
197 AddError(namespace
, Foo2X
,
198 'Overlap in releases: 3.0 vs 2.0 when adding foo (2.0 : None)')
200 BarXX
= MockNode('bar', None, None)
201 Bar12
= MockNode('bar', 1.0, 2.0)
202 Bar23
= MockNode('bar', 2.0, 3.0)
203 Bar34
= MockNode('bar', 3.0, 4.0)
206 # Verify we succeed with fully qualified releases
207 namespace
= IDLNamespace(namespace
)
208 AddOkay(namespace
, BarXX
)
209 AddOkay(namespace
, Bar12
)
210 # Verify we warn when detecting a gap
211 AddWarn(namespace
, Bar34
, 'Gap in release numbers.')
212 # Verify we fail when inserting into this gap
213 # (NOTE: while this could be legal, it is sloppy so we disallow it)
214 AddError(namespace
, Bar23
, 'Declarations out of order.')
216 # Verify local namespace
217 VerifyFindOne(namespace
, 'bar', 0.0, BarXX
)
218 VerifyFindAll(namespace
, 'bar', 0.5, 1.5, [BarXX
, Bar12
])
220 # Verify the correct release of the object is found recursively
221 VerifyFindOne(namespace
, 'foo', 0.0, FooXX
)
222 VerifyFindOne(namespace
, 'foo', 0.5, FooXX
)
223 VerifyFindOne(namespace
, 'foo', 1.0, Foo1X
)
224 VerifyFindOne(namespace
, 'foo', 1.5, Foo1X
)
225 VerifyFindOne(namespace
, 'foo', 3.0, Foo3X
)
226 VerifyFindOne(namespace
, 'foo', 100.0, Foo3X
)
228 # Verify the correct range of objects is found
229 VerifyFindAll(namespace
, 'foo', 0.0, 1.0, [FooXX
])
230 VerifyFindAll(namespace
, 'foo', 0.5, 1.0, [FooXX
])
231 VerifyFindAll(namespace
, 'foo', 1.0, 1.1, [Foo1X
])
232 VerifyFindAll(namespace
, 'foo', 0.5, 1.5, [FooXX
, Foo1X
])
233 VerifyFindAll(namespace
, 'foo', 0.0, 3.0, [FooXX
, Foo1X
])
234 VerifyFindAll(namespace
, 'foo', 3.0, 100.0, [Foo3X
])
236 FooBar
= MockNode('foobar', 1.0, 2.0)
237 namespace
= IDLNamespace(namespace
)
238 AddOkay(namespace
, FooBar
)
241 print 'Test failed with %d errors.' % errors
247 if __name__
== '__main__':
248 sys
.exit(Main(sys
.argv
[1:]))