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.gather.chrome_html'''
7
8
9import os
10import re
11import sys
12if __name__ == '__main__':
13  sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
14
15import unittest
16
17from grit import lazy_re
18from grit import util
19from grit.gather import chrome_html
20
21
22_NEW_LINE = lazy_re.compile('(\r\n|\r|\n)', re.MULTILINE)
23
24
25def StandardizeHtml(text):
26  '''Standardizes the newline format and png mime type in Html text.'''
27  return _NEW_LINE.sub('\n', text).replace('data:image/x-png;',
28                                           'data:image/png;')
29
30
31class ChromeHtmlUnittest(unittest.TestCase):
32  '''Unit tests for ChromeHtml.'''
33
34  def testFileResources(self):
35    '''Tests inlined image file resources with available high DPI assets.'''
36
37    tmp_dir = util.TempDir({
38      'index.html': '''
39      <!DOCTYPE HTML>
40      <html>
41        <head>
42          <link rel="stylesheet" href="test.css">
43        </head>
44        <body>
45          <!-- Don't need a body. -->
46        </body>
47      </html>
48      ''',
49
50      'test.css': '''
51      .image {
52        background: url('test.png');
53      }
54      ''',
55
56      'test.png': 'PNG DATA',
57
58      '1.4x/test.png': '1.4x PNG DATA',
59
60      '1.8x/test.png': '1.8x PNG DATA',
61    })
62
63    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
64    html.SetDefines({'scale_factors': '1.4x,1.8x'})
65    html.SetAttributes({'flattenhtml': 'true'})
66    html.Parse()
67    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
68                         StandardizeHtml('''
69      <!DOCTYPE HTML>
70      <html>
71        <head>
72          <style>
73      .image {
74        background: -webkit-image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x, url('data:image/png;base64,MS40eCBQTkcgREFUQQ==') 1.4x, url('data:image/png;base64,MS44eCBQTkcgREFUQQ==') 1.8x);
75      }
76      </style>
77        </head>
78        <body>
79          <!-- Don't need a body. -->
80        </body>
81      </html>
82      '''))
83    tmp_dir.CleanUp()
84
85  def testFileResourcesImageTag(self):
86    '''Tests inlined image file resources with available high DPI assets on
87    an image tag.'''
88
89    tmp_dir = util.TempDir({
90      'index.html': '''
91      <!DOCTYPE HTML>
92      <html>
93        <body>
94          <img id="foo" src="test.png">
95        </body>
96      </html>
97      ''',
98
99      'test.png': 'PNG DATA',
100
101      '2x/test.png': '2x PNG DATA',
102    })
103
104    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
105    html.SetDefines({'scale_factors': '2x'})
106    html.SetAttributes({'flattenhtml': 'true'})
107    html.Parse()
108    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
109                         StandardizeHtml('''
110      <!DOCTYPE HTML>
111      <html>
112        <body>
113          <img id="foo" src="data:image/png;base64,UE5HIERBVEE=" style="content: -webkit-image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x, url('data:image/png;base64,MnggUE5HIERBVEE=') 2x);">
114        </body>
115      </html>
116      '''))
117    tmp_dir.CleanUp()
118
119  def testFileResourcesNoFlatten(self):
120    '''Tests non-inlined image file resources with available high DPI assets.'''
121
122    tmp_dir = util.TempDir({
123      'test.css': '''
124      .image {
125        background: url('test.png');
126      }
127      ''',
128
129      'test.png': 'PNG DATA',
130
131      '1.4x/test.png': '1.4x PNG DATA',
132
133      '1.8x/test.png': '1.8x PNG DATA',
134    })
135
136    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
137    html.SetDefines({'scale_factors': '1.4x,1.8x'})
138    html.SetAttributes({'flattenhtml': 'false'})
139    html.Parse()
140    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
141                         StandardizeHtml('''
142      .image {
143        background: -webkit-image-set(url('test.png') 1x, url('1.4x/test.png') 1.4x, url('1.8x/test.png') 1.8x);
144      }
145      '''))
146    tmp_dir.CleanUp()
147
148  def testFileResourcesDoubleQuotes(self):
149    '''Tests inlined image file resources if url() filename is double quoted.'''
150
151    tmp_dir = util.TempDir({
152      'test.css': '''
153      .image {
154        background: url("test.png");
155      }
156      ''',
157
158      'test.png': 'PNG DATA',
159
160      '2x/test.png': '2x PNG DATA',
161    })
162
163    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
164    html.SetDefines({'scale_factors': '2x'})
165    html.SetAttributes({'flattenhtml': 'true'})
166    html.Parse()
167    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
168                         StandardizeHtml('''
169      .image {
170        background: -webkit-image-set(url("data:image/png;base64,UE5HIERBVEE=") 1x, url("data:image/png;base64,MnggUE5HIERBVEE=") 2x);
171      }
172      '''))
173    tmp_dir.CleanUp()
174
175  def testFileResourcesNoQuotes(self):
176    '''Tests inlined image file resources when url() filename is unquoted.'''
177
178    tmp_dir = util.TempDir({
179      'test.css': '''
180      .image {
181        background: url(test.png);
182      }
183      ''',
184
185      'test.png': 'PNG DATA',
186
187      '2x/test.png': '2x PNG DATA',
188    })
189
190    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
191    html.SetDefines({'scale_factors': '2x'})
192    html.SetAttributes({'flattenhtml': 'true'})
193    html.Parse()
194    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
195                         StandardizeHtml('''
196      .image {
197        background: -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
198      }
199      '''))
200    tmp_dir.CleanUp()
201
202  def testFileResourcesNoFile(self):
203    '''Tests inlined image file resources without available high DPI assets.'''
204
205    tmp_dir = util.TempDir({
206      'index.html': '''
207      <!DOCTYPE HTML>
208      <html>
209        <head>
210          <link rel="stylesheet" href="test.css">
211        </head>
212        <body>
213          <!-- Don't need a body. -->
214        </body>
215      </html>
216      ''',
217
218      'test.css': '''
219      .image {
220        background: url('test.png');
221      }
222      ''',
223
224      'test.png': 'PNG DATA',
225    })
226
227    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
228    html.SetDefines({'scale_factors': '2x'})
229    html.SetAttributes({'flattenhtml': 'true'})
230    html.Parse()
231    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
232                         StandardizeHtml('''
233      <!DOCTYPE HTML>
234      <html>
235        <head>
236          <style>
237      .image {
238        background: url('data:image/png;base64,UE5HIERBVEE=');
239      }
240      </style>
241        </head>
242        <body>
243          <!-- Don't need a body. -->
244        </body>
245      </html>
246      '''))
247    tmp_dir.CleanUp()
248
249  def testFileResourcesMultipleBackgrounds(self):
250    '''Tests inlined image file resources with two url()s.'''
251
252    tmp_dir = util.TempDir({
253      'test.css': '''
254      .image {
255        background: url(test.png), url(test.png);
256      }
257      ''',
258
259      'test.png': 'PNG DATA',
260
261      '2x/test.png': '2x PNG DATA',
262    })
263
264    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
265    html.SetDefines({'scale_factors': '2x'})
266    html.SetAttributes({'flattenhtml': 'true'})
267    html.Parse()
268    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
269                         StandardizeHtml('''
270      .image {
271        background: -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x), -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
272      }
273      '''))
274    tmp_dir.CleanUp()
275
276  def testFileResourcesMultipleBackgroundsWithNewline1(self):
277    '''Tests inlined image file resources with line break after first url().'''
278
279    tmp_dir = util.TempDir({
280      'test.css': '''
281      .image {
282        background: url(test.png),
283                    url(test.png);
284      }
285      ''',
286
287      'test.png': 'PNG DATA',
288
289      '2x/test.png': '2x PNG DATA',
290    })
291
292    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
293    html.SetDefines({'scale_factors': '2x'})
294    html.SetAttributes({'flattenhtml': 'true'})
295    html.Parse()
296    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
297                         StandardizeHtml('''
298      .image {
299        background: -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x),
300                    -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
301      }
302      '''))
303    tmp_dir.CleanUp()
304
305  def testFileResourcesMultipleBackgroundsWithNewline2(self):
306    '''Tests inlined image file resources with line break before first url()
307    and before second url().'''
308
309    tmp_dir = util.TempDir({
310      'test.css': '''
311      .image {
312        background:
313          url(test.png),
314          url(test.png);
315      }
316      ''',
317
318      'test.png': 'PNG DATA',
319
320      '2x/test.png': '2x PNG DATA',
321    })
322
323    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
324    html.SetDefines({'scale_factors': '2x'})
325    html.SetAttributes({'flattenhtml': 'true'})
326    html.Parse()
327    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
328                         StandardizeHtml('''
329      .image {
330        background: -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x),
331          -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
332      }
333      '''))
334    tmp_dir.CleanUp()
335
336  def testFileResourcesCRLF(self):
337    '''Tests inlined image file resource when url() is preceded by a Windows
338    style line break.'''
339
340    tmp_dir = util.TempDir({
341      'test.css': '''
342      .image {
343        background:\r\nurl(test.png);
344      }
345      ''',
346
347      'test.png': 'PNG DATA',
348
349      '2x/test.png': '2x PNG DATA',
350    })
351
352    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
353    html.SetDefines({'scale_factors': '2x'})
354    html.SetAttributes({'flattenhtml': 'true'})
355    html.Parse()
356    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
357                         StandardizeHtml('''
358      .image {
359        background: -webkit-image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
360      }
361      '''))
362    tmp_dir.CleanUp()
363
364  def testThemeResources(self):
365    '''Tests inserting high DPI chrome://theme references.'''
366
367    tmp_dir = util.TempDir({
368      'index.html': '''
369      <!DOCTYPE HTML>
370      <html>
371        <head>
372          <link rel="stylesheet" href="test.css">
373        </head>
374        <body>
375          <!-- Don't need a body. -->
376        </body>
377      </html>
378      ''',
379
380      'test.css': '''
381      .image {
382        background: url('chrome://theme/IDR_RESOURCE_NAME');
383        content: url('chrome://theme/IDR_RESOURCE_NAME_WITH_Q?$1');
384      }
385      ''',
386    })
387
388    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
389    html.SetDefines({'scale_factors': '2x'})
390    html.SetAttributes({'flattenhtml': 'true'})
391    html.Parse()
392    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
393                         StandardizeHtml('''
394      <!DOCTYPE HTML>
395      <html>
396        <head>
397          <style>
398      .image {
399        background: -webkit-image-set(url('chrome://theme/IDR_RESOURCE_NAME') 1x, url('chrome://theme/IDR_RESOURCE_NAME@2x') 2x);
400        content: -webkit-image-set(url('chrome://theme/IDR_RESOURCE_NAME_WITH_Q?$1') 1x, url('chrome://theme/IDR_RESOURCE_NAME_WITH_Q@2x?$1') 2x);
401      }
402      </style>
403        </head>
404        <body>
405          <!-- Don't need a body. -->
406        </body>
407      </html>
408      '''))
409    tmp_dir.CleanUp()
410
411  def testRemoveUnsupportedScale(self):
412    '''Tests removing an unsupported scale factor from an explicit image-set.'''
413
414    tmp_dir = util.TempDir({
415      'index.html': '''
416      <!DOCTYPE HTML>
417      <html>
418        <head>
419          <link rel="stylesheet" href="test.css">
420        </head>
421        <body>
422          <!-- Don't need a body. -->
423        </body>
424      </html>
425      ''',
426
427      'test.css': '''
428      .image {
429        background: -webkit-image-set(url('test.png') 1x,
430                                      url('test1.4.png') 1.4x,
431                                      url('test1.8.png') 1.8x);
432      }
433      ''',
434
435      'test.png': 'PNG DATA',
436
437      'test1.4.png': '1.4x PNG DATA',
438
439      'test1.8.png': '1.8x PNG DATA',
440    })
441
442    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
443    html.SetDefines({'scale_factors': '1.8x'})
444    html.SetAttributes({'flattenhtml': 'true'})
445    html.Parse()
446    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
447                         StandardizeHtml('''
448      <!DOCTYPE HTML>
449      <html>
450        <head>
451          <style>
452      .image {
453        background: -webkit-image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x,
454                                      url('data:image/png;base64,MS44eCBQTkcgREFUQQ==') 1.8x);
455      }
456      </style>
457        </head>
458        <body>
459          <!-- Don't need a body. -->
460        </body>
461      </html>
462      '''))
463    tmp_dir.CleanUp()
464
465  def testExpandVariablesInFilename(self):
466    '''
467    Tests variable substitution in filenames while flattening images
468    with multiple scale factors.
469    '''
470
471    tmp_dir = util.TempDir({
472      'index.html': '''
473      <!DOCTYPE HTML>
474      <html>
475        <head>
476          <link rel="stylesheet" href="test.css">
477        </head>
478        <body>
479          <!-- Don't need a body. -->
480        </body>
481      </html>
482      ''',
483
484      'test.css': '''
485      .image {
486        background: url('test[WHICH].png');
487      }
488      ''',
489
490      'test1.png': 'PNG DATA',
491      '1.4x/test1.png': '1.4x PNG DATA',
492      '1.8x/test1.png': '1.8x PNG DATA',
493    })
494
495    def replacer(var, repl):
496      return lambda filename: filename.replace('[%s]' % var, repl)
497
498    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
499    html.SetDefines({'scale_factors': '1.4x,1.8x'})
500    html.SetAttributes({'flattenhtml': 'true'})
501    html.SetFilenameExpansionFunction(replacer('WHICH', '1'));
502    html.Parse()
503    self.failUnlessEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
504                         StandardizeHtml('''
505      <!DOCTYPE HTML>
506      <html>
507        <head>
508          <style>
509      .image {
510        background: -webkit-image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x, url('data:image/png;base64,MS40eCBQTkcgREFUQQ==') 1.4x, url('data:image/png;base64,MS44eCBQTkcgREFUQQ==') 1.8x);
511      }
512      </style>
513        </head>
514        <body>
515          <!-- Don't need a body. -->
516        </body>
517      </html>
518      '''))
519    tmp_dir.CleanUp()
520
521
522if __name__ == '__main__':
523  unittest.main()
524