1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#!/usr/bin/env python
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# found in the LICENSE file.
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import posixpath
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import unittest
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)from extensions_paths import PUBLIC_TEMPLATES, SERVER2
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from local_file_system import LocalFileSystem
11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)from test_file_system import TestFileSystem
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from object_store_creator import ObjectStoreCreator
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochfrom path_canonicalizer import PathCanonicalizer
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from special_paths import SITE_VERIFICATION_FILE
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class PathCanonicalizerTest(unittest.TestCase):
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def setUp(self):
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._path_canonicalizer = PathCanonicalizer(
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        LocalFileSystem.Create(PUBLIC_TEMPLATES),
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ObjectStoreCreator.ForTest(),
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ('.html', '.md'))
23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  def testSpecifyCorrectly(self):
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('extensions/browserAction')
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('extensions/storage')
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('extensions/blah')
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('extensions/index')
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('extensions/whats_new')
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('apps/storage')
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('apps/bluetooth')
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('apps/blah')
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('apps/tags/webview')
34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
35ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  def testSpecifyIncorrectly(self):
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'extensions/browserAction', 'apps/browserAction')
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'extensions/browserAction', 'apps/extensions/browserAction')
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/bluetooth', 'extensions/bluetooth')
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/bluetooth', 'extensions/apps/bluetooth')
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'extensions/index', 'apps/index')
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'extensions/browserAction', 'static/browserAction')
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/tags/webview', 'apps/webview')
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/tags/webview', 'extensions/webview')
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/tags/webview', 'extensions/tags/webview')
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # These are a little trickier because storage.html is in both directories.
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # They must canonicalize to the closest match.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'extensions/storage', 'extensions/apps/storage')
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/storage', 'apps/extensions/storage')
61ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  def testUnspecified(self):
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'extensions/browserAction', 'browserAction')
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/bluetooth', 'bluetooth')
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Default happens to be apps because it's first alphabetically.
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirectWithDefaultExtensions(
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'apps/storage', 'storage')
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    # Nonexistent APIs should be left alone.
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    self._AssertIdentity('blah.html')
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def testDirectories(self):
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Directories can be canonicalized too!
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('apps/')
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('apps/tags/')
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('extensions/')
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # No trailing slash should be treated as files not directories, at least
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # at least according to PathCanonicalizer.
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('extensions/apps', 'apps')
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('extensions', 'extensions')
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Just as tolerant of spelling mistakes.
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('apps/', 'Apps/')
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('apps/tags/', 'Apps/TAGS/')
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('extensions/', 'Extensions/')
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Find directories in the correct place.
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('apps/tags/', 'tags/')
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('apps/tags/', 'extensions/tags/')
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
90ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  def testSpellingErrors(self):
91ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    for spelme in ('browseraction', 'browseraction.htm', 'BrowserAction',
92ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                   'BrowserAction.html', 'browseraction.html', 'Browseraction',
93ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                   'browser-action', 'Browser.action.html', 'browser_action',
94ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                   'browser-action.html', 'Browser_Action.html'):
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._AssertRedirect('extensions/browserAction', spelme)
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._AssertRedirect('extensions/browserAction', 'extensions/%s' % spelme)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._AssertRedirect('extensions/browserAction', 'apps/%s' % spelme)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def testNonDefaultExtensions(self):
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # The only example currently of a file with a non-default extension is
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # the redirects.json file. That shouldn't have its extension stripped since
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # it's not in the default extensions.
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity('redirects.json')
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('redirects.json', 'redirects')
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('redirects.json', 'redirects.html')
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('redirects.json', 'redirects.js')
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect('redirects.json', 'redirects.md')
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def testSiteVerificationFile(self):
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # The site verification file should not redirect.
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertIdentity(SITE_VERIFICATION_FILE)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect(SITE_VERIFICATION_FILE,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         posixpath.splitext(SITE_VERIFICATION_FILE)[0])
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
115c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  def testDotSeparated(self):
116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self._AssertIdentity('extensions/devtools_inspectedWindow')
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self._AssertRedirect('extensions/devtools_inspectedWindow',
118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                         'extensions/devtools.inspectedWindow')
119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  def testUnderscoreSeparated(self):
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    file_system = TestFileSystem({
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      'pepper_dev': {
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        'c': {
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          'index.html': ''
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        }
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      },
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      'pepper_stable': {
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        'c': {
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          'index.html': ''
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        }
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      }
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    })
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    self._path_canonicalizer = PathCanonicalizer(
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        file_system,
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        ObjectStoreCreator.ForTest(),
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        ('.html', '.md'))
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    self._AssertIdentity('pepper_stable/c/index')
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    self._AssertRedirect('pepper_stable/c/index',
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                         'pepper_stable/c/index.html')
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  def _AssertIdentity(self, path):
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._AssertRedirect(path, path)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _AssertRedirect(self, to, from_):
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(to, self._path_canonicalizer.Canonicalize(from_))
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _AssertRedirectWithDefaultExtensions(self, to, from_):
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for ext in ('', '.html', '.md'):
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._AssertRedirect(
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          to, self._path_canonicalizer.Canonicalize(from_ + ext))
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)if __name__ == '__main__':
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  unittest.main()
155