1#!/usr/bin/env python 2# Copyright 2013 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 6from cStringIO import StringIO 7import json 8import unittest 9from zipfile import ZipFile 10 11from compiled_file_system import CompiledFileSystem 12from content_provider import ContentProvider 13from file_system import FileNotFoundError 14from object_store_creator import ObjectStoreCreator 15from path_canonicalizer import PathCanonicalizer 16from test_file_system import TestFileSystem 17from third_party.motemplate import Motemplate 18 19_REDIRECTS_JSON = json.dumps({ 20 'oldfile.html': 'storage.html', 21 'index.html': 'https://developers.google.com/chrome', 22}) 23 24 25_MARKDOWN_CONTENT = ( 26 ('# Header 1 #', u'<h1 id="header-1">Header 1</h1>'), 27 ('1. Foo\n', u'<ol>\n<li>Foo</li>\n</ol>'), 28 ('![alt text](/path/img.jpg "Title")\n', 29 '<p><img alt="alt text" src="/path/img.jpg" title="Title" /></p>'), 30 ('* Unordered item 1', u'<ul>\n<li>Unordered item 1</li>\n</ul>') 31) 32 33# Test file system data which exercises many different mimetypes. 34_TEST_DATA = { 35 'dir': { 36 'a.txt': 'a.txt content', 37 'b.txt': 'b.txt content', 38 'c': { 39 'd.txt': 'd.txt content', 40 }, 41 }, 42 'dir2': { 43 'dir3': { 44 'a.txt': 'a.txt content', 45 'b.txt': 'b.txt content', 46 'c': { 47 'd.txt': 'd.txt content', 48 }, 49 }, 50 }, 51 'dir4': { 52 'index.html': 'index.html content 1' 53 }, 54 'dir5': { 55 'index.html': 'index.html content 2' 56 }, 57 'dir6': { 58 'notindex.html': 'notindex.html content' 59 }, 60 'dir7': { 61 'index.md': '\n'.join(text[0] for text in _MARKDOWN_CONTENT) 62 }, 63 'dir.txt': 'dir.txt content', 64 'dir5.html': 'dir5.html content', 65 'img.png': 'img.png content', 66 'index.html': 'index.html content', 67 'read.txt': 'read.txt content', 68 'redirects.json': _REDIRECTS_JSON, 69 'noextension': 'noextension content', 70 'run.js': 'run.js content', 71 'site.css': 'site.css content', 72 'storage.html': 'storage.html content', 73 'markdown.md': '\n'.join(text[0] for text in _MARKDOWN_CONTENT) 74} 75 76 77class ContentProviderUnittest(unittest.TestCase): 78 def setUp(self): 79 self._test_file_system = TestFileSystem(_TEST_DATA) 80 self._content_provider = self._CreateContentProvider() 81 82 def _CreateContentProvider(self, supports_zip=False): 83 object_store_creator = ObjectStoreCreator.ForTest() 84 return ContentProvider( 85 'foo', 86 CompiledFileSystem.Factory(object_store_creator), 87 self._test_file_system, 88 object_store_creator, 89 default_extensions=('.html', '.md'), 90 # TODO(kalman): Test supports_templates=False. 91 supports_templates=True, 92 supports_zip=supports_zip) 93 94 def _assertContent(self, content, content_type, content_and_type): 95 # Assert type so that str is differentiated from unicode. 96 self.assertEqual(type(content), type(content_and_type.content)) 97 self.assertEqual(content, content_and_type.content) 98 self.assertEqual(content_type, content_and_type.content_type) 99 100 def _assertTemplateContent(self, content, path, version): 101 content_and_type = self._content_provider.GetContentAndType(path).Get() 102 self.assertEqual(Motemplate, type(content_and_type.content)) 103 content_and_type.content = content_and_type.content.source 104 self._assertContent(content, 'text/html', content_and_type) 105 self.assertEqual(version, self._content_provider.GetVersion(path).Get()) 106 107 def _assertMarkdownContent(self, content, path, version): 108 content_and_type = self._content_provider.GetContentAndType(path).Get() 109 content_and_type.content = content_and_type.content.source 110 self._assertContent(content, 'text/html', content_and_type) 111 self.assertEqual(version, self._content_provider.GetVersion(path).Get()) 112 113 def testPlainText(self): 114 self._assertContent( 115 u'a.txt content', 'text/plain', 116 self._content_provider.GetContentAndType('dir/a.txt').Get()) 117 self._assertContent( 118 u'd.txt content', 'text/plain', 119 self._content_provider.GetContentAndType('dir/c/d.txt').Get()) 120 self._assertContent( 121 u'read.txt content', 'text/plain', 122 self._content_provider.GetContentAndType('read.txt').Get()) 123 self._assertContent( 124 unicode(_REDIRECTS_JSON, 'utf-8'), 'application/json', 125 self._content_provider.GetContentAndType('redirects.json').Get()) 126 self._assertContent( 127 u'run.js content', 'application/javascript', 128 self._content_provider.GetContentAndType('run.js').Get()) 129 self._assertContent( 130 u'site.css content', 'text/css', 131 self._content_provider.GetContentAndType('site.css').Get()) 132 133 def testTemplate(self): 134 self._assertTemplateContent(u'storage.html content', 'storage.html', '0') 135 self._test_file_system.IncrementStat('storage.html') 136 self._assertTemplateContent(u'storage.html content', 'storage.html', '1') 137 138 def testImage(self): 139 self._assertContent( 140 'img.png content', 'image/png', 141 self._content_provider.GetContentAndType('img.png').Get()) 142 143 def testZipTopLevel(self): 144 zip_content_provider = self._CreateContentProvider(supports_zip=True) 145 content_and_type = zip_content_provider.GetContentAndType('dir.zip').Get() 146 zipfile = ZipFile(StringIO(content_and_type.content)) 147 content_and_type.content = zipfile.namelist() 148 self._assertContent( 149 ['dir/a.txt', 'dir/b.txt', 'dir/c/d.txt'], 'application/zip', 150 content_and_type) 151 152 def testZip2ndLevel(self): 153 zip_content_provider = self._CreateContentProvider(supports_zip=True) 154 content_and_type = zip_content_provider.GetContentAndType( 155 'dir2/dir3.zip').Get() 156 zipfile = ZipFile(StringIO(content_and_type.content)) 157 content_and_type.content = zipfile.namelist() 158 self._assertContent( 159 ['dir3/a.txt', 'dir3/b.txt', 'dir3/c/d.txt'], 'application/zip', 160 content_and_type) 161 162 def testCanonicalZipPaths(self): 163 # Without supports_zip the path is canonicalized as a file. 164 self.assertEqual( 165 'dir.txt', 166 self._content_provider.GetCanonicalPath('dir.zip')) 167 self.assertEqual( 168 'dir.txt', 169 self._content_provider.GetCanonicalPath('diR.zip')) 170 # With supports_zip the path is canonicalized as the zip file which 171 # corresponds to the canonical directory. 172 zip_content_provider = self._CreateContentProvider(supports_zip=True) 173 self.assertEqual( 174 'dir.zip', 175 zip_content_provider.GetCanonicalPath('dir.zip')) 176 self.assertEqual( 177 'dir.zip', 178 zip_content_provider.GetCanonicalPath('diR.zip')) 179 180 def testMarkdown(self): 181 expected_content = '\n'.join(text[1] for text in _MARKDOWN_CONTENT) 182 self._assertMarkdownContent(expected_content, 'markdown', '0') 183 self._test_file_system.IncrementStat('markdown.md') 184 self._assertMarkdownContent(expected_content, 'markdown', '1') 185 186 def testNotFound(self): 187 self.assertRaises( 188 FileNotFoundError, 189 self._content_provider.GetContentAndType('oops').Get) 190 191 def testIndexRedirect(self): 192 self._assertTemplateContent(u'index.html content', '', '0') 193 self._assertTemplateContent(u'index.html content 1', 'dir4', '0') 194 self._assertTemplateContent(u'dir5.html content', 'dir5', '0') 195 self._assertMarkdownContent( 196 '\n'.join(text[1] for text in _MARKDOWN_CONTENT), 197 'dir7', 198 '0') 199 self._assertContent( 200 'noextension content', 'text/plain', 201 self._content_provider.GetContentAndType('noextension').Get()) 202 self.assertRaises( 203 FileNotFoundError, 204 self._content_provider.GetContentAndType('dir6').Get) 205 206 def testRefresh(self): 207 # Not entirely sure what to test here, but get some code coverage. 208 self._content_provider.Refresh().Get() 209 210 211if __name__ == '__main__': 212 unittest.main() 213