import unittest
import turbogears
from turbogears import controllers
from turbogears import url
from turbogears import validators
import cherrypy
import util
import formencode

class SubApp(controllers.Root):
    @turbogears.expose()
    def index(self):
        pass

class MyRoot(controllers.Root):
    subthing = SubApp()
    
    @turbogears.expose()
    def index(self):
        pass
    
    @turbogears.expose(html="turbogears.tests.simple")
    def test(self):
        return dict(title="Foobar", mybool=False, someval="niggles")
    
    @turbogears.expose()
    def unicode(self):
        cherrypy.response.headerMap["Content-Type"] = "text/html"
        return u'\u00bfHabla espa\u00f1ol?'
        
    @turbogears.expose()
    def returnedtemplate(self):
        return dict(title="Foobar", mybool=False, someval="foo",
            tg_template="turbogears.tests.simple")
        
    @turbogears.expose(validators={'value': validators.StringBoolean()})
    def istrue(self, value):
        self.value = value
        return str(value)
        
    @turbogears.expose(format="json", html="turbogears.tests.simple")
    def returnjson(self):
        return dict(title="Foobar", mybool=False, someval="foo",
            tg_html="turbogears.tests.simple")
    
    @turbogears.expose(content_type="xml/atom", template="turbogears.tests.simple")
    def contenttype(self):
        return dict(title="Foobar", mybool=False, someval="niggles")

    @turbogears.expose(validators={
        "firstname": validators.String(min=2, not_empty=True),
        "lastname": validators.String()})
    def save(self, submit, firstname, lastname="Miller"):
        self.submit = submit
        self.firstname = firstname
        self.lastname = lastname
        self.fullname = "%s %s" % (self.firstname, self.lastname)
        return self.fullname
        
    class Registration(formencode.Schema):
        allow_extra_fields = True
        firstname = validators.String(min=2, not_empty=True)
        lastname = validators.String()

    @turbogears.expose(validators=Registration())
    def save2(self, submit, firstname, lastname="Miller"):
        return self.save(submit, firstname, lastname)

    def validation_error(self, functionname, values, errors):
        self.functionname = functionname
        self.values = values
        self.errors = errors
        return "Error Message"
        
    @turbogears.expose(html="turbogears.tests.simple")
    def useother(self):
        return dict(tg_template="turbogears.tests.othertemplate")

class TestRoot(unittest.TestCase):
    def setUp(self):
        cherrypy.root = MyRoot()
    
    def test_jsFiles(self):
        'Can access the JavaScript files'
        util.createRequest("/tg_js/MochiKit.js")
        self.failUnlessEqual("application/x-javascript", 
            cherrypy.response.headerMap["Content-Type"])
        self.failUnlessEqual("200 OK", cherrypy.response.status)

    def test_jsonOutput(self):
        util.createRequest("/test?tg_format=json")
        import json
        values = json.read(cherrypy.response.body[0])
        assert values == dict(title="Foobar", mybool=False, someval="niggles",
            tg_flash=None)
        assert cherrypy.response.headerMap["Content-Type"] == "text/javascript"
    
    def test_retrieveDictDirectly(self):
        d = util.call(cherrypy.root.returnjson)
        assert d["title"] == "Foobar"

    def test_templateOutput(self):
        util.createRequest("/test")
        assert "Paging all niggles" in cherrypy.response.body[0]
        
    def test_safariUnicodeFix(self):
        util.createRequest("/unicode", headers={'User-Agent' : 
            "Apple WebKit Safari/412.2"})
        firstline = cherrypy.response.body[0].split('\n')[0]
        self.failUnlessEqual("&#xbf;Habla espa&#xf1;ol?", firstline)
        self.failUnless(isinstance(firstline, str))
    
    def test_defaultFormat(self):
        """The default format can be set via expose"""
        util.createRequest("/returnjson")
        firstline = cherrypy.response.body[0]
        assert '"title":"Foobar"' in firstline
        util.createRequest("/returnjson?tg_format=html")
        firstline = cherrypy.response.body[0]
        assert '"title":"Foobar"' not in firstline
    
    def test_contentType(self):
        """The content-type can be set via expose"""
        util.createRequest("/contenttype")
        assert cherrypy.response.headerMap["Content-Type"] == "xml/atom"

    def test_returnedTemplateName(self):
        util.createRequest("/returnedtemplate")
        data = cherrypy.response.body[0]
        assert "<HTML>" in data
        
    def test_validation(self):
        "Data can be converted and validated"
        util.createRequest("/istrue?value=true")
        assert cherrypy.root.value is True
        util.createRequest("/istrue?value=false")
        assert cherrypy.root.value is False
        cherrypy.root = MyRoot()
        util.createRequest("/istrue?value=foo")
        assert not hasattr(cherrypy.root, "value")
        assert len(cherrypy.root.errors) == 1
        assert cherrypy.root.functionname == "istrue"
    
        util.createRequest("/save?submit=send&firstname=John&lastname=Doe")
        assert cherrypy.root.fullname == "John Doe"
        assert cherrypy.root.submit == "send"
        util.createRequest("/save?submit=send&firstname=Arthur")
        assert cherrypy.root.fullname == "Arthur Miller"
        util.createRequest("/save?submit=send&firstname=Arthur&lastname=")
        assert cherrypy.root.fullname == "Arthur "
        util.createRequest("/save?submit=send&firstname=D&lastname=")
        assert len(cherrypy.root.values) == 3
        assert len(cherrypy.root.errors) == 1
        assert cherrypy.root.errors.has_key("firstname")
        assert "characters" in cherrypy.root.errors["firstname"].msg.lower()
        util.createRequest("/save?submit=send&firstname=&lastname=")
        assert len(cherrypy.root.values) == 3
        assert len(cherrypy.root.errors) == 1
        assert cherrypy.root.errors.has_key("firstname")

    def test_validationwithschema(self):
        "Data can be converted and validated with formencode.Schema instance"
        util.createRequest("/save2?submit=send&firstname=John&lastname=Doe")
        assert cherrypy.root.fullname == "John Doe"
        assert cherrypy.root.submit == "send"
        # this one results in an error, in contrast to the non-schema case
        util.createRequest("/save2?submit=send&firstname=Arthur")
        assert len(cherrypy.root.values) == 2
        assert len(cherrypy.root.errors) == 1
        assert cherrypy.root.errors.has_key("lastname")
        assert "missing" in cherrypy.root.errors['lastname'].msg.lower()
        util.createRequest("/save2?submit=send&firstname=Arthur&lastname=")
        assert cherrypy.root.fullname == "Arthur "
        util.createRequest("/save2?submit=send&firstname=&lastname=")
        assert len(cherrypy.root.values) == 3
        assert len(cherrypy.root.errors) == 1
        assert cherrypy.root.errors.has_key("firstname")
        util.createRequest("/save2?submit=send&firstname=D&lastname=")
        assert len(cherrypy.root.values) == 3
        assert len(cherrypy.root.errors) == 1
        assert cherrypy.root.errors.has_key("firstname")
        
    def test_othertemplate(self):
        "'tg_html' in a returned dict will use the template specified there"
        util.createRequest("/useother")
        assert "This is the other template" in cherrypy.response.body[0]
       
class TestURLs(unittest.TestCase):
    def setUp(self):
        cherrypy.root = MyRoot()
        
    def test_basicurls(self):
        util.createRequest("/")
        self.failUnlessEqual("/foo", url("/foo"))
        self.failUnlessEqual("foo/bar", url(["foo", "bar"]))
        assert url("/foo", bar=1, baz=2) in \
                ["/foo?bar=1&baz=2", "/foo?baz=2&bar=1"]
        assert url("/foo", dict(bar=1, baz=2)) in \
                ["/foo?bar=1&baz=2", "/foo?baz=2&bar=1"]
    
    def test_approots(self):
        util.createRequest("/subthing/")
        self.failUnlessEqual("foo", url("foo"))
        self.failUnlessEqual("/subthing/foo", url("/foo"))
        
    def test_approotsWithPath(self):
        cherrypy.config.update({"server.webpath" : "/coolsite/root"})
        turbogears.startup.startTurboGears()
        util.createRequest("/subthing/")
        self.failUnlessEqual("/coolsite/root/subthing/foo",
                        url("/foo"))
    
    def tearDown(self):
        cherrypy.config.update({"server.webpath" : ""})
        turbogears.startup.startTurboGears()
        
