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 grit.node.message'''
7
8from __future__ import print_function
9
10import os
11import sys
12import unittest
13
14if __name__ == '__main__':
15  sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
16
17from grit import exception
18from grit import tclib
19from grit import util
20from grit.node import message
21
22class MessageUnittest(unittest.TestCase):
23  def testMessage(self):
24    root = util.ParseGrdForUnittest('''
25        <messages>
26        <message name="IDS_GREETING"
27                 desc="Printed to greet the currently logged in user">
28        Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today?
29        </message>
30        </messages>''')
31    msg, = root.GetChildrenOfType(message.MessageNode)
32    cliques = msg.GetCliques()
33    content = cliques[0].GetMessage().GetPresentableContent()
34    self.failUnless(content == 'Hello USERNAME, how are you doing today?')
35
36  def testMessageWithWhitespace(self):
37    root = util.ParseGrdForUnittest("""\
38        <messages>
39        <message name="IDS_BLA" desc="">
40        '''  Hello there <ph name="USERNAME">%s</ph>   '''
41        </message>
42        </messages>""")
43    msg, = root.GetChildrenOfType(message.MessageNode)
44    content = msg.GetCliques()[0].GetMessage().GetPresentableContent()
45    self.failUnless(content == 'Hello there USERNAME')
46    self.failUnless(msg.ws_at_start == '  ')
47    self.failUnless(msg.ws_at_end == '   ')
48
49  def testConstruct(self):
50    msg = tclib.Message(text="   Hello USERNAME, how are you?   BINGO\t\t",
51                        placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi'),
52                                      tclib.Placeholder('BINGO', '%d', '11')])
53    msg_node = message.MessageNode.Construct(None, msg, 'BINGOBONGO')
54    self.failUnless(msg_node.children[0].name == 'ph')
55    self.failUnless(msg_node.children[0].children[0].name == 'ex')
56    self.failUnless(msg_node.children[0].children[0].GetCdata() == 'Joi')
57    self.failUnless(msg_node.children[1].children[0].GetCdata() == '11')
58    self.failUnless(msg_node.ws_at_start == '   ')
59    self.failUnless(msg_node.ws_at_end == '\t\t')
60
61  def testUnicodeConstruct(self):
62    text = u'Howdie \u00fe'
63    msg = tclib.Message(text=text)
64    msg_node = message.MessageNode.Construct(None, msg, 'BINGOBONGO')
65    msg_from_node = msg_node.GetCdata()
66    self.failUnless(msg_from_node == text)
67
68  def testFormatterData(self):
69    root = util.ParseGrdForUnittest("""\
70        <messages>
71        <message name="IDS_BLA" desc="" formatter_data="  foo=123 bar  qux=low">
72          Text
73        </message>
74        </messages>""")
75    msg, = root.GetChildrenOfType(message.MessageNode)
76    expected_formatter_data = {
77        'foo': '123',
78        'bar': '',
79        'qux': 'low'}
80
81    # Can't use assertDictEqual, not available in Python 2.6, so do it
82    # by hand.
83    self.failUnlessEqual(len(expected_formatter_data),
84                         len(msg.formatter_data))
85    for key in expected_formatter_data:
86      self.failUnlessEqual(expected_formatter_data[key],
87                           msg.formatter_data[key])
88
89  def testReplaceEllipsis(self):
90    root = util.ParseGrdForUnittest('''
91        <messages>
92        <message name="IDS_GREETING" desc="">
93        A...B.... <ph name="PH">%s<ex>A</ex></ph>... B... C...
94        </message>
95        </messages>''')
96    msg, = root.GetChildrenOfType(message.MessageNode)
97    msg.SetReplaceEllipsis(True)
98    content = msg.Translate('en')
99    self.failUnlessEqual(u'A...B.... %s\u2026 B\u2026 C\u2026', content)
100
101  def testRemoveByteOrderMark(self):
102    root = util.ParseGrdForUnittest(u'''
103        <messages>
104        <message name="IDS_HAS_BOM" desc="">
105        \uFEFFThis\uFEFF i\uFEFFs OK\uFEFF
106        </message>
107        </messages>''')
108    msg, = root.GetChildrenOfType(message.MessageNode)
109    content = msg.Translate('en')
110    self.failUnlessEqual(u'This is OK', content)
111
112  def testPlaceholderHasTooManyExamples(self):
113    try:
114      util.ParseGrdForUnittest("""\
115        <messages>
116        <message name="IDS_FOO" desc="foo">
117          Hi <ph name="NAME">$1<ex>Joi</ex><ex>Joy</ex></ph>
118        </message>
119        </messages>""")
120    except exception.TooManyExamples:
121      return
122    self.fail('Should have gotten exception')
123
124  def testPlaceholderHasInvalidName(self):
125    try:
126      util.ParseGrdForUnittest("""\
127        <messages>
128        <message name="IDS_FOO" desc="foo">
129          Hi <ph name="ABC!">$1</ph>
130        </message>
131        </messages>""")
132    except exception.InvalidPlaceholderName:
133      return
134    self.fail('Should have gotten exception')
135
136  def testChromeLocalizedFormatIsInsidePhNode(self):
137    try:
138      util.ParseGrdForUnittest("""\
139        <messages>
140        <message name="IDS_CHROME_L10N" desc="l10n format">
141          This message is missing the ph node: $1
142        </message>
143        </messages>""")
144    except exception.PlaceholderNotInsidePhNode:
145      return
146    self.fail('Should have gotten exception')
147
148  def testAndroidStringFormatIsInsidePhNode(self):
149    try:
150      util.ParseGrdForUnittest("""\
151        <messages>
152        <message name="IDS_ANDROID" desc="string format">
153          This message is missing a ph node: %1$s
154        </message>
155        </messages>""")
156    except exception.PlaceholderNotInsidePhNode:
157      return
158    self.fail('Should have gotten exception')
159
160  def testAndroidIntegerFormatIsInsidePhNode(self):
161    try:
162      util.ParseGrdForUnittest("""\
163        <messages>
164        <message name="IDS_ANDROID" desc="integer format">
165          This message is missing a ph node: %2$d
166        </message>
167        </messages>""")
168    except exception.PlaceholderNotInsidePhNode:
169      return
170    self.fail('Should have gotten exception')
171
172  def testAndroidIntegerWidthFormatIsInsidePhNode(self):
173    try:
174      util.ParseGrdForUnittest("""\
175        <messages>
176        <message name="IDS_ANDROID" desc="integer width format">
177          This message is missing a ph node: %2$3d
178        </message>
179        </messages>""")
180    except exception.PlaceholderNotInsidePhNode:
181      return
182    self.fail('Should have gotten exception')
183
184  def testValidAndroidIntegerWidthFormatInPhNode(self):
185    try:
186      util.ParseGrdForUnittest("""\
187        <messages>
188        <message name="IDS_ANDROID_WIDTH">
189          <ph name="VALID">%2$3d<ex>042</ex></ph>
190        </message>
191        </messages>""")
192    except:
193      self.fail('Should not have gotten exception')
194
195  def testAndroidFloatFormatIsInsidePhNode(self):
196    try:
197      util.ParseGrdForUnittest("""\
198        <messages>
199        <message name="IDS_ANDROID" desc="float number format">
200          This message is missing a ph node: %3$4.5f
201        </message>
202        </messages>""")
203    except exception.PlaceholderNotInsidePhNode:
204      return
205    self.fail('Should have gotten exception')
206
207  def testGritStringFormatIsInsidePhNode(self):
208    try:
209      util.ParseGrdForUnittest("""\
210        <messages>
211        <message name="IDS_GRIT_STRING" desc="grit string format">
212          This message is missing the ph node: %s
213        </message>
214        </messages>""")
215    except exception.PlaceholderNotInsidePhNode:
216      return
217    self.fail('Should have gotten exception')
218
219  def testGritIntegerFormatIsInsidePhNode(self):
220    try:
221      util.ParseGrdForUnittest("""\
222        <messages>
223        <message name="IDS_GRIT_INTEGER" desc="grit integer format">
224          This message is missing the ph node: %d
225        </message>
226        </messages>""")
227    except exception.PlaceholderNotInsidePhNode:
228      return
229    self.fail('Should have gotten exception')
230
231  def testWindowsETWIntegerFormatIsInsidePhNode(self):
232    try:
233      util.ParseGrdForUnittest("""\
234        <messages>
235        <message name="IDS_WINDOWS_ETW" desc="ETW tracing integer">
236          This message is missing the ph node: %1
237        </message>
238        </messages>""")
239    except exception.PlaceholderNotInsidePhNode:
240      return
241    self.fail('Should have gotten exception')
242
243  def testValidMultipleFormattersInsidePhNodes(self):
244    root = util.ParseGrdForUnittest("""\
245      <messages>
246      <message name="IDS_MULTIPLE_FORMATTERS">
247        <ph name="ERROR_COUNT">%1$d<ex>1</ex></ph> error, <ph name="WARNING_COUNT">%2$d<ex>1</ex></ph> warning
248      </message>
249      </messages>""")
250    msg, = root.GetChildrenOfType(message.MessageNode)
251    cliques = msg.GetCliques()
252    content = cliques[0].GetMessage().GetPresentableContent()
253    self.failUnless(content == 'ERROR_COUNT error, WARNING_COUNT warning')
254
255  def testMultipleFormattersAreInsidePhNodes(self):
256    failed = True
257    try:
258      util.ParseGrdForUnittest("""\
259        <messages>
260        <message name="IDS_MULTIPLE_FORMATTERS">
261          %1$d error, %2$d warning
262        </message>
263        </messages>""")
264    except exception.PlaceholderNotInsidePhNode:
265      failed = False
266    if failed:
267      self.fail('Should have gotten exception')
268      return
269
270    failed = True
271    try:
272      util.ParseGrdForUnittest("""\
273        <messages>
274        <message name="IDS_MULTIPLE_FORMATTERS">
275          <ph name="ERROR_COUNT">%1$d<ex>1</ex></ph> error, %2$d warning
276        </message>
277        </messages>""")
278    except exception.PlaceholderNotInsidePhNode:
279      failed = False
280    if failed:
281      self.fail('Should have gotten exception')
282      return
283
284    failed = True
285    try:
286      util.ParseGrdForUnittest("""\
287        <messages>
288        <message name="IDS_MULTIPLE_FORMATTERS">
289          <ph name="INVALID">%1$d %2$d</ph>
290        </message>
291        </messages>""")
292    except exception.InvalidCharactersInsidePhNode:
293      failed = False
294    if failed:
295      self.fail('Should have gotten exception')
296      return
297
298  def testValidHTMLFormatInsidePhNode(self):
299    try:
300      util.ParseGrdForUnittest("""\
301        <messages>
302        <message name="IDS_HTML">
303          <ph name="VALID">&lt;span&gt;$1&lt;/span&gt;<ex>1</ex></ph>
304        </message>
305        </messages>""")
306    except:
307      self.fail('Should not have gotten exception')
308
309  def testValidHTMLWithAttributesFormatInsidePhNode(self):
310    try:
311      util.ParseGrdForUnittest("""\
312        <messages>
313        <message name="IDS_HTML_ATTRIBUTE">
314          <ph name="VALID">&lt;span attribute="js:$this %"&gt;$2&lt;/span&gt;<ex>2</ex></ph>
315        </message>
316        </messages>""")
317    except:
318      self.fail('Should not have gotten exception')
319
320  def testValidHTMLEntityFormatInsidePhNode(self):
321    try:
322      util.ParseGrdForUnittest("""\
323        <messages>
324        <message name="IDS_ENTITY">
325          <ph name="VALID">&gt;%1$d&lt;<ex>1</ex></ph>
326        </message>
327        </messages>""")
328    except:
329      self.fail('Should not have gotten exception')
330
331  def testValidMultipleDollarFormatInsidePhNode(self):
332    try:
333      util.ParseGrdForUnittest("""\
334        <messages>
335        <message name="IDS_DOLLARS" desc="l10n dollars format">
336          <ph name="VALID">$$1</ph>
337        </message>
338        </messages>""")
339    except:
340      self.fail('Should not have gotten exception')
341
342  def testInvalidDollarCharacterInsidePhNode(self):
343    try:
344      util.ParseGrdForUnittest("""\
345        <messages>
346        <message name="IDS_BAD_DOLLAR">
347          <ph name="INVALID">%1$d $</ph>
348        </message>
349        </messages>""")
350    except exception.InvalidCharactersInsidePhNode:
351      return
352    self.fail('Should have gotten exception')
353
354  def testInvalidPercentCharacterInsidePhNode(self):
355    try:
356      util.ParseGrdForUnittest("""\
357        <messages>
358        <message name="IDS_BAD_PERCENT">
359          <ph name="INVALID">%1$d %</ph>
360        </message>
361        </messages>""")
362    except exception.InvalidCharactersInsidePhNode:
363      return
364    self.fail('Should have gotten exception')
365
366  def testInvalidMixedFormatCharactersInsidePhNode(self):
367    try:
368      util.ParseGrdForUnittest("""\
369        <messages>
370        <message name="IDS_MIXED_FORMATS">
371          <ph name="INVALID">%1$2</ph>
372        </message>
373        </messages>""")
374    except exception.InvalidCharactersInsidePhNode:
375      return
376    self.fail('Should have gotten exception')
377
378
379if __name__ == '__main__':
380  unittest.main()
381