chromium/tools/grit/grit/gather/chrome_html_unittest.py

#!/usr/bin/env python3
# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

'''Unit tests for grit.gather.chrome_html'''


import os
import re
import sys
if __name__ == '__main__':
  sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))

import unittest

from grit import lazy_re
from grit import util
from grit.gather import chrome_html


_NEW_LINE = lazy_re.compile('(\r\n|\r|\n)', re.MULTILINE)


def StandardizeHtml(text):
  '''Standardizes the newline format and png mime type in Html text.'''
  return _NEW_LINE.sub('\n', text).replace('data:image/x-png;',
                                           'data:image/png;')


class ChromeHtmlUnittest(unittest.TestCase):
  '''Unit tests for ChromeHtml.'''

  @classmethod
  def setUpClass(cls):
    os.environ["root_gen_dir"] = "gen"

  def testFileResources(self):
    '''Tests inlined image file resources with available high DPI assets.'''

    tmp_dir = util.TempDir({
      'index.html': '''
      <!DOCTYPE HTML>
      <html>
        <head>
          <link rel="stylesheet" href="test.css">
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      ''',

      'test.css': '''
      .image {
        background: url('test.png');
      }
      ''',

      'test.png': 'PNG DATA',

      '1.4x/test.png': '1.4x PNG DATA',

      '1.8x/test.png': '1.8x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
    html.SetDefines({'scale_factors': '1.4x,1.8x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      <!DOCTYPE HTML>
      <html>
        <head>
          <style>
      .image {
        background: 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);
      }
      </style>
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesImageTag(self):
    '''Tests inlined image file resources with available high DPI assets on
    an image tag.'''

    tmp_dir = util.TempDir({
      'index.html': '''
      <!DOCTYPE HTML>
      <html>
        <body>
          <img id="foo" src="test.png">
        </body>
      </html>
      ''',

      'test.png': 'PNG DATA',

      '2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      <!DOCTYPE HTML>
      <html>
        <body>
          <img id="foo" src="data:image/png;base64,UE5HIERBVEE=" style="content: image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x, url('data:image/png;base64,MnggUE5HIERBVEE=') 2x);">
        </body>
      </html>
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesNoFlatten(self):
    '''Tests non-inlined image file resources with available high DPI assets.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url('test.png');
      }
      ''',

      'test.png': 'PNG DATA',

      '1.4x/test.png': '1.4x PNG DATA',

      '1.8x/test.png': '1.8x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '1.4x,1.8x'})
    html.SetAttributes({'flattenhtml': 'false'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url('test.png') 1x, url('1.4x/test.png') 1.4x, url('1.8x/test.png') 1.8x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesNoFlattenSubdir(self):
    '''Tests non-inlined image file resources w/high DPI assets in subdirs.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url('sub/test.png');
      }
      ''',

      'sub/test.png': 'PNG DATA',

      'sub/1.4x/test.png': '1.4x PNG DATA',

      'sub/1.8x/test.png': '1.8x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '1.4x,1.8x'})
    html.SetAttributes({'flattenhtml': 'false'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url('sub/test.png') 1x, url('sub/1.4x/test.png') 1.4x, url('sub/1.8x/test.png') 1.8x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesPreprocess(self):
    '''Tests preprocessed image file resources with available high DPI
    assets.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url('test.png');
      }
      ''',

      'test.png': 'PNG DATA',

      '1.4x/test.png': '1.4x PNG DATA',

      '1.8x/test.png': '1.8x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '1.4x,1.8x'})
    html.SetAttributes({'flattenhtml': 'false', 'preprocess': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url('test.png') 1x, url('1.4x/test.png') 1.4x, url('1.8x/test.png') 1.8x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesDoubleQuotes(self):
    '''Tests inlined image file resources if url() filename is double quoted.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url("test.png");
      }
      ''',

      'test.png': 'PNG DATA',

      '2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url("data:image/png;base64,UE5HIERBVEE=") 1x, url("data:image/png;base64,MnggUE5HIERBVEE=") 2x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesNoQuotes(self):
    '''Tests inlined image file resources when url() filename is unquoted.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url(test.png);
      }
      ''',

      'test.png': 'PNG DATA',

      '2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesSubdirs(self):
    '''Tests inlined image file resources if url() filename is in a subdir.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url('some/sub/path/test.png');
      }
      ''',

      'some/sub/path/test.png': 'PNG DATA',

      'some/sub/path/2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x, url('data:image/png;base64,MnggUE5HIERBVEE=') 2x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesNoFile(self):
    '''Tests inlined image file resources without available high DPI assets.'''

    tmp_dir = util.TempDir({
      'index.html': '''
      <!DOCTYPE HTML>
      <html>
        <head>
          <link rel="stylesheet" href="test.css">
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      ''',

      'test.css': '''
      .image {
        background: url('test.png');
      }
      ''',

      'test.png': 'PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      <!DOCTYPE HTML>
      <html>
        <head>
          <style>
      .image {
        background: url('data:image/png;base64,UE5HIERBVEE=');
      }
      </style>
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesMultipleBackgrounds(self):
    '''Tests inlined image file resources with two url()s.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url(test.png), url(test.png);
      }
      ''',

      'test.png': 'PNG DATA',

      '2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x), image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesMultipleBackgroundsWithNewline1(self):
    '''Tests inlined image file resources with line break after first url().'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background: url(test.png),
                    url(test.png);
      }
      ''',

      'test.png': 'PNG DATA',

      '2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x),
                    image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesMultipleBackgroundsWithNewline2(self):
    '''Tests inlined image file resources with line break before first url()
    and before second url().'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background:
          url(test.png),
          url(test.png);
      }
      ''',

      'test.png': 'PNG DATA',

      '2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x),
          image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
      }
      '''))
    tmp_dir.CleanUp()

  def testFileResourcesCRLF(self):
    '''Tests inlined image file resource when url() is preceded by a Windows
    style line break.'''

    tmp_dir = util.TempDir({
      'test.css': '''
      .image {
        background:\r\nurl(test.png);
      }
      ''',

      'test.png': 'PNG DATA',

      '2x/test.png': '2x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('test.css'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      .image {
        background: image-set(url(data:image/png;base64,UE5HIERBVEE=) 1x, url(data:image/png;base64,MnggUE5HIERBVEE=) 2x);
      }
      '''))
    tmp_dir.CleanUp()

  def testThemeResources(self):
    '''Tests inserting high DPI chrome://theme references.'''

    tmp_dir = util.TempDir({
      'index.html': '''
      <!DOCTYPE HTML>
      <html>
        <head>
          <link rel="stylesheet" href="test.css">
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      ''',

      'test.css': '''
      .image {
        background: url('chrome://theme/IDR_RESOURCE_NAME');
        content: url('chrome://theme/IDR_RESOURCE_NAME_WITH_Q?$1');
      }
      ''',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
    html.SetDefines({'scale_factors': '2x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      <!DOCTYPE HTML>
      <html>
        <head>
          <style>
      .image {
        background: image-set(url('chrome://theme/IDR_RESOURCE_NAME') 1x, url('chrome://theme/IDR_RESOURCE_NAME@2x') 2x);
        content: image-set(url('chrome://theme/IDR_RESOURCE_NAME_WITH_Q?$1') 1x, url('chrome://theme/IDR_RESOURCE_NAME_WITH_Q@2x?$1') 2x);
      }
      </style>
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      '''))
    tmp_dir.CleanUp()

  def testRemoveUnsupportedScale(self):
    '''Tests removing an unsupported scale factor from an explicit image-set.'''

    tmp_dir = util.TempDir({
      'index.html': '''
      <!DOCTYPE HTML>
      <html>
        <head>
          <link rel="stylesheet" href="test.css">
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      ''',

      'test.css': '''
      .image {
        background: -webkit-image-set(url('test.png') 1x,
                                      url('test1.4.png') 1.4x,
                                      url('test1.8.png') 1.8x);
      }
      ''',

      'test.png': 'PNG DATA',

      'test1.4.png': '1.4x PNG DATA',

      'test1.8.png': '1.8x PNG DATA',
    })

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
    html.SetDefines({'scale_factors': '1.8x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      <!DOCTYPE HTML>
      <html>
        <head>
          <style>
      .image {
        background: image-set(url('data:image/png;base64,UE5HIERBVEE=') 1x,
                                      url('data:image/png;base64,MS44eCBQTkcgREFUQQ==') 1.8x);
      }
      </style>
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      '''))
    tmp_dir.CleanUp()

  def testExpandVariablesInFilename(self):
    '''
    Tests variable substitution in filenames while flattening images
    with multiple scale factors.
    '''

    tmp_dir = util.TempDir({
      'index.html': '''
      <!DOCTYPE HTML>
      <html>
        <head>
          <link rel="stylesheet" href="test.css">
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      ''',

      'test.css': '''
      .image {
        background: url('test[WHICH].png');
      }
      ''',

      'test1.png': 'PNG DATA',
      '1.4x/test1.png': '1.4x PNG DATA',
      '1.8x/test1.png': '1.8x PNG DATA',
    })

    def replacer(var, repl):
      return lambda filename: filename.replace('[%s]' % var, repl)

    html = chrome_html.ChromeHtml(tmp_dir.GetPath('index.html'))
    html.SetDefines({'scale_factors': '1.4x,1.8x'})
    html.SetAttributes({'flattenhtml': 'true'})
    html.SetFilenameExpansionFunction(replacer('WHICH', '1'));
    html.Parse()
    self.assertEqual(StandardizeHtml(html.GetData('en', 'utf-8')),
                         StandardizeHtml('''
      <!DOCTYPE HTML>
      <html>
        <head>
          <style>
      .image {
        background: 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);
      }
      </style>
        </head>
        <body>
          <!-- Don't need a body. -->
        </body>
      </html>
      '''))
    tmp_dir.CleanUp()


if __name__ == '__main__':
  unittest.main()