#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # Copyright 2002-2005 John J. Lee # Copyright 2005 Gary Poster # Copyright 2005 Zope Corporation # Copyright 1998-2000 Gisle Aas. import unittest, string from unittest import TestCase from cStringIO import StringIO import urllib2 import ClientForm from ClientForm import ControlNotFoundError, ItemNotFoundError, \ ItemCountError, AmbiguityError, ParseError # XXX # HTMLForm.set/get_value_by_label() # Base control tests on ParseFile, so can use same tests for DOMForm and # ClientForm. That wouldn't be unit testing exactly, but saner than the # current situation with massive duplication of tests between the two # modules. # HTMLForm.enctype # XHTML try: True except NameError: True = 1 False = 0 try: bool except NameError: def bool(expr): if expr: return True else: return False try: import warnings except ImportError: warnings_imported = False def hide_deprecations(): pass def reset_deprecations(): pass def raise_deprecations(): pass else: warnings_imported = True def hide_deprecations(): warnings.filterwarnings('ignore', category=DeprecationWarning) def reset_deprecations(): warnings.filterwarnings('default', category=DeprecationWarning) #warnings.resetwarnings() # XXX probably safer def raise_deprecations(): try: registry = ClientForm.__warningregistry__ except AttributeError: pass else: registry.clear() warnings.filterwarnings('error', category=DeprecationWarning) class DummyForm: def __init__(self): self._forms = [] self._labels = [] self._id_to_labels = {} self.backwards_compat = False self.controls = [] def find_control(self, name, type): raise ClientForm.ControlNotFoundError class MonkeyPatcher: def __init__(self): self._patches = [] def monkey_patch(self, obj, name, value): orig_value = getattr(obj, name) setattr(obj, name, value) self._patches.append((obj, name, orig_value)) def reverse_patches(self): while self._patches: obj, name, orig_value = self._patches[-1] setattr(obj, name, orig_value) self._patches.pop() class MonkeyTestCase(TestCase): def setUp(self): unittest.TestCase.setUp(self) self._patcher = MonkeyPatcher() def tearDown(self): unittest.TestCase.tearDown(self) self._patcher.reverse_patches() def monkey_patch(self, obj, name, value): self._patcher.monkey_patch(obj, name, value) class UnescapeTests(TestCase): def test_unescape_charref(self): from ClientForm import unescape_charref, get_entitydefs mdash_utf8 = u"\u2014".encode("utf-8") for ref, codepoint, utf8, latin1 in [ ("38", 38, u"&".encode("utf-8"), "&"), ("x2014", 0x2014, mdash_utf8, "—"), ("8212", 8212, mdash_utf8, "—"), ]: self.assertEqual(unescape_charref(ref, None), unichr(codepoint)) self.assertEqual(unescape_charref(ref, 'latin-1'), latin1) self.assertEqual(unescape_charref(ref, 'utf-8'), utf8) def test_get_entitydefs(self): from ClientForm import get_entitydefs ed = get_entitydefs() for name, char in [ ("&", u"&"), ("<", u"<"), (">", u">"), ("—", u"\u2014"), ("♠", u"\u2660"), ]: self.assertEqual(ed[name], char) def test_unescape1(self): import htmlentitydefs from ClientForm import unescape, get_entitydefs data = "& < — — —" mdash_utf8 = u"\u2014".encode("utf-8") ue = unescape(data, get_entitydefs(), "utf-8") self.assertEqual("& < %s %s %s" % ((mdash_utf8,)*3), ue) for text, expect in [ ("&a&", "&a&"), ("a&", "a&"), ]: got = unescape(text, get_entitydefs(), "latin-1") self.assertEqual(got, expect) def test_unescape2(self): from ClientForm import unescape, get_entitydefs self.assertEqual(unescape("Donald Duck & Co", {"&": "&"}), "Donald Duck & Co") self.assertEqual( unescape("<Donald Duck & Co>", {"&": "&", "<": "<", ">": ">"}), "") self.assertEqual(unescape("Hei på deg", {"å" : "å"}), "Hei på deg") self.assertEqual( unescape("&foo;", {"&": "&", "&foo;": "splat"}), "&foo;") self.assertEqual(unescape("&", {}), "&") for encoding, expected in [ ("utf-8", u"&\u06aa\u2014\u2014".encode("utf-8")), ("latin-1", "&ڪ——")]: self.assertEqual( expected, unescape("&ڪ——", get_entitydefs(), encoding)) def test_unescape_parsing(self): file = StringIO( """
""") #" forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False, encoding="utf-8") form = forms[0] test_string = "&"+(u"\u2014".encode('utf8')*3) self.assertEqual(form.action, "http://localhost/"+test_string) control = form.find_control(type="textarea", nr=0) self.assertEqual(control.value, "val"+test_string) self.assertEqual(control.name, "name"+test_string) def test_unescape_parsing_select(self): f = StringIO("""\
""") #" forms = ClientForm.ParseFileEx( f, "http://localhost/", encoding="utf-8") form = forms[1] test_string = "&"+(u"\u2014".encode('utf8')*3) control = form.find_control(nr=0) for ii in range(len(control.items)): item = control.items[ii] self.assertEqual(item.name, str(ii+1)+test_string) # XXX label def test_unescape_parsing_data(self): file = StringIO( """\
""") #" # don't crash if we can't encode -- rather, leave entity ref intact forms = ClientForm.ParseFile( file, "http://localhost/", backwards_compat=False, encoding="latin-1") label = forms[0].find_control(nr=0).get_labels()[0] self.assertEqual(label.text, "Blah ” ” blah") class LWPFormTests(TestCase): """The original tests from libwww-perl 5.64.""" def testEmptyParse(self): forms = ClientForm.ParseFile(StringIO(""), "http://localhost", backwards_compat=False) self.assert_(len(forms) == 0) def _forms(self): file = StringIO("""
""") return ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) def testParse(self): forms = self._forms() self.assert_(len(forms) == 1) self.assert_(forms[0]["firstname"] == "Gisle") def testFillForm(self): forms = self._forms() form = forms[0] form["firstname"] = "Gisle Aas" req = form.click() def request_method(req): if req.has_data(): return "POST" else: return "GET" self.assert_(request_method(req) == "GET") self.assert_(req.get_full_url() == "http://localhost/abc?firstname=Gisle+Aas") def get_header(req, name): try: return req.get_header(name) except AttributeError: return req.headers[name] def header_items(req): try: return req.header_items() except AttributeError: return req.headers.items() class MockResponse: def __init__(self, f, url): self._file = f self._url = url def geturl(self): return self._url def __getattr__(self, name): return getattr(self._file, name) class ParseTests(TestCase): def test_failing_parse(self): # XXX couldn't provoke an error from BeautifulSoup (!), so this has not # been tested with RobustFormParser import sgmllib # Python 2.0 sgmllib raises RuntimeError rather than SGMLParseError, # but seems never to even raise that except as an assertion, from # reading the code... if hasattr(sgmllib, "SGMLParseError"): f = StringIO("") base_uri = "http://localhost/" self.assertRaises( ClientForm.ParseError, ClientForm.ParseFile, f, base_uri, backwards_compat=False, ) self.assert_(issubclass(ClientForm.ParseError, sgmllib.SGMLParseError)) def test_unknown_control(self): f = StringIO( """
""") base_uri = "http://localhost/" forms = ClientForm.ParseFile(f, base_uri, backwards_compat=False) form = forms[0] for ctl in form.controls: self.assert_(isinstance(ctl, ClientForm.TextControl)) def test_ParseFileEx(self): # empty "outer form" (where the "outer form" is the form consisting of # all controls outside of any form) f = StringIO( """
""") base_uri = "http://localhost/" forms = ClientForm.ParseFileEx(f, base_uri) outer = forms[0] self.assertEqual(len(forms), 2) self.assertEqual(outer.controls, []) self.assertEqual(outer.name, None) self.assertEqual(outer.action, base_uri) self.assertEqual(outer.method, "GET") self.assertEqual(outer.enctype, "application/x-www-form-urlencoded") self.assertEqual(outer.attrs, {}) # non-empty outer form f = StringIO( """
""") base_uri = "http://localhost/" forms = ClientForm.ParseFileEx(f, base_uri) outer = forms[0] self.assertEqual(len(forms), 3) self.assertEqual([c.name for c in outer.controls], ["a", "c", "e"]) self.assertEqual(outer.name, None) self.assertEqual(outer.action, base_uri) self.assertEqual(outer.method, "GET") self.assertEqual(outer.enctype, "application/x-www-form-urlencoded") self.assertEqual(outer.attrs, {}) def test_ParseResponse(self): url = "http://example.com/" r = MockResponse( StringIO("""\
"""), url, ) hide_deprecations() forms = ClientForm.ParseResponse(r) reset_deprecations() self.assertEqual(len(forms), 1) form = forms[0] self.assertEqual(form.action, url+"abc") self.assertEqual(form.controls[0].name, "inner") def test_ParseResponseEx(self): url = "http://example.com/" r = MockResponse( StringIO("""\
"""), url, ) forms = ClientForm.ParseResponseEx(r) self.assertEqual(len(forms), 2) outer = forms[0] inner = forms[1] self.assertEqual(inner.action, url+"abc") self.assertEqual(outer.action, url) self.assertEqual(outer.controls[0].name, "outer") self.assertEqual(inner.controls[0].name, "inner") def test_ParseString(self): class DerivedRequest(urllib2.Request): pass forms = ClientForm.ParseString('', "http://example.com/", request_class=DerivedRequest) self.assertEqual(len(forms), 1) self.assertEqual(forms[0].controls[0].name, "a") # arguments were passed through self.assertTrue(isinstance(forms[0].click(), DerivedRequest)) def test_parse_error(self): f = StringIO( """
""") base_uri = "http://localhost/" try: ClientForm.ParseFile(f, base_uri, backwards_compat=False) except ClientForm.ParseError, e: self.assert_(e.base_uri == base_uri) else: self.assert_(0) def test_base_uri(self): # BASE element takes priority over document URI file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] self.assert_(form.action == "http://example.com/abc") file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] self.assert_(form.action == "http://localhost/abc") def testTextarea(self): file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False, encoding="utf-8") self.assert_(len(forms) == 1) form = forms[0] self.assert_(form.name is None) self.assertEqual( form.action, "http://localhost/abc&"+u"\u2014".encode('utf8')+"d") control = form.find_control(type="textarea", nr=0) self.assert_(control.name is None) self.assert_(control.value == "blah, blah,\r\nRhubarb.\r\n\r\n") empty_control = form.find_control(type="textarea", nr=1) self.assert_(str(empty_control) == "=)>") self.assert_(empty_control.value == "") entity_ctl = form.find_control(type="textarea", nr=2) self.assertEqual(entity_ctl.name, '"ta"') self.assertEqual(entity_ctl.attrs["id"], "foo&bar") self.assertEqual(entity_ctl.value, "Hello testers & users!") def testSelect(self): file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) self.assert_(len(forms) == 1) form = forms[0] entity_ctl = form.find_control(type="select") self.assert_(entity_ctl.name == "foo") self.assertEqual(entity_ctl.value[0], "Hello testers & &blah; users!") hide_deprecations() opt = entity_ctl.get_item_attrs("Hello testers & &blah; users!") reset_deprecations() self.assertEqual(opt["value"], "Hello testers & &blah; users!") self.assertEqual(opt["label"], "Hello testers & &blah; users!") self.assertEqual(opt["contents"], "Hello testers & &blah; users!") def testButton(self): file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] self.assert_(form.name == "myform") control = form.find_control(name="b") self.assert_(control.type == "submitbutton") self.assert_(control.value == "") self.assert_(form.find_control("b2").type == "resetbutton") self.assert_(form.find_control("b3").type == "buttonbutton") pairs = form.click_pairs() self.assert_(pairs == [("moo", "cow"), ("b", "")]) def testIsindex(self): file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] control = form.find_control(type="isindex") self.assert_(control.type == "isindex") self.assert_(control.name is None) self.assert_(control.value == "") control.value = "some stuff" self.assert_(form.click_pairs() == []) self.assert_(form.click_request_data() == ("http://localhost/abc?some+stuff", None, [])) self.assert_(form.click().get_full_url() == "http://localhost/abc?some+stuff") def testEmptySelect(self): file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] control0 = form.find_control(type="select", nr=0) control1 = form.find_control(type="select", nr=1) self.assert_(str(control0) == "") self.assert_(str(control1) == "") form.set_value([], "foo") self.assertRaises(ItemNotFoundError, form.set_value, ["oops"], "foo") self.assert_(form.click_pairs() == []) # XXX figure out what to do in these sorts of cases ## def badSelect(self): ## # what objects should these generate, if any? ## # what should happen on submission of these? ## # what about similar checkboxes and radios? ## """
## ## ##
## """ ## """
## ##
## """ ## ## ## """ ## """
## ## ##
## """ ## def testBadCheckbox(self): ## # see comments above ## # split checkbox -- is it one control, or two? ## """ ## ## ## ## ## ## ## ## """ def testUnnamedControl(self): file = StringIO("""
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] self.assert_(form.controls[0].name is None) def testNamelessListItems(self): # XXX SELECT # these controls have no item names file = StringIO("""
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] hide_deprecations() self.assert_(form.possible_items("foo") == ["on"]) self.assert_(form.possible_items("bar") == ["on"]) reset_deprecations() #self.assert_(form.possible_items("baz") == []) self.assert_(form["foo"] == []) self.assert_(form["bar"] == []) #self.assert_(form["baz"] == []) form["foo"] = ["on"] form["bar"] = ["on"] pairs = form.click_pairs() self.assert_(pairs == [("foo", "on"), ("bar", "on"), ("submit", "")]) def testSingleSelectFixup(self): # HTML 4.01 section 17.6.1: single selection SELECT controls shouldn't # have > 1 item selected, but if they do, not more than one should end # up selected. # In fact, testing really obscure stuff here, which follows Firefox # 1.0.7 -- IE doesn't even support disabled OPTIONs. file = StringIO("""
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] # deselect all but last item if more than one were selected... spam = form.find_control("spam") self.assertEqual([ii.name for ii in spam.items if ii.selected], ["2"]) # ...even if it's disabled cow = form.find_control("cow") self.assertEqual([ii.name for ii in cow.items if ii.selected], ["2"]) # exactly one selected item is OK even if it's disabled moo = form.find_control("moo") self.assertEqual([ii.name for ii in moo.items if ii.selected], ["1"]) # if nothing was selected choose the first non-disabled item moo = form.find_control("nnn") self.assertEqual([ii.name for ii in moo.items if ii.selected], ["2"]) def testSelectDefault(self): file = StringIO( """
""") forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] control = form.find_control("a") self.assert_(control.value == []) single_control = form.find_control("b") self.assert_(single_control.value == ["1"]) file.seek(0) forms = ClientForm.ParseFile(file, "http://localhost/", select_default=1, backwards_compat=False) form = forms[0] # select_default only affects *multiple* selection select controls control = form.find_control(type="select", nr=0) self.assert_(control.value == ["1"]) single_control = form.find_control(type="select", nr=1) self.assert_(single_control.value == ["1"]) def test_close_base_tag(self): # Benji York: a single newline immediately after a start tag is # stripped by browsers, but not one immediately before an end tag. # TEXTAREA content is converted to the DOS newline convention. forms = ClientForm.ParseFile( StringIO("
"), "http://example.com/", backwards_compat=False, ) ctl = forms[0].find_control(type="textarea") self.assertEqual(ctl.value, "\r\nblah\r\n") def test_embedded_newlines(self): # newlines that happen to be at the start of strings passed to the # parser's .handle_data() method must not be trimmed unless they also # follow immediately after a start tag forms = ClientForm.ParseFile( StringIO("
"), "http://example.com/", backwards_compat=False, ) ctl = forms[0].find_control(type="textarea") self.assertEqual(ctl.value, "\r\nspam&\r\neggs\r\n") def test_double_select(self): # More than one SELECT control of the same name in a form never # represent a single control (unlike RADIO and CHECKBOX elements), so # don't merge them. forms = ClientForm.ParseFile( StringIO("""\
"""), "http://example.com/", backwards_compat=False, ) form = forms[0] self.assertEquals(len(form.controls), 2) ctl = form.find_control(name="a", nr=0) self.assertEqual([item.name for item in ctl.items], ["b", "c"]) ctl = form.find_control(name="a", nr=1) self.assertEqual([item.name for item in ctl.items], ["d", "e"]) def test_global_select(self): # regression test: closing select and textarea tags should not be # ignored, causing a ParseError due to incorrect tag nesting forms = ClientForm.ParseFileEx( StringIO("""\ """), "http://example.com/", ) forms = ClientForm.ParseFile( StringIO("""\ """), "http://example.com/", backwards_compat=False, ) def test_empty_document(self): forms = ClientForm.ParseFileEx(StringIO(""), "http://example.com/") self.assertEquals(len(forms), 1) # just the "global form" def test_missing_closing_body_tag(self): # Even if there is no closing form or body tag, the last form on the # page should be returned. forms = ClientForm.ParseFileEx( StringIO('
'), "http://example.com/", ) self.assertEquals(len(forms), 2) self.assertEquals(forms[1].name, "spam") class DisabledTests(TestCase): def testOptgroup(self): for compat in [False, True]: self._testOptgroup(compat) def _testOptgroup(self, compat): file = StringIO( """
""") def get_control(name, file=file, compat=compat): file.seek(0) forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=False) form = forms[0] form.backwards_compat = compat return form.find_control(name) # can't call item_disabled with no args control = get_control("foo") self.assertRaises(TypeError, control.get_item_disabled) hide_deprecations() control.set_item_disabled(True, "2") reset_deprecations() self.assertEqual( str(control), "") # list controls only allow assignment to .value if no attempt is # made to set any disabled item... # ...multi selection control = get_control("foo") if compat: extra = ["7"] else: extra = [] # disabled items are not part of the submitted value, so "7" not # included (they are not "successful": # http://www.w3.org/TR/REC-html40/interact/forms.html#successful-controls # ). This behavior was confirmed in Firefox 1.0.4 at least. self.assertEqual(control.value, []+extra) control.value = ["1"] self.assertEqual(control.value, ["1"]) control = get_control("foo") self.assertRaises(AttributeError, setattr, control, 'value', ['8']) self.assertEqual(control.value, []+extra) # even though 7 is set already, attempt to set it fails self.assertRaises(AttributeError, setattr, control, 'value', ['7']) control.value = ["1", "3"] self.assertEqual(control.value, ["1", "3"]) control = get_control("foo") self.assertRaises(AttributeError, setattr, control, 'value', ['1', '7']) self.assertEqual(control.value, []+extra) # enable all items control.set_all_items_disabled(False) control.value = ['1', '7'] self.assertEqual(control.value, ["1", "7"]) control = get_control("foo") hide_deprecations() for name in 7, 8, 10: self.assert_(control.get_item_disabled(str(name))) if not compat: # a disabled option is never "successful" (see above) so never # in value self.assert_(str(name) not in control.value) # a disabled option always is always upset if you try to set it self.assertRaises(AttributeError, control.set, True, str(name)) self.assert_(str(name) not in control.value) self.assertRaises(AttributeError, control.set, False, str(name)) self.assert_(str(name) not in control.value) self.assertRaises(AttributeError, control.toggle, str(name)) self.assert_(str(name) not in control.value) else: self.assertRaises(AttributeError, control.set, True, str(name)) control.set(False, str(name)) self.assert_(str(name) not in control.value) control.set(False, str(name)) self.assert_(str(name) not in control.value) self.assertRaises(AttributeError, control.toggle, str(name)) self.assert_(str(name) not in control.value) self.assertRaises(AttributeError, control.set, True, str(name)) self.assert_(str(name) not in control.value) control = get_control("foo") for name in 1, 2, 3, 4, 5, 6, 9: self.assert_(not control.get_item_disabled(str(name))) control.set(False, str(name)) self.assert_(str(name) not in control.value) control.toggle(str(name)) self.assert_(str(name) in control.value) control.set(True, str(name)) self.assert_(str(name) in control.value) control.toggle(str(name)) self.assert_(str(name) not in control.value) control = get_control("foo") self.assert_(control.get_item_disabled("7")) control.set_item_disabled(True, "7") self.assert_(control.get_item_disabled("7")) self.assertRaises(AttributeError, control.set, True, "7") control.set_item_disabled(False, "7") self.assert_(not control.get_item_disabled("7")) control.set(True, "7") control.set(False, "7") control.toggle("7") control.toggle("7") reset_deprecations() # ...single-selection control = get_control("bar") # 7 is selected but disabled if compat: value = ["7"] else: value = [] self.assertEqual(control.value, value) self.assertEqual( [ii.name for ii in control.items if ii.selected], ["7"]) control.value = ["2"] control = get_control("bar") def assign_8(control=control): control.value = ["8"] self.assertRaises(AttributeError, assign_8) self.assertEqual(control.value, value) def assign_7(control=control): control.value = ["7"] self.assertRaises(AttributeError, assign_7) # enable all items control.set_all_items_disabled(False) assign_7() self.assertEqual(control.value, ['7']) control = get_control("bar") hide_deprecations() for name in 7, 8, 10: self.assert_(control.get_item_disabled(str(name))) if not compat: # a disabled option is never "successful" (see above) so never in # value self.assert_(str(name) not in control.value) # a disabled option always is always upset if you try to set it self.assertRaises(AttributeError, control.set, True, str(name)) self.assert_(str(name) not in control.value) self.assertRaises(AttributeError, control.set, False, str(name)) self.assert_(str(name) not in control.value) self.assertRaises(AttributeError, control.toggle, str(name)) self.assert_(str(name) not in control.value) else: self.assertRaises(AttributeError, control.set, True, str(name)) control.set(False, str(name)) self.assert_(str(name) != control.value) control.set(False, str(name)) self.assert_(str(name) != control.value) self.assertRaises(AttributeError, control.toggle, str(name)) self.assert_(str(name) != control.value) self.assertRaises(AttributeError, control.set, True, str(name)) self.assert_(str(name) != control.value) control = get_control("bar") for name in 1, 2, 3, 4, 5, 6, 9: self.assert_(not control.get_item_disabled(str(name))) control.set(False, str(name)) self.assert_(str(name) not in control.value) control.toggle(str(name)) self.assert_(str(name) == control.value[0]) control.set(True, str(name)) self.assert_(str(name) == control.value[0]) control.toggle(str(name)) self.assert_(str(name) not in control.value) control = get_control("bar") self.assert_(control.get_item_disabled("7")) control.set_item_disabled(True, "7") self.assert_(control.get_item_disabled("7")) self.assertRaises(AttributeError, control.set, True, "7") self.assertEqual(control.value, value) control.set_item_disabled(False, "7") self.assertEqual(control.value, ["7"]) self.assert_(not control.get_item_disabled("7")) control.set(True, "7") control.set(False, "7") control.toggle("7") control.toggle("7") # set_all_items_disabled for name in "foo", "bar": control = get_control(name) control.set_all_items_disabled(False) control.set(True, "7") control.set(True, "1") control.set_all_items_disabled(True) self.assertRaises(AttributeError, control.set, True, "7") self.assertRaises(AttributeError, control.set, True, "1") reset_deprecations() # XXX single select def testDisabledSelect(self): for compat in [False, True]: self._testDisabledSelect(compat) def _testDisabledSelect(self, compat): file = StringIO( """
""") hide_deprecations() forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=compat) reset_deprecations() form = forms[0] for name, control_disabled, item_disabled in [ ("foo", False, False), ("bar", False, True), ("baz", True, False), ("spam", True, True)]: control = form.find_control(name) self.assertEqual(bool(control.disabled), control_disabled) hide_deprecations() item = control.get_item_attrs("2") reset_deprecations() self.assertEqual(bool(item.has_key("disabled")), item_disabled) def bad_assign(value, control=control): control.value = value hide_deprecations() if control_disabled: for name in "1", "2", "3": self.assertRaises(AttributeError, control.set, True, name) self.assertRaises(AttributeError, bad_assign, [name]) elif item_disabled: self.assertRaises(AttributeError, control.set, True, "2") self.assertRaises(AttributeError, bad_assign, ["2"]) for name in "1", "3": control.set(True, name) else: control.value = ["1", "2", "3"] reset_deprecations() control = form.find_control("foo") # missing disabled arg hide_deprecations() self.assertRaises(TypeError, control.set_item_disabled, "1") # by_label self.assert_(not control.get_item_disabled("a", by_label=True)) control.set_item_disabled(True, "a", by_label=True) self.assert_(control.get_item_disabled("a", by_label=True)) reset_deprecations() def testDisabledRadio(self): for compat in False, True: self._testDisabledRadio(compat) def _testDisabledRadio(self, compat): file = StringIO( """
""") hide_deprecations() forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=compat) form = forms[0] control = form.find_control('foo') # since all items are disabled, .fixup() should not select # anything self.assertEquals( [item.name for item in control.items if item.selected], [], ) reset_deprecations() def testDisabledCheckbox(self): for compat in False, True: self._testDisabledCheckbox(compat) def _testDisabledCheckbox(self, compat): file = StringIO( """
""") hide_deprecations() forms = ClientForm.ParseFile(file, "http://localhost/", backwards_compat=compat) reset_deprecations() form = forms[0] for name, control_disabled, item_disabled in [ ("foo", False, False), ("bar", False, True), ("baz", False, True)]: control = form.find_control(name) self.assert_(bool(control.disabled) == control_disabled) hide_deprecations() item = control.get_item_attrs("2") self.assert_(bool(item.has_key("disabled")) == item_disabled) self.assert_(control.get_item_disabled("2") == item_disabled) def bad_assign(value, control=control): control.value = value if item_disabled: self.assertRaises(AttributeError, control.set, True, "2") self.assertRaises(AttributeError, bad_assign, ["2"]) if not control.get_item_disabled("1"): control.set(True, "1") else: control.value = ["1", "2", "3"] reset_deprecations() control = form.find_control("foo") hide_deprecations() control.set_item_disabled(False, "1") # missing disabled arg self.assertRaises(TypeError, control.set_item_disabled, "1") # by_label self.failIf(control.get_item_disabled('a', by_label=True)) self.assert_(not control.get_item_disabled("1")) control.set_item_disabled(True, 'a', by_label=True) self.assert_(control.get_item_disabled("1")) reset_deprecations() class ControlTests(TestCase): def testTextControl(self): attrs = {"type": "this is ignored", "name": "ath_Uname", "value": "", "maxlength": "20", "id": "foo"} c = ClientForm.TextControl("texT", "ath_Uname", attrs) c.fixup() self.assert_(c.type == "text") self.assert_(c.name == "ath_Uname") self.assert_(c.id == "foo") self.assert_(c.value == "") self.assert_(str(c) == "") self.assert_(c.pairs() == [("ath_Uname", "")]) def bad_assign(c=c): c.type = "sometype" self.assertRaises(AttributeError, bad_assign) self.assert_(c.type == "text") def bad_assign(c=c): c.name = "somename" self.assertRaises(AttributeError, bad_assign) self.assert_(c.name == "ath_Uname") c.value = "2" self.assert_(c.value == "2") c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value is None) self.assert_(c.pairs() == []) c.value = "2" # reset value... self.assert_(str(c) == "") def bad_assign(c=c): c.value = ["foo"] self.assertRaises(TypeError, bad_assign) self.assert_(c.value == "2") self.assert_(not c.readonly) c.readonly = True def bad_assign(c=c): c.value = "foo" self.assertRaises(AttributeError, bad_assign) self.assert_(c.value == "2") c.disabled = True self.assert_(str(c) == "") c.readonly = False self.assert_(str(c) == "") self.assertRaises(AttributeError, bad_assign) self.assert_(c.value == "2") self.assert_(c.pairs() == []) c.disabled = False self.assert_(str(c) == "") self.assert_(c.attrs.has_key("maxlength")) for key in "name", "type", "value": self.assert_(c.attrs.has_key(key)) # initialisation of readonly and disabled attributes attrs["readonly"] = True c = ClientForm.TextControl("text", "ath_Uname", attrs) def bad_assign(c=c): c.value = "foo" self.assertRaises(AttributeError, bad_assign) del attrs["readonly"] attrs["disabled"] = True c = ClientForm.TextControl("text", "ath_Uname", attrs) def bad_assign(c=c): c.value = "foo" self.assertRaises(AttributeError, bad_assign) del attrs["disabled"] c = ClientForm.TextControl("hidden", "ath_Uname", attrs) self.assert_(c.readonly) def bad_assign(c=c): c.value = "foo" self.assertRaises(AttributeError, bad_assign) def testFileControl(self): c = ClientForm.FileControl("file", "test_file", {}) fp = StringIO() c.add_file(fp) fp2 = StringIO() c.add_file(fp2, None, "fp2 file test") self.assert_(str(c) == ', fp2 file test)>') c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(str(c) == ')>') def testIsindexControl(self): attrs = {"type": "this is ignored", "prompt": ">>>"} c = ClientForm.IsindexControl("isIndex", None, attrs) c.fixup() self.assert_(c.type == "isindex") self.assert_(c.name is None) self.assert_(c.value == "") self.assert_(str(c) == "") self.assert_(c.pairs() == []) def set_type(c=c): c.type = "sometype" self.assertRaises(AttributeError, set_type) self.assert_(c.type == "isindex") def set_name(c=c): c.name = "somename" self.assertRaises(AttributeError, set_name) def set_value(value, c=c): c.value = value self.assertRaises(TypeError, set_value, [None]) self.assert_(c.name is None) c.value = "2" self.assert_(c.value == "2") self.assert_(str(c) == "") c.disabled = True self.assert_(str(c) == "") self.assertRaises(AttributeError, set_value, "foo") self.assert_(c.value == "2") self.assert_(c.pairs() == []) c.readonly = True self.assert_(str(c) == "") self.assertRaises(AttributeError, set_value, "foo") c.disabled = False self.assert_(str(c) == "") self.assertRaises(AttributeError, set_value, "foo") c.readonly = False self.assert_(str(c) == "") self.assert_(c.attrs.has_key("type")) self.assert_(c.attrs.has_key("prompt")) self.assert_(c.attrs["prompt"] == ">>>") for key in "name", "value": self.assert_(not c.attrs.has_key(key)) c.value = "foo 1 bar 2" class FakeForm: action = "http://localhost/" form = FakeForm() self.assert_(c._click(form, (1,1), "request_data") == ("http://localhost/?foo+1+bar+2", None, [])) c.value = "foo 1 bar 2" c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value is None) def testIgnoreControl(self): attrs = {"type": "this is ignored"} c = ClientForm.IgnoreControl("reset", None, attrs) self.assert_(c.type == "reset") self.assert_(c.value is None) self.assert_(str(c) == "=)>") def set_value(value, c=c): c.value = value self.assertRaises(AttributeError, set_value, "foo") self.assert_(c.value is None) # this is correct, but silly; basically nothing should happen c.clear() self.assert_(c.value is None) def testSubmitControl(self): attrs = {"type": "this is ignored", "name": "name_value", "value": "value_value", "img": "foo.gif"} c = ClientForm.SubmitControl("submit", "name_value", attrs) self.assert_(c.type == "submit") self.assert_(c.name == "name_value") self.assert_(c.value == "value_value") self.assert_(str(c) == "") c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value is None) c.value = "value_value" c.readonly = True def set_value(value, c=c): c.value = value self.assertRaises(TypeError, set_value, ["foo"]) c.disabled = True self.assertRaises(AttributeError, set_value, "value_value") self.assert_(str(c) == "") c.disabled = False c.readonly = False set_value("value_value") self.assert_(str(c) == "") c.readonly = True # click on button form = ClientForm.HTMLForm("http://foo.bar.com/") c.add_to_form(form) self.assert_(c.pairs() == []) pairs = c._click(form, (1,1), "pairs") request = c._click(form, (1,1), "request") data = c._click(form, (1,1), "request_data") self.assert_(c.pairs() == []) self.assert_(pairs == [("name_value", "value_value")]) self.assert_(request.get_full_url() == "http://foo.bar.com/?name_value=value_value") self.assert_(data == ("http://foo.bar.com/?name_value=value_value", None, [])) c.disabled = True pairs = c._click(form, (1,1), "pairs") request = c._click(form, (1,1), "request") data = c._click(form, (1,1), "request_data") self.assert_(pairs == []) # XXX not sure if should have '?' on end of this URL, or if it really matters... self.assert_(request.get_full_url() == "http://foo.bar.com/") self.assert_(data == ("http://foo.bar.com/", None, [])) def testImageControl(self): attrs = {"type": "this is ignored", "name": "name_value", "img": "foo.gif"} c = ClientForm.ImageControl("image", "name_value", attrs, index=0) self.assert_(c.type == "image") self.assert_(c.name == "name_value") self.assert_(c.value == "") self.assert_(str(c) == "") c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value is None) c.value = "" # click, at coordinate (0, 55), on image form = ClientForm.HTMLForm("http://foo.bar.com/") c.add_to_form(form) self.assert_(c.pairs() == []) request = c._click(form, (0, 55), "request") self.assert_(c.pairs() == []) self.assert_(request.get_full_url() == "http://foo.bar.com/?name_value.x=0&name_value.y=55") self.assert_(c._click(form, (0,55), return_type="request_data") == ("http://foo.bar.com/?name_value.x=0&name_value.y=55", None, [])) c.value = "blah" request = c._click(form, (0, 55), "request") self.assertEqual(request.get_full_url(), "http://foo.bar.com/?" "name_value.x=0&name_value.y=55&name_value=blah") c.disabled = True self.assertEqual(c.value, "blah") self.assert_(str(c) == "") def set_value(value, c=c): c.value = value self.assertRaises(AttributeError, set_value, "blah") self.assert_(c._click(form, (1,1), return_type="pairs") == []) c.readonly = True self.assert_(str(c) == "") self.assertRaises(AttributeError, set_value, "blah") self.assert_(c._click(form, (1,1), return_type="pairs") == []) c.disabled = c.readonly = False self.assert_(c._click(form, (1,1), return_type="pairs") == [("name_value.x", "1"), ("name_value.y", "1"), ('name_value', 'blah')]) def testCheckboxControl(self): attrs = {"type": "this is ignored", "name": "name_value", "value": "value_value", "alt": "some string"} form = DummyForm() c = ClientForm.CheckboxControl("checkbox", "name_value", attrs) c.add_to_form(form) c.fixup() self.assert_(c.type == "checkbox") self.assert_(c.name == "name_value") self.assert_(c.value == []) hide_deprecations() self.assert_(c.possible_items() == ["value_value"]) reset_deprecations() def set_type(c=c): c.type = "sometype" self.assertRaises(AttributeError, set_type) self.assert_(c.type == "checkbox") def set_name(c=c): c.name = "somename" self.assertRaises(AttributeError, set_name) self.assert_(c.name == "name_value") # construct larger list from length-1 lists c = ClientForm.CheckboxControl("checkbox", "name_value", attrs) attrs2 = attrs.copy() attrs2["value"] = "value_value2" c2 = ClientForm.CheckboxControl("checkbox", "name_value", attrs2) c2.add_to_form(form) c.merge_control(c2) c.add_to_form(form) c.fixup() self.assert_(str(c) == "") hide_deprecations() self.assert_(c.possible_items() == ["value_value", "value_value2"]) attrs = c.get_item_attrs("value_value") for key in "alt", "name", "value", "type": self.assert_(attrs.has_key(key)) self.assertRaises(ItemNotFoundError, c.get_item_attrs, "oops") reset_deprecations() def set_value(value, c=c): c.value = value c.value = ["value_value", "value_value2"] self.assert_(c.value == ["value_value", "value_value2"]) c.value = ["value_value"] self.assertEqual(c.value, ["value_value"]) self.assertRaises(ItemNotFoundError, set_value, ["oops"]) self.assertRaises(TypeError, set_value, "value_value") c.value = ["value_value2"] self.assert_(c.value == ["value_value2"]) hide_deprecations() c.toggle("value_value") self.assert_(c.value == ["value_value", "value_value2"]) c.toggle("value_value2") reset_deprecations() self.assert_(c.value == ["value_value"]) hide_deprecations() self.assertRaises(ItemNotFoundError, c.toggle, "oops") reset_deprecations() self.assert_(c.value == ["value_value"]) c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value == []) # set hide_deprecations() c.set(True, "value_value") self.assert_(c.value == ["value_value"]) c.set(True, "value_value2") self.assert_(c.value == ["value_value", "value_value2"]) c.set(True, "value_value2") self.assert_(c.value == ["value_value", "value_value2"]) c.set(False, "value_value2") self.assert_(c.value == ["value_value"]) c.set(False, "value_value2") self.assert_(c.value == ["value_value"]) self.assertRaises(ItemNotFoundError, c.set, True, "oops") self.assertRaises(TypeError, c.set, True, ["value_value"]) self.assertRaises(ItemNotFoundError, c.set, False, "oops") self.assertRaises(TypeError, c.set, False, ["value_value"]) reset_deprecations() self.assert_(str(c) == "") c.disabled = True self.assertRaises(AttributeError, set_value, ["value_value"]) self.assert_(str(c) == "") self.assert_(c.value == ["value_value"]) self.assert_(c.pairs() == []) c.readonly = True self.assertRaises(AttributeError, set_value, ["value_value"]) self.assert_(str(c) == "") self.assert_(c.value == ["value_value"]) self.assert_(c.pairs() == []) c.disabled = False self.assert_(str(c) == "") self.assertRaises(AttributeError, set_value, ["value_value"]) self.assert_(c.value == ["value_value"]) self.assert_(c.pairs() == [("name_value", "value_value")]) c.readonly = False c.value = [] self.assert_(c.value == []) def testSelectControlMultiple(self): import copy attrs = {"type": "this is ignored", "name": "name_value", "value": "value_value", "alt": "some string", "label": "contents_value", "contents": "contents_value", "__select": {"type": "this is ignored", "name": "select_name", "multiple": "", "alt": "alt_text"}} form = DummyForm() # with Netscape / IE default selection... c = ClientForm.SelectControl("select", "select_name", attrs) c.add_to_form(form) c.fixup() self.assert_(c.type == "select") self.assert_(c.name == "select_name") self.assert_(c.value == []) hide_deprecations() self.assert_(c.possible_items() == ["value_value"]) reset_deprecations() self.assert_(c.attrs.has_key("name")) self.assert_(c.attrs.has_key("type")) self.assert_(c.attrs["alt"] == "alt_text") # ... and with RFC 1866 default selection c = ClientForm.SelectControl("select", "select_name", attrs, select_default=True) c.add_to_form(form) c.fixup() self.assert_(c.value == ["value_value"]) # construct larger list from length-1 lists c = ClientForm.SelectControl("select", "select_name", attrs) attrs2 = attrs.copy() attrs2["value"] = "value_value2" c2 = ClientForm.SelectControl("select", "select_name", attrs2) c2.add_to_form(form) c.merge_control(c2) c.add_to_form(form) c.fixup() self.assert_(str(c) == "") hide_deprecations() self.assert_(c.possible_items() == ["value_value", "value_value2"]) # get_item_attrs attrs3 = c.get_item_attrs("value_value") reset_deprecations() self.assert_(attrs3.has_key("alt")) self.assert_(not attrs3.has_key("multiple")) # HTML attributes dictionary should have been copied by ListControl # constructor. attrs["new_attr"] = "new" attrs2["new_attr2"] = "new2" for key in ("new_attr", "new_attr2"): self.assert_(not attrs3.has_key(key)) hide_deprecations() self.assertRaises(ItemNotFoundError, c.get_item_attrs, "oops") reset_deprecations() c.value = ["value_value", "value_value2"] self.assert_(c.value == ["value_value", "value_value2"]) c.value = ["value_value"] self.assertEqual(c.value, ["value_value"]) def set_value(value, c=c): c.value = value self.assertRaises(ItemNotFoundError, set_value, ["oops"]) self.assertRaises(TypeError, set_value, "value_value") self.assertRaises(TypeError, set_value, None) c.value = ["value_value2"] self.assert_(c.value == ["value_value2"]) hide_deprecations() c.toggle("value_value") self.assert_(c.value == ["value_value", "value_value2"]) c.toggle("value_value2") self.assert_(c.value == ["value_value"]) self.assertRaises(ItemNotFoundError, c.toggle, "oops") self.assert_(c.value == ["value_value"]) reset_deprecations() c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value == []) # test ordering of items c.value = ["value_value2", "value_value"] self.assert_(c.value == ["value_value", "value_value2"]) # set hide_deprecations() c.set(True, "value_value") self.assert_(c.value == ["value_value", "value_value2"]) c.set(True, "value_value2") self.assert_(c.value == ["value_value", "value_value2"]) c.set(False, "value_value") self.assert_(c.value == ["value_value2"]) c.set(False, "value_value") self.assert_(c.value == ["value_value2"]) self.assertRaises(ItemNotFoundError, c.set, True, "oops") self.assertRaises(TypeError, c.set, True, ["value_value"]) self.assertRaises(ItemNotFoundError, c.set, False, "oops") self.assertRaises(TypeError, c.set, False, ["value_value"]) reset_deprecations() c.value = [] self.assert_(c.value == []) def testSelectControlMultiple_label(self): import ClientForm ## attrs = {"type": "ignored", "name": "year", "value": "0", "label": "2002", "contents": "current year", "__select": {"type": "this is ignored", "name": "select_name", "multiple": ""}} attrs2 = {"type": "ignored", "name": "year", "value": "1", "label": "2001", # label defaults to contents "contents": "2001", "__select": {"type": "this is ignored", "name": "select_name", "multiple": ""}} attrs3 = {"type": "ignored", "name": "year", "value": "2000", # value defaults to contents "label": "2000", # label defaults to contents "contents": "2000", "__select": {"type": "this is ignored", "name": "select_name", "multiple": ""}} c = ClientForm.SelectControl("select", "select_name", attrs) c2 = ClientForm.SelectControl("select", "select_name", attrs2) c3 = ClientForm.SelectControl("select", "select_name", attrs3) form = DummyForm() c.merge_control(c2) c.merge_control(c3) c.add_to_form(form) c.fixup() hide_deprecations() self.assert_(c.possible_items() == ["0", "1", "2000"]) self.assert_(c.possible_items(by_label=True) == ["2002", "2001", "2000"]) self.assert_(c.value == []) c.toggle("2002", by_label=True) self.assert_(c.value == ["0"]) c.toggle("0") self.assert_(c.value == []) c.toggle("0") self.assert_(c.value == ["0"]) self.assert_(c.get_value_by_label() == ["2002"]) c.toggle("2002", by_label=True) self.assertRaises(ItemNotFoundError, c.toggle, "blah", by_label=True) self.assert_(c.value == []) c.toggle("2000") reset_deprecations() self.assert_(c.value == ["2000"]) self.assert_(c.get_value_by_label() == ["2000"]) def set_value(value, c=c): c.value = value self.assertRaises(ItemNotFoundError, set_value, ["2002"]) self.assertRaises(TypeError, set_value, "1") self.assertRaises(TypeError, set_value, None) self.assert_(c.value == ["2000"]) c.value = ["0"] self.assertEqual(c.value, ["0"]) c.value = [] self.assertRaises(TypeError, c.set_value_by_label, "2002") c.set_value_by_label(["2002"]) self.assert_(c.value == ["0"]) self.assert_(c.get_value_by_label() == ["2002"]) c.set_value_by_label(["2000"]) self.assert_(c.value == ["2000"]) self.assert_(c.get_value_by_label() == ["2000"]) c.set_value_by_label(["2000", "2002"]) self.assert_(c.value == ["0", "2000"]) self.assert_(c.get_value_by_label() == ["2002", "2000"]) c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value == []) c.set_value_by_label(["2000", "2002"]) hide_deprecations() c.set(False, "2002", by_label=True) self.assert_(c.get_value_by_label() == c.value == ["2000"]) c.set(False, "2002", by_label=True) self.assert_(c.get_value_by_label() == c.value == ["2000"]) c.set(True, "2002", by_label=True) self.assert_(c.get_value_by_label() == ["2002", "2000"]) self.assert_(c.value == ["0", "2000"]) c.set(False, "2000", by_label=True) self.assert_(c.get_value_by_label() == ["2002"]) self.assert_(c.value == ["0"]) c.set(True, "2001", by_label=True) self.assert_(c.get_value_by_label() == ["2002", "2001"]) self.assert_(c.value == ["0", "1"]) self.assertRaises(ItemNotFoundError, c.set, True, "blah", by_label=True) self.assertRaises(ItemNotFoundError, c.set, False, "blah", by_label=True) reset_deprecations() def testSelectControlSingle_label(self): import ClientForm ## attrs = {"type": "ignored", "name": "year", "value": "0", "label": "2002", "contents": "current year", "__select": {"type": "this is ignored", "name": "select_name"}} attrs2 = {"type": "ignored", "name": "year", "value": "1", "label": "2001", # label defaults to contents "contents": "2001", "__select": {"type": "this is ignored", "name": "select_name"}} attrs3 = {"type": "ignored", "name": "year", "value": "2000", # value defaults to contents "label": "2000", # label defaults to contents "contents": "2000", "__select": {"type": "this is ignored", "name": "select_name"}} c = ClientForm.SelectControl("select", "select_name", attrs) c2 = ClientForm.SelectControl("select", "select_name", attrs2) c3 = ClientForm.SelectControl("select", "select_name", attrs3) form = DummyForm() c.merge_control(c2) c.merge_control(c3) c.add_to_form(form) c.fixup() hide_deprecations() self.assert_(c.possible_items() == ["0", "1", "2000"]) self.assert_(c.possible_items(by_label=True) == ["2002", "2001", "2000"]) reset_deprecations() def set_value(value, c=c): c.value = value self.assertRaises(ItemNotFoundError, set_value, ["2002"]) self.assertRaises(TypeError, set_value, "1") self.assertRaises(TypeError, set_value, None) self.assert_(c.value == ["0"]) c.value = [] self.assert_(c.value == []) c.value = ["0"] self.assert_(c.value == ["0"]) c.value = [] self.assertRaises(TypeError, c.set_value_by_label, "2002") self.assertRaises(ItemCountError, c.set_value_by_label, ["2000", "2001"]) self.assertRaises(ItemNotFoundError, c.set_value_by_label, ["foo"]) c.set_value_by_label(["2002"]) self.assert_(c.value == ["0"]) self.assert_(c.get_value_by_label() == ["2002"]) c.set_value_by_label(["2000"]) self.assert_(c.value == ["2000"]) self.assert_(c.get_value_by_label() == ["2000"]) c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value == []) def testSelectControlSingle(self): attrs = {"type": "this is ignored", "name": "name_value", "value": "value_value", "label": "contents_value", "contents": "contents_value", "__select": {"type": "this is ignored", "name": "select_name", "alt": "alt_text"}} # Netscape and IE behaviour... c = ClientForm.SelectControl("select", "select_name", attrs) form = DummyForm() c.add_to_form(form) c.fixup() self.assert_(c.type == "select") self.assert_(c.name == "select_name") self.assert_(c.value == ["value_value"]) hide_deprecations() self.assert_(c.possible_items() == ["value_value"]) reset_deprecations() self.assert_(c.attrs.has_key("name")) self.assert_(c.attrs.has_key("type")) self.assert_(c.attrs["alt"] == "alt_text") # ...and RFC 1866 behaviour are identical (unlike multiple SELECT). c = ClientForm.SelectControl("select", "select_name", attrs, select_default=1) c.add_to_form(form) c.fixup() self.assert_(c.value == ["value_value"]) # construct larger list from length-1 lists c = ClientForm.SelectControl("select", "select_name", attrs) attrs2 = attrs.copy() attrs2["value"] = "value_value2" c2 = ClientForm.SelectControl("select", "select_name", attrs2) c.merge_control(c2) c.add_to_form(form) c.fixup() self.assert_(str(c) == "") c.value = [] self.assert_(c.value == []) self.assert_(str(c) == "") c.value = ["value_value"] self.assert_(c.value == ["value_value"]) self.assert_(str(c) == "") hide_deprecations() self.assert_(c.possible_items() == ["value_value", "value_value2"]) reset_deprecations() def set_value(value, c=c): c.value = value self.assertRaises(ItemCountError, set_value, ["value_value", "value_value2"]) self.assertRaises(TypeError, set_value, "value_value") self.assertRaises(TypeError, set_value, None) c.value = ["value_value2"] self.assert_(c.value == ["value_value2"]) c.value = ["value_value"] self.assert_(c.value == ["value_value"]) self.assertRaises(ItemNotFoundError, set_value, ["oops"]) self.assert_(c.value == ["value_value"]) hide_deprecations() c.toggle("value_value") self.assertRaises(ItemNotFoundError, c.toggle, "oops") self.assertRaises(TypeError, c.toggle, ["oops"]) reset_deprecations() self.assert_(c.value == []) c.value = ["value_value"] self.assert_(c.value == ["value_value"]) # nothing selected is allowed c.value = [] self.assert_(c.value == []) hide_deprecations() c.set(True, "value_value") self.assert_(c.value == ["value_value"]) c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assert_(c.value == []) # set c.set(True, "value_value") self.assert_(c.value == ["value_value"]) c.set(True, "value_value") self.assert_(c.value == ["value_value"]) c.set(True, "value_value2") self.assert_(c.value == ["value_value2"]) c.set(False, "value_value") self.assert_("value_value2") c.set(False, "value_value2") self.assert_(c.value == []) c.set(False, "value_value2") self.assert_(c.value == []) self.assertRaises(ItemNotFoundError, c.set, True, "oops") self.assertRaises(TypeError, c.set, True, ["value_value"]) self.assertRaises(ItemNotFoundError, c.set, False, "oops") self.assertRaises(TypeError, c.set, False, ["value_value"]) reset_deprecations() def testRadioControl(self): attrs = {"type": "this is ignored", "name": "name_value", "value": "value_value", "id": "blah"} # Netscape and IE behaviour... c = ClientForm.RadioControl("radio", "name_value", attrs) form = DummyForm() c.add_to_form(form) c.fixup() self.assert_(c.type == "radio") self.assert_(c.name == "name_value") self.assert_(c.id == "blah") self.assert_(c.value == []) hide_deprecations() self.assert_(c.possible_items() == ["value_value"]) reset_deprecations() # ...and RFC 1866 behaviour c = ClientForm.RadioControl("radio", "name_value", attrs, select_default=True) c.add_to_form(form) c.fixup() self.assert_(c.value == ["value_value"]) # construct larger list from length-1 lists c = ClientForm.RadioControl("radio", "name_value", attrs, select_default=True) attrs2 = attrs.copy() attrs2["value"] = "value_value2" c2 = ClientForm.RadioControl("radio", "name_value", attrs2, select_default=True) c.merge_control(c2) c.add_to_form(form) c.fixup() self.assert_(str(c) == "") hide_deprecations() self.assert_(c.possible_items() == ["value_value", "value_value2"]) reset_deprecations() def set_value(value, c=c): c.value = value self.assertRaises(ItemCountError, set_value, ["value_value", "value_value2"]) self.assertRaises(TypeError, set_value, "value_value") self.assertEqual(c.value, ["value_value"]) c.value = ["value_value2"] self.assertEqual(c.value, ["value_value2"]) c.value = ["value_value"] self.assertEqual(c.value, ["value_value"]) self.assertRaises(ItemNotFoundError, set_value, ["oops"]) self.assertEqual(c.value, ["value_value"]) hide_deprecations() c.toggle("value_value") self.assertEqual(c.value, []) c.toggle("value_value") self.assertEqual(c.value, ["value_value"]) self.assertRaises(TypeError, c.toggle, ["value_value"]) self.assertEqual(c.value, ["value_value"]) # nothing selected is allowed c.value = [] self.assertEqual(c.value, []) c.set(True, "value_value") reset_deprecations() self.assertEqual(c.value, ["value_value"]) c.readonly = True self.assertRaises(AttributeError, c.clear) c.readonly = False c.clear() self.assertEqual(c.value, []) # set hide_deprecations() c.set(True, "value_value") self.assertEqual(c.value, ["value_value"]) c.set(True, "value_value") self.assertEqual(c.value, ["value_value"]) c.set(True, "value_value2") self.assertEqual(c.value, ["value_value2"]) c.set(False, "value_value") self.assert_("value_value2") c.set(False, "value_value2") self.assertEqual(c.value, []) c.set(False, "value_value2") self.assertEqual(c.value, []) self.assertRaises(ItemNotFoundError, c.set, True, "oops") self.assertRaises(TypeError, c.set, True, ["value_value"]) self.assertRaises(ItemNotFoundError, c.set, False, "oops") self.assertRaises(TypeError, c.set, False, ["value_value"]) reset_deprecations() # tests for multiple identical values attrs = {"type": "this is ignored", "name": "name_value", "value": "value_value", "id": "name_value_1"} c1 = ClientForm.RadioControl("radio", "name_value", attrs) attrs = {"type": "this is ignored", "name": "name_value", "value": "value_value", "id": "name_value_2", "checked": "checked"} c2 = ClientForm.RadioControl("radio", "name_value", attrs) attrs = {"type": "this is ignored", "name": "name_value", "value": "another_value", "id": "name_value_3", "__label": {"__text": "Third Option"}} c3 = ClientForm.RadioControl("radio", "name_value", attrs) form = DummyForm() c1.merge_control(c2) c1.merge_control(c3) c1.add_to_form(form) c1.fixup() self.assertEqual(c1.value, ['value_value']) hide_deprecations() self.assertEqual( c1.possible_items(), ['value_value', 'value_value', 'another_value']) reset_deprecations() self.assertEqual(c1.value, ['value_value']) self.failIf(c1.items[0].selected) self.failUnless(c1.items[1].selected) self.failIf(c1.items[2].selected) c1.value = ['value_value'] # should be no change self.failUnless(c1.items[1].selected) self.assertEqual(c1.value, ['value_value']) c1.value = ['another_value'] self.failUnless(c1.items[2].selected) self.assertEqual(c1.value, ['another_value']) c1.value = ['value_value'] self.failUnless(c1.items[0].selected) self.assertEqual(c1.value, ['value_value']) # id labels form._id_to_labels['name_value_1'] = [ ClientForm.Label({'for': 'name_value_1', '__text':'First Option'})] form._id_to_labels['name_value_2'] = [ ClientForm.Label({'for': 'name_value_2', '__text':'Second Option'})] form._id_to_labels['name_value_3'] = [ ClientForm.Label({'for': 'name_value_3', '__text':'Last Option'})] # notice __label above self.assertEqual([l.text for l in c1.items[0].get_labels()], ['First Option']) self.assertEqual([l.text for l in c1.items[1].get_labels()], ['Second Option']) self.assertEqual([l.text for l in c1.items[2].get_labels()], ['Third Option', 'Last Option']) self.assertEqual(c1.get_value_by_label(), ['First Option']) c1.set_value_by_label(['Second Option']) self.assertEqual(c1.get_value_by_label(), ['Second Option']) self.assertEqual(c1.value, ['value_value']) c1.set_value_by_label(['Third Option']) self.assertEqual(c1.get_value_by_label(), ['Third Option']) self.assertEqual(c1.value, ['another_value']) c1.items[1].selected = True self.assertEqual(c1.get_value_by_label(), ['Second Option']) self.assertEqual(c1.value, ['value_value']) c1.set_value_by_label(['Last Option']) # by second label self.assertEqual(c1.get_value_by_label(), ['Third Option']) self.assertEqual(c1.value, ['another_value']) c1.set_value_by_label(['irst']) # by substring self.assertEqual(c1.get_value_by_label(), ['First Option']) class FormTests(TestCase): base_uri = "http://auth.athensams.net/" def test_find_control(self): f = StringIO("""\
""") form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=False)[0] for compat in True, False: form.backwards_compat = compat fc = form.find_control self.assertEqual(fc("form.title").id, "form.title") self.assertEqual(fc("form.title", nr=0).id, "form.title") if compat: self.assertEqual(fc("password").id, "pswd1") else: self.assertRaises(AmbiguityError, fc, "password") self.assertEqual(fc("password", id="pswd2").id, "pswd2") self.assertEqual(fc("password", nr=0).id, "pswd1") self.assertRaises(ControlNotFoundError, fc, "form.title", nr=1) self.assertRaises(ControlNotFoundError, fc, nr=50) self.assertRaises(ValueError, fc, nr=-1) self.assertRaises(ControlNotFoundError, fc, label="Bananas") # label self.assertEqual(fc(label="Title").id, "form.title") self.assertEqual(fc(label="Book Title").id, "form.title") self.assertRaises(ControlNotFoundError, fc, label=" Book Title ") self.assertRaises(ControlNotFoundError, fc, label="Bananas") self.assertRaises(ControlNotFoundError, fc, label="title") self.assertEqual(fc(label="Book", nr=0).id, "form.title") self.assertEqual(fc(label="Book", nr=1).id, "form.quality") if compat: self.assertEqual(fc(label="Book").id, "form.title") else: self.assertRaises(AmbiguityError, fc, label="Book") def test_find_nameless_control(self): data = """\
""" f = StringIO(data) form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=False)[0] self.assertRaises( AmbiguityError, form.find_control, type="checkbox", name=ClientForm.Missing) ctl = form.find_control(type="checkbox", name=ClientForm.Missing, nr=1) self.assertEqual(ctl.id, "a") def test_deselect_disabled(self): def get_new_form(f, compat): f.seek(0) form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=False)[0] form.backwards_compat = compat return form f = StringIO("""\
""") for compat in [False]:#True, False: def new_form(compat=compat, f=f, get_new_form=get_new_form): form = get_new_form(f, compat) ctl = form.find_control("p") a = ctl.get("a") return ctl, a ctl, a = new_form() ctl.value = ["b"] # :-(( if compat: # rationale: allowed to deselect, but not select, disabled # items ctl, a = new_form() self.assertRaises(AttributeError, setattr, a, "selected", True) self.assertRaises(AttributeError, setattr, ctl, "value", ["a"]) a.selected = False ctl, a = new_form() ctl.value = ["b"] self.assertEqual(a.selected, False) self.assertEqual(ctl.value, ["b"]) ctl, a = new_form() self.assertRaises(AttributeError, setattr, ctl, "value", ["a", "b"]) else: # rationale: Setting an individual item's selected state to its # present value is a no-op, as is setting the whole control # value where an item name doesn't appear in the new value, but # that item is disabled anyway (but an item name that does # appear in the new value is treated an explicit request that # that item name get sent to the server). However, if the # item's state does change, both selecting and deselecting are # disallowed for disabled items. ctl, a = new_form() self.assertRaises(AttributeError, setattr, a, "selected", True) ctl, a = new_form() self.assertRaises(AttributeError, setattr, ctl, "value", ["a"]) ctl, a = new_form() self.assertRaises(AttributeError, setattr, a, "selected", False) ctl.value = ["b"] self.assertEqual(a.selected, True) self.assertEqual(ctl.value, ["b"]) ctl, a = new_form() self.assertRaises(AttributeError, setattr, ctl, "value", ["a", "b"]) f = StringIO("""\
""") for compat in [False]:#True, False: def new_form(compat=compat, f=f, get_new_form=get_new_form): form = get_new_form(f, compat) ctl = form.find_control("p") a = ctl.get("a") return ctl, a ctl, a = new_form() ctl.value = ["b"] if compat: ctl, a = new_form() self.assertRaises(AttributeError, setattr, a, "selected", True) self.assertRaises(AttributeError, setattr, ctl, "value", ["a"]) a.selected = False ctl, a = new_form() ctl.value = ["b"] self.assertEqual(a.selected, False) self.assertEqual(ctl.value, ["b"]) ctl, a = new_form() self.assertRaises(ItemCountError, setattr, ctl, "value", ["a", "b"]) else: ctl, a = new_form() self.assertRaises(AttributeError, setattr, a, "selected", True) ctl, a = new_form() self.assertRaises(AttributeError, setattr, ctl, "value", ["a"]) ctl, a = new_form() self.assertRaises(AttributeError, setattr, a, "selected", False) ctl.value = ["b"] self.assertEqual(a.selected, False) self.assertEqual(ctl.value, ["b"]) ctl, a = new_form() self.assertRaises(ItemCountError, setattr, ctl, "value", ["a", "b"]) def test_click(self): file = StringIO( """
""") form = ClientForm.ParseFile(file, "http://blah/", backwards_compat=False)[0] self.assertRaises(ControlNotFoundError, form.click, nr=2) self.assert_(form.click().get_full_url() == "http://blah/abc?foo=") self.assert_(form.click(name="bar").get_full_url() == "http://blah/abc?bar=") for method in ["GET", "POST"]: file = StringIO( """
""" % method) # " (this line is here for emacs) form = ClientForm.ParseFile(file, "http://blah/", backwards_compat=False)[0] if method == "GET": url = "http://blah/abc?foo=" else: url = "http://blah/abc?bang=whizz" self.assert_(form.click().get_full_url() == url) def testAuth(self): file = open("./testdata/Auth.html", "r") forms = ClientForm.ParseFile(file, self.base_uri, backwards_compat=False) self.assert_(len(forms) == 1) form = forms[0] self.assert_(form.action == "http://auth.athensams.net/" "?ath_returl=%22http%3A%2F%2Ftame.mimas.ac.uk%2Fisicgi" "%2FWOS-login.cgi%22&ath_dspid=MIMAS.WOS") self.assertRaises(ControlNotFoundError, lambda form=form: form.toggle("d'oh", "oops")) self.assertRaises(ControlNotFoundError, lambda form=form: form["oops"]) def bad_assign(form=form): form["oops"] = ["d'oh"] self.assertRaises(ControlNotFoundError, bad_assign) self.assertRaises(ValueError, form.find_control) keys = ["ath_uname", "ath_passwd"] values = ["", ""] types = ["text", "password"] for i in range(len(keys)): key = keys[i] c = form.find_control(key) self.assert_(c.value == values[i]) self.assert_(c.type == types[i]) c = form.find_control(type="image") self.assert_(c.name is None) self.assert_(c.value == "") self.assert_(c.type == "image") form["ath_uname"] = "jbloggs" form["ath_passwd"] = "foobar" self.assert_(form.click_pairs() == [("ath_uname", "jbloggs"), ("ath_passwd", "foobar")]) def testSearchType(self): file = open("./testdata/SearchType.html", "r") forms = ClientForm.ParseFile(file, self.base_uri, backwards_compat=False) self.assert_(len(forms) == 1) form = forms[0] keys = ["SID", "SESSION_DIR", "Full Search", "Easy Search", "New Session", "Log off", "Form", "JavaScript"] values = ["PMrU0IJYy4MAAELSXic_E2011300_PMrU0IJYy4MAAELSXic-0", "", "", "", "", "", "Welcome", "No"] types = ["hidden", "hidden", "image", "image", "image", "image", "hidden", "hidden"] for i in range(len(keys)): key = keys[i] self.assert_(form.find_control(key).value == values[i]) self.assert_(form.find_control(key).type == types[i]) pairs = form.click_pairs("Full Search") self.assert_(pairs == [ ("SID", "PMrU0IJYy4MAAELSXic_E2011300_PMrU0IJYy4MAAELSXic-0"), ("SESSION_DIR", ""), ("Full Search.x", "1"), ("Full Search.y", "1"), ("Form", "Welcome"), ("JavaScript", "No")]) def testFullSearch(self): pass # XXX def testGeneralSearch(self): file = open("./testdata/GeneralSearch.html", "r") forms = ClientForm.ParseFile(file, self.base_uri, backwards_compat=False) self.assert_(len(forms) == 1) form = forms[0] keys = ["SID", "SESSION_DIR", "Home", "Date & Database Limits", "Cited Ref Search", "Log off", "Search", "topic", "titleonly", "author", "journal", "address", "Search", "Save query", "Clear", "languagetype", "doctype", "Sort", "Form", "Func"] values = ["PMrU0IJYy4MAAELSXic_E2011300_PMrU0IJYy4MAAELSXic-0", "", "", "", "", "", "", "", [], "", "", "", "", "", "", ["All languages"], ["All document types"], ["Latest date"], "General", "Search"] types = ["hidden", "hidden", "image", "image", "image", "image", "image", "text", "checkbox", "text", "text", "text", "image", "image", "image", "select", "select", "select", "hidden", "hidden"] fc = form.find_control for i in range(len(keys)): name = keys[i] type = types[i] self.assertEqual(fc(name, nr=0).value, form.get_value(name, nr=0)) self.assertEqual(fc(name, nr=0).value, values[i]) self.assertEqual(fc(name, nr=0).type, type) self.assertEqual(fc(name, type, nr=0).name, name) self.assert_(fc(type="hidden", nr=0).name == "SID") self.assert_(fc(type="image", nr=0).name == "Home") self.assert_(fc(nr=6).name == "Search") self.assertRaises(ControlNotFoundError, fc, nr=50) self.assertRaises(ValueError, fc, nr=-1) self.assert_(fc("Search", "image", nr=0).name == "Search") self.assertRaises(ControlNotFoundError, fc, "Search", "hidden") s0 = fc("Search", "image", nr=0) s0b = fc("Search", "image", nr=0) s1 = fc("Search", "image", nr=1) self.assert_(s0.name == s1.name == "Search") self.assert_(s0 is s0b) self.assert_(s0 is not s1) self.assertRaises(ControlNotFoundError, fc, "Search", "image", nr=2) self.assert_(fc(type="text", nr=2).name == "journal") self.assert_(fc("Search", nr=0) is not fc("Search", nr=1)) form["topic"] = "foo" self.assert_(form["topic"] == "foo") form["author"] = "bar" form["journal"] = "" form["address"] = "baz" form["languagetype"] = ["English", "Catalan"] self.assert_(form["languagetype"] == ["English", "Catalan"]) form["titleonly"] = ["on"] self.assert_(form["titleonly"] == ["on"]) pairs = form.click_pairs("Search") self.assert_(pairs == [ ("SID", "PMrU0IJYy4MAAELSXic_E2011300_PMrU0IJYy4MAAELSXic-0"), ("SESSION_DIR", ""), ("Search.x", "1"), ("Search.y", "1"), ("topic", "foo"), ("titleonly", "on"), ("author", "bar"), ("journal", ""), ("address", "baz"), ("languagetype", "English"), ("languagetype", "Catalan"), ("doctype", "All document types"), ("Sort", "Latest date"), ("Form", "General"), ("Func", "Search")]) hide_deprecations() pvs = form.possible_items("languagetype") self.assert_(pvs[0] == "All languages") self.assert_(len(pvs) == 47) self.assertRaises( ItemNotFoundError, lambda form=form: form.toggle("d'oh", "languagetype")) form.toggle("English", "languagetype") self.assert_(form["languagetype"] == ["Catalan"]) self.assertRaises(TypeError, form.toggle, ["Catalan"], "languagetype") self.assertRaises(TypeError, form.toggle, "Catalan", ["languagetype"]) # XXX type, nr, by_label args self.assertRaises(ControlNotFoundError, form.set, True, "blah", "SID") # multiple select form["languagetype"] = [] self.assert_(form["languagetype"] == []) form.set(True, "Catalan", "languagetype") self.assert_(form["languagetype"] == ["Catalan"]) form.set(True, "English", "languagetype") self.assert_(form["languagetype"] == ["English", "Catalan"]) form.set(False, "English", "languagetype") self.assert_(form["languagetype"] == ["Catalan"]) form.set(False, "Catalan", "languagetype") self.assert_(form["languagetype"] == []) self.assertRaises(ItemNotFoundError, form.set, True, "doh", "languagetype") self.assertRaises(ItemNotFoundError, form.set, False, "doh", "languagetype") self.assertRaises(ControlNotFoundError, form.set, True, "blah", "oops") self.assertRaises(TypeError, form.set, True, ["Catalan"], "languagetype") self.assertRaises(TypeError, form.set, False, ["Catalan"], "languagetype") self.assertRaises(TypeError, form.set, True, "Catalan", ["languagetype"]) self.assertRaises(TypeError, form.set, False, "Catalan", ["languagetype"]) def setitem(name, value, form=form): form[name] = value form["languagetype"] = ["Catalan"] self.assert_(form["languagetype"] == ["Catalan"]) self.assertRaises(ItemNotFoundError, setitem, "languagetype", ["doh"]) self.assertRaises(ControlNotFoundError, setitem, "oops", ["blah"]) self.assertRaises(TypeError, setitem, ["languagetype"], "Catalan") # single select form["Sort"] = [] self.assert_(form["Sort"] == []) form.set(True, "Relevance", "Sort") self.assert_(form["Sort"] == ["Relevance"]) form.set(True, "Times Cited", "Sort") self.assert_(form["Sort"] == ["Times Cited"]) form.set(False, "Times Cited", "Sort") self.assert_(form["Sort"] == []) self.assertRaises(ItemNotFoundError, form.set, True, "doh", "Sort") self.assertRaises(ItemNotFoundError, form.set, False, "doh", "Sort") self.assertRaises(ControlNotFoundError, form.set, True, "blah", "oops") self.assertRaises(TypeError, form.set, True, ["Relevance"], "Sort") self.assertRaises(TypeError, form.set, False, ["Relevance"], "Sort") self.assertRaises(TypeError, form.set, True, "Relevance", ["Sort"]) self.assertRaises(TypeError, form.set, False, "Relevance", ["Sort"]) reset_deprecations() form["Sort"] = ["Relevance"] self.assert_(form["Sort"] == ["Relevance"]) self.assertRaises(ItemNotFoundError, setitem, "Sort", ["doh"]) self.assertRaises(ControlNotFoundError, setitem, "oops", ["blah"]) self.assertRaises(TypeError, setitem, ["Sort"], ["Relevance"]) def testSetValueByLabelIgnoringAmbiguity(self): # regression test: follow ClientForm 0.1 behaviour # also test that backwards_compat argument to ParseFile works f = StringIO("""\
""") for kwds, backwards_compat in [({}, True), ({"backwards_compat": True}, True), ({"backwards_compat": False}, False), ]: hide_deprecations() form = ClientForm.ParseFile(f, "http://localhost/", **kwds)[0] reset_deprecations() f.seek(0) c = form.find_control("form.grocery") #for item in c.items: # print [label.text for label in item.get_labels()] c.set_value_by_label( ["Loaf of Bread", "Loaf of Bread", "Loaf of Challah"]) if backwards_compat: # select first item of ambiguous set self.assertEqual( c.get_value_by_label(), ["Loaf of Bread", "Loaf of Challah"]) self.assertEqual( [item.id for item in c.items if item.selected], ["1", None]) # disabled items still part of 'value by label' c.get(label="Loaf of Challah").disabled = True self.assertEqual( c.get_value_by_label(), ["Loaf of Bread", "Loaf of Challah"]) else: self.assertEqual( c.get_value_by_label(), ["Loaf of Bread", "Loaf of Bread", "Loaf of Challah"]) self.assertEqual( [item.id for item in c.items if item.selected], ["1", "2", None]) # disabled items NOT part of 'value by label' c.get(label="Challah").disabled = True self.assertEqual( c.get_value_by_label(), ["Loaf of Bread", "Loaf of Bread"]) def testClearValue(self): # regression test: follow ClientForm 0.1 behaviour # assigning [] to value is implemented as a special case f = StringIO("""\
""") for kwds, backwards_compat in [ ({}, True), ({"backwards_compat": True}, True), ({"backwards_compat": False}, False), ]: hide_deprecations() form = ClientForm.ParseFile(f, "http://localhost/", **kwds)[0] reset_deprecations() f.seek(0) cc = form.find_control("s") if backwards_compat: self.assertEqual(cc.value, ["a", "b"]) cc.value = [] self.assertEqual( [ii.name for ii in cc.items if ii.selected], []) else: self.assertEqual(cc.value, ["b"]) cc.value = [] # first is disabled, so no need to deselect self.assertEqual( [ii.name for ii in cc.items if ii.selected], ["a"]) def testSearchByLabel(self): f = StringIO("""\
Quality
Genre
In this grocery list of requested food items, mark the items you intend to purchase:  |  |  |  |  |  |  |  |  |  |
""") form = ClientForm.ParseFile(f, "http://localhost/", backwards_compat=False)[0] # basic tests self.assertEqual(form.find_control(label="Title").value, "The Grapes of Wrath") self.assertEqual(form.find_control(label="Submit").value, "Submit") self.assertEqual( form.find_control(label="Country").get( label="Britain").name, "EU: Great Britain") self.assertEqual( form.find_control(label="Origin").get( label="GB").name, "EU: Great Britain") self.assertEqual(form.find_control(label="Password").value, "123") self.assertEqual(form.find_control(label="Title").value, "The Grapes of Wrath") # Test item ambiguity, get, get_items, and set_value_by_label. # A form can be in two states: either ignoring ambiguity or being # careful about it. Currently, by default, a form's backwards_compat # attribute is True, so ambiguity is ignored. For instance, notice # that the form.grocery checkboxes include some loaves of bread and # a loaf of challah. The code just guesses what you mean: form.backwards_compat = True c = form.find_control("form.grocery") # label substring matching is turned off for compat mode self.assertRaises(ItemNotFoundError, c.get, label="Loaf") self.assertEqual(c.get(label="Loaf of Bread"), c.items[0]) c.set_value_by_label(["Loaf of Bread"]) self.assertEqual(c.get_value_by_label(), ["Loaf of Bread"]) self.assertEqual(c.items[0].id, "1") # However, if the form's backwards_compat attribute is False, Ambiguity # Errors may be raised. This is generally a preferred approach, but is # not backwards compatible. form.backwards_compat = False self.assertRaises(ClientForm.AmbiguityError, c.get, label="Loaf") self.assertRaises( ClientForm.AmbiguityError, c.set_value_by_label, ["Loaf"]) # If items have the same name (value), set_value_by_label will # be happy (since it is just setting the value anyway). c.set_value_by_label(["Loaf of Bread"]) self.assertEqual(c.get_value_by_label(), ["Loaf of Bread"]) c.set_value_by_label( ["Loaf of Bread", "Loaf of Bread", "Loaf of Challah"]) self.assertEqual( c.get_value_by_label(), ["Loaf of Bread", "Loaf of Bread", "Loaf of Challah"]) # "get" will still raise an exception, though. self.assertRaises( ClientForm.AmbiguityError, c.get, label="Loaf of Bread") # If you want an item, you need to specify which one you want (or use # get_items to explicitly get all of them). self.assertEqual(c.get(label="Loaf of Bread", nr=0).selected, True) self.assertEqual(c.get(label="Loaf of Bread", nr=1).selected, True) self.assertEqual(c.get(label="Loaf of Bread", nr=2).selected, False) self.assertEqual(c.get(label="Loaf of Challah").selected, True) self.assertEqual( [i.selected for i in c.get_items(label="Loaf of Bread")], [True, True, False]) self.assertEqual( [i.selected for i in c.get_items(label="Loaf of Challah")], [True]) self.assertEqual( [i.name for i in c.get_items(label="Loaf")], ["bread", "bread", "bread", "challah"]) self.assertEqual( [i.get_labels()[0].text for i in c.get_items("bread")], ["Loaf of Bread", "Loaf of Bread", "Loaf of Bread"]) # test deprecation if warnings_imported: try: for c, f in ( (form.find_control("form.genre"), "western"), (form.find_control("form.country"), "zimbabwe"), (form.find_control("form.quality"), "good")): # warnings are nasty. :-( raise_deprecations() # clear onceregistry try: c.possible_items() except DeprecationWarning: pass else: self.fail("deprecation failed") try: c.toggle_single() except DeprecationWarning: pass else: self.fail("deprecation failed") try: c.set_single(True) except DeprecationWarning: pass else: self.fail("deprecation failed") try: c.toggle(f) except DeprecationWarning: pass else: self.fail("deprecation failed") try: c.get_item_disabled(f) except DeprecationWarning: pass else: self.fail("deprecation failed") try: c.set_item_disabled(True, f) except DeprecationWarning: pass else: self.fail("deprecation failed") try: c.get_item_attrs(True, f) except DeprecationWarning: pass else: self.fail("deprecation failed") finally: reset_deprecations() def testResults(self): file = open("./testdata/Results.html", "r") forms = ClientForm.ParseFile(file, self.base_uri, backwards_compat=False) self.assert_(len(forms) == 1) form = forms[0] hide_deprecations() pvs = form.possible_items("marked_list_candidates") reset_deprecations() self.assert_(pvs == [ "000174872000059/1", "000174858300003/2", "000174827900006/3"]) def bad_setitem(form=form): form["marked_list_candidates"] = ["blah"] self.assertRaises(ItemNotFoundError, bad_setitem) form["marked_list_candidates"] = [pvs[0]] # I've removed most of the INPUT elements from this page, and # corrected an HTML error keys = ["Add marked records to list", "Add records on page to list", "Add all records retrieved to list", "marked_list_candidates", "Add marked records to list", "Add records on page to list", "Add all records retrieved to list" ] types = ["image", "image", "image", "checkbox", "image", "image", "image"] values = ["", "", "", [pvs[0]], "", "", "", ] for i in range(len(keys)): key = keys[i] control = form.find_control(key, nr=0) self.assert_(control.value == values[i]) self.assert_(control.type == types[i]) pairs = form.click_pairs("Add all records retrieved to list") self.assert_(pairs == [ ("Add all records retrieved to list.x", "1"), ("Add all records retrieved to list.y", "1"), ("marked_list_candidates", pvs[0])]) def testMarkedResults(self): file = open("./testdata/MarkedResults.html", "r") forms = ClientForm.ParseFile(file, self.base_uri, backwards_compat=False) self.assert_(len(forms) == 1) form = forms[0] pairs = form.click_pairs() # I've removed most of the INPUT elements from this page, and # corrected an HTML error self.assert_(pairs == [ ("Add marked records to list.x", "1"), ("Add marked records to list.y", "1"), ("marked_list_candidates", "000174872000059/1"), ("marked_list_candidates", "000174858300003/2"), ("marked_list_candidates", "000174827900006/3") ]) def testMarkedRecords(self): pass # XXX class MoreFormTests(TestCase): def test_interspersed_controls(self): # must preserve item ordering even across controls f = StringIO("""\
""") form = ClientForm.ParseFile(f, "http://blah/", backwards_compat=False)[0] form["murphy"] = ["a", "b", "c"] form["woof"] = ["d"] self.assertEqual(form.click_pairs(), [ ("murphy", "a"), ("woof", "d"), ("murphy", "b"), ("murphy", "c"), ]) form.method = "POST" form.enctype = "multipart/form-data" lines = [line for line in form.click_request_data()[1].split("\r\n") if line != '' and not line.startswith("--")] self.assertEqual( lines, ['Content-Disposition: form-data; name="murphy"', 'a', 'Content-Disposition: form-data; name="woof"', 'd', 'Content-Disposition: form-data; name="murphy"', 'b', 'Content-Disposition: form-data; name="murphy"', 'c', ] ) def make_form(self): f = StringIO("""\
""") return ClientForm.ParseFile(f, "http://blah/", backwards_compat=False)[0] def test_value(self): form = self.make_form() form.set_value(["v3"], type="select", kind="multilist") self.assert_(form.get_value("d") == ["v3"]) hide_deprecations() form.set_value(["l2"], type="select", kind="multilist", by_label=True) self.assert_(form.get_value("d", by_label=True) == ["l2"]) self.assert_(form.get_value( "b", "radio", "singlelist", None, 0, False) == []) form.set_value(["One"], "b", by_label=True) self.assertEqual( form.get_value("b", "radio", "singlelist", None, 0, False), ["1"]) form.set_value(["Three"], "b", by_label=True) reset_deprecations() self.assertEqual( form.get_value("b", "radio", "singlelist", None, 0, False), ["3"]) def test_id(self): form = self.make_form() self.assert_(form.find_control("c").id == "cselect") self.assert_(form.find_control("a").id == "1a") self.assert_(form.find_control("b").id is None) self.assert_(form.find_control(id="cselect").id == "cselect") self.assertRaises(ControlNotFoundError, form.find_control, id="coption1") self.assert_(form.find_control(id="1a").id == "1a") self.assertRaises(ControlNotFoundError, form.find_control, id="1") def test_single(self): form = self.make_form() hide_deprecations() self.assertRaises(ItemCountError, form.set_single, True, "d") form.set_single(True, 'e', by_label=True) self.assertEqual(form.get_value("e"), ["1"]) form.set_single(False, 'e', by_label=True) self.assertEqual(form.get_value("e"), []) form.toggle_single("e", "checkbox", "list", nr=0) self.assert_("1" in form.get_value("e")) form.set_single(False, "e", "checkbox", "list", nr=0) self.assert_("1" not in form.get_value("e")) form.set_single(True, "e", "checkbox", "list", nr=0) self.assert_("1" in form.get_value("e")) reset_deprecations() def test_possible_items(self): form = self.make_form() hide_deprecations() self.assert_(form.possible_items("c") == ["1", "2", "3"]) self.assert_(form.possible_items("d", by_label=True) == ["l1", "l2", "l3"]) self.assert_(form.possible_items("a") == ["1", "2", "3"]) self.assertEqual(form.possible_items('e', by_label=True), [None]) self.assertEqual(form.possible_items('a', by_label=True), ['One', 'Two', 'Three']) self.assertEqual(form.possible_items('b', by_label=True), ['One', 'Two', 'Three', 'Four']) reset_deprecations() def test_set_all_readonly(self): form = self.make_form() form.set_all_readonly(True) for c in form.controls: self.assert_(c.readonly) form.set_all_readonly(False) for c in form.controls: self.assert_(not c.readonly) def test_clear_all(self): form = self.make_form() form.set_all_readonly(True) self.assertRaises(AttributeError, form.clear_all) form.set_all_readonly(False) form.clear_all() for c in form.controls: self.assert_(not c.value) def test_clear(self): form = self.make_form() form.set_all_readonly(True) self.assertRaises(AttributeError, form.clear, "b") form.set_all_readonly(False) form["b"] = ["1"] self.assertEqual(form["b"], ["1"]) form.clear("b") self.assertEqual(form["b"], []) def test_attrs(self): form = self.make_form() self.assert_(form.attrs["blah"] == "nonsense") self.assert_(form.attrs["name"] == "formname") a = form.find_control("a") self.assertRaises(AttributeError, getattr, a, 'attrs') hide_deprecations() self.assert_(a.get_item_attrs("1")["blah"] == "spam") self.assert_(a.get_item_attrs("2")["blah"] == "eggs") self.assert_(not a.get_item_attrs("3").has_key("blah")) c = form.find_control("c") self.assert_(c.attrs["blah"] == "foo") self.assert_(c.get_item_attrs("1")["blah"] == "bar") self.assert_(c.get_item_attrs("2")["blah"] == "baz") self.assert_(not c.get_item_attrs("3").has_key("blah")) reset_deprecations() def test_select_control_nr_and_label(self): for compat in [False, True]: self._test_select_control_nr_and_label(compat) def _test_select_control_nr_and_label(self, compat): f = StringIO("""\
""") if compat: hide_deprecations() form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=compat)[0] if compat: reset_deprecations() ctl = form.find_control("form.grocery") # ordinary case self.assertEqual(ctl.get("p", nr=1).id, "3") # nr too high self.assertRaises(ItemNotFoundError, ctl.get, "p", nr=50) # first having label "a" self.assertEqual(ctl.get(label="a", nr=0).id, "1") # second having label "a"... item = ctl.get(label="a", nr=1) # ...as opposed to second with label attribute "a"! -- each item # has multiple labels accessible by .get_labels(), but only one # label HTML-attribute self.assertEqual(item.id, "2") self.assertEqual(item.attrs.get("label"), "b") # ! # third having label "a" (but only the second whose label is "a") self.assertEqual(ctl.get(label="a", nr=1).id, "2") # nr too high again self.assertRaises(ItemNotFoundError, ctl.get, label="a", nr=3) self.assertEqual(ctl.get(id="2").id, "2") self.assertRaises(ItemNotFoundError, ctl.get, id="4") self.assertRaises(ItemNotFoundError, ctl.get, id="4") def test_label_whitespace(self): for compat in [False, True]: f = StringIO("""\
""") if compat: hide_deprecations() form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=compat)[0] ctl = form.find_control("eg") p = ctl.get("p") q = ctl.get("q") self.assertEqual(p.get_labels()[0].text, (compat and "a b c" or "a b c")) self.assertEqual(q.get_labels()[0].text, "b") if compat: reset_deprecations() def test_nameless_list_control(self): # ListControls are built up from elements that match by name and type # attributes. Nameless controls cause some tricky cases. We should # get a new control for nameless controls. for data in [ """\
""", """\
""", """\
""", ]: f = StringIO(data) form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=False)[0] bar = form.find_control(type="checkbox", id="a") # should have value "on", but not be successful self.assertEqual([item.name for item in bar.items], ["on"]) self.assertEqual(bar.value, []) self.assertEqual(form.click_pairs(), []) def test_action_with_fragment(self): for method in ["GET", "POST"]: data = ('
' '
' % method ) f = StringIO(data) form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=False)[0] self.assertEqual( form.click().get_full_url(), "http://example.com/"+(method=="GET" and "?s=" or ""), ) data = '
' f = StringIO(data) form = ClientForm.ParseFile(f, "http://example.com/", backwards_compat=False)[0] form.find_control(type="isindex").value = "blah" self.assertEqual(form.click(type="isindex").get_full_url(), "http://example.com/?blah") class ContentTypeTests(TestCase): def test_content_type(self): import ClientForm class OldStyleRequest: def __init__(self, url, data=None, hdrs=None): self.ah = self.auh = False def add_header(self, key, val): self.ah = True class NewStyleRequest(OldStyleRequest): def add_unredirected_header(self, key, val): self.auh = True class FakeForm(ClientForm.HTMLForm): def __init__(self, hdr): self.hdr = hdr def _request_data(self): return "http://example.com", "", [(self.hdr, "spam")] for request_class, hdr, auh in [ (OldStyleRequest, "Foo", False), (NewStyleRequest, "Foo", False), (OldStyleRequest, "Content-type", False), (NewStyleRequest, "Content-type", True), ]: form = FakeForm(hdr) req = form._switch_click("request", request_class) self.assertEqual(req.auh, auh) self.assertEqual(req.ah, not auh) class FunctionTests(TestCase): def test_normalize_line_endings(self): def check(text, expected, self=self): got = ClientForm.normalize_line_endings(text) self.assertEqual(got, expected) # unix check("foo\nbar", "foo\r\nbar") check("foo\nbar\n", "foo\r\nbar\r\n") # mac check("foo\rbar", "foo\r\nbar") check("foo\rbar\r", "foo\r\nbar\r\n") # dos check("foo\r\nbar", "foo\r\nbar") check("foo\r\nbar\r\n", "foo\r\nbar\r\n") # inconsistent -- we just blithely convert anything that looks like a # line ending to the DOS convention, following Firefox's behaviour when # normalizing textarea content check("foo\r\nbar\nbaz\rblah\r\n", "foo\r\nbar\r\nbaz\r\nblah\r\n") # pathological ;-O check("\r\n\n\r\r\r\n", "\r\n"*5) def startswith(string, initial): if len(initial) > len(string): return False return string[:len(initial)] == initial class CaseInsensitiveDict: def __init__(self, items): self._dict = {} for key, val in items: self._dict[string.lower(key)] = val def __getitem__(self, key): return self._dict[key] def __getattr__(self, name): return getattr(self._dict, name) class UploadTests(MonkeyTestCase): def test_choose_boundary(self): from ClientForm import choose_boundary bndy = choose_boundary() ii = string.find(bndy, '.') self.assert_(ii < 0) def make_form(self): html = """\

""" return ClientForm.ParseFile(StringIO(html), "http://localhost/cgi-bin/upload.cgi", backwards_compat=False)[0] def test_file_request(self): import cgi # fill in a file upload form... form = self.make_form() form["user"] = "john" data_control = form.find_control("data") data = "blah\nbaz\n" data_control.add_file(StringIO(data)) #print "data_control._upload_data", data_control._upload_data req = form.click() self.assert_(startswith(get_header(req, "Content-type"), 'multipart/form-data; boundary=')) #print "req.get_data()\n>>%s<<" % req.get_data() # ...and check the resulting request is understood by cgi module fs = cgi.FieldStorage(StringIO(req.get_data()), CaseInsensitiveDict(header_items(req)), environ={"REQUEST_METHOD": "POST"}) self.assert_(fs["user"].value == "john") self.assert_(fs["data"].value == data) self.assertEquals(fs["data"].filename, "") def test_file_request_with_filename(self): import cgi # fill in a file upload form... form = self.make_form() form["user"] = "john" data_control = form.find_control("data") data = "blah\nbaz\n" data_control.add_file(StringIO(data), filename="afilename") req = form.click() self.assert_(startswith(get_header(req, "Content-type"), 'multipart/form-data; boundary=')) # ...and check the resulting request is understood by cgi module fs = cgi.FieldStorage(StringIO(req.get_data()), CaseInsensitiveDict(header_items(req)), environ={"REQUEST_METHOD": "POST"}) self.assert_(fs["user"].value == "john") self.assert_(fs["data"].value == data) self.assert_(fs["data"].filename == "afilename") def test_multipart_file_request(self): import cgi # fill in a file upload form... form = self.make_form() form["user"] = "john" data_control = form.find_control("data") data = "blah\nbaz\n" data_control.add_file(StringIO(data), filename="filenamea") more_data = "rhubarb\nrhubarb\n" data_control.add_file(StringIO(more_data)) yet_more_data = "rheum\nrhaponicum\n" data_control.add_file(StringIO(yet_more_data), filename="filenamec") req = form.click() self.assert_(startswith(get_header(req, "Content-type"), 'multipart/form-data; boundary=')) #print "req.get_data()\n>>%s<<" % req.get_data() # ...and check the resulting request is understood by cgi module fs = cgi.FieldStorage(StringIO(req.get_data()), CaseInsensitiveDict(header_items(req)), environ={"REQUEST_METHOD": "POST"}) self.assert_(fs["user"].value == "john") fss = fs["data"][None] filenames = "filenamea", "", "filenamec" datas = data, more_data, yet_more_data for i in range(len(fss)): fs = fss[i] filename = filenames[i] data = datas[i] self.assert_(fs.filename == filename) self.assert_(fs.value == data) def test_upload_data(self): form = self.make_form() data = form.click().get_data() self.assert_(startswith(data, "--")) def test_empty_upload(self): # no controls except for INPUT/SUBMIT forms = ClientForm.ParseFile(StringIO("""
"""), ".", backwards_compat=False) form = forms[0] data = form.click().get_data() lines = string.split(data, "\r\n") self.assert_(startswith(lines[0], "--")) self.assert_(lines[1] == 'Content-Disposition: form-data; name="submit"') self.assert_(lines[2] == lines[3] == "") self.assert_(startswith(lines[4], "--")) def test_no_files(self): # no files uploaded self.monkey_patch(ClientForm, "choose_boundary", lambda: "123") forms = ClientForm.ParseFileEx(StringIO("""
"""), ".") form = forms[1] data = form.click().get_data() self.assertEquals(data, """\ --123\r Content-Disposition: form-data; name="spam"; filename=""\r Content-Type: application/octet-stream\r \r \r --123--\r """) class ImportTests(TestCase): def test_import_all(self): # the following will raise an exception if __all__ contains undefined # classes from ClientForm import * if __name__ == "__main__": import test_clientform unittest.main(test_clientform)