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.format.html_inline''' 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 util 18from grit.format import html_inline 19 20 21class HtmlInlineUnittest(unittest.TestCase): 22 '''Unit tests for HtmlInline.''' 23 24 def testGetResourceFilenames(self): 25 '''Tests that all included files are returned by GetResourceFilenames.''' 26 27 files = { 28 'index.html': ''' 29 <!DOCTYPE HTML> 30 <html> 31 <head> 32 <link rel="stylesheet" href="test.css"> 33 <link rel="stylesheet" 34 href="really-long-long-long-long-long-test.css"> 35 </head> 36 <body> 37 <include src="test.html"> 38 <include 39 src="really-long-long-long-long-long-test-file-omg-so-long.html"> 40 </body> 41 </html> 42 ''', 43 44 'test.html': ''' 45 <include src="test2.html"> 46 ''', 47 48 'really-long-long-long-long-long-test-file-omg-so-long.html': ''' 49 <!-- This really long named resource should be included. --> 50 ''', 51 52 'test2.html': ''' 53 <!-- This second level resource should also be included. --> 54 ''', 55 56 'test.css': ''' 57 .image { 58 background: url('test.png'); 59 } 60 ''', 61 62 'really-long-long-long-long-long-test.css': ''' 63 a:hover { 64 font-weight: bold; /* Awesome effect is awesome! */ 65 } 66 ''', 67 68 'test.png': 'PNG DATA', 69 } 70 71 source_resources = set() 72 tmp_dir = util.TempDir(files) 73 for filename in files: 74 source_resources.add(tmp_dir.GetPath(filename)) 75 76 resources = html_inline.GetResourceFilenames(tmp_dir.GetPath('index.html')) 77 resources.add(tmp_dir.GetPath('index.html')) 78 self.failUnlessEqual(resources, source_resources) 79 tmp_dir.CleanUp() 80 81 def testCompressedJavaScript(self): 82 '''Tests that ".src=" doesn't treat as a tag.''' 83 84 files = { 85 'index.js': ''' 86 if(i<j)a.src="hoge.png"; 87 ''', 88 } 89 90 source_resources = set() 91 tmp_dir = util.TempDir(files) 92 for filename in files: 93 source_resources.add(tmp_dir.GetPath(filename)) 94 95 resources = html_inline.GetResourceFilenames(tmp_dir.GetPath('index.js')) 96 resources.add(tmp_dir.GetPath('index.js')) 97 self.failUnlessEqual(resources, source_resources) 98 tmp_dir.CleanUp() 99 100 def testInlineCSSImports(self): 101 '''Tests that @import directives in inlined CSS files are inlined too. 102 ''' 103 104 files = { 105 'index.html': ''' 106 <html> 107 <head> 108 <link rel="stylesheet" href="css/test.css"> 109 </head> 110 </html> 111 ''', 112 113 'css/test.css': ''' 114 @import url('test2.css'); 115 blink { 116 display: none; 117 } 118 ''', 119 120 'css/test2.css': ''' 121 .image { 122 background: url('../images/test.png'); 123 } 124 '''.strip(), 125 126 'images/test.png': 'PNG DATA' 127 } 128 129 expected_inlined = ''' 130 <html> 131 <head> 132 <style> 133 .image { 134 background: url('data:image/png;base64,UE5HIERBVEE='); 135 } 136 blink { 137 display: none; 138 } 139 </style> 140 </head> 141 </html> 142 ''' 143 144 source_resources = set() 145 tmp_dir = util.TempDir(files) 146 for filename in files: 147 source_resources.add(tmp_dir.GetPath(util.normpath(filename))) 148 149 result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) 150 resources = result.inlined_files 151 resources.add(tmp_dir.GetPath('index.html')) 152 self.failUnlessEqual(resources, source_resources) 153 self.failUnlessEqual(expected_inlined, 154 util.FixLineEnd(result.inlined_data, '\n')) 155 156 tmp_dir.CleanUp() 157 158 def testInlineCSSLinks(self): 159 '''Tests that only CSS files referenced via relative URLs are inlined.''' 160 161 files = { 162 'index.html': ''' 163 <html> 164 <head> 165 <link rel="stylesheet" href="foo.css"> 166 <link rel="stylesheet" href="chrome://resources/bar.css"> 167 </head> 168 </html> 169 ''', 170 171 'foo.css': ''' 172 @import url(chrome://resources/blurp.css); 173 blink { 174 display: none; 175 } 176 ''', 177 } 178 179 expected_inlined = ''' 180 <html> 181 <head> 182 <style> 183 @import url(chrome://resources/blurp.css); 184 blink { 185 display: none; 186 } 187 </style> 188 <link rel="stylesheet" href="chrome://resources/bar.css"> 189 </head> 190 </html> 191 ''' 192 193 source_resources = set() 194 tmp_dir = util.TempDir(files) 195 for filename in files: 196 source_resources.add(tmp_dir.GetPath(filename)) 197 198 result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None) 199 resources = result.inlined_files 200 resources.add(tmp_dir.GetPath('index.html')) 201 self.failUnlessEqual(resources, source_resources) 202 self.failUnlessEqual(expected_inlined, 203 util.FixLineEnd(result.inlined_data, '\n')) 204 205 def testFilenameVariableExpansion(self): 206 '''Tests that variables are expanded in filenames before inlining.''' 207 208 files = { 209 'index.html': ''' 210 <html> 211 <head> 212 <link rel="stylesheet" href="style[WHICH].css"> 213 <script src="script[WHICH].js"></script> 214 </head> 215 <include src="tmpl[WHICH].html"> 216 <img src="img[WHICH].png"> 217 </html> 218 ''', 219 'style1.css': '''h1 {}''', 220 'tmpl1.html': '''<h1></h1>''', 221 'script1.js': '''console.log('hello');''', 222 'img1.png': '''abc''', 223 } 224 225 expected_inlined = ''' 226 <html> 227 <head> 228 <style>h1 {}</style> 229 <script>console.log('hello');</script> 230 </head> 231 <h1></h1> 232 <img src="data:image/png;base64,YWJj"> 233 </html> 234 ''' 235 236 source_resources = set() 237 tmp_dir = util.TempDir(files) 238 for filename in files: 239 source_resources.add(tmp_dir.GetPath(filename)) 240 241 def replacer(var, repl): 242 return lambda filename: filename.replace('[%s]' % var, repl) 243 244 # Test normal inlining. 245 result = html_inline.DoInline( 246 tmp_dir.GetPath('index.html'), 247 None, 248 filename_expansion_function=replacer('WHICH', '1')) 249 resources = result.inlined_files 250 resources.add(tmp_dir.GetPath('index.html')) 251 self.failUnlessEqual(resources, source_resources) 252 self.failUnlessEqual(expected_inlined, 253 util.FixLineEnd(result.inlined_data, '\n')) 254 255 # Test names-only inlining. 256 result = html_inline.DoInline( 257 tmp_dir.GetPath('index.html'), 258 None, 259 names_only=True, 260 filename_expansion_function=replacer('WHICH', '1')) 261 resources = result.inlined_files 262 resources.add(tmp_dir.GetPath('index.html')) 263 self.failUnlessEqual(resources, source_resources) 264 265 def testWithCloseTags(self): 266 '''Tests that close tags are removed.''' 267 268 files = { 269 'index.html': ''' 270 <html> 271 <head> 272 <link rel="stylesheet" href="style1.css"></link> 273 <link rel="stylesheet" href="style2.css"> 274 </link> 275 <link rel="stylesheet" href="style2.css" 276 > 277 </link> 278 <script src="script1.js"></script> 279 </head> 280 <include src="tmpl1.html"></include> 281 <include src="tmpl2.html"> 282 </include> 283 <include src="tmpl2.html" 284 > 285 </include> 286 <img src="img1.png"> 287 </html> 288 ''', 289 'style1.css': '''h1 {}''', 290 'style2.css': '''h2 {}''', 291 'tmpl1.html': '''<h1></h1>''', 292 'tmpl2.html': '''<h2></h2>''', 293 'script1.js': '''console.log('hello');''', 294 'img1.png': '''abc''', 295 } 296 297 expected_inlined = ''' 298 <html> 299 <head> 300 <style>h1 {}</style> 301 <style>h2 {}</style> 302 <style>h2 {}</style> 303 <script>console.log('hello');</script> 304 </head> 305 <h1></h1> 306 <h2></h2> 307 <h2></h2> 308 <img src="data:image/png;base64,YWJj"> 309 </html> 310 ''' 311 312 source_resources = set() 313 tmp_dir = util.TempDir(files) 314 for filename in files: 315 source_resources.add(tmp_dir.GetPath(filename)) 316 317 # Test normal inlining. 318 result = html_inline.DoInline( 319 tmp_dir.GetPath('index.html'), 320 None) 321 resources = result.inlined_files 322 resources.add(tmp_dir.GetPath('index.html')) 323 self.failUnlessEqual(resources, source_resources) 324 self.failUnlessEqual(expected_inlined, 325 util.FixLineEnd(result.inlined_data, '\n')) 326 327if __name__ == '__main__': 328 unittest.main() 329