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 misc.GritNode'''
7
8
9import os
10import sys
11if __name__ == '__main__':
12  sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
13
14import unittest
15import StringIO
16
17from grit import grd_reader
18import grit.exception
19from grit import util
20from grit.format import rc
21from grit.node import misc
22
23
24class GritNodeUnittest(unittest.TestCase):
25  def testUniqueNameAttribute(self):
26    try:
27      restree = grd_reader.Parse(
28        util.PathFromRoot('grit/testdata/duplicate-name-input.xml'))
29      self.fail('Expected parsing exception because of duplicate names.')
30    except grit.exception.Parsing:
31      pass  # Expected case
32
33  def testReadFirstIdsFromFile(self):
34    test_resource_ids = os.path.join(os.path.dirname(__file__), '..',
35                                     'testdata', 'resource_ids')
36    base_dir = os.path.dirname(test_resource_ids)
37
38    src_dir, id_dict = misc._ReadFirstIdsFromFile(
39        test_resource_ids,
40        {
41          'FOO': os.path.join(base_dir, 'bar'),
42          'SHARED_INTERMEDIATE_DIR': os.path.join(base_dir,
43                                                  'out/Release/obj/gen'),
44        })
45    self.assertEqual({}, id_dict.get('bar/file.grd', None))
46    self.assertEqual({},
47        id_dict.get('out/Release/obj/gen/devtools/devtools.grd', None))
48
49    src_dir, id_dict = misc._ReadFirstIdsFromFile(
50        test_resource_ids,
51        {
52          'SHARED_INTERMEDIATE_DIR': '/outside/src_dir',
53        })
54    self.assertEqual({}, id_dict.get('devtools.grd', None))
55
56class IfNodeUnittest(unittest.TestCase):
57  def testIffyness(self):
58    grd = grd_reader.Parse(StringIO.StringIO('''
59      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
60        <release seq="3">
61          <messages>
62            <if expr="'bingo' in defs">
63              <message name="IDS_BINGO">
64                Bingo!
65              </message>
66            </if>
67            <if expr="'hello' in defs">
68              <message name="IDS_HELLO">
69                Hello!
70              </message>
71            </if>
72            <if expr="lang == 'fr' or 'FORCE_FRENCH' in defs">
73              <message name="IDS_HELLO" internal_comment="French version">
74                Good morning
75              </message>
76            </if>
77            <if expr="is_win">
78              <message name="IDS_ISWIN">is_win</message>
79            </if>
80          </messages>
81        </release>
82      </grit>'''), dir='.')
83
84    messages_node = grd.children[0].children[0]
85    bingo_message = messages_node.children[0].children[0]
86    hello_message = messages_node.children[1].children[0]
87    french_message = messages_node.children[2].children[0]
88    is_win_message = messages_node.children[3].children[0]
89
90    self.assertTrue(bingo_message.name == 'message')
91    self.assertTrue(hello_message.name == 'message')
92    self.assertTrue(french_message.name == 'message')
93
94    grd.SetOutputLanguage('fr')
95    grd.SetDefines({'hello': '1'})
96    active = set(grd.ActiveDescendants())
97    self.failUnless(bingo_message not in active)
98    self.failUnless(hello_message in active)
99    self.failUnless(french_message in active)
100
101    grd.SetOutputLanguage('en')
102    grd.SetDefines({'bingo': 1})
103    active = set(grd.ActiveDescendants())
104    self.failUnless(bingo_message in active)
105    self.failUnless(hello_message not in active)
106    self.failUnless(french_message not in active)
107
108    grd.SetOutputLanguage('en')
109    grd.SetDefines({'FORCE_FRENCH': '1', 'bingo': '1'})
110    active = set(grd.ActiveDescendants())
111    self.failUnless(bingo_message in active)
112    self.failUnless(hello_message not in active)
113    self.failUnless(french_message in active)
114
115    grd.SetOutputLanguage('en')
116    grd.SetDefines({})
117    self.failUnless(grd.target_platform == sys.platform)
118    grd.SetTargetPlatform('darwin')
119    active = set(grd.ActiveDescendants())
120    self.failUnless(is_win_message not in active)
121    grd.SetTargetPlatform('win32')
122    active = set(grd.ActiveDescendants())
123    self.failUnless(is_win_message in active)
124
125  def testElsiness(self):
126    grd = util.ParseGrdForUnittest('''
127        <messages>
128          <if expr="True">
129            <then> <message name="IDS_YES1"></message> </then>
130            <else> <message name="IDS_NO1"></message> </else>
131          </if>
132          <if expr="True">
133            <then> <message name="IDS_YES2"></message> </then>
134            <else> </else>
135          </if>
136          <if expr="True">
137            <then> </then>
138            <else> <message name="IDS_NO2"></message> </else>
139          </if>
140          <if expr="True">
141            <then> </then>
142            <else> </else>
143          </if>
144          <if expr="False">
145            <then> <message name="IDS_NO3"></message> </then>
146            <else> <message name="IDS_YES3"></message> </else>
147          </if>
148          <if expr="False">
149            <then> <message name="IDS_NO4"></message> </then>
150            <else> </else>
151          </if>
152          <if expr="False">
153            <then> </then>
154            <else> <message name="IDS_YES4"></message> </else>
155          </if>
156          <if expr="False">
157            <then> </then>
158            <else> </else>
159          </if>
160        </messages>''')
161    included = [msg.attrs['name'] for msg in grd.ActiveDescendants()
162                                  if msg.name == 'message']
163    self.assertEqual(['IDS_YES1', 'IDS_YES2', 'IDS_YES3', 'IDS_YES4'], included)
164
165  def testIffynessWithOutputNodes(self):
166    grd = grd_reader.Parse(StringIO.StringIO('''
167      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
168        <outputs>
169          <output filename="uncond1.rc" type="rc_data" />
170          <if expr="lang == 'fr' or 'hello' in defs">
171            <output filename="only_fr.adm" type="adm" />
172            <output filename="only_fr.plist" type="plist" />
173          </if>
174          <if expr="lang == 'ru'">
175            <output filename="doc.html" type="document" />
176          </if>
177          <output filename="uncond2.adm" type="adm" />
178          <output filename="iftest.h" type="rc_header">
179            <emit emit_type='prepend'></emit>
180          </output>
181        </outputs>
182      </grit>'''), dir='.')
183
184    outputs_node = grd.children[0]
185    uncond1_output = outputs_node.children[0]
186    only_fr_adm_output = outputs_node.children[1].children[0]
187    only_fr_plist_output = outputs_node.children[1].children[1]
188    doc_output = outputs_node.children[2].children[0]
189    uncond2_output = outputs_node.children[0]
190    self.assertTrue(uncond1_output.name == 'output')
191    self.assertTrue(only_fr_adm_output.name == 'output')
192    self.assertTrue(only_fr_plist_output.name == 'output')
193    self.assertTrue(doc_output.name == 'output')
194    self.assertTrue(uncond2_output.name == 'output')
195
196    grd.SetOutputLanguage('ru')
197    grd.SetDefines({'hello': '1'})
198    outputs = [output.GetFilename() for output in grd.GetOutputFiles()]
199    self.assertEquals(
200        outputs,
201        ['uncond1.rc', 'only_fr.adm', 'only_fr.plist', 'doc.html',
202         'uncond2.adm', 'iftest.h'])
203
204    grd.SetOutputLanguage('ru')
205    grd.SetDefines({'bingo': '2'})
206    outputs = [output.GetFilename() for output in grd.GetOutputFiles()]
207    self.assertEquals(
208        outputs,
209        ['uncond1.rc', 'doc.html', 'uncond2.adm', 'iftest.h'])
210
211    grd.SetOutputLanguage('fr')
212    grd.SetDefines({'hello': '1'})
213    outputs = [output.GetFilename() for output in grd.GetOutputFiles()]
214    self.assertEquals(
215        outputs,
216        ['uncond1.rc', 'only_fr.adm', 'only_fr.plist', 'uncond2.adm',
217         'iftest.h'])
218
219    grd.SetOutputLanguage('en')
220    grd.SetDefines({'bingo': '1'})
221    outputs = [output.GetFilename() for output in grd.GetOutputFiles()]
222    self.assertEquals(outputs, ['uncond1.rc', 'uncond2.adm', 'iftest.h'])
223
224    grd.SetOutputLanguage('fr')
225    grd.SetDefines({'bingo': '1'})
226    outputs = [output.GetFilename() for output in grd.GetOutputFiles()]
227    self.assertNotEquals(outputs, ['uncond1.rc', 'uncond2.adm', 'iftest.h'])
228
229  def testChildrenAccepted(self):
230    grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0"?>
231      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
232        <release seq="3">
233          <includes>
234            <if expr="'bingo' in defs">
235              <include type="gif" name="ID_LOGO2" file="images/logo2.gif" />
236            </if>
237            <if expr="'bingo' in defs">
238              <if expr="'hello' in defs">
239                <include type="gif" name="ID_LOGO2" file="images/logo2.gif" />
240              </if>
241            </if>
242          </includes>
243          <structures>
244            <if expr="'bingo' in defs">
245              <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\test\data\klonk.rc" encoding="utf-16" />
246            </if>
247            <if expr="'bingo' in defs">
248              <if expr="'hello' in defs">
249                <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\test\data\klonk.rc" encoding="utf-16" />
250              </if>
251            </if>
252          </structures>
253          <messages>
254            <if expr="'bingo' in defs">
255              <message name="IDS_BINGO">Bingo!</message>
256            </if>
257            <if expr="'bingo' in defs">
258              <if expr="'hello' in defs">
259                <message name="IDS_BINGO">Bingo!</message>
260              </if>
261            </if>
262          </messages>
263        </release>
264        <translations>
265          <if expr="'bingo' in defs">
266            <file lang="nl" path="nl_translations.xtb" />
267          </if>
268          <if expr="'bingo' in defs">
269            <if expr="'hello' in defs">
270              <file lang="nl" path="nl_translations.xtb" />
271            </if>
272          </if>
273        </translations>
274      </grit>'''), dir='.')
275
276  def testIfBadChildrenNesting(self):
277    # includes
278    xml = StringIO.StringIO('''<?xml version="1.0"?>
279      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
280        <release seq="3">
281          <includes>
282            <if expr="'bingo' in defs">
283              <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\test\data\klonk.rc" encoding="utf-16" />
284            </if>
285          </includes>
286        </release>
287      </grit>''')
288    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
289    # messages
290    xml = StringIO.StringIO('''<?xml version="1.0"?>
291      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
292        <release seq="3">
293          <messages>
294            <if expr="'bingo' in defs">
295              <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\test\data\klonk.rc" encoding="utf-16" />
296            </if>
297          </messages>
298        </release>
299      </grit>''')
300    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
301    # structures
302    xml = StringIO.StringIO('''<?xml version="1.0"?>
303      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
304        <release seq="3">
305          <structures>
306            <if expr="'bingo' in defs">
307              <message name="IDS_BINGO">Bingo!</message>
308            </if>
309          </structures>
310        </release>
311      </grit>''')
312    # translations
313    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
314    xml = StringIO.StringIO('''<?xml version="1.0"?>
315      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
316        <translations>
317          <if expr="'bingo' in defs">
318            <message name="IDS_BINGO">Bingo!</message>
319          </if>
320        </translations>
321      </grit>''')
322    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
323    # same with nesting
324    xml = StringIO.StringIO('''<?xml version="1.0"?>
325      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
326        <release seq="3">
327          <includes>
328            <if expr="'bingo' in defs">
329              <if expr="'hello' in defs">
330                <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\test\data\klonk.rc" encoding="utf-16" />
331              </if>
332            </if>
333          </includes>
334        </release>
335      </grit>''')
336    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
337    xml = StringIO.StringIO('''<?xml version="1.0"?>
338      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
339        <release seq="3">
340          <messages>
341            <if expr="'bingo' in defs">
342              <if expr="'hello' in defs">
343                <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\test\data\klonk.rc" encoding="utf-16" />
344              </if>
345            </if>
346          </messages>
347        </release>
348      </grit>''')
349    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
350    xml = StringIO.StringIO('''<?xml version="1.0"?>
351      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
352        <release seq="3">
353          <structures>
354            <if expr="'bingo' in defs">
355              <if expr="'hello' in defs">
356                <message name="IDS_BINGO">Bingo!</message>
357              </if>
358            </if>
359          </structures>
360        </release>
361      </grit>''')
362    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
363    xml = StringIO.StringIO('''<?xml version="1.0"?>
364      <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir=".">
365        <translations>
366          <if expr="'bingo' in defs">
367            <if expr="'hello' in defs">
368              <message name="IDS_BINGO">Bingo!</message>
369            </if>
370          </if>
371        </translations>
372      </grit>''')
373    self.assertRaises(grit.exception.UnexpectedChild, grd_reader.Parse, xml)
374
375
376class ReleaseNodeUnittest(unittest.TestCase):
377  def testPseudoControl(self):
378    grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?>
379      <grit latest_public_release="1" source_lang_id="en-US" current_release="2" base_dir=".">
380        <release seq="1" allow_pseudo="false">
381          <messages>
382            <message name="IDS_HELLO">
383              Hello
384            </message>
385          </messages>
386          <structures>
387            <structure type="dialog" name="IDD_ABOUTBOX" encoding="utf-16" file="klonk.rc" />
388          </structures>
389        </release>
390        <release seq="2">
391          <messages>
392            <message name="IDS_BINGO">
393              Bingo
394            </message>
395          </messages>
396          <structures>
397            <structure type="menu" name="IDC_KLONKMENU" encoding="utf-16" file="klonk.rc" />
398          </structures>
399        </release>
400      </grit>'''), util.PathFromRoot('grit/testdata'))
401    grd.SetOutputLanguage('en')
402    grd.RunGatherers()
403
404    hello = grd.GetNodeById('IDS_HELLO')
405    aboutbox = grd.GetNodeById('IDD_ABOUTBOX')
406    bingo = grd.GetNodeById('IDS_BINGO')
407    menu = grd.GetNodeById('IDC_KLONKMENU')
408
409    for node in [hello, aboutbox]:
410      self.failUnless(not node.PseudoIsAllowed())
411
412    for node in [bingo, menu]:
413      self.failUnless(node.PseudoIsAllowed())
414
415    # TODO(benrg): There was a test here that formatting hello and aboutbox with
416    # a pseudo language should fail, but they do not fail and the test was
417    # broken and failed to catch it. Fix this.
418
419    # Should not raise an exception since pseudo is allowed
420    rc.FormatMessage(bingo, 'xyz-pseudo')
421    rc.FormatStructure(menu, 'xyz-pseudo', '.')
422
423
424if __name__ == '__main__':
425  unittest.main()
426