15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto_functional  # Must be imported before pyauto
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import pyauto
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import test_utils
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from webdriver_pages import settings
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from webdriver_pages.settings import Behaviors, ContentTypes
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from webdriver_pages.settings import RestoreOnStartupType
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PrefsUITest(pyauto.PyUITest):
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """TestCase for Preferences UI."""
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INFOBAR_TYPE = 'rph_infobar'
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def setUp(self):
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyauto.PyUITest.setUp(self)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver = self.NewWebDriver()
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Debug(self):
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Test method for experimentation.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method will not run automatically.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    driver = self.NewWebDriver()
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ContentSettingsPage.FromNavigation(driver)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    import pdb
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pdb.set_trace()
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetGeolocationContentSettingsBehavior(self):
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the Content Settings behavior for Geolocation.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The exceptions behavior for the specified content type.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The content type is the available content setting available.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    behavior_key = self.GetPrefsInfo().Prefs(
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pyauto.kGeolocationDefaultContentSetting)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    behaviors_dict = {1: 'ALLOW', 2: 'BLOCK', 3: 'ASK'}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        behavior_key in behaviors_dict,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        msg=('Invalid default behavior key "%s" for "geolocation" content' %
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             behavior_key))
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return behaviors_dict[behavior_key]
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _VerifyContentExceptionUI(self, content_type, hostname_pattern, behavior,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                incognito=False):
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Find hostname pattern and behavior within UI on content exceptions page.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content_type: The string content settings type to manage.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hostname_pattern: The URL or pattern associated with the behavior.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      behavior: The exception to allow or block the hostname.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      incognito: Incognito list displayed on exceptions settings page.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 Default to False.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ManageExceptionsPage.FromNavigation(
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._driver, content_type)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(page.GetExceptions(incognito).has_key(hostname_pattern),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg=('No displayed host name matches pattern "%s"'
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          % hostname_pattern))
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(behavior, page.GetExceptions(incognito)[hostname_pattern],
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg=('Displayed behavior "%s" does not match behavior "%s"'
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          % (page.GetExceptions(incognito)[hostname_pattern],
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             behavior)))
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testLocationSettingOptionsUI(self):
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify the location options setting UI.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Set the options through the UI using webdriver and verify the settings in
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyAuto.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ContentSettingsPage.FromNavigation(self._driver)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.ALLOW)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        1, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.BLOCK)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        2, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.ASK)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        3, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testBehaviorValueCorrectlyDisplayed(self):
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify the set behavior value is correctly displayed."""
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Block all sites.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 2)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetGeolocationContentSettingsBehavior(), Behaviors.BLOCK.upper(),
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        msg='The behavior was incorrectly set.')
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Allow all sites.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 1)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetGeolocationContentSettingsBehavior(), Behaviors.ALLOW.upper(),
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        msg='The behavior was incorrectly set.')
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ask for permission when site wants to track.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._GetGeolocationContentSettingsBehavior(), Behaviors.ASK.upper(),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        msg='The behavior was incorrectly set.')
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testExceptionsEntryCorrectlyDisplayed(self):
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify the exceptions line entry is correctly displayed in the UI."""
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    geo_exception = (
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {'http://maps.google.com:80,http://maps.google.com:80':
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            {'geolocation': 2}})
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kContentSettingsPatternPairs, geo_exception)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._VerifyContentExceptionUI(
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ContentTypes.GEOLOCATION, 'http://maps.google.com:80',
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Behaviors.BLOCK)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    geo_exception = (
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {'http://maps.google.com:80,http://maps.google.com:80':
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            {'geolocation': 1}})
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kContentSettingsPatternPairs, geo_exception)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._VerifyContentExceptionUI(
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ContentTypes.GEOLOCATION, 'http://maps.google.com:80',
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Behaviors.ALLOW)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    geo_exception = (
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        {'http://maps.google.com:80,http://maps.google.com:80':
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            {'geolocation': 3}})
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kContentSettingsPatternPairs, geo_exception)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._VerifyContentExceptionUI(
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ContentTypes.GEOLOCATION, 'http://maps.google.com:80', Behaviors.ASK)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testAddNewExceptionUI(self):
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify new exception added for hostname pattern and behavior in UI."""
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content_type = ContentTypes.PLUGINS
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ManageExceptionsPage.FromNavigation(
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._driver, content_type)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pattern, behavior = ('bing.com', Behaviors.BLOCK)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.AddNewException(pattern, behavior)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(page.GetExceptions()[pattern], Behaviors.BLOCK,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg='The behavior "%s" was not added for pattern "%s"'
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     % (behavior, pattern))
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testChangeExceptionBehaviorUI(self):
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify behavior for hostname pattern is changed in the UI."""
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content_type = ContentTypes.PLUGINS
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ManageExceptionsPage.FromNavigation(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._driver, content_type)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pattern, behavior = ('bing.com', Behaviors.BLOCK)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.AddNewException(pattern, behavior)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_behavior = Behaviors.ALLOW
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.SetBehaviorForPattern(pattern, new_behavior)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(page.GetExceptions()[pattern], Behaviors.ALLOW,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg='The behavior for "%s" did not change: "%s"'
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     % (pattern, behavior))
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testDeleteExceptionUI(self):
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify exception deleted for hostname pattern and behavior in the UI."""
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content_type = ContentTypes.PLUGINS
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ManageExceptionsPage.FromNavigation(
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._driver, content_type)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pattern, behavior = ('bing.com', Behaviors.BLOCK)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.AddNewException(pattern, behavior)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(page.GetExceptions()[pattern], Behaviors.BLOCK,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg='The behavior "%s" was not added for pattern "%s"'
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     % (behavior, pattern))
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.DeleteException(pattern)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(page.GetExceptions().get(pattern, KeyError), KeyError,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg='Pattern "%s" was not deleted' % pattern)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testNoInitialLineEntryInUI(self):
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify no initial line entry is displayed in UI."""
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ask for permission when site wants to track.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        3, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ManageExceptionsPage.FromNavigation(
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._driver, ContentTypes.GEOLOCATION)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(0, len(page.GetExceptions()))
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testCorrectCookiesSessionInUI(self):
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify exceptions for cookies in UI list entry."""
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Block cookies for for a session for google.com.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetPrefs(pyauto.kContentSettingsPatternPairs,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  {'http://google.com:80': {'cookies': 2}})
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._VerifyContentExceptionUI(
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ContentTypes.COOKIES, 'http://google.com:80', Behaviors.BLOCK)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testInitialLineEntryInIncognitoUI(self):
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify initial line entry is displayed in Incognito UI."""
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)  # Display incognito list.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ManageExceptionsPage.FromNavigation(
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._driver, ContentTypes.PLUGINS)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(1, len(page.GetExceptions(incognito=True)))
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testIncognitoExceptionsEntryCorrectlyDisplayed(self):
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify exceptions entry is correctly displayed in the incognito UI."""
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)  # Display incognito list.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.ManageExceptionsPage.FromNavigation(
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._driver, ContentTypes.PLUGINS)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pattern, behavior = ('http://maps.google.com:80', Behaviors.BLOCK)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.AddNewException(pattern, behavior, incognito=True)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._VerifyContentExceptionUI(
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ContentTypes.PLUGINS, 'http://maps.google.com:80',
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Behaviors.BLOCK, incognito=True)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testSetPasswordAndDelete(self):
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify a password can be deleted in the Content Settings UI."""
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    password_list = []
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Add two passwords, 1 for example0.com and 1 for example1.com.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for i in range(2):
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Construct a password dictionary with required fields.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password = {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'username_value': 'user%s@example.com'  % i,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'password_value': 'test.password',
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'signon_realm': 'https://www.example%s.com/'  % i,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'time': 1279650942.0,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'origin_url': 'https://www.example%s.com/login'  % i,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'username_element': 'username%s',
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'password_element': 'password',
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'submit_element': 'submit',
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'action_target': 'https://www.example%s.com/login/'  % i,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'blacklist': False,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password_list.append(password)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.AddSavedPassword(password)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_passwords = self.GetSavedPasswords()
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEquals(len(password_list), len(saved_passwords),
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      msg='Not all Passwords were saved.')
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for password in password_list:
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.assertTrue(password in saved_passwords,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      msg='Passwords were not saved correctly.')
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.PasswordsSettings.FromNavigation(self._driver)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Delete one of the passwords.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    password = password_list[1]
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.DeleteItem(password['origin_url'], password['username_value'])
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(password not in self.GetSavedPasswords(),
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    msg='Password was not deleted.')
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testSetCookieAndDeleteInContentSettings(self):
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify a cookie can be deleted in the Content Settings UI."""
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Create a cookie.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cookie_dict = {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'name': 'test_cookie',
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'value': 'test_value',
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'expiry': time.time() + 30,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    site = '127.0.0.1'
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.NavigateToURL(self.GetHttpURLForDataPath('google', 'google.html'))
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver.add_cookie(cookie_dict)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.CookiesAndSiteDataSettings.FromNavigation(self._driver)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.DeleteSiteData(site)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertTrue(site not in page.GetSiteNameList(),
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    'Site "%s" was not deleted.'  % site)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testRemoveMailProtocolHandler(self):
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify the mail protocol handler is added and removed successfully."""
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url = self.GetHttpURLForDataPath('settings', 'protocol_handler.html')
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.NavigateToURL(url)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Returns a dictionary with the mail handler that was asked for
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # registration.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asked_handler_dict = self._driver.execute_script(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'return registerMailClient()')
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.PerformActionOnInfobar(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'accept', infobar_index=test_utils.WaitForInfobarTypeAndGetIndex(
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self, self.INFOBAR_TYPE))
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver.find_element_by_id('test_mail_protocol').click()
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protocol_handlers_list = (
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetPrefsInfo().Prefs(pyauto.kRegisteredProtocolHandlers))
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registered_mail_handler = {}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for handler_dict in protocol_handlers_list:
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (handler_dict['protocol'] == 'mailto' and
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          handler_dict['url'] == asked_handler_dict['url'] and
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          handler_dict['title'] == asked_handler_dict['title'] and
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          handler_dict.get('default')):
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        registered_mail_handler = handler_dict
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Verify the mail handler is registered as asked.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.assertNotEqual(
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registered_mail_handler, {},
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      msg='Mail protocol handler was not registered correctly.')
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Verify the registered mail handler works as expected.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.assertTrue(
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._driver.execute_script(
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'return doesQueryConformsToProtocol("%s", "%s")'
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              % (asked_handler_dict['query_key'],
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 asked_handler_dict['query_value'])),
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              msg='Mail protocol did not register correctly.')
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver.get('chrome://settings-frame/handlers')
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # There are 3 DIVs in a handler entry. The last one acts as a remove button.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The remove button is also equivalent to setting the site to NONE.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver.find_element_by_id('handlers-list').\
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        find_element_by_xpath('.//div[@role="listitem"]').\
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        find_element_by_xpath('.//div[@class="handlers-site-column"]').\
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        find_element_by_xpath('.//option[@value="-1"]').click()
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver.get(url)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver.find_element_by_id('test_mail_protocol').click()
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(url, self._driver.current_url,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     msg='Mail protocol still registered.')
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BasicSettingsUITest(pyauto.PyUITest):
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Testcases for uber page basic settings UI."""
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def setUp(self):
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pyauto.PyUITest.setUp(self)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._driver = self.NewWebDriver()
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Debug(self):
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """chrome://plugins test debug method.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This method will not run automatically.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    driver = self.NewWebDriver()
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.BasicSettingsPage.FromNavigation(driver)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    import pdb
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pdb.set_trace()
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testOnStartupSettings(self):
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify user can set startup options."""
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.BasicSettingsPage.FromNavigation(self._driver)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.SetOnStartupOptions(RestoreOnStartupType.NEW_TAB_PAGE)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(RestoreOnStartupType.NEW_TAB_PAGE,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.SetOnStartupOptions(RestoreOnStartupType.RESTORE_SESSION)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(RestoreOnStartupType.RESTORE_SESSION,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.SetOnStartupOptions(RestoreOnStartupType.RESTORE_URLS)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(RestoreOnStartupType.RESTORE_URLS,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testSetStartupPages(self):
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify user can add urls for startup pages."""
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.BasicSettingsPage.FromNavigation(self._driver)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for url in ['www.google.com', 'http://www.amazon.com', 'ebay.com']:
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page.AddStartupPage(url)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(RestoreOnStartupType.RESTORE_URLS,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    startup_urls = self.GetPrefsInfo().Prefs(pyauto.kURLsToRestoreOnStartup)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(startup_urls[0], 'http://www.google.com/')
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(startup_urls[1], 'http://www.amazon.com/')
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(startup_urls[2], 'http://ebay.com/')
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testUseCurrentPagesForStartup(self):
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify user can start up browser using current pages."""
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.BasicSettingsPage.FromNavigation(self._driver)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.OpenNewBrowserWindow(True)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url1 = self.GetHttpURLForDataPath('title2.html')
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url2 = self.GetHttpURLForDataPath('title3.html')
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.NavigateToURL(url1, 1, 0)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.AppendTab(pyauto.GURL(url2), 1)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    title_list = ['Title Of Awesomeness',
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'Title Of More Awesomeness']
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.UseCurrentPageForStartup(title_list)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page.VerifyStartupURLs(title_list)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(RestoreOnStartupType.RESTORE_URLS,
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    startup_urls = self.GetPrefsInfo().Prefs(pyauto.kURLsToRestoreOnStartup)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(len(startup_urls), 3)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(startup_urls[1], url1)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(startup_urls[2], url2)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def testCancelStartupURLSetting(self):
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Verify canceled start up URLs settings are not saved."""
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    page = settings.BasicSettingsPage.FromNavigation(self._driver)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for url in ['www.google.com', 'http://www.amazon.com']:
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      page.CancelStartupURLSetting(url)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    startup_urls = self.GetPrefsInfo().Prefs(pyauto.kURLsToRestoreOnStartup)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.assertEqual(len(startup_urls), 0)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pyauto_functional.Main()
380