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.clique''' 7 8import os 9import sys 10if __name__ == '__main__': 11 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 12 13import re 14import StringIO 15import unittest 16 17from grit import clique 18from grit import exception 19from grit import pseudo 20from grit import tclib 21from grit import grd_reader 22from grit import util 23 24class MessageCliqueUnittest(unittest.TestCase): 25 def testClique(self): 26 factory = clique.UberClique() 27 msg = tclib.Message(text='Hello USERNAME, how are you?', 28 placeholders=[ 29 tclib.Placeholder('USERNAME', '%s', 'Joi')]) 30 c = factory.MakeClique(msg) 31 32 self.failUnless(c.GetMessage() == msg) 33 self.failUnless(c.GetId() == msg.GetId()) 34 35 msg_fr = tclib.Translation(text='Bonjour USERNAME, comment ca va?', 36 id=msg.GetId(), placeholders=[ 37 tclib.Placeholder('USERNAME', '%s', 'Joi')]) 38 msg_de = tclib.Translation(text='Guten tag USERNAME, wie geht es dir?', 39 id=msg.GetId(), placeholders=[ 40 tclib.Placeholder('USERNAME', '%s', 'Joi')]) 41 42 c.AddTranslation(msg_fr, 'fr') 43 factory.FindCliqueAndAddTranslation(msg_de, 'de') 44 45 # sort() sorts lists in-place and does not return them 46 for lang in ('en', 'fr', 'de'): 47 self.failUnless(lang in c.clique) 48 49 self.failUnless(c.MessageForLanguage('fr').GetRealContent() == 50 msg_fr.GetRealContent()) 51 52 try: 53 c.MessageForLanguage('zh-CN', False) 54 self.fail('Should have gotten exception') 55 except: 56 pass 57 58 self.failUnless(c.MessageForLanguage('zh-CN', True) != None) 59 60 rex = re.compile('fr|de|bingo') 61 self.failUnless(len(c.AllMessagesThatMatch(rex, False)) == 2) 62 self.failUnless(c.AllMessagesThatMatch(rex, True)[pseudo.PSEUDO_LANG] != None) 63 64 def testBestClique(self): 65 factory = clique.UberClique() 66 factory.MakeClique(tclib.Message(text='Alfur', description='alfaholl')) 67 factory.MakeClique(tclib.Message(text='Alfur', description='')) 68 factory.MakeClique(tclib.Message(text='Vaettur', description='')) 69 factory.MakeClique(tclib.Message(text='Vaettur', description='')) 70 factory.MakeClique(tclib.Message(text='Troll', description='')) 71 factory.MakeClique(tclib.Message(text='Gryla', description='ID: IDS_GRYLA')) 72 factory.MakeClique(tclib.Message(text='Gryla', description='vondakerling')) 73 factory.MakeClique(tclib.Message(text='Leppaludi', description='ID: IDS_LL')) 74 factory.MakeClique(tclib.Message(text='Leppaludi', description='')) 75 76 count_best_cliques = 0 77 for c in factory.BestCliquePerId(): 78 count_best_cliques += 1 79 msg = c.GetMessage() 80 text = msg.GetRealContent() 81 description = msg.GetDescription() 82 if text == 'Alfur': 83 self.failUnless(description == 'alfaholl') 84 elif text == 'Gryla': 85 self.failUnless(description == 'vondakerling') 86 elif text == 'Leppaludi': 87 self.failUnless(description == 'ID: IDS_LL') 88 self.failUnless(count_best_cliques == 5) 89 90 def testAllInUberClique(self): 91 resources = grd_reader.Parse( 92 StringIO.StringIO(u'''<?xml version="1.0" encoding="UTF-8"?> 93<grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir="."> 94 <release seq="3"> 95 <messages> 96 <message name="IDS_GREETING" desc="Printed to greet the currently logged in user"> 97 Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today? 98 </message> 99 </messages> 100 <structures> 101 <structure type="dialog" name="IDD_ABOUTBOX" encoding="utf-16" file="grit/testdata/klonk.rc" /> 102 <structure type="tr_html" name="ID_HTML" file="grit/testdata/simple.html" /> 103 </structures> 104 </release> 105</grit>'''), util.PathFromRoot('.')) 106 resources.SetOutputLanguage('en') 107 resources.RunGatherers() 108 content_list = [] 109 for clique_list in resources.UberClique().cliques_.values(): 110 for clique in clique_list: 111 content_list.append(clique.GetMessage().GetRealContent()) 112 self.failUnless('Hello %s, how are you doing today?' in content_list) 113 self.failUnless('Jack "Black" Daniels' in content_list) 114 self.failUnless('Hello!' in content_list) 115 116 def testCorrectExceptionIfWrongEncodingOnResourceFile(self): 117 '''This doesn't really belong in this unittest file, but what the heck.''' 118 resources = grd_reader.Parse( 119 StringIO.StringIO(u'''<?xml version="1.0" encoding="UTF-8"?> 120<grit latest_public_release="2" source_lang_id="en-US" current_release="3" base_dir="."> 121 <release seq="3"> 122 <structures> 123 <structure type="dialog" name="IDD_ABOUTBOX" file="grit/testdata/klonk.rc" /> 124 </structures> 125 </release> 126</grit>'''), util.PathFromRoot('.')) 127 self.assertRaises(exception.SectionNotFound, resources.RunGatherers) 128 129 def testSemiIdenticalCliques(self): 130 messages = [ 131 tclib.Message(text='Hello USERNAME', 132 placeholders=[tclib.Placeholder('USERNAME', '$1', 'Joi')]), 133 tclib.Message(text='Hello USERNAME', 134 placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi')]), 135 ] 136 self.failUnless(messages[0].GetId() == messages[1].GetId()) 137 138 # Both of the above would share a translation. 139 translation = tclib.Translation(id=messages[0].GetId(), 140 text='Bonjour USERNAME', 141 placeholders=[tclib.Placeholder( 142 'USERNAME', '$1', 'Joi')]) 143 144 factory = clique.UberClique() 145 cliques = [factory.MakeClique(msg) for msg in messages] 146 147 for clq in cliques: 148 clq.AddTranslation(translation, 'fr') 149 150 self.failUnless(cliques[0].MessageForLanguage('fr').GetRealContent() == 151 'Bonjour $1') 152 self.failUnless(cliques[1].MessageForLanguage('fr').GetRealContent() == 153 'Bonjour %s') 154 155 def testMissingTranslations(self): 156 messages = [ tclib.Message(text='Hello'), tclib.Message(text='Goodbye') ] 157 factory = clique.UberClique() 158 cliques = [factory.MakeClique(msg) for msg in messages] 159 160 cliques[1].MessageForLanguage('fr', False, True) 161 162 self.failUnless(not factory.HasMissingTranslations()) 163 164 cliques[0].MessageForLanguage('de', False, False) 165 166 self.failUnless(factory.HasMissingTranslations()) 167 168 report = factory.MissingTranslationsReport() 169 self.failUnless(report.count('WARNING') == 1) 170 self.failUnless(report.count('8053599568341804890 "Goodbye" fr') == 1) 171 self.failUnless(report.count('ERROR') == 1) 172 self.failUnless(report.count('800120468867715734 "Hello" de') == 1) 173 174 def testCustomTypes(self): 175 factory = clique.UberClique() 176 message = tclib.Message(text='Bingo bongo') 177 c = factory.MakeClique(message) 178 try: 179 c.SetCustomType(DummyCustomType()) 180 self.fail() 181 except: 182 pass # expected case - 'Bingo bongo' does not start with 'jjj' 183 184 message = tclib.Message(text='jjjBingo bongo') 185 c = factory.MakeClique(message) 186 c.SetCustomType(util.NewClassInstance( 187 'grit.clique_unittest.DummyCustomType', clique.CustomType)) 188 translation = tclib.Translation(id=message.GetId(), text='Bilingo bolongo') 189 c.AddTranslation(translation, 'fr') 190 self.failUnless(c.MessageForLanguage('fr').GetRealContent().startswith('jjj')) 191 192 def testWhitespaceMessagesAreNontranslateable(self): 193 factory = clique.UberClique() 194 195 message = tclib.Message(text=' \t') 196 c = factory.MakeClique(message, translateable=True) 197 self.failIf(c.IsTranslateable()) 198 199 message = tclib.Message(text='\n \n ') 200 c = factory.MakeClique(message, translateable=True) 201 self.failIf(c.IsTranslateable()) 202 203 message = tclib.Message(text='\n hello') 204 c = factory.MakeClique(message, translateable=True) 205 self.failUnless(c.IsTranslateable()) 206 207 def testEachCliqueKeptSorted(self): 208 factory = clique.UberClique() 209 msg_a = tclib.Message(text='hello', description='a') 210 msg_b = tclib.Message(text='hello', description='b') 211 msg_c = tclib.Message(text='hello', description='c') 212 # Insert out of order 213 clique_b = factory.MakeClique(msg_b, translateable=True) 214 clique_a = factory.MakeClique(msg_a, translateable=True) 215 clique_c = factory.MakeClique(msg_c, translateable=True) 216 clique_list = factory.cliques_[clique_a.GetId()] 217 self.failUnless(len(clique_list) == 3) 218 self.failUnless(clique_list[0] == clique_a) 219 self.failUnless(clique_list[1] == clique_b) 220 self.failUnless(clique_list[2] == clique_c) 221 222 def testBestCliqueSortIsStable(self): 223 factory = clique.UberClique() 224 text = 'hello' 225 msg_no_description = tclib.Message(text=text) 226 msg_id_description_a = tclib.Message(text=text, description='ID: a') 227 msg_id_description_b = tclib.Message(text=text, description='ID: b') 228 msg_description_x = tclib.Message(text=text, description='x') 229 msg_description_y = tclib.Message(text=text, description='y') 230 clique_id = msg_no_description.GetId() 231 232 # Insert in an order that tests all outcomes. 233 clique_no_description = factory.MakeClique(msg_no_description, 234 translateable=True) 235 self.failUnless(factory.BestClique(clique_id) == clique_no_description) 236 clique_id_description_b = factory.MakeClique(msg_id_description_b, 237 translateable=True) 238 self.failUnless(factory.BestClique(clique_id) == clique_id_description_b) 239 clique_id_description_a = factory.MakeClique(msg_id_description_a, 240 translateable=True) 241 self.failUnless(factory.BestClique(clique_id) == clique_id_description_a) 242 clique_description_y = factory.MakeClique(msg_description_y, 243 translateable=True) 244 self.failUnless(factory.BestClique(clique_id) == clique_description_y) 245 clique_description_x = factory.MakeClique(msg_description_x, 246 translateable=True) 247 self.failUnless(factory.BestClique(clique_id) == clique_description_x) 248 249 250class DummyCustomType(clique.CustomType): 251 def Validate(self, message): 252 return message.GetRealContent().startswith('jjj') 253 def ValidateAndModify(self, lang, translation): 254 is_ok = self.Validate(translation) 255 self.ModifyEachTextPart(lang, translation) 256 def ModifyTextPart(self, lang, text): 257 return 'jjj%s' % text 258 259 260if __name__ == '__main__': 261 unittest.main() 262