blob: 5f018e46736791852f7cf62a6c573f637d73bde5 [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2016 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00004
5"""Unit tests for template_helpers module."""
6
7from __future__ import division
8from __future__ import print_function
9from __future__ import absolute_import
10
11import unittest
12
13from framework import pbproxy_test_pb2
14from framework import template_helpers
15
16
17class HelpersUnitTest(unittest.TestCase):
18
19 def testDictionaryProxy(self):
20
21 # basic in 'n out test
22 item = template_helpers.EZTItem(label='foo', group_name='bar')
23
24 self.assertEqual('foo', item.label)
25 self.assertEqual('bar', item.group_name)
26
27 # be sure the __str__ returns the fields
28 self.assertEqual(
29 "EZTItem({'group_name': 'bar', 'label': 'foo'})", str(item))
30
31 def testPBProxy(self):
32 """Checks that PBProxy wraps protobuf objects as expected."""
33 # check that protobuf fields are accessible in ".attribute" form
34 pbe = pbproxy_test_pb2.PBProxyExample()
35 pbe.nickname = 'foo'
36 pbe.invited = False
37 pbep = template_helpers.PBProxy(pbe)
38 self.assertEqual(pbep.nickname, 'foo')
39 # _bool suffix converts protobuf field 'bar' to None (EZT boolean false)
40 self.assertEqual(pbep.invited_bool, None)
41
42 # check that a new field can be added to the PBProxy
43 pbep.baz = 'bif'
44 self.assertEqual(pbep.baz, 'bif')
45
46 # check that a PBProxy-local field can hide a protobuf field
47 pbep.nickname = 'local foo'
48 self.assertEqual(pbep.nickname, 'local foo')
49
50 # check that a nested protobuf is recursively wrapped with a PBProxy
51 pbn = pbproxy_test_pb2.PBProxyNested()
52 pbn.nested = pbproxy_test_pb2.PBProxyExample()
53 pbn.nested.nickname = 'bar'
54 pbn.nested.invited = True
55 pbnp = template_helpers.PBProxy(pbn)
56 self.assertEqual(pbnp.nested.nickname, 'bar')
57 # _bool suffix converts protobuf field 'bar' to 'yes' (EZT boolean true)
58 self.assertEqual(pbnp.nested.invited_bool, 'yes')
59
60 # check that 'repeated' lists of items produce a list of strings
61 pbn.multiple_strings.append('1')
62 pbn.multiple_strings.append('2')
63 self.assertEqual(pbnp.multiple_strings, ['1', '2'])
64
65 # check that 'repeated' messages produce lists of PBProxy instances
66 pbe1 = pbproxy_test_pb2.PBProxyExample()
67 pbn.multiple_pbes.append(pbe1)
68 pbe1.nickname = '1'
69 pbe1.invited = True
70 pbe2 = pbproxy_test_pb2.PBProxyExample()
71 pbn.multiple_pbes.append(pbe2)
72 pbe2.nickname = '2'
73 pbe2.invited = False
74 self.assertEqual(pbnp.multiple_pbes[0].nickname, '1')
75 self.assertEqual(pbnp.multiple_pbes[0].invited_bool, 'yes')
76 self.assertEqual(pbnp.multiple_pbes[1].nickname, '2')
77 self.assertEqual(pbnp.multiple_pbes[1].invited_bool, None)
78
79 def testFitTextMethods(self):
80 """Tests both FitUnsafeText with an eye on i18n."""
81 # pylint: disable=anomalous-unicode-escape-in-string
82 test_data = (
83 u'This is a short string.',
Copybara854996b2021-09-07 19:36:02 +000084 u'This is a much longer string. '
85 u'This is a much longer string. '
86 u'This is a much longer string. '
87 u'This is a much longer string. '
88 u'This is a much longer string. '
89 u'This is a much longer string. '
90 u'This is a much longer string. '
91 u'This is a much longer string. '
92 u'This is a much longer string. '
93 u'This is a much longer string. ',
94
95 # This is a short escaped i18n string
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010096 b'\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab'.decode('utf-8'),
Copybara854996b2021-09-07 19:36:02 +000097
98 # This is a longer i18n string
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010099 b'\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
100 b'\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '
101 b'\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
102 b'\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '
103 b'\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
104 b'\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '
105 b'\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
106 b'\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '.decode('utf-8'),
Copybara854996b2021-09-07 19:36:02 +0000107
108 # This is a longer i18n string that was causing trouble.
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100109 u'\u041d\u0430 \u0431\u0435\u0440\u0435\u0433\u0443'
110 u' \u043f\u0443\u0441\u0442\u044b\u043d\u043d\u044b\u0445'
111 u' \u0432\u043e\u043b\u043d \u0421\u0442\u043e\u044f\u043b'
112 u' \u043e\u043d, \u0434\u0443\u043c'
113 u' \u0432\u0435\u043b\u0438\u043a\u0438\u0445'
114 u' \u043f\u043e\u043b\u043d, \u0418'
115 u' \u0432\u0434\u0430\u043b\u044c'
116 u' \u0433\u043b\u044f\u0434\u0435\u043b.'
117 u' \u041f\u0440\u0435\u0434 \u043d\u0438\u043c'
118 u' \u0448\u0438\u0440\u043e\u043a\u043e'
119 u' \u0420\u0435\u043a\u0430'
120 u' \u043d\u0435\u0441\u043b\u0430\u0441\u044f;'
121 u' \u0431\u0435\u0434\u043d\u044b\u0439'
122 u' \u0447\u0451\u043b\u043d \u041f\u043e'
123 u' \u043d\u0435\u0439'
124 u' \u0441\u0442\u0440\u0435\u043c\u0438\u043b\u0441\u044f'
125 u' \u043e\u0434\u0438\u043d\u043e\u043a\u043e.'
126 u' \u041f\u043e \u043c\u0448\u0438\u0441\u0442\u044b\u043c,'
127 u' \u0442\u043e\u043f\u043a\u0438\u043c'
128 u' \u0431\u0435\u0440\u0435\u0433\u0430\u043c'
129 u' \u0427\u0435\u0440\u043d\u0435\u043b\u0438'
130 u' \u0438\u0437\u0431\u044b \u0437\u0434\u0435\u0441\u044c'
131 u' \u0438 \u0442\u0430\u043c, \u041f\u0440\u0438\u044e\u0442'
132 u' \u0443\u0431\u043e\u0433\u043e\u0433\u043e'
133 u' \u0447\u0443\u0445\u043e\u043d\u0446\u0430;'
134 u' \u0418 \u043b\u0435\u0441,'
135 u' \u043d\u0435\u0432\u0435\u0434\u043e\u043c\u044b\u0439'
136 u' \u043b\u0443\u0447\u0430\u043c \u0412'
137 u' \u0442\u0443\u043c\u0430\u043d\u0435'
138 u' \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u043d\u043e'
139 u'\u0433\u043e \u0441\u043e\u043b\u043d\u0446\u0430,'
140 u' \u041a\u0440\u0443\u0433\u043e\u043c'
141 u' \u0448\u0443\u043c\u0435\u043b.')
Copybara854996b2021-09-07 19:36:02 +0000142
143 for unicode_s in test_data:
144 # Get the length in characters, not bytes.
145 length = len(unicode_s)
146
147 # Test the FitUnsafeText method at the length boundary.
148 fitted_unsafe_text = template_helpers.FitUnsafeText(unicode_s, length)
149 self.assertEqual(fitted_unsafe_text, unicode_s)
150
151 # Set some values that test FitString well.
152 available_space = length // 2
153 max_trailing = length // 4
154 # Break the string at various places - symmetric range around 0
155 for i in range(1-max_trailing, max_trailing):
156 # Test the FitUnsafeText method.
157 fitted_unsafe_text = template_helpers.FitUnsafeText(
158 unicode_s, available_space - i)
159 self.assertEqual(fitted_unsafe_text[:available_space - i],
160 unicode_s[:available_space - i])
161
162 # Test a string that is already unicode
163 u_string = u'This is already unicode'
164 fitted_unsafe_text = template_helpers.FitUnsafeText(u_string, 100)
165 self.assertEqual(u_string, fitted_unsafe_text)
166
167 # Test a string that is already unicode, and has non-ascii in it.
168 u_string = u'This is already unicode este\\u0301tico'
169 fitted_unsafe_text = template_helpers.FitUnsafeText(u_string, 100)
170 self.assertEqual(u_string, fitted_unsafe_text)
171
172 def testEZTError(self):
173 errors = template_helpers.EZTError()
174 self.assertFalse(errors.AnyErrors())
175
176 errors.error_a = 'A'
177 self.assertTrue(errors.AnyErrors())
178 self.assertEqual('A', errors.error_a)
179
180 errors.SetError('error_b', 'B')
181 self.assertTrue(errors.AnyErrors())
182 self.assertEqual('A', errors.error_a)
183 self.assertEqual('B', errors.error_b)
184
185 def testBytesKbOrMb(self):
186 self.assertEqual('1023 bytes', template_helpers.BytesKbOrMb(1023))
187 self.assertEqual('1.0 KB', template_helpers.BytesKbOrMb(1024))
188 self.assertEqual('1023 KB', template_helpers.BytesKbOrMb(1024 * 1023))
189 self.assertEqual('1.0 MB', template_helpers.BytesKbOrMb(1024 * 1024))
190 self.assertEqual('98.0 MB', template_helpers.BytesKbOrMb(98 * 1024 * 1024))
191 self.assertEqual('99 MB', template_helpers.BytesKbOrMb(99 * 1024 * 1024))
192
193
194class TextRunTest(unittest.TestCase):
195
196 def testLink(self):
197 run = template_helpers.TextRun(
198 'content', tag='a', href='http://example.com')
199 expected = '<a href="http://example.com">content</a>'
200 self.assertEqual(expected, run.FormatForHTMLEmail())
201
202 run = template_helpers.TextRun(
203 'con<tent>', tag='a', href='http://exa"mple.com')
204 expected = '<a href="http://exa&quot;mple.com">con&lt;tent&gt;</a>'
205 self.assertEqual(expected, run.FormatForHTMLEmail())
206
207 def testText(self):
208 run = template_helpers.TextRun('content')
209 expected = 'content'
210 self.assertEqual(expected, run.FormatForHTMLEmail())
211
212 run = template_helpers.TextRun('con<tent>')
213 expected = 'con&lt;tent&gt;'
214 self.assertEqual(expected, run.FormatForHTMLEmail())