1#!/usr/bin/env python 2# Copyright (c) 2011 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.format.rc''' 7 8import os 9import re 10import sys 11if __name__ == '__main__': 12 sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) 13 14import tempfile 15import unittest 16import StringIO 17 18from grit import grd_reader 19from grit import util 20from grit.node import structure 21from grit.tool import build 22 23 24_PREAMBLE = '''\ 25#include "resource.h" 26#include <winresrc.h> 27#ifdef IDC_STATIC 28#undef IDC_STATIC 29#endif 30#define IDC_STATIC (-1) 31''' 32 33 34class DummyOutput(object): 35 def __init__(self, type, language, file = 'hello.gif'): 36 self.type = type 37 self.language = language 38 self.file = file 39 def GetType(self): 40 return self.type 41 def GetLanguage(self): 42 return self.language 43 def GetOutputFilename(self): 44 return self.file 45 46class FormatRcUnittest(unittest.TestCase): 47 def testMessages(self): 48 root = util.ParseGrdForUnittest(''' 49 <messages> 50 <message name="IDS_BTN_GO" desc="Button text" meaning="verb">Go!</message> 51 <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> 52 Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? 53 </message> 54 <message name="BONGO" desc="Flippo nippo"> 55 Howdie "Mr. Elephant", how are you doing? \'\'\' 56 </message> 57 <message name="IDS_WITH_LINEBREAKS"> 58Good day sir, 59I am a bee 60Sting sting 61 </message> 62 </messages> 63 ''') 64 65 buf = StringIO.StringIO() 66 build.RcBuilder.ProcessNode(root, DummyOutput('rc_all', 'en'), buf) 67 output = util.StripBlankLinesAndComments(buf.getvalue()) 68 self.assertEqual(_PREAMBLE + u'''\ 69STRINGTABLE 70BEGIN 71 IDS_BTN_GO "Go!" 72 IDS_GREETING "Hello %s, how are you doing today?" 73 BONGO "Howdie ""Mr. Elephant"", how are you doing? " 74 IDS_WITH_LINEBREAKS "Good day sir,\\nI am a bee\\nSting sting" 75END''', output) 76 77 78 def testRcSection(self): 79 root = util.ParseGrdForUnittest(''' 80 <structures> 81 <structure type="menu" name="IDC_KLONKMENU" file="grit\\testdata\klonk.rc" encoding="utf-16" /> 82 <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\testdata\klonk.rc" encoding="utf-16" /> 83 <structure type="version" name="VS_VERSION_INFO" file="grit\\testdata\klonk.rc" encoding="utf-16" /> 84 </structures>''') 85 root.SetOutputLanguage('en') 86 root.RunGatherers() 87 88 buf = StringIO.StringIO() 89 build.RcBuilder.ProcessNode(root, DummyOutput('rc_all', 'en'), buf) 90 output = util.StripBlankLinesAndComments(buf.getvalue()) 91 expected = _PREAMBLE + u'''\ 92IDC_KLONKMENU MENU 93BEGIN 94 POPUP "&File" 95 BEGIN 96 MENUITEM "E&xit", IDM_EXIT 97 MENUITEM "This be ""Klonk"" me like", ID_FILE_THISBE 98 POPUP "gonk" 99 BEGIN 100 MENUITEM "Klonk && is [good]", ID_GONK_KLONKIS 101 END 102 END 103 POPUP "&Help" 104 BEGIN 105 MENUITEM "&About ...", IDM_ABOUT 106 END 107END 108 109IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75 110STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU 111CAPTION "About" 112FONT 8, "System", 0, 0, 0x0 113BEGIN 114 ICON IDI_KLONK,IDC_MYICON,14,9,20,20 115 LTEXT "klonk Version ""yibbee"" 1.0",IDC_STATIC,49,10,119,8, 116 SS_NOPREFIX 117 LTEXT "Copyright (C) 2005",IDC_STATIC,49,20,119,8 118 DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP 119 CONTROL "Jack ""Black"" Daniels",IDC_RADIO1,"Button", 120 BS_AUTORADIOBUTTON,46,51,84,10 121END 122 123VS_VERSION_INFO VERSIONINFO 124 FILEVERSION 1,0,0,1 125 PRODUCTVERSION 1,0,0,1 126 FILEFLAGSMASK 0x17L 127#ifdef _DEBUG 128 FILEFLAGS 0x1L 129#else 130 FILEFLAGS 0x0L 131#endif 132 FILEOS 0x4L 133 FILETYPE 0x1L 134 FILESUBTYPE 0x0L 135BEGIN 136 BLOCK "StringFileInfo" 137 BEGIN 138 BLOCK "040904b0" 139 BEGIN 140 VALUE "FileDescription", "klonk Application" 141 VALUE "FileVersion", "1, 0, 0, 1" 142 VALUE "InternalName", "klonk" 143 VALUE "LegalCopyright", "Copyright (C) 2005" 144 VALUE "OriginalFilename", "klonk.exe" 145 VALUE "ProductName", " klonk Application" 146 VALUE "ProductVersion", "1, 0, 0, 1" 147 END 148 END 149 BLOCK "VarFileInfo" 150 BEGIN 151 VALUE "Translation", 0x409, 1200 152 END 153END'''.strip() 154 for expected_line, output_line in zip(expected.split(), output.split()): 155 self.assertEqual(expected_line, output_line) 156 157 def testRcIncludeStructure(self): 158 root = util.ParseGrdForUnittest(''' 159 <structures> 160 <structure type="tr_html" name="IDR_HTML" file="bingo.html"/> 161 <structure type="tr_html" name="IDR_HTML2" file="bingo2.html"/> 162 </structures>''', base_dir = '/temp') 163 # We do not run gatherers as it is not needed and wouldn't find the file 164 165 buf = StringIO.StringIO() 166 build.RcBuilder.ProcessNode(root, DummyOutput('rc_all', 'en'), buf) 167 output = util.StripBlankLinesAndComments(buf.getvalue()) 168 expected = (_PREAMBLE + 169 u'IDR_HTML HTML "%s"\n' 170 u'IDR_HTML2 HTML "%s"' 171 % (util.normpath('/temp/bingo.html').replace('\\', '\\\\'), 172 util.normpath('/temp/bingo2.html').replace('\\', '\\\\'))) 173 # hackety hack to work on win32&lin 174 output = re.sub('"[c-zC-Z]:', '"', output) 175 self.assertEqual(expected, output) 176 177 def testRcIncludeFile(self): 178 root = util.ParseGrdForUnittest(''' 179 <includes> 180 <include type="TXT" name="TEXT_ONE" file="bingo.txt"/> 181 <include type="TXT" name="TEXT_TWO" file="bingo2.txt" filenameonly="true" /> 182 </includes>''', base_dir = '/temp') 183 184 buf = StringIO.StringIO() 185 build.RcBuilder.ProcessNode(root, DummyOutput('rc_all', 'en'), buf) 186 output = util.StripBlankLinesAndComments(buf.getvalue()) 187 expected = (_PREAMBLE + 188 u'TEXT_ONE TXT "%s"\n' 189 u'TEXT_TWO TXT "%s"' 190 % (util.normpath('/temp/bingo.txt').replace('\\', '\\\\'), 191 'bingo2.txt')) 192 # hackety hack to work on win32&lin 193 output = re.sub('"[c-zC-Z]:', '"', output) 194 self.assertEqual(expected, output) 195 196 def testRcIncludeFlattenedHtmlFile(self): 197 input_file = util.PathFromRoot('grit/testdata/include_test.html') 198 output_file = '%s/HTML_FILE1_include_test.html' % tempfile.gettempdir() 199 root = util.ParseGrdForUnittest(''' 200 <includes> 201 <include name="HTML_FILE1" flattenhtml="true" file="%s" type="BINDATA" /> 202 </includes>''' % input_file) 203 204 buf = StringIO.StringIO() 205 build.RcBuilder.ProcessNode(root, DummyOutput('rc_all', 'en', output_file), 206 buf) 207 output = util.StripBlankLinesAndComments(buf.getvalue()) 208 209 expected = (_PREAMBLE + 210 u'HTML_FILE1 BINDATA "HTML_FILE1_include_test.html"') 211 # hackety hack to work on win32&lin 212 output = re.sub('"[c-zC-Z]:', '"', output) 213 self.assertEqual(expected, output) 214 215 file_contents = util.ReadFile(output_file, util.RAW_TEXT) 216 217 # Check for the content added by the <include> tag. 218 self.failUnless(file_contents.find('Hello Include!') != -1) 219 # Check for the content that was removed by if tag. 220 self.failUnless(file_contents.find('should be removed') == -1) 221 # Check for the content that was kept in place by if. 222 self.failUnless(file_contents.find('should be kept') != -1) 223 self.failUnless(file_contents.find('in the middle...') != -1) 224 self.failUnless(file_contents.find('at the end...') != -1) 225 # Check for nested content that was kept 226 self.failUnless(file_contents.find('nested true should be kept') != -1) 227 self.failUnless(file_contents.find('silbing true should be kept') != -1) 228 # Check for removed "<if>" and "</if>" tags. 229 self.failUnless(file_contents.find('<if expr=') == -1) 230 self.failUnless(file_contents.find('</if>') == -1) 231 232 233 def testStructureNodeOutputfile(self): 234 input_file = util.PathFromRoot('grit/testdata/simple.html') 235 root = util.ParseGrdForUnittest('''\ 236 <structures> 237 <structure type="tr_html" name="IDR_HTML" file="%s" /> 238 </structures>''' % input_file) 239 struct, = root.GetChildrenOfType(structure.StructureNode) 240 # We must run the gatherer since we'll be wanting the translation of the 241 # file. The file exists in the location pointed to. 242 root.SetOutputLanguage('en') 243 root.RunGatherers() 244 245 output_dir = tempfile.gettempdir() 246 en_file = struct.FileForLanguage('en', output_dir) 247 self.failUnless(en_file == input_file) 248 fr_file = struct.FileForLanguage('fr', output_dir) 249 self.failUnless(fr_file == os.path.join(output_dir, 'fr_simple.html')) 250 251 contents = util.ReadFile(fr_file, util.RAW_TEXT) 252 253 self.failUnless(contents.find('<p>') != -1) # should contain the markup 254 self.failUnless(contents.find('Hello!') == -1) # should be translated 255 256 257 def testChromeHtmlNodeOutputfile(self): 258 input_file = util.PathFromRoot('grit/testdata/chrome_html.html') 259 output_file = '%s/HTML_FILE1_chrome_html.html' % tempfile.gettempdir() 260 root = util.ParseGrdForUnittest('''\ 261 <structures> 262 <structure type="chrome_html" name="HTML_FILE1" file="%s" flattenhtml="true" /> 263 </structures>''' % input_file) 264 struct, = root.GetChildrenOfType(structure.StructureNode) 265 struct.gatherer.SetDefines({'scale_factors': '2x'}) 266 # We must run the gatherers since we'll be wanting the chrome_html output. 267 # The file exists in the location pointed to. 268 root.SetOutputLanguage('en') 269 root.RunGatherers() 270 271 buf = StringIO.StringIO() 272 build.RcBuilder.ProcessNode(root, DummyOutput('rc_all', 'en', output_file), 273 buf) 274 output = util.StripBlankLinesAndComments(buf.getvalue()) 275 expected = (_PREAMBLE + 276 u'HTML_FILE1 BINDATA "HTML_FILE1_chrome_html.html"') 277 # hackety hack to work on win32&lin 278 output = re.sub('"[c-zC-Z]:', '"', output) 279 self.assertEqual(expected, output) 280 281 file_contents = util.ReadFile(output_file, util.RAW_TEXT) 282 283 # Check for the content added by the <include> tag. 284 self.failUnless(file_contents.find('Hello Include!') != -1) 285 # Check for inserted -webkit-image-set. 286 self.failUnless(file_contents.find('content: -webkit-image-set') != -1) 287 288 289 def testSubstitutionHtml(self): 290 input_file = util.PathFromRoot('grit/testdata/toolbar_about.html') 291 root = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> 292 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir="."> 293 <release seq="1" allow_pseudo="False"> 294 <structures fallback_to_english="True"> 295 <structure type="tr_html" name="IDR_HTML" file="%s" expand_variables="true"/> 296 </structures> 297 </release> 298 </grit> 299 ''' % input_file), util.PathFromRoot('.')) 300 root.SetOutputLanguage('ar') 301 # We must run the gatherers since we'll be wanting the translation of the 302 # file. The file exists in the location pointed to. 303 root.RunGatherers() 304 305 output_dir = tempfile.gettempdir() 306 struct, = root.GetChildrenOfType(structure.StructureNode) 307 ar_file = struct.FileForLanguage('ar', output_dir) 308 self.failUnless(ar_file == os.path.join(output_dir, 309 'ar_toolbar_about.html')) 310 311 contents = util.ReadFile(ar_file, util.RAW_TEXT) 312 313 self.failUnless(contents.find('dir="RTL"') != -1) 314 315 316 def testFallbackToEnglish(self): 317 root = util.ParseGrdForUnittest('''\ 318 <structures fallback_to_english="True"> 319 <structure type="dialog" name="IDD_ABOUTBOX" file="grit\\testdata\klonk.rc" encoding="utf-16" /> 320 </structures>''', base_dir=util.PathFromRoot('.')) 321 root.SetOutputLanguage('en') 322 root.RunGatherers() 323 324 buf = StringIO.StringIO() 325 formatter = build.RcBuilder.ProcessNode( 326 root, DummyOutput('rc_all', 'bingobongo'), buf) 327 output = util.StripBlankLinesAndComments(buf.getvalue()) 328 self.assertEqual(_PREAMBLE + '''\ 329IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75 330STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU 331CAPTION "About" 332FONT 8, "System", 0, 0, 0x0 333BEGIN 334 ICON IDI_KLONK,IDC_MYICON,14,9,20,20 335 LTEXT "klonk Version ""yibbee"" 1.0",IDC_STATIC,49,10,119,8, 336 SS_NOPREFIX 337 LTEXT "Copyright (C) 2005",IDC_STATIC,49,20,119,8 338 DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP 339 CONTROL "Jack ""Black"" Daniels",IDC_RADIO1,"Button", 340 BS_AUTORADIOBUTTON,46,51,84,10 341END''', output) 342 343 344 def testSubstitutionRc(self): 345 root = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?> 346 <grit latest_public_release="2" source_lang_id="en-US" current_release="3" 347 base_dir="."> 348 <outputs> 349 <output lang="en" type="rc_all" filename="grit\\testdata\klonk_resources.rc"/> 350 </outputs> 351 <release seq="1" allow_pseudo="False"> 352 <structures> 353 <structure type="menu" name="IDC_KLONKMENU" 354 file="grit\\testdata\klonk.rc" encoding="utf-16" 355 expand_variables="true" /> 356 </structures> 357 <messages> 358 <message name="good" sub_variable="true"> 359 excellent 360 </message> 361 </messages> 362 </release> 363 </grit> 364 '''), util.PathFromRoot('.')) 365 root.SetOutputLanguage('en') 366 root.RunGatherers() 367 368 buf = StringIO.StringIO() 369 build.RcBuilder.ProcessNode(root, DummyOutput('rc_all', 'en'), buf) 370 output = buf.getvalue() 371 self.assertEqual(''' 372// This file is automatically generated by GRIT. Do not edit. 373 374#include "resource.h" 375#include <winresrc.h> 376#ifdef IDC_STATIC 377#undef IDC_STATIC 378#endif 379#define IDC_STATIC (-1) 380 381LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 382 383 384IDC_KLONKMENU MENU 385BEGIN 386 POPUP "&File" 387 BEGIN 388 MENUITEM "E&xit", IDM_EXIT 389 MENUITEM "This be ""Klonk"" me like", ID_FILE_THISBE 390 POPUP "gonk" 391 BEGIN 392 MENUITEM "Klonk && is excellent", ID_GONK_KLONKIS 393 END 394 END 395 POPUP "&Help" 396 BEGIN 397 MENUITEM "&About ...", IDM_ABOUT 398 END 399END 400 401STRINGTABLE 402BEGIN 403 good "excellent" 404END 405'''.strip(), output.strip()) 406 407 408if __name__ == '__main__': 409 unittest.main() 410