import unittest

class SERVER_RETURN(Exception): pass
def dummyApache():
    """Create a dummy _apache module to make it so that we can import
    mod_python's apache module."""
    import new
    _apache = new.module('_apache')
    _apache.table = None
    _apache.log_error = None
    _apache.config_tree = None
    _apache.server_root = None
    _apache.mpm_query = lambda x: False
    _apache.exists_config_define = None
    _apache.SERVER_RETURN = SERVER_RETURN
    _apache.parse_qs = None
    _apache.parse_qsl = None
    import sys
    sys.modules['_apache'] = _apache
    import _apache
    return _apache

dummyApache()
import mpopenid


###### Authorized users

def mkAuthTest(case, expected):
    def test(self):
        actual = mpopenid.parseAuthorizedURLs(case)
        self.failUnlessEqual(
            actual,
            expected,
            'Case %r, got %r, expected %r' % (case, actual, expected))
    return test

class ParseAuthorizedTest(unittest.TestCase):
    test_empty = mkAuthTest('', [])
    test_empty2 = mkAuthTest(' ', [])
    test_empty3 = mkAuthTest('\n\n', [])
    test_one = mkAuthTest('http://www.jyte.com/', ['http://www.jyte.com/'])
    test_one_trail = mkAuthTest('http://www.jyte.com', ['http://www.jyte.com/'])
    test_one_trail_pfx = mkAuthTest('www.jyte.com', ['http://www.jyte.com/'])
    test_one_pfx = mkAuthTest('www.jyte.com/', ['http://www.jyte.com/'])
    test_two = mkAuthTest('http://one.com/ http://two.com/',
                          ['http://one.com/', 'http://two.com/'])
    test_two_nl = mkAuthTest('http://one.com/\nhttp://two.com/',
                             ['http://one.com/', 'http://two.com/'])
    test_two_leadtrail = mkAuthTest(' http://one.com/\nhttp://two.com/ ',
                                    ['http://one.com/', 'http://two.com/'])
    test_two_pfx = mkAuthTest('one.com/ two.com/',
                              ['http://one.com/', 'http://two.com/'])

    test_file_list = mkAuthTest('''\
http://j3h.livejournal.com/
http://j3h.janrain.com/
http://j3h.us/

http://mylid.net/j3h.

http://josh.utest.magbox.com/

http://josh.myopenid.com/
http://j3h.myopenid.com/
''', [
        'http://j3h.livejournal.com/',
        'http://j3h.janrain.com/',
        'http://j3h.us/',
        'http://mylid.net/j3h.',
        'http://josh.utest.magbox.com/',
        'http://josh.myopenid.com/',
        'http://j3h.myopenid.com/',
      ])


###### Cookied User

def mkRequest(cls, session, options, req):
    self = object.__new__(cls)
    self.session = session
    self.options = options
    self.apache_request = req
    return self

class CookiedUserTest(unittest.TestCase):
    def test_missing(self):
        req = mkRequest(mpopenid.OpenIDAccessRequest, {}, None, None)
        self.failUnless(req.cookied_user is None)

    def test_present(self):
        session = {
            'cookied_user': 'http://j3h.us/',
            }
        req = mkRequest(mpopenid.OpenIDAccessRequest, session, None, None)
        self.failUnlessEqual(req.cookied_user, 'http://j3h.us/')
        self.failUnlessEqual(req.get_cookied_user(), 'http://j3h.us/')

    def test_set(self):
        req = mkRequest(mpopenid.OpenIDAccessRequest, {}, None, None)
        self.failUnless(req.cookied_user is None)
        req.set_cookied_user('http://josh.myopenid.com/')
        self.failUnlessEqual(req.cookied_user, 'http://josh.myopenid.com/')
        req.cookied_user = 'http://j3h.us/'
        self.failUnlessEqual(req.cookied_user, 'http://j3h.us/')
        self.failUnlessEqual(req.get_cookied_user(), 'http://j3h.us/')
        self.failUnlessEqual(req.session.get('cookied_user'), 'http://j3h.us/')


###### Server URL

class Dummy(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

def mkServerURLTest(case, expected):
    def test(self):
        req = self._request(*case)
        actual = req.getServerURL()
        self.failUnlessEqual(actual, expected)

    return test

class ServerURLTest(unittest.TestCase):
    def _request(self, hostname, local_port, https=None):
        req = Dummy(hostname=hostname)
        req.connection = Dummy(local_addr=(None, local_port))
        req.subprocess_env = {}
        if https:
            req.subprocess_env['HTTPS'] = https

        return mkRequest(mpopenid.OpenIDAccessRequest, None, None, req)

    # Standard ports
    test_localhost80 = mkServerURLTest(
        ('localhost', 80), 'http://localhost/')
    test_localhost443_ssl = mkServerURLTest(
        ('localhost', 443, 'on'), 'https://localhost/')
    test_myopenid_com443_ssl = mkServerURLTest(
        ('myopenid.com', 443, 'on'), 'https://myopenid.com/')

    # Non-standard ports
    test_localhost8000 = mkServerURLTest(
        ('localhost', 8000), 'http://localhost:8000/')
    test_localhost8000_ssl = mkServerURLTest(
        ('localhost', 8000, 'on'), 'https://localhost:8000/')
    test_localhost80_ssl = mkServerURLTest(
        ('localhost', 80, 'on'), 'https://localhost:80/')


###### Redirection

class Redirect(Exception): pass

class DummyOpenIDRequest(mpopenid.OpenIDAccessRequest):
    def actionURL(self, action):
        return 'action://' + action

    def redirect(self, url):
        raise Redirect(url)

def mkRedirectTest(message, target):
    def test(self):
        req = mkRequest(DummyOpenIDRequest, {}, None, None)
        try:
            req.loginRedirect(message, target)
        except Redirect, e:
            self.failUnlessEqual(e[0], 'action://login')
            self.failUnlessEqual(req.session['message'], message)
            if target is None:
                self.failUnlessRaises(
                    KeyError, req.session.__getitem__, 'target')
            else:
                self.failUnlessEqual(req.session['target'], target)
        else:
            self.fail('Expected redirect')
    return test

class RedirectTest(unittest.TestCase):
    test_loginRedirect = mkRedirectTest(None, None)
    test_loginRedirect_msg = mkRedirectTest('hi', None)
    test_loginRedirect_target = mkRedirectTest(None, 'target')
    test_loginRedirect_msg_target = mkRedirectTest('hi', 'target')


###### Creating a consumer

import openid.store.dumbstore

class ConsumerTest(unittest.TestCase):
    def test_dumb(self):
        options = {}
        req = mkRequest(mpopenid.OpenIDLogin, None, options, None)
        self.failUnless(isinstance(req.getConsumer().consumer.store,
                                   openid.store.dumbstore.DumbStore))

    def test_dumb_stateless(self):
        options = {'store-type':'stateless'}
        req = mkRequest(mpopenid.OpenIDLogin, None, options, None)
        self.failUnless(isinstance(req.getConsumer().consumer.store,
                                   openid.store.dumbstore.DumbStore))

    def test_file(self):
        options = {'store-type':'file',
                   'store-directory':'/tmp/test-mpopenid-store/',
                   }
        req = mkRequest(mpopenid.OpenIDLogin, None, options, None)
        self.failUnless(isinstance(req.getConsumer().consumer.store,
                                   openid.store.filestore.FileOpenIDStore))

    def test_bad(self):
        options = {'store-type':'filex',
                   'store-directory':'/tmp/test-mpopenid-store/',
                   }
        errors = []
        def log_error(*args):
            errors.append(args)
        apache_request = Dummy(log_error=log_error)

        req = mkRequest(mpopenid.OpenIDLogin, None, options, apache_request)
        self.failUnlessRaises(SERVER_RETURN, req.getConsumer)
        self.failUnlessEqual(len(errors), 1)
        self.failUnless('filex' in errors[0][0])



###### Action Path
# options['action-path']
# apache_request.path_info
# apache_request.uri

def mkLoginActionPathTest(expected, uri, action_path=None, path_info=''):
    def test(self):
        options = {}
        if action_path:
            options['action-path'] = action_path

        apache_request = Dummy(path_info=path_info,
                               uri=uri)

        req = mkRequest(mpopenid.OpenIDLogin, None, options, apache_request)
        self.failUnlessEqual(req.getActionPath(), expected)
    return test

class LoginActionPathTest(unittest.TestCase):
    test_empty = mkLoginActionPathTest('/', '/')

    test_basic = mkLoginActionPathTest('/openid/', '/openid')

    test_option = mkLoginActionPathTest('/foo/', '/openid/greeble', '/foo')

    test_pathinfo = mkLoginActionPathTest('/openid/', '/openid/', None, '/')

    test_pathinfo2 = mkLoginActionPathTest(
        '/openid/', '/openid/login', None, '/login')

    test_pathinfo_option = mkLoginActionPathTest(
        '/beans/', '/openid/login', '/beans', '/login')

    test_option_slash = mkLoginActionPathTest(
        '/beans/', '/openid/login', '/beans/', '/login')


###### Action Path
# options['action-path']
# apache_request.path_info
# apache_request.uri

def mkProtectActionPathTest(expected, uri, action_path=None, path_info=''):
    def test(self):
        options = {}
        if action_path:
            options['action-path'] = action_path

        apache_request = Dummy(path_info=path_info,
                               uri=uri,
                               hlist=Dummy(directory=path_info),
                               log_error=lambda x:x,
                               document_root=lambda :'/dummy/')

        req = mkRequest(mpopenid.OpenIDProtect, None, options, apache_request)
        self.failUnlessEqual(req.getActionPath(), expected)
    return test

class ProtectActionPathTest(unittest.TestCase):
    test_empty = mkProtectActionPathTest('/openid/', '/')

    test_basic = mkProtectActionPathTest('/openid/', '/openid')

    test_option = mkProtectActionPathTest('/foo/', '/openid/greeble', '/foo')

    test_pathinfo = mkProtectActionPathTest(
        '/openid/', '/openid/', None, '/')

    test_pathinfo2 = mkProtectActionPathTest(
        '/openid/', '/openid/login', None, '/login')

    test_pathinfo_option = mkProtectActionPathTest(
        '/beans/', '/openid/login', '/beans', '/login')

    test_option_slash = mkProtectActionPathTest(
        '/beans/', '/openid/login', '/beans/', '/login')


###### Tests that need to be written
# mpopenid.OpenIDLogin
#  .openid
#  .do_login
#  .do_logout
#  .do_return
#  .fillLoginPage
#
# mpopenid.OpenIDProtect
#  .getAuthorizedUsers
#  .protect

if __name__ == '__main__':
    unittest.main()
