#
# Copyright 2002 by Object Craft P/L, Melbourne, Australia.
#
# LICENCE - see LICENCE file distributed with this software for details.
#
#
# Test CGI Request functionality
#
# $Id: request.py,v 1.3 2003/01/24 11:34:31 andrewm Exp $

import sys
import os
import unittest
import cgi
import re
import StringIO
import albatross
import albatross.cgiapp

class Page:
    def page_process(self, ctx):
        self.locals = ctx.locals

class App(albatross.SimpleApp):
    def __init__(self):
        self.page = Page()
        page_name = self.page.__class__.__name__
        albatross.SimpleApp.__init__(self,
                                     base_url = '.', 
                                     template_path = '.', 
                                     start_page = page_name,
                                     secret = '')
        self.register_page(page_name, self.page)

class SimpleRequestTest(unittest.TestCase):
    def test_request(self, request):
        app = App()
        saved_stdout, sys.stdout = sys.stdout, StringIO.StringIO()
        try:
            app.run(request)
        finally:
            sys.stdout = saved_stdout
        self.failUnless(app.page.locals.foo, 'bah')
        self.failUnless(app.page.locals.list, ['a','b'])

class CGIGetRequestTestCase(SimpleRequestTest):
    def runTest(self):
        environ = {
            'REQUEST_METHOD': 'GET',
            'QUERY_STRING': 'foo=bah&list=a&list=b',
        }
        fields = cgi.FieldStorage(environ=environ)
        self.test_request(albatross.cgiapp.Request(fields=fields))

class CGIPostRequestTestCase(SimpleRequestTest):
    def runTest(self):
        environ = {
            'REQUEST_METHOD': 'POST',
            'CONTENT_TYPE': 'application/x-www-form-urlencoded',
        }
        input_file = StringIO.StringIO("foo=bah&list=a&list=b")
        fields = cgi.FieldStorage(fp=input_file, environ=environ)
        self.test_request(albatross.cgiapp.Request(fields=fields))

class CGIFormRequestTestCase(SimpleRequestTest):
    input = """\
----------AXBYCZ
Content-Disposition: form-data; name="foo"

bah
----------AXBYCZ
Content-Disposition: form-data; name="list"

a
----------AXBYCZ
Content-Disposition: form-data; name="list"

b
----------AXBYCZ--
"""
    def runTest(self):
        environ = {
            'REQUEST_METHOD': 'POST',
            'CONTENT_TYPE': 'multipart/form-data; boundary=--------AXBYCZ',
        }
        input_file = StringIO.StringIO(self.input)
        fields = cgi.FieldStorage(fp=input_file, environ=environ)
        self.test_request(albatross.cgiapp.Request(fields=fields))

class FileRequestTest(unittest.TestCase):
    def test_request(self, input_str):
        boundary = '--------AXBYCZ'
        environ = {
            'REQUEST_METHOD': 'POST',
            'CONTENT_TYPE': 'multipart/form-data; boundary=--------AXBYCZ',
        }
        app = App()
        input_file = StringIO.StringIO(input_str % self.make_albform())
        fields = cgi.FieldStorage(fp=input_file, environ=environ)
        saved_stdout, sys.stdout = sys.stdout, StringIO.StringIO()
        try:
            app.run(albatross.cgiapp.Request(fields=fields))
        finally:
            sys.stdout = saved_stdout
        return app.page.locals.foo

    def make_albform(self):
        # trick albatross into generating an __albform__ value for us
        app = App()
        ctx = albatross.SimpleAppContext(app)
        ctx.push_content_trap()
        ctx.form_open()
        ctx.input_add('file','foo','',0)
        ctx.form_close()
        result = ctx.pop_content_trap()
        match = re.search('name="__albform__" value="([^"]+)"', result)
        if match:
            return match.group(1)
        return ""

class CGISingleFileRequestTestCase(FileRequestTest):
    input_str = """\
----------AXBYCZ
Content-Disposition: form-data; name="foo"; filename="baz"

bah
----------AXBYCZ
Content-Disposition: form-data; name="__albform__"

%s
----------AXBYCZ--
"""
    def runTest(self):
        foo = self.test_request(self.input_str)
        self.failUnless(len(foo), 1)
        self.failUnless(foo[0].file.read(), 'bah')
        self.failUnless(foo[0].filename, 'baz')


class CGIListFileRequestTestCase(FileRequestTest):
    input_str = """\
----------AXBYCZ
Content-Disposition: form-data; name="foo"; filename="baz"

bah
----------AXBYCZ
Content-Disposition: form-data; name="foo"; filename="blot"

bling
----------AXBYCZ
Content-Disposition: form-data; name="__albform__"

%s
----------AXBYCZ--
"""
    def runTest(self):
        foo = self.test_request(self.input_str)
        self.failUnless(len(foo), 2)
        self.failUnless(foo[0].file.read(), 'bah')
        self.failUnless(foo[0].filename, 'baz')
        self.failUnless(foo[1].file.read(), 'bling')
        self.failUnless(foo[1].filename, 'blot')

class CGIMultiFileRequestTestCase(FileRequestTest):
    input_str = """\
----------AXBYCZ
Content-Disposition: form-data; name="foo"
Content-Type: multipart/mixed; boundary=--------ZCYBXA

----------ZCYBXA
Content-Disposition: attachment; filename="baz"
Content-Type: text/plain

bah
----------ZCYBXA
Content-Disposition: attachment; filename="blot"

bling
----------ZCYBXA--
----------AXBYCZ
Content-Disposition: form-data; name="__albform__"

%s
----------AXBYCZ--
"""
    def runTest(self):
        foo = self.test_request(self.input_str)
        self.failUnless(len(foo), 2)
        self.failUnless(foo[0].file.read(), 'bah')
        self.failUnless(foo[0].filename, 'baz')
        self.failUnless(foo[1].file.read(), 'bling')
        self.failUnless(foo[1].filename, 'blot')


"""
Driver for the above tests
"""

class RequestSuite(unittest.TestSuite):
    def __init__(self):
        unittest.TestSuite.__init__(self)
        self.addTest(CGIGetRequestTestCase())
        self.addTest(CGIPostRequestTestCase())
        self.addTest(CGIFormRequestTestCase())
        self.addTest(CGISingleFileRequestTestCase())
        self.addTest(CGIListFileRequestTestCase())
        self.addTest(CGIMultiFileRequestTestCase())

def suite():
    return RequestSuite()

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