# Copyright (C) 2009, 2010 Canonical Ltd
#
# 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 3 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, see <http://www.gnu.org/licenses/>.

import os
from unittest import TestCase

from openid.consumer import consumer
from openid.message import Message
from openid.store.memstore import MemoryStore

from apache_openid import get_action_path
from apache_openid.handlers.openid.actions import (LoginAction,
    LogoutAction, ReturnAction)
from apache_openid.handlers.openidteams.actions import (TeamsLoginAction,
    TeamsLogoutAction, TeamsReturnAction)
from apache_openid.request import Request
from apache_openid.response import Response
from apache_openid.utils import FieldStorage, SERVER_RETURN
from apache_openid.utils.mock import ApacheMockRequest, Options, Session

__all__ = [
    'LoginActionTest', 'LogoutActionTest', 'ReturnActionTest',
    'TeamsLoginActionTest', 'TeamsLogoutActionTest', 'TeamsReturnActionTest']


def create_mock_consumer(session):
    store = MemoryStore()
    _consumer = consumer.Consumer(session, store)
    return _consumer


class ActionTestCase(TestCase):

    def setUp(self):
        self.apache_request = ApacheMockRequest()
        overrides = {
            'authorized-teams': "canonical-isd-hackers bzr-core",
            'action-path': "/openid",
            'allowed-op-list-url': "file://%s" % os.path.abspath(os.path.join(os.path.dirname(__file__), 'allowed-ops.txt')),
        }
        self.options = Options(overrides)
        self.action_path = get_action_path(self.options, self.apache_request)
        self.session = Session()
        self.request = Request(
            self.apache_request, self.action_path, self.session)
        self.response = Response(self.request, self.action_path, self.session)
        self.consumer = create_mock_consumer(self.session)


class FakeOpenIDRequest(object):
    extension = None
    
    def endpoint(self):
        pass
    endpoint.server_url = 'login.launchpad.net'

    def addExtension(self, extension):
        self.extension = extension


class FakeOpenIDResponse(FakeOpenIDRequest):
    message = Message.fromPostArgs({'namesapces': ''})
    identity_url = 'http://launchpad.net/~test'

    def getSignedNS(self, uri):
        return uri


class LoginActionTest(ActionTestCase):

    def setUp(self):
        super(LoginActionTest, self).setUp()
        self.action = LoginAction(
            self.request, self.response,
            self.session, self.consumer, self.options)

    def test_get_openid_identifier_from_request(self):
        # FIXME: test with actual request data
        self.assertEqual(
            self.action.get_openid_identifier_from_request(self.request),
            '')

    def test_get_messages_from_session(self):
        # FIXME: test with actual messages
        self.assertEqual(
            self.action.get_messages_from_session(self.session),
            [])

    def test_process_login_request(self):
        # FIXME: test with actual openid identifier
        self.assertRaises(
            AssertionError,
            self.action.process_login_request,
            '')

    def test_add_openid_extensions(self):
        openid_request = FakeOpenIDRequest()
        modified_request = self.action.add_openid_extensions(openid_request)
        self.assertEqual(openid_request, modified_request)

    def test_store_op_for_endpoint(self):
        # FIXME: test with actual openid identifier
        openid_request = FakeOpenIDRequest()
        self.action.store_op_for_endpoint('login.launchpad.net', None)

    def test_do(self):
        # FIXME: test with POST data
        self.request.method = 'GET'
        self.action.do()


class LogoutActionTest(ActionTestCase):

    def setUp(self):
        super(LogoutActionTest, self).setUp()
        self.action = LogoutAction(
            self.request, self.response,
            self.session, self.consumer, self.options)

    def test_external_cookie_names(self):
        # FIXME: test with actual 'external-cookie-names' option set
        self.assertEqual(
            self.action.external_cookie_names,
            [])

    def test_do(self):
        self.action.do()

    def test_clear_user_session(self):
        # FIXME: find a way to test if they were really del'ed
        self.action.clear_user_session()

    def test_clear_external_cookies(self):
        # FIXME: test with actual cookies
        self.action.clear_external_cookies()

    def test_split_values(self):
        values = self.action.split_values('a-cookie b-cookie c-cookie')
        self.assertEqual(
            values,
            ['a-cookie', 'b-cookie', 'c-cookie'])


class ReturnActionTest(ActionTestCase):

    def setUp(self):
        super(ReturnActionTest, self).setUp()
        self.action = ReturnAction(
            self.request, self.response,
            self.session, self.consumer, self.options)
        self.openid_response = FakeOpenIDResponse()

    def test_do(self):
        self.assertRaises(
            SERVER_RETURN,
            self.action.do)

    def test_get_response(self):
        form = FieldStorage(self.request)
        self.assertEqual(
            self.action.get_response(form),
            None)

    def test_on_success(self):
        # FIXME: test both branches
        self.assertRaises(
            SERVER_RETURN,
            self.action.on_success,
            self.openid_response)

    def test_fetch_op_for_endpoint(self):
        self.assertEqual(
            self.action.fetch_op_for_endpoint(None),
            None)

    def test_complete_login(self):
        self.assertRaises(
            SERVER_RETURN,
            self.action.complete_login,
            self.openid_response)


class TeamsLoginActionTest(ActionTestCase):

    def setUp(self):
        super(TeamsLoginActionTest, self).setUp()
        self.action = TeamsLoginAction(
            self.request, self.response, self.session, None, self.options)
        self.openid_request = FakeOpenIDRequest()

    def test_add_openid_extensions(self):
        modified_request = self.action.add_openid_extensions(
            self.openid_request)
        memberships_requested = modified_request.extension.query_membership
        self.assertEqual(
            memberships_requested,
            ['canonical-isd-hackers', 'bzr-core'])


class TeamsLogoutActionTest(ActionTestCase):

    def setUp(self):
        super(TeamsLogoutActionTest, self).setUp()
        self.action = TeamsLogoutAction(
            self.request, self.response, self.session, None, self.options)

    def test_do(self):
        self.action.do()


class TeamsReturnActionTest(ActionTestCase):

    def setUp(self):
        super(TeamsReturnActionTest, self).setUp()
        self.action = TeamsReturnAction(
            self.request, self.response, self.session, None, self.options)
        self.openid_response = FakeOpenIDResponse()

    def test_complete_login(self):
        self.assertRaises(
            SERVER_RETURN,
            self.action.complete_login,
            self.openid_response)
        self.assertEqual(self.apache_request.status, 302)
        self.assertEqual(
            self.apache_request.headers_out['location'], '/openid')
