>>> import mechanize
>>> from mechanize._response import test_response
>>> from test_browser import TestBrowser2, make_mock_handler


Opening a new response should close the old one.

>>> class TestHttpHandler(mechanize.BaseHandler):
...     def http_open(self, request):
...         return test_response(url=request.get_full_url())
>>> class TestHttpBrowser(TestBrowser2):
...     handler_classes = TestBrowser2.handler_classes.copy()
...     handler_classes["http"] = TestHttpHandler
...     default_schemes = ["http"]
>>> def response_impl(response):
...     return response.wrapped.fp.__class__.__name__

>>> br = TestHttpBrowser()
>>> r = br.open("http://example.com")
>>> print response_impl(r)
StringI
>>> r2 = br.open("http://example.com")
>>> print response_impl(r2)
StringI
>>> print response_impl(r)
eofresponse

So should .set_response()

>>> br.set_response(test_response())
>>> print response_impl(r2)
eofresponse


.visit_response() works very similarly to .open()

>>> br = TestHttpBrowser()
>>> r = br.open("http://example.com")
>>> r2 = test_response(url="http://example.com/2")
>>> print response_impl(r2)
StringI
>>> br.visit_response(r2)
>>> print response_impl(r)
eofresponse
>>> br.geturl() == br.request.get_full_url() == "http://example.com/2"
True
>>> junk = br.back()
>>> br.geturl() == br.request.get_full_url() == "http://example.com"
True


.back() may reload if the complete response was not read.  If so, it
should return the new response, not the old one

>>> class ReloadCheckBrowser(TestHttpBrowser):
...     reloaded = False
...     def reload(self):
...         self.reloaded = True
...         return TestHttpBrowser.reload(self)
>>> br = ReloadCheckBrowser()
>>> old = br.open("http://example.com")
>>> junk = br.open("http://example.com/2")
>>> new = br.back()
>>> br.reloaded
True
>>> new.wrapped is not old.wrapped
True


Warn early about some mistakes setting a response object

>>> import StringIO
>>> br = TestBrowser2()
>>> br.set_response("blah")
Traceback (most recent call last):
...
ValueError: not a response object
>>> br.set_response(StringIO.StringIO())
Traceback (most recent call last):
...
ValueError: not a response object


.open() without an appropriate scheme handler should fail with
URLError

>>> br = TestBrowser2()
>>> br.open("http://example.com")
Traceback (most recent call last):
...
URLError: <urlopen error unknown url type: http>

Reload after failed .open() should fail due to failure to open, not
with BrowserStateError

>>> br.reload()
Traceback (most recent call last):
...
URLError: <urlopen error unknown url type: http>


.clear_history() should do what it says on the tin.  Note that the
history does not include the current response!

>>> br = TestBrowser2()
>>> br.add_handler(make_mock_handler(test_response)([("http_open", None)]))

>>> br.response() is None
True
>>> len(br._history._history)
0

>>> r = br.open("http://example.com/1")
>>> br.response() is not None
True
>>> len(br._history._history)
0

>>> br.clear_history()
>>> br.response() is not None
True
>>> len(br._history._history)
0

>>> r = br.open("http://example.com/2")
>>> br.response() is not None
True
>>> len(br._history._history)
1

>>> br.clear_history()
>>> br.response() is not None
True
>>> len(br._history._history)
0


.open()ing a Request with False .visit does not affect Browser state.
Redirections during such a non-visiting request should also be
non-visiting.

>>> from mechanize import BrowserStateError, Request, HTTPRedirectHandler
>>> from test_urllib2 import MockHTTPHandler

>>> def make_browser_with_redirect():
...     br = TestBrowser2()
...     hh = MockHTTPHandler(302, "Location: http://example.com/\r\n\r\n")
...     br.add_handler(hh)
...     br.add_handler(HTTPRedirectHandler())
...     return br
>>> def raises(exc_class, fn, *args, **kwds):
...     try:
...         fn(*args, **kwds)
...     except exc_class, exc:
...         return True
...     return False
>>> def test_state(br):
...     return (br.request is None and
...             br.response() is None and
...             raises(BrowserStateError, br.back)
...             )
>>> br = make_browser_with_redirect()
>>> test_state(br)
True
>>> req = Request("http://example.com")
>>> req.visit = False
>>> r = br.open(req)
>>> test_state(br)
True

.open_novisit() mutates the request object

>>> br = make_browser_with_redirect()
>>> test_state(br)
True
>>> req = Request("http://example.com")
>>> print req.visit
None
>>> r = br.open_novisit(req)
>>> test_state(br)
True
>>> req.visit
False


...in fact, any redirection (but not refresh), proxy request, basic or
digest auth request, or robots.txt request should be non-visiting,
even if .visit is True:

>>> from test_urllib2 import MockPasswordManager
>>> def test_one_visit(handlers):
...     br = TestBrowser2()
...     for handler in handlers: br.add_handler(handler)
...     req = Request("http://example.com")
...     req.visit = True
...     br.open(req)
...     return br
>>> def test_state(br):
...     # XXX the _history._history check is needed because of the weird
...     # throwing-away of history entries by .back() where response is
...     # None, which makes the .back() check insufficient to tell if a
...     # history entry was .add()ed.  I don't want to change this until
...     # post-stable.
...     return (
...         br.response() and
...         br.request and
...         len(br._history._history) == 0 and
...         raises(BrowserStateError, br.back))

>>> hh = MockHTTPHandler(302, "Location: http://example.com/\r\n\r\n")
>>> br = test_one_visit([hh, HTTPRedirectHandler()])
>>> test_state(br)
True

>>> class MockPasswordManager:
...     def add_password(self, realm, uri, user, password): pass
...     def find_user_password(self, realm, authuri): return '', ''

>>> ah = mechanize.HTTPBasicAuthHandler(MockPasswordManager())
>>> hh = MockHTTPHandler(
...     401, 'WWW-Authenticate: Basic realm="realm"\r\n\r\n')
>>> test_state(test_one_visit([hh, ah]))
True

>>> ph = mechanize.ProxyHandler(dict(http="proxy.example.com:3128"))
>>> ah = mechanize.ProxyBasicAuthHandler(MockPasswordManager())
>>> hh = MockHTTPHandler(
...     407, 'Proxy-Authenticate: Basic realm="realm"\r\n\r\n')
>>> test_state(test_one_visit([ph, hh, ah]))
True

XXX Can't really fix this one properly without significant changes --
the refresh should go onto the history *after* the call, but currently
all redirects, including refreshes, are done by recursive .open()
calls, which gets the history wrong in this case.  Will have to wait
until after stable release:

#>>> hh = MockHTTPHandler(
#...     "refresh", 'Location: http://example.com/\r\n\r\n')
#>>> br = test_one_visit([hh, HTTPRedirectHandler()])
#>>> br.response() is not None
#True
#>>> br.request is not None
#True
#>>> r = br.back()

XXX digest, robots


.global_form() is separate from the other forms (partly for backwards-
compatibility reasons).

>>> from mechanize._response import test_response
>>> br = TestBrowser2()
>>> html = """\
... <html><body>
... <input type="text" name="a" />
... <form><input type="text" name="b" /></form>
... </body></html>
... """
>>> response = test_response(html, headers=[("Content-type", "text/html")])
>>> br.global_form()
Traceback (most recent call last):
BrowserStateError: not viewing any document
>>> br.set_response(response)
>>> br.global_form().find_control(nr=0).name
'a'
>>> len(list(br.forms()))
1
>>> iter(br.forms()).next().find_control(nr=0).name
'b'



.select_form() works with the global form

>>> import ClientForm
>>> from mechanize._response import test_html_response
>>> br = TestBrowser2()
>>> br.visit_response(test_html_response("""\
... <html><head><title></title></head><body>
... <input type="text" name="a" value="b"></input>
... <form>
...     <input type="text" name="p" value="q"></input>
... </form>
... </body></html>"""))
>>> def has_a(form):
...     try:
...         form.find_control(name="a")
...     except ClientForm.ControlNotFoundError:
...         return False
...     else:
...         return True
>>> br.select_form(predicate=has_a)
>>> br.form.find_control(name="a").value
'b'
