##
## test_browser.py
## Login : <uli@pu.smp.net>
## Started on  Tue Mar 29 11:31:11 2011 Uli Fouquet
## $Id$
## 
## Copyright (C) 2011 Uli Fouquet
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
## 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
"""
Test the applicant-related UI components.
"""
import shutil
import tempfile
import unittest
from datetime import datetime
from zope.app.testing.functional import FunctionalTestCase
from zope.app.testing.functional import HTTPCaller as http
from zope.component import createObject
from zope.security.interfaces import Unauthorized
from zope.testbrowser.testing import Browser
from waeup.sirp.testing import FunctionalLayer
from waeup.sirp.app import University
from waeup.sirp.applicants.container import ApplicantsContainer

class LoginTest(FunctionalTestCase):
    # Here we check login view of applicants containers.
    #
    # Tests in here do only cover login attempts without any PINs
    # created before.

    layer = FunctionalLayer

    def setUp(self):
        super(LoginTest, self).setUp()

        # Setup a sample site for each test
        app = University()
        self.dc_root = tempfile.mkdtemp()
        app['datacenter'].setStoragePath(self.dc_root)
        self.login_path = 'http://localhost/app/applicants/testapplicants/login'

        # Add an applicants container where we can login (or not)
        applicantscontainer = ApplicantsContainer()
        applicantscontainer.ac_prefix = 'APP'
        app['applicants']['testapplicants'] = applicantscontainer

        # Put the prepopulated site into test ZODB and prepare test
        # browser
        self.getRootFolder()['app'] = app
        self.browser = Browser()
        self.browser.handleErrors = False

    def tearDown(self):
        super(LoginTest, self).tearDown()
        shutil.rmtree(self.dc_root)

    def test_anonymous_access(self):
        # Anonymous users can access a login page
        self.browser.open(self.login_path)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        return

    def test_anonymous_invalid_creds(self):
        # Anonymous users giving invalid credentials stay at the page
        self.browser.open(self.login_path)
        # We do not give credentials but send the form as-is
        submit = self.browser.getControl(name='SUBMIT')
        submit.click()
        # We are still at the same page...
        self.assertEqual(self.browser.url, self.login_path)
        self.assertEqual(self.browser.headers['Status'], '200 Ok')
        return

    def test_anonymous_invalid_creds_warning(self):
        # Entering wrong credentials will yield a warning
        self.browser.open(self.login_path)
        # We do not give credentials but send the form as-is
        submit = self.browser.getControl(name='SUBMIT')
        submit.click()
        self.assertTrue(
            'Entered credentials are invalid' in self.browser.contents)
        return

    def test_manager_no_warnings(self):
        # Browsing the login screen as a manager, won't raise warnings
        # Authenticate ourself as manager
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.login_path)
        # Submit the form w/o any credentials
        self.browser.getControl(name="SUBMIT").click()
        self.assertTrue(
            'Entered credentials are invalid' not in self.browser.contents)
        return

    def test_manager_no_redirect(self):
        # Browsing the login screen as a manager won't trigger a redirect
        # Authenticate ourself as manager
        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
        self.browser.open(self.login_path)
        # Submit the form w/o any credentials
        self.browser.getControl(name="SUBMIT").click()
        self.assertEqual(self.browser.url, self.login_path)
        return

    def test_display_entered_values(self):
        # After submit the entered values are displayed in the form
        self.browser.open(self.login_path)
        # Enter some value we can look for after submit
        ac_series = self.browser.getControl(name="form.ac_series")
        ac_series.value = '666'
        self.browser.getControl(name="SUBMIT").click()
        self.assertTrue('666' in self.browser.contents)
        return

class LoginTestWithPINs(LoginTest):
    # Here we check login view of applicants containers with PINs provided.

    # As setting up pins is time-consuming we only set them up when
    # really needed (i.e. in this separate TestCase).

    layer = FunctionalLayer

    def setUp(self):
        super(LoginTestWithPINs, self).setUp()

        # Create 5 access codes with prefix'FOO' and cost 9.99 each
        pin_container = self.getRootFolder()['app']['accesscodes']
        pin_container.createBatch(
            datetime.now(), 'some_userid', 'APP', 9.99, 5)
        pins = pin_container[pin_container.keys()[0]].values()
        self.pins = [x.representation for x in pins]
        self.existing_pin = self.pins[0]
        parts = self.existing_pin.split('-')[1:]
        self.existing_series, self.existing_number = parts
        self.browser.handleErrors = False

    def tearDown(self):
        super(LoginTestWithPINs, self).tearDown()

    def test_anonymous_valid_login(self):
        # If we enter valid credentials, we get to the applicants form
        self.browser.open(self.login_path)
        # Enter some value we can look for after submit
        ac_series = self.browser.getControl(name="form.ac_series")
        ac_series.value = self.existing_series
        ac_number = self.browser.getControl(name="form.ac_number")
        ac_number.value = self.existing_number
        self.browser.getControl(name="SUBMIT").click()
        # We should be redirected to applicants form.
        self.assertTrue(self.browser.url != self.login_path)
        return

    def test_anonymous_invalid_login(self):
        # If we enter wrong credentials we won't get far
        self.browser.open(self.login_path)
        # Enter some value we can look for after submit
        ac_series = self.browser.getControl(name="form.ac_series")
        ac_series.value = 'illegal series'
        ac_number = self.browser.getControl(name="form.ac_number")
        ac_number.value = 'invalid number'
        self.browser.getControl(name="SUBMIT").click()
        # We get a warning message
        self.assertTrue(
            'Entered credentials are invalid' in self.browser.contents)
        # We stay at the login page (no redirect)
        self.assertTrue(self.browser.url == self.login_path)
        return


def suite():
    suite = unittest.TestSuite()
    for testcase in [
        LoginTest,
        LoginTestWithPINs,
            ]:
        suite.addTests(unittest.makeSuite(testcase))
    return suite

test_suite = suite
