from six.moves import cStringIO as StringIO
from pathod import language
from pathod.language import http, base
import tutils


def parse_request(s):
    return language.parse_pathoc(s).next()


def test_make_error_response():
    d = StringIO()
    s = http.make_error_response("foo")
    language.serve(s, d, {})


class TestRequest:

    def test_nonascii(self):
        tutils.raises("ascii", parse_request, "get:\xf0")

    def test_err(self):
        tutils.raises(language.ParseException, parse_request, 'GET')

    def test_simple(self):
        r = parse_request('GET:"/foo"')
        assert r.method.string() == "GET"
        assert r.path.string() == "/foo"
        r = parse_request('GET:/foo')
        assert r.path.string() == "/foo"
        r = parse_request('GET:@1k')
        assert len(r.path.string()) == 1024

    def test_multiple(self):
        r = list(language.parse_pathoc("GET:/ PUT:/"))
        assert r[0].method.string() == "GET"
        assert r[1].method.string() == "PUT"
        assert len(r) == 2

        l = """
            GET
            "/foo"
            ir,@1

            PUT

            "/foo



            bar"

            ir,@1
        """
        r = list(language.parse_pathoc(l))
        assert len(r) == 2
        assert r[0].method.string() == "GET"
        assert r[1].method.string() == "PUT"

        l = """
            get:"http://localhost:9999/p/200":ir,@1
            get:"http://localhost:9999/p/200":ir,@2
        """
        r = list(language.parse_pathoc(l))
        assert len(r) == 2
        assert r[0].method.string() == "GET"
        assert r[1].method.string() == "GET"

    def test_nested_response(self):
        l = "get:/p:s'200'"
        r = list(language.parse_pathoc(l))
        assert len(r) == 1
        assert len(r[0].tokens) == 3
        assert isinstance(r[0].tokens[2], http.NestedResponse)
        assert r[0].values({})

    def test_render(self):
        s = StringIO()
        r = parse_request("GET:'/foo'")
        assert language.serve(
            r,
            s,
            language.Settings(request_host="foo.com")
        )

    def test_multiline(self):
        l = """
            GET
            "/foo"
            ir,@1
        """
        r = parse_request(l)
        assert r.method.string() == "GET"
        assert r.path.string() == "/foo"
        assert r.actions

        l = """
            GET

            "/foo



            bar"

            ir,@1
        """
        r = parse_request(l)
        assert r.method.string() == "GET"
        assert r.path.string().endswith("bar")
        assert r.actions

    def test_spec(self):
        def rt(s):
            s = parse_request(s).spec()
            assert parse_request(s).spec() == s
        rt("get:/foo")
        rt("get:/foo:da")

    def test_freeze(self):
        r = parse_request("GET:/:b@100").freeze(language.Settings())
        assert len(r.spec()) > 100

    def test_path_generator(self):
        r = parse_request("GET:@100").freeze(language.Settings())
        assert len(r.spec()) > 100

    def test_websocket(self):
        r = parse_request('ws:/path/')
        res = r.resolve(language.Settings())
        assert res.method.string().lower() == "get"
        assert res.tok(http.Path).value.val == "/path/"
        assert res.tok(http.Method).value.val.lower() == "get"
        assert http.get_header("Upgrade", res.headers).value.val == "websocket"

        r = parse_request('ws:put:/path/')
        res = r.resolve(language.Settings())
        assert r.method.string().lower() == "put"
        assert res.tok(http.Path).value.val == "/path/"
        assert res.tok(http.Method).value.val.lower() == "put"
        assert http.get_header("Upgrade", res.headers).value.val == "websocket"


class TestResponse:

    def dummy_response(self):
        return language.parse_pathod("400'msg'").next()

    def test_response(self):
        r = language.parse_pathod("400:m'msg'").next()
        assert r.status_code.string() == "400"
        assert r.reason.string() == "msg"

        r = language.parse_pathod("400:m'msg':b@100b").next()
        assert r.reason.string() == "msg"
        assert r.body.values({})
        assert str(r)

        r = language.parse_pathod("200").next()
        assert r.status_code.string() == "200"
        assert not r.reason
        assert "OK" in [i[:] for i in r.preamble({})]

    def test_render(self):
        s = StringIO()
        r = language.parse_pathod("400:m'msg'").next()
        assert language.serve(r, s, {})

        r = language.parse_pathod("400:p0,100:dr").next()
        assert "p0" in r.spec()
        s = r.preview_safe()
        assert "p0" not in s.spec()

    def test_raw(self):
        s = StringIO()
        r = language.parse_pathod("400:b'foo'").next()
        language.serve(r, s, {})
        v = s.getvalue()
        assert "Content-Length" in v

        s = StringIO()
        r = language.parse_pathod("400:b'foo':r").next()
        language.serve(r, s, {})
        v = s.getvalue()
        assert "Content-Length" not in v

    def test_length(self):
        def testlen(x):
            s = StringIO()
            x = x.next()
            language.serve(x, s, language.Settings())
            assert x.length(language.Settings()) == len(s.getvalue())
        testlen(language.parse_pathod("400:m'msg':r"))
        testlen(language.parse_pathod("400:m'msg':h'foo'='bar':r"))
        testlen(language.parse_pathod("400:m'msg':h'foo'='bar':b@100b:r"))

    def test_maximum_length(self):
        def testlen(x):
            x = x.next()