1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
9 from tvcm import fake_fs
10 from tvcm import generate
11 from tvcm import html_generation_controller
12 from tvcm import html_module
13 from tvcm import module
14 from tvcm import parse_html_deps
15 from tvcm import project as project_module
16 from tvcm import resource
17 from tvcm import resource_loader as resource_loader
18 from tvcm import strip_js_comments
20 class ResourceWithFakeContents(resource.Resource):
21 def __init__(self, toplevel_dir, absolute_path, fake_contents):
22 """A resource with explicitly provided contents.
24 If the resource does not exist, then pass fake_contents=None. This will
25 cause accessing the resource contents to raise an exception mimicking the
26 behavior of regular resources."""
27 super(ResourceWithFakeContents, self).__init__(toplevel_dir, absolute_path)
28 self._fake_contents = fake_contents
32 if self._fake_contents == None:
33 raise Exception('File not found')
34 return self._fake_contents
36 class FakeLoader(object):
37 def __init__(self, source_paths, initial_filenames_and_contents=None):
38 self._source_paths = source_paths
39 self._file_contents = {}
40 if initial_filenames_and_contents:
41 for k,v in initial_filenames_and_contents.iteritems():
42 self._file_contents[k] = v
44 def FindResourceGivenAbsolutePath(self, absolute_path):
46 for source_path in self._source_paths:
47 if absolute_path.startswith(source_path):
48 candidate_paths.append(source_path)
49 if len(candidate_paths) == 0:
52 # Sort by length. Longest match wins.
53 candidate_paths.sort(lambda x, y: len(x) - len(y))
54 longest_candidate = candidate_paths[-1]
56 return ResourceWithFakeContents(longest_candidate, absolute_path,
57 self._file_contents.get(absolute_path, None))
59 def FindResourceGivenRelativePath(self, relative_path):
61 for script_path in self._source_paths:
62 absolute_path = os.path.join(script_path, relative_path)
63 if absolute_path in self._file_contents:
64 return ResourceWithFakeContents(script_path, absolute_path,
65 self._file_contents[absolute_path])
69 class ParseTests(unittest.TestCase):
70 def testMissingDocType(self):
71 parse_results = parse_html_deps.HTMLModuleParserResults("")
76 html_module.Parse(FakeLoader(["/tmp"], file_contents),
80 self.assertRaises(Exception, DoIt)
82 def testValidExternalScriptReferenceToRawScript(self):
83 parse_results = parse_html_deps.HTMLModuleParserResults("""<!DOCTYPE html>
84 <script src="../foo.js">
88 file_contents['/tmp/a/foo.js'] = """
89 'i am just some raw script';
92 metadata = html_module.Parse(FakeLoader(["/tmp"], file_contents),
96 self.assertEquals([], metadata.dependent_module_names)
97 self.assertEquals(['a/foo.js'], metadata.dependent_raw_script_relative_paths)
100 def testExternalScriptReferenceToModuleOutsideScriptPath(self):
101 parse_results = parse_html_deps.HTMLModuleParserResults("""<!DOCTYPE html>
102 <script src="/foo.js">
106 file_contents['/foo.js'] = ''
109 html_module.Parse(FakeLoader(["/tmp"], file_contents),
113 self.assertRaises(Exception, DoIt)
115 def testExternalScriptReferenceToFileThatDoesntExist(self):
116 parse_results = parse_html_deps.HTMLModuleParserResults("""<!DOCTYPE html>
117 <script src="/foo.js">
123 html_module.Parse(FakeLoader(["/tmp"], file_contents),
127 self.assertRaises(Exception, DoIt)
129 def testInlineScriptWithoutStrictNote(self):
130 parse_results = parse_html_deps.HTMLModuleParserResults("""<!DOCTYPE html>
132 console.log('Logging without strict mode is no fun.');
138 metadata = html_module.Parse(FakeLoader(["/tmp"], file_contents),
142 self.assertRaises(Exception, DoIt)
144 def testValidImportOfModule(self):
145 parse_results = parse_html_deps.HTMLModuleParserResults("""<!DOCTYPE html>
146 <link rel="import" href="../foo.html">
150 file_contents['/tmp/a/foo.html'] = """
153 metadata = html_module.Parse(FakeLoader(["/tmp"], file_contents),
157 self.assertEquals(['a.foo'], metadata.dependent_module_names)
159 def testStyleSheetImport(self):
160 parse_results = parse_html_deps.HTMLModuleParserResults("""<!DOCTYPE html>
161 <link rel="stylesheet" href="../foo.css">
165 file_contents['/tmp/a/foo.css'] = """
167 metadata = html_module.Parse(FakeLoader(["/tmp"], file_contents),
171 self.assertEquals([], metadata.dependent_module_names)
172 self.assertEquals(['a.foo'], metadata.style_sheet_names)
174 def testUsingAbsoluteHref(self):
175 parse_results = parse_html_deps.HTMLModuleParserResults("""<!DOCTYPE html>
176 <script src="/foo.js">
180 file_contents['/src/foo.js'] = ''
182 metadata = html_module.Parse(FakeLoader(["/tmp", "/src"], file_contents),
186 self.assertEquals(['foo.js'], metadata.dependent_raw_script_relative_paths)
189 class HTMLModuleTests(unittest.TestCase):
192 file_contents['/tmp/a/b/start.html'] = """
194 <link rel="import" href="/widget.html">
195 <link rel="stylesheet" href="../common.css">
196 <script src="/raw_script.js"></script>
197 <polymer-element name="start">
202 console.log('inline script for start.html got written');
206 file_contents['/tvcm/tvcm.html'] = """<!DOCTYPE html>
208 file_contents['/components/widget.html'] = """
210 <link rel="import" href="/tvcm.html">
211 <widget name="widget.html"></widget>
214 console.log('inline script for widget.html');
217 file_contents['/tmp/a/common.css'] = """
218 /* /tmp/a/common.css was written */
220 file_contents['/raw/raw_script.js'] = """
221 console.log('/raw/raw_script.js was written');
223 file_contents['/raw/polymer.js'] = """
226 with fake_fs.FakeFS(file_contents):
227 project = project_module.Project(['/tvcm/', '/tmp/', '/components/', '/raw/'],
228 include_tvcm_paths=False)
229 loader = resource_loader.ResourceLoader(project)
230 a_b_start_module = loader.LoadModule(module_name='a.b.start')
231 load_sequence = project.CalcLoadSequenceForModules([a_b_start_module])
233 # Check load sequence names.
234 load_sequence_names = [x.name for x in load_sequence]
235 self.assertEquals(['tvcm',
237 'a.b.start'], load_sequence_names)
240 # Check module_deps on a_b_start_module
241 def HasDependentModule(module, name):
242 return [x for x in module.dependent_modules
244 assert HasDependentModule(a_b_start_module, 'widget')
246 # Check JS generation.
247 js = generate.GenerateJS(load_sequence)
248 assert 'inline script for start.html' in js
249 assert 'inline script for widget.html' in js
250 assert '/raw/raw_script.js' in js
252 # Check HTML generation.
253 html = generate.GenerateStandaloneHTMLAsString(load_sequence, title='',
254 flattened_js_url="/blah.js")
255 assert '<polymer-element name="start">' in html
256 assert 'inline script for widget.html' not in html
257 assert 'common.css' in html
259 def testPolymerConversion(self):
261 file_contents['/tmp/a/b/my_component.html'] = """
263 <polymer-element name="my-component">
273 with fake_fs.FakeFS(file_contents):
274 project = project_module.Project(['/tvcm/', '/tmp/'],
275 include_tvcm_paths=False)
276 loader = resource_loader.ResourceLoader(project)
277 my_component = loader.LoadModule(module_name='a.b.my_component')
279 f = StringIO.StringIO()
280 my_component.AppendJSContentsToFile(
282 use_include_tags_for_scripts=False,
283 dir_for_include_tag_root=None)
284 js = f.getvalue().rstrip()
287 Polymer ( 'my-component', {
290 self.assertEquals(expected_js, js)
292 def testPolymerConversion2(self):
294 file_contents['/tmp/a/b/my_component.html'] = """
296 <polymer-element name="my-component">
305 with fake_fs.FakeFS(file_contents):
306 project = project_module.Project(['/tvcm/', '/tmp/'],
307 include_tvcm_paths=False)
308 loader = resource_loader.ResourceLoader(project)
309 my_component = loader.LoadModule(module_name='a.b.my_component')
311 f = StringIO.StringIO()
312 my_component.AppendJSContentsToFile(
314 use_include_tags_for_scripts=False,
315 dir_for_include_tag_root=None)
316 js = f.getvalue().rstrip()
319 Polymer ( 'my-component');
321 self.assertEquals(expected_js, js)
324 def testInlineStylesheetURLs(self):
326 file_contents['/tmp/a/b/my_component.html'] = """
330 background-image: url('../something.jpg');
334 file_contents['/tmp/a/something.jpg'] = 'jpgdata'
335 with fake_fs.FakeFS(file_contents):
336 project = project_module.Project(['/tvcm/', '/tmp/'],
337 include_tvcm_paths=False)
338 loader = resource_loader.ResourceLoader(project)
339 my_component = loader.LoadModule(module_name='a.b.my_component')
342 my_component.AppendDirectlyDependentFilenamesTo(computed_deps)
343 self.assertEquals(set(computed_deps),
344 set(['/tmp/a/b/my_component.html',
345 '/tmp/a/something.jpg']))
347 f = StringIO.StringIO()
348 ctl = html_generation_controller.HTMLGenerationController()
349 my_component.AppendHTMLContentsToFile(f, ctl)
350 html = f.getvalue().rstrip()
353 background-image: url(data:image/jpg;base64,anBnZGF0YQ==);