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 grd_reader package''' 7 8 import os 9 import sys 10 if __name__ == '__main__': 11 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 12 13 import unittest 14 import StringIO 15 16 from grit import exception 17 from grit import grd_reader 18 from grit import util 19 from grit.node import base 20 from grit.node import empty 21 22 23 class GrdReaderUnittest(unittest.TestCase): 24 def testParsingAndXmlOutput(self): 25 input = u'''<?xml version="1.0" encoding="UTF-8"?> 26 <grit base_dir="." current_release="3" latest_public_release="2" source_lang_id="en-US"> 27 <release seq="3"> 28 <includes> 29 <include file="images/logo.gif" name="ID_LOGO" type="gif" /> 30 </includes> 31 <messages> 32 <if expr="True"> 33 <message desc="Printed to greet the currently logged in user" name="IDS_GREETING"> 34 Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? 35 </message> 36 </if> 37 </messages> 38 <structures> 39 <structure file="rc_files/dialogs.rc" name="IDD_NARROW_DIALOG" type="dialog"> 40 <skeleton expr="lang == 'fr-FR'" file="bla.rc" variant_of_revision="3" /> 41 </structure> 42 <structure file="rc_files/version.rc" name="VS_VERSION_INFO" type="version" /> 43 </structures> 44 </release> 45 <translations> 46 <file lang="nl" path="nl_translations.xtb" /> 47 </translations> 48 <outputs> 49 <output filename="resource.h" type="rc_header" /> 50 <output filename="resource.rc" lang="en-US" type="rc_all" /> 51 </outputs> 52 </grit>''' 53 pseudo_file = StringIO.StringIO(input) 54 tree = grd_reader.Parse(pseudo_file, '.') 55 output = unicode(tree) 56 expected_output = input.replace(u' base_dir="."', u'') 57 self.assertEqual(expected_output, output) 58 self.failUnless(tree.GetNodeById('IDS_GREETING')) 59 60 61 def testStopAfter(self): 62 input = u'''<?xml version="1.0" encoding="UTF-8"?> 63 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir="."> 64 <outputs> 65 <output filename="resource.h" type="rc_header" /> 66 <output filename="resource.rc" lang="en-US" type="rc_all" /> 67 </outputs> 68 <release seq="3"> 69 <includes> 70 <include type="gif" name="ID_LOGO" file="images/logo.gif"/> 71 </includes> 72 </release> 73 </grit>''' 74 pseudo_file = StringIO.StringIO(input) 75 tree = grd_reader.Parse(pseudo_file, '.', stop_after='outputs') 76 # only an <outputs> child 77 self.failUnless(len(tree.children) == 1) 78 self.failUnless(tree.children[0].name == 'outputs') 79 80 def testLongLinesWithComments(self): 81 input = u'''<?xml version="1.0" encoding="UTF-8"?> 82 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir="."> 83 <release seq="3"> 84 <messages> 85 <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> 86 This is a very long line with no linebreaks yes yes it stretches on <!-- 87 -->and on <!-- 88 -->and on! 89 </message> 90 </messages> 91 </release> 92 </grit>''' 93 pseudo_file = StringIO.StringIO(input) 94 tree = grd_reader.Parse(pseudo_file, '.') 95 96 greeting = tree.GetNodeById('IDS_GREETING') 97 self.failUnless(greeting.GetCliques()[0].GetMessage().GetRealContent() == 98 'This is a very long line with no linebreaks yes yes it ' 99 'stretches on and on and on!') 100 101 def doTestAssignFirstIds(self, first_ids_path): 102 input = u'''<?xml version="1.0" encoding="UTF-8"?> 103 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" 104 base_dir="." first_ids_file="%s"> 105 <release seq="3"> 106 <messages> 107 <message name="IDS_TEST" desc="test"> 108 test 109 </message> 110 </messages> 111 </release> 112 </grit>''' % first_ids_path 113 pseudo_file = StringIO.StringIO(input) 114 grit_root_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 115 '..') 116 fake_input_path = os.path.join( 117 grit_root_dir, "grit/testdata/chrome/app/generated_resources.grd") 118 root = grd_reader.Parse(pseudo_file, os.path.split(fake_input_path)[0]) 119 root.AssignFirstIds(fake_input_path, {}) 120 messages_node = root.children[0].children[0] 121 self.failUnless(isinstance(messages_node, empty.MessagesNode)) 122 self.failUnless(messages_node.attrs["first_id"] != 123 empty.MessagesNode().DefaultAttributes()["first_id"]) 124 125 def testAssignFirstIds(self): 126 self.doTestAssignFirstIds("../../tools/grit/resource_ids") 127 128 def testAssignFirstIdsUseGritDir(self): 129 self.doTestAssignFirstIds("GRIT_DIR/grit/testdata/tools/grit/resource_ids") 130 131 def testAssignFirstIdsMultipleMessages(self): 132 """If there are multiple messages sections, the resource_ids file 133 needs to list multiple first_id values.""" 134 input = u'''<?xml version="1.0" encoding="UTF-8"?> 135 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" 136 base_dir="." first_ids_file="resource_ids"> 137 <release seq="3"> 138 <messages> 139 <message name="IDS_TEST" desc="test"> 140 test 141 </message> 142 </messages> 143 <messages> 144 <message name="IDS_TEST2" desc="test"> 145 test2 146 </message> 147 </messages> 148 </release> 149 </grit>''' 150 pseudo_file = StringIO.StringIO(input) 151 grit_root_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 152 '..') 153 fake_input_path = os.path.join(grit_root_dir, "grit/testdata/test.grd") 154 155 root = grd_reader.Parse(pseudo_file, os.path.split(fake_input_path)[0]) 156 root.AssignFirstIds(fake_input_path, {}) 157 messages_node = root.children[0].children[0] 158 self.assertTrue(isinstance(messages_node, empty.MessagesNode)) 159 self.assertEqual('100', messages_node.attrs["first_id"]) 160 messages_node = root.children[0].children[1] 161 self.assertTrue(isinstance(messages_node, empty.MessagesNode)) 162 self.assertEqual('10000', messages_node.attrs["first_id"]) 163 164 def testUseNameForIdAndPpIfdef(self): 165 input = u'''<?xml version="1.0" encoding="UTF-8"?> 166 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir="."> 167 <release seq="3"> 168 <messages> 169 <if expr="pp_ifdef('hello')"> 170 <message name="IDS_HELLO" use_name_for_id="true"> 171 Hello! 172 </message> 173 </if> 174 </messages> 175 </release> 176 </grit>''' 177 pseudo_file = StringIO.StringIO(input) 178 root = grd_reader.Parse(pseudo_file, '.', defines={'hello': '1'}) 179 180 # Check if the ID is set to the name. In the past, there was a bug 181 # that caused the ID to be a generated number. 182 hello = root.GetNodeById('IDS_HELLO') 183 self.failUnless(hello.GetCliques()[0].GetId() == 'IDS_HELLO') 184 185 def testUseNameForIdWithIfElse(self): 186 input = u'''<?xml version="1.0" encoding="UTF-8"?> 187 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir="."> 188 <release seq="3"> 189 <messages> 190 <if expr="pp_ifdef('hello')"> 191 <then> 192 <message name="IDS_HELLO" use_name_for_id="true"> 193 Hello! 194 </message> 195 </then> 196 <else> 197 <message name="IDS_HELLO" use_name_for_id="true"> 198 Yellow! 199 </message> 200 </else> 201 </if> 202 </messages> 203 </release> 204 </grit>''' 205 pseudo_file = StringIO.StringIO(input) 206 root = grd_reader.Parse(pseudo_file, '.', defines={'hello': '1'}) 207 208 # Check if the ID is set to the name. In the past, there was a bug 209 # that caused the ID to be a generated number. 210 hello = root.GetNodeById('IDS_HELLO') 211 self.failUnless(hello.GetCliques()[0].GetId() == 'IDS_HELLO') 212 213 def testPartInclusion(self): 214 top_grd = u'''\ 215 <grit latest_public_release="2" current_release="3"> 216 <release seq="3"> 217 <messages> 218 <message name="IDS_TEST" desc="test"> 219 test 220 </message> 221 <part file="sub.grp" /> 222 </messages> 223 </release> 224 </grit>''' 225 sub_grd = u'''\ 226 <grit-part> 227 <message name="IDS_TEST2" desc="test2">test2</message> 228 <part file="subsub.grp" /> 229 <message name="IDS_TEST3" desc="test3">test3</message> 230 </grit-part>''' 231 subsub_grd = u'''\ 232 <grit-part> 233 <message name="IDS_TEST4" desc="test4">test4</message> 234 </grit-part>''' 235 expected_output = u'''\ 236 <grit current_release="3" latest_public_release="2"> 237 <release seq="3"> 238 <messages> 239 <message desc="test" name="IDS_TEST"> 240 test 241 </message> 242 <part file="sub.grp"> 243 <message desc="test2" name="IDS_TEST2"> 244 test2 245 </message> 246 <part file="subsub.grp"> 247 <message desc="test4" name="IDS_TEST4"> 248 test4 249 </message> 250 </part> 251 <message desc="test3" name="IDS_TEST3"> 252 test3 253 </message> 254 </part> 255 </messages> 256 </release> 257 </grit>''' 258 with util.TempDir({'sub.grp': sub_grd, 259 'subsub.grp': subsub_grd}) as temp_dir: 260 output = grd_reader.Parse(StringIO.StringIO(top_grd), temp_dir.GetPath()) 261 self.assertEqual(expected_output.split(), output.FormatXml().split()) 262 263 def testPartInclusionFailure(self): 264 template = u''' 265 <grit latest_public_release="2" current_release="3"> 266 <outputs> 267 %s 268 </outputs> 269 </grit>''' 270 271 part_failures = [ 272 (exception.UnexpectedContent, u'<part file="x">fnord</part>'), 273 (exception.UnexpectedChild, 274 u'<part file="x"><output filename="x" type="y" /></part>'), 275 ] 276 for raises, data in part_failures: 277 data = StringIO.StringIO(template % data) 278 self.assertRaises(raises, grd_reader.Parse, data, '.') 279 280 gritpart_failures = [ 281 (exception.UnexpectedAttribute, u'<grit-part file="xyz"></grit-part>'), 282 (exception.MissingElement, u'<output filename="x" type="y" />'), 283 ] 284 for raises, data in gritpart_failures: 285 top_grd = StringIO.StringIO(template % u'<part file="bad.grp" />') 286 with util.TempDir({'bad.grp': data}) as temp_dir: 287 self.assertRaises(raises, grd_reader.Parse, top_grd, temp_dir.GetPath()) 288 289 def testEarlyEnoughPlatformSpecification(self): 290 # This is a regression test for issue 291 # https://code.google.com/p/grit-i18n/issues/detail?id=23 292 grd_text = u'''<?xml version="1.0" encoding="UTF-8"?> 293 <grit latest_public_release="1" current_release="1"> 294 <release seq="1"> 295 <messages> 296 <if expr="not pp_ifdef('use_titlecase')"> 297 <message name="IDS_XYZ">foo</message> 298 </if> 299 <!-- The assumption is that use_titlecase is never true for 300 this platform. When the platform isn't set to 'android' 301 early enough, we get a duplicate message name. --> 302 <if expr="os == '%s'"> 303 <message name="IDS_XYZ">boo</message> 304 </if> 305 </messages> 306 </release> 307 </grit>''' % sys.platform 308 with util.TempDir({}) as temp_dir: 309 grd_reader.Parse(StringIO.StringIO(grd_text), temp_dir.GetPath(), 310 target_platform='android') 311 312 313 if __name__ == '__main__': 314 unittest.main() 315