diff --git a/networks/templates/modify_ipv4_fixed_address.html b/networks/templates/modify_ipv4_fixed_address.html
index 05bf1ff9..4886e0bc 100644
--- a/networks/templates/modify_ipv4_fixed_address.html
+++ b/networks/templates/modify_ipv4_fixed_address.html
@@ -24,13 +24,13 @@
diff --git a/networks/templates/modify_ipv6_fixed_address.html b/networks/templates/modify_ipv6_fixed_address.html
index e5439bda..4ca340bc 100644
--- a/networks/templates/modify_ipv6_fixed_address.html
+++ b/networks/templates/modify_ipv6_fixed_address.html
@@ -30,7 +30,7 @@
diff --git a/networks/tests/__init__.py b/networks/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/networks/tests/test_fixed_address_form.py b/networks/tests/test_fixed_address_form.py
new file mode 100644
index 00000000..3f92317a
--- /dev/null
+++ b/networks/tests/test_fixed_address_form.py
@@ -0,0 +1,31 @@
+"""The fixed-address dialogs take real MAC addresses and host names: the
+browser refuses what their pattern attributes do not match."""
+
+import re
+from types import SimpleNamespace
+
+from django.template.loader import render_to_string
+from django.test import SimpleTestCase
+from lxml import html
+
+
+def pattern(template, name):
+ superuser = SimpleNamespace(user=SimpleNamespace(is_superuser=True))
+ page = html.fromstring(render_to_string(template, {"request": superuser}))
+ return re.compile(page.xpath(f"//input[@name='{name}']/@pattern")[0])
+
+
+class FixedAddressFormTests(SimpleTestCase):
+ def test_macs_and_host_names_are_accepted(self):
+ mac = pattern("modify_ipv4_fixed_address.html", "mac")
+ for value in ("52:54:00:ab:cd:ef", "52:54:00:AB:CD:EF"):
+ with self.subTest(mac=value):
+ self.assertTrue(mac.fullmatch(value))
+ for template in ("modify_ipv4_fixed_address.html", "modify_ipv6_fixed_address.html"):
+ name = pattern(template, "name")
+ for value in ("web-01", "db.lan", "vm_1"):
+ with self.subTest(template=template, name=value):
+ self.assertTrue(name.fullmatch(value))
+ for value in ("a b", 'x"<'):
+ with self.subTest(template=template, refused=value):
+ self.assertFalse(name.fullmatch(value))