from datetime import date
from django.forms import DateField, Form, SelectDateWidget
from django.test import ignore_warnings, override_settings
from django.utils import translation
from django.utils.dates import MONTHS_AP
from django.utils.deprecation import RemovedInDjango50Warning
from .base import WidgetTest
class SelectDateWidgetTest(WidgetTest):
maxDiff = None
widget = SelectDateWidget(
years=(
"2007",
"2008",
"2009",
"2010",
"2011",
"2012",
"2013",
"2014",
"2015",
"2016",
),
)
def test_render_empty(self):
self.check_html(
self.widget,
"mydate",
"",
html=(
"""
"""
),
)
def test_render_none(self):
"""
Rendering the None or '' values should yield the same output.
"""
self.assertHTMLEqual(
self.widget.render("mydate", None),
self.widget.render("mydate", ""),
)
def test_render_string(self):
self.check_html(
self.widget,
"mydate",
"2010-04-15",
html=(
"""
"""
),
)
def test_render_datetime(self):
self.assertHTMLEqual(
self.widget.render("mydate", date(2010, 4, 15)),
self.widget.render("mydate", "2010-04-15"),
)
def test_render_invalid_date(self):
"""
Invalid dates should still render the failed date.
"""
self.check_html(
self.widget,
"mydate",
"2010-02-31",
html=(
"""
"""
),
)
def test_custom_months(self):
widget = SelectDateWidget(months=MONTHS_AP, years=("2013",))
self.check_html(
widget,
"mydate",
"",
html=(
"""
"""
),
)
def test_selectdate_required(self):
class GetNotRequiredDate(Form):
mydate = DateField(widget=SelectDateWidget, required=False)
class GetRequiredDate(Form):
mydate = DateField(widget=SelectDateWidget, required=True)
self.assertFalse(GetNotRequiredDate().fields["mydate"].widget.is_required)
self.assertTrue(GetRequiredDate().fields["mydate"].widget.is_required)
def test_selectdate_empty_label(self):
w = SelectDateWidget(years=("2014",), empty_label="empty_label")
# Rendering the default state with empty_label set as string.
self.assertInHTML(
'',
w.render("mydate", ""),
count=3,
)
w = SelectDateWidget(
years=("2014",), empty_label=("empty_year", "empty_month", "empty_day")
)
# Rendering the default state with empty_label tuple.
self.assertHTMLEqual(
w.render("mydate", ""),
"""
""",
)
with self.assertRaisesMessage(
ValueError, "empty_label list/tuple must have 3 elements."
):
SelectDateWidget(years=("2014",), empty_label=("not enough", "values"))
@translation.override("nl")
def test_l10n(self):
w = SelectDateWidget(
years=(
"2007",
"2008",
"2009",
"2010",
"2011",
"2012",
"2013",
"2014",
"2015",
"2016",
)
)
self.assertEqual(
w.value_from_datadict(
{"date_year": "2010", "date_month": "8", "date_day": "13"}, {}, "date"
),
"13-08-2010",
)
self.assertHTMLEqual(
w.render("date", "13-08-2010"),
"""
""",
)
# Even with an invalid date, the widget should reflect the entered
# value.
self.assertEqual(w.render("mydate", "2010-02-30").count("selected"), 3)
# Years before 1900 should work.
w = SelectDateWidget(years=("1899",))
self.assertEqual(
w.value_from_datadict(
{"date_year": "1899", "date_month": "8", "date_day": "13"}, {}, "date"
),
"13-08-1899",
)
# And years before 1000 (demonstrating the need for
# sanitize_strftime_format).
w = SelectDateWidget(years=("0001",))
self.assertEqual(
w.value_from_datadict(
{"date_year": "0001", "date_month": "8", "date_day": "13"}, {}, "date"
),
"13-08-0001",
)
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The test should remain because
# format-related settings will take precedence over locale-dictated
# formats.
@ignore_warnings(category=RemovedInDjango50Warning)
@override_settings(USE_L10N=False, DATE_INPUT_FORMATS=["%d.%m.%Y"])
def test_custom_input_format(self):
w = SelectDateWidget(years=("0001", "1899", "2009", "2010"))
for values, expected_value in (
(("0001", "8", "13"), "13.08.0001"),
(("1899", "7", "11"), "11.07.1899"),
(("2009", "3", "7"), "07.03.2009"),
):
with self.subTest(values=values):
data = {
"field_%s" % field: value
for field, value in zip(("year", "month", "day"), values)
}
self.assertEqual(
w.value_from_datadict(data, {}, "field"), expected_value
)
expected_dict = {
field: int(value)
for field, value in zip(("year", "month", "day"), values)
}
self.assertEqual(w.format_value(expected_value), expected_dict)
def test_format_value(self):
valid_formats = [
"2000-1-1",
"2000-10-15",
"2000-01-01",
"2000-01-0",
"2000-0-01",
"2000-0-0",
"0-01-01",
"0-01-0",
"0-0-01",
"0-0-0",
]
for value in valid_formats:
year, month, day = (int(x) or "" for x in value.split("-"))
with self.subTest(value=value):
self.assertEqual(
self.widget.format_value(value),
{"day": day, "month": month, "year": year},
)
invalid_formats = [
"2000-01-001",
"2000-001-01",
"2-01-01",
"20-01-01",
"200-01-01",
"20000-01-01",
]
for value in invalid_formats:
with self.subTest(value=value):
self.assertEqual(
self.widget.format_value(value),
{"day": None, "month": None, "year": None},
)
def test_value_from_datadict(self):
tests = [
(("2000", "12", "1"), "2000-12-01"),
(("", "12", "1"), "0-12-1"),
(("2000", "", "1"), "2000-0-1"),
(("2000", "12", ""), "2000-12-0"),
(("", "", "", ""), None),
((None, "12", "1"), None),
(("2000", None, "1"), None),
(("2000", "12", None), None),
]
for values, expected in tests:
with self.subTest(values=values):
data = {}
for field_name, value in zip(("year", "month", "day"), values):
if value is not None:
data["field_%s" % field_name] = value
self.assertEqual(
self.widget.value_from_datadict(data, {}, "field"), expected
)
def test_value_omitted_from_data(self):
self.assertIs(self.widget.value_omitted_from_data({}, {}, "field"), True)
self.assertIs(
self.widget.value_omitted_from_data({"field_month": "12"}, {}, "field"),
False,
)
self.assertIs(
self.widget.value_omitted_from_data({"field_year": "2000"}, {}, "field"),
False,
)
self.assertIs(
self.widget.value_omitted_from_data({"field_day": "1"}, {}, "field"), False
)
data = {"field_day": "1", "field_month": "12", "field_year": "2000"}
self.assertIs(self.widget.value_omitted_from_data(data, {}, "field"), False)
@override_settings(USE_THOUSAND_SEPARATOR=True)
def test_years_rendered_without_separator(self):
widget = SelectDateWidget(years=(2007,))
self.check_html(
widget,
"mydate",
"",
html=(
"""
"""
),
)