1#!/usr/bin/env python
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.
5
6'''Unit tests for base.Node functionality (as used in various subclasses)'''
7
8
9import os
10import sys
11if __name__ == '__main__':
12  sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
13
14import StringIO
15import unittest
16
17from grit import grd_reader
18from grit import util
19from grit.node import base
20from grit.node import message
21
22
23def MakePlaceholder(phname='BINGO'):
24  ph = message.PhNode()
25  ph.StartParsing(u'ph', None)
26  ph.HandleAttribute(u'name', phname)
27  ph.AppendContent(u'bongo')
28  ph.EndParsing()
29  return ph
30
31
32class NodeUnittest(unittest.TestCase):
33  def testWhitespaceHandling(self):
34    # We test using the Message node type.
35    node = message.MessageNode()
36    node.StartParsing(u'hello', None)
37    node.HandleAttribute(u'name', u'bla')
38    node.AppendContent(u" '''  two spaces  ")
39    node.EndParsing()
40    self.failUnless(node.GetCdata() == u'  two spaces')
41
42    node = message.MessageNode()
43    node.StartParsing(u'message', None)
44    node.HandleAttribute(u'name', u'bla')
45    node.AppendContent(u"  two spaces  '''  ")
46    node.EndParsing()
47    self.failUnless(node.GetCdata() == u'two spaces  ')
48
49  def testWhitespaceHandlingWithChildren(self):
50    # We test using the Message node type.
51    node = message.MessageNode()
52    node.StartParsing(u'message', None)
53    node.HandleAttribute(u'name', u'bla')
54    node.AppendContent(u" '''  two spaces  ")
55    node.AddChild(MakePlaceholder())
56    node.AppendContent(u' space before and after ')
57    node.AddChild(MakePlaceholder('BONGO'))
58    node.AppendContent(u" space before two after  '''")
59    node.EndParsing()
60    self.failUnless(node.mixed_content[0] == u'  two spaces  ')
61    self.failUnless(node.mixed_content[2] == u' space before and after ')
62    self.failUnless(node.mixed_content[-1] == u' space before two after  ')
63
64  def testXmlFormatMixedContent(self):
65    # Again test using the Message node type, because it is the only mixed
66    # content node.
67    node = message.MessageNode()
68    node.StartParsing(u'message', None)
69    node.HandleAttribute(u'name', u'name')
70    node.AppendContent(u'Hello <young> ')
71
72    ph = message.PhNode()
73    ph.StartParsing(u'ph', None)
74    ph.HandleAttribute(u'name', u'USERNAME')
75    ph.AppendContent(u'$1')
76    ex = message.ExNode()
77    ex.StartParsing(u'ex', None)
78    ex.AppendContent(u'Joi')
79    ex.EndParsing()
80    ph.AddChild(ex)
81    ph.EndParsing()
82
83    node.AddChild(ph)
84    node.EndParsing()
85
86    non_indented_xml = node.FormatXml()
87    self.failUnless(non_indented_xml == u'<message name="name">\n  Hello '
88                    u'&lt;young&gt; <ph name="USERNAME">$1<ex>Joi</ex></ph>'
89                    u'\n</message>')
90
91    indented_xml = node.FormatXml(u'  ')
92    self.failUnless(indented_xml == u'  <message name="name">\n    Hello '
93                    u'&lt;young&gt; <ph name="USERNAME">$1<ex>Joi</ex></ph>'
94                    u'\n  </message>')
95
96  def testXmlFormatMixedContentWithLeadingWhitespace(self):
97    # Again test using the Message node type, because it is the only mixed
98    # content node.
99    node = message.MessageNode()
100    node.StartParsing(u'message', None)
101    node.HandleAttribute(u'name', u'name')
102    node.AppendContent(u"'''   Hello <young> ")
103
104    ph = message.PhNode()
105    ph.StartParsing(u'ph', None)
106    ph.HandleAttribute(u'name', u'USERNAME')
107    ph.AppendContent(u'$1')
108    ex = message.ExNode()
109    ex.StartParsing(u'ex', None)
110    ex.AppendContent(u'Joi')
111    ex.EndParsing()
112    ph.AddChild(ex)
113    ph.EndParsing()
114
115    node.AddChild(ph)
116    node.AppendContent(u" yessiree '''")
117    node.EndParsing()
118
119    non_indented_xml = node.FormatXml()
120    self.failUnless(non_indented_xml ==
121                    u"<message name=\"name\">\n  '''   Hello"
122                    u' &lt;young&gt; <ph name="USERNAME">$1<ex>Joi</ex></ph>'
123                    u" yessiree '''\n</message>")
124
125    indented_xml = node.FormatXml(u'  ')
126    self.failUnless(indented_xml ==
127                    u"  <message name=\"name\">\n    '''   Hello"
128                    u' &lt;young&gt; <ph name="USERNAME">$1<ex>Joi</ex></ph>'
129                    u" yessiree '''\n  </message>")
130
131    self.failUnless(node.GetNodeById('name'))
132
133  def testXmlFormatContentWithEntities(self):
134    '''Tests a bug where &nbsp; would not be escaped correctly.'''
135    from grit import tclib
136    msg_node = message.MessageNode.Construct(None, tclib.Message(
137      text = 'BEGIN_BOLDHelloWHITESPACEthere!END_BOLD Bingo!',
138      placeholders = [
139        tclib.Placeholder('BEGIN_BOLD', '<b>', 'bla'),
140        tclib.Placeholder('WHITESPACE', '&nbsp;', 'bla'),
141        tclib.Placeholder('END_BOLD', '</b>', 'bla')]),
142                                             'BINGOBONGO')
143    xml = msg_node.FormatXml()
144    self.failUnless(xml.find('&nbsp;') == -1, 'should have no entities')
145
146  def testIter(self):
147    # First build a little tree of message and ph nodes.
148    node = message.MessageNode()
149    node.StartParsing(u'message', None)
150    node.HandleAttribute(u'name', u'bla')
151    node.AppendContent(u" '''  two spaces  ")
152    node.AppendContent(u' space before and after ')
153    ph = message.PhNode()
154    ph.StartParsing(u'ph', None)
155    ph.AddChild(message.ExNode())
156    ph.HandleAttribute(u'name', u'BINGO')
157    ph.AppendContent(u'bongo')
158    node.AddChild(ph)
159    node.AddChild(message.PhNode())
160    node.AppendContent(u" space before two after  '''")
161
162    order = [message.MessageNode, message.PhNode, message.ExNode, message.PhNode]
163    for n in node:
164      self.failUnless(type(n) == order[0])
165      order = order[1:]
166    self.failUnless(len(order) == 0)
167
168  def testGetChildrenOfType(self):
169    xml = '''<?xml version="1.0" encoding="UTF-8"?>
170      <grit latest_public_release="2" source_lang_id="en-US"
171            current_release="3" base_dir=".">
172        <outputs>
173          <output filename="resource.h" type="rc_header" />
174          <output filename="en/generated_resources.rc" type="rc_all"
175                  lang="en" />
176          <if expr="pp_if('NOT_TRUE')">
177            <output filename="de/generated_resources.rc" type="rc_all"
178                    lang="de" />
179          </if>
180        </outputs>
181        <release seq="3">
182          <messages>
183            <message name="ID_HELLO">Hello!</message>
184          </messages>
185        </release>
186      </grit>'''
187    grd = grd_reader.Parse(StringIO.StringIO(xml),
188                           util.PathFromRoot('grit/test/data'))
189    from grit.node import io
190    output_nodes = grd.GetChildrenOfType(io.OutputNode)
191    self.failUnlessEqual(len(output_nodes), 3)
192    self.failUnlessEqual(output_nodes[2].attrs['filename'],
193                         'de/generated_resources.rc')
194
195  def testEvaluateExpression(self):
196    def AssertExpr(expected_value, expr, defs, target_platform,
197                   extra_variables):
198      self.failUnlessEqual(expected_value, base.Node.EvaluateExpression(
199          expr, defs, target_platform, extra_variables))
200
201    AssertExpr(True, "True", {}, 'linux', {})
202    AssertExpr(False, "False", {}, 'linux', {})
203    AssertExpr(True, "True or False", {}, 'linux', {})
204    AssertExpr(False, "True and False", {}, 'linux', {})
205    AssertExpr(True, "os == 'linux'", {}, 'linux', {})
206    AssertExpr(False, "os == 'linux'", {}, 'ios', {})
207    AssertExpr(True, "'foo' in defs", {'foo': 'bar'}, 'ios', {})
208    AssertExpr(False, "'foo' in defs", {'baz': 'bar'}, 'ios', {})
209    AssertExpr(False, "'foo' in defs", {}, 'ios', {})
210    AssertExpr(True, "is_linux", {}, 'linux2', {})
211    AssertExpr(False, "is_linux", {}, 'win32', {})
212    AssertExpr(True, "is_macosx", {}, 'darwin', {})
213    AssertExpr(False, "is_macosx", {}, 'ios', {})
214    AssertExpr(True, "is_win", {}, 'win32', {})
215    AssertExpr(False, "is_win", {}, 'darwin', {})
216    AssertExpr(True, "is_android", {}, 'android', {})
217    AssertExpr(False, "is_android", {}, 'linux3', {})
218    AssertExpr(True, "is_ios", {}, 'ios', {})
219    AssertExpr(False, "is_ios", {}, 'darwin', {})
220    AssertExpr(True, "is_posix", {}, 'linux2', {})
221    AssertExpr(True, "is_posix", {}, 'darwin', {})
222    AssertExpr(True, "is_posix", {}, 'android', {})
223    AssertExpr(True, "is_posix", {}, 'ios', {})
224    AssertExpr(True, "is_posix", {}, 'freebsd7', {})
225    AssertExpr(False, "is_posix", {}, 'win32', {})
226    AssertExpr(True, "pp_ifdef('foo')", {'foo': True}, 'win32', {})
227    AssertExpr(True, "pp_ifdef('foo')", {'foo': False}, 'win32', {})
228    AssertExpr(False, "pp_ifdef('foo')", {'bar': True}, 'win32', {})
229    AssertExpr(True, "pp_if('foo')", {'foo': True}, 'win32', {})
230    AssertExpr(False, "pp_if('foo')", {'foo': False}, 'win32', {})
231    AssertExpr(False, "pp_if('foo')", {'bar': True}, 'win32', {})
232    AssertExpr(True, "foo", {'foo': True}, 'win32', {})
233    AssertExpr(False, "foo", {'foo': False}, 'win32', {})
234    AssertExpr(False, "foo", {'bar': True}, 'win32', {})
235    AssertExpr(True, "foo == 'baz'", {'foo': 'baz'}, 'win32', {})
236    AssertExpr(False, "foo == 'baz'", {'foo': True}, 'win32', {})
237    AssertExpr(False, "foo == 'baz'", {}, 'win32', {})
238    AssertExpr(True, "lang == 'de'", {}, 'win32', {'lang': 'de'})
239    AssertExpr(False, "lang == 'de'", {}, 'win32', {'lang': 'fr'})
240    AssertExpr(False, "lang == 'de'", {}, 'win32', {})
241
242    # Test a couple more complex expressions for good measure.
243    AssertExpr(True, "is_ios and (lang in ['de', 'fr'] or foo)",
244               {'foo': 'bar'}, 'ios', {'lang': 'fr', 'context': 'today'})
245    AssertExpr(False, "is_ios and (lang in ['de', 'fr'] or foo)",
246               {'foo': False}, 'linux2', {'lang': 'fr', 'context': 'today'})
247    AssertExpr(False, "is_ios and (lang in ['de', 'fr'] or foo)",
248               {'baz': 'bar'}, 'ios', {'lang': 'he', 'context': 'today'})
249    AssertExpr(True, "foo == 'bar' or not baz",
250               {'foo': 'bar', 'fun': True}, 'ios', {'lang': 'en'})
251    AssertExpr(True, "foo == 'bar' or not baz",
252               {}, 'ios', {'lang': 'en', 'context': 'java'})
253    AssertExpr(False, "foo == 'bar' or not baz",
254               {'foo': 'ruz', 'baz': True}, 'ios', {'lang': 'en'})
255
256if __name__ == '__main__':
257  unittest.main()
258
259