diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index c4743a78a6..2644355951 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -29,6 +29,84 @@ u''
>>> w.render('email', '', attrs={'class': 'special'})
u''
+# PasswordInput Widget ############################################################
+
+>>> w = PasswordInput()
+>>> w.render('email', '')
+u''
+>>> w.render('email', None)
+u''
+>>> w.render('email', 'test@example.com')
+u''
+>>> w.render('email', 'some "quoted" & ampersanded value')
+u''
+>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
+u''
+
+You can also pass 'attrs' to the constructor:
+>>> w = PasswordInput(attrs={'class': 'fun'})
+>>> w.render('email', '')
+u''
+>>> w.render('email', 'foo@example.com')
+u''
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = PasswordInput(attrs={'class': 'pretty'})
+>>> w.render('email', '', attrs={'class': 'special'})
+u''
+
+# HiddenInput Widget ############################################################
+
+>>> w = HiddenInput()
+>>> w.render('email', '')
+u''
+>>> w.render('email', None)
+u''
+>>> w.render('email', 'test@example.com')
+u''
+>>> w.render('email', 'some "quoted" & ampersanded value')
+u''
+>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
+u''
+
+You can also pass 'attrs' to the constructor:
+>>> w = HiddenInput(attrs={'class': 'fun'})
+>>> w.render('email', '')
+u''
+>>> w.render('email', 'foo@example.com')
+u''
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = HiddenInput(attrs={'class': 'pretty'})
+>>> w.render('email', '', attrs={'class': 'special'})
+u''
+
+# FileInput Widget ############################################################
+
+>>> w = FileInput()
+>>> w.render('email', '')
+u''
+>>> w.render('email', None)
+u''
+>>> w.render('email', 'test@example.com')
+u''
+>>> w.render('email', 'some "quoted" & ampersanded value')
+u''
+>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
+u''
+
+You can also pass 'attrs' to the constructor:
+>>> w = FileInput(attrs={'class': 'fun'})
+>>> w.render('email', '')
+u''
+>>> w.render('email', 'foo@example.com')
+u''
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = HiddenInput(attrs={'class': 'pretty'})
+>>> w.render('email', '', attrs={'class': 'special'})
+u''
+
# Textarea Widget #############################################################
>>> w = Textarea()
@@ -77,6 +155,87 @@ u''
>>> w.render('is_cool', '', attrs={'class': 'special'})
u''
+# Select Widget ###############################################################
+
+>>> w = Select()
+>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+If the value is None, none of the options are selected:
+>>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+If the value corresponds to a label (but not to an option value), none of the options are selected:
+>>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+The value is compared to its str():
+>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
+
+>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
+
+>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
+
+
+The 'choices' argument can be any iterable:
+>>> def get_choices():
+... for i in range(5):
+... yield (i, i)
+>>> print w.render('num', 2, choices=get_choices())
+
+
+You can also pass 'choices' to the constructor:
+>>> w = Select(choices=[(1, 1), (2, 2), (3, 3)])
+>>> print w.render('num', 2)
+
+
+If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
+>>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
+
+
# CharField ###################################################################
>>> f = CharField(required=False)
@@ -353,6 +512,56 @@ Traceback (most recent call last):
...
ValidationError: [u'Enter a valid e-mail address.']
+# URLField ##################################################################
+
+>>> f = URLField()
+>>> f.to_python('http://example.com')
+u'http://example.com'
+>>> f.to_python('http://www.example.com')
+u'http://www.example.com'
+>>> f.to_python('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.to_python('example.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.to_python('http://')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.to_python('http://example')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.to_python('http://example.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.to_python('http://.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+
+URLField takes an optional verify_exists parameter, which is False by default.
+This verifies that the URL is live on the Internet and doesn't return a 404 or 500:
+>>> f = URLField(verify_exists=True)
+>>> f.to_python('http://www.google.com')
+u'http://www.google.com'
+>>> f.to_python('http://example')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.to_python('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com') # bad domain
+Traceback (most recent call last):
+...
+ValidationError: [u'This URL appears to be a broken link.']
+>>> f.to_python('http://google.com/we-love-microsoft.html') # good domain, bad page
+Traceback (most recent call last):
+...
+ValidationError: [u'This URL appears to be a broken link.']
+
# BooleanField ################################################################
>>> f = BooleanField()