tests: fix remove unnecessary workaround for some unittest assertions.

This commit is contained in:
Jacob Graves 2020-07-28 13:35:25 -06:00 committed by GitHub
parent c75fa45fd8
commit 8117ef6692
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 410 additions and 427 deletions

View file

@ -46,19 +46,19 @@ class PinsTestCase(FHDLTestCase):
self.assertEqual(p.map_names(mapping, p), ["A1"]) self.assertEqual(p.map_names(mapping, p), ["A1"])
def test_wrong_names(self): def test_wrong_names(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Names must be a whitespace-separated string, not ['A0', 'A1', 'A2']"): r"^Names must be a whitespace-separated string, not \['A0', 'A1', 'A2'\]$"):
p = Pins(["A0", "A1", "A2"]) p = Pins(["A0", "A1", "A2"])
def test_wrong_dir(self): def test_wrong_dir(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Direction must be one of \"i\", \"o\", \"oe\", or \"io\", not 'wrong'"): r"^Direction must be one of \"i\", \"o\", \"oe\", or \"io\", not 'wrong'$"):
p = Pins("A0 A1", dir="wrong") p = Pins("A0 A1", dir="wrong")
def test_wrong_conn(self): def test_wrong_conn(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Connector must be None or a pair of string (connector name) and " (r"^Connector must be None or a pair of string \(connector name\) and "
"integer/string (connector number), not ('foo', None)"): r"integer\/string \(connector number\), not \('foo', None\)$")):
p = Pins("A0 A1", conn=("foo", None)) p = Pins("A0 A1", conn=("foo", None))
def test_wrong_map_names(self): def test_wrong_map_names(self):
@ -66,14 +66,14 @@ class PinsTestCase(FHDLTestCase):
mapping = { mapping = {
"pmod_0:0": "A0", "pmod_0:0": "A0",
} }
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Resource (pins io pmod_0:0 pmod_0:1 pmod_0:2) refers to nonexistent " (r"^Resource \(pins io pmod_0:0 pmod_0:1 pmod_0:2\) refers to nonexistent "
"connector pin pmod_0:1"): r"connector pin pmod_0:1$")):
p.map_names(mapping, p) p.map_names(mapping, p)
def test_wrong_assert_width(self): def test_wrong_assert_width(self):
with self.assertRaises(AssertionError, with self.assertRaisesRegex(AssertionError,
msg="3 names are specified (0 1 2), but 4 names are expected"): r"^3 names are specified \(0 1 2\), but 4 names are expected$"):
Pins("0 1 2", assert_width=4) Pins("0 1 2", assert_width=4)
@ -108,14 +108,14 @@ class DiffPairsTestCase(FHDLTestCase):
self.assertEqual(dp.n.dir, "o") self.assertEqual(dp.n.dir, "o")
def test_wrong_width(self): def test_wrong_width(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Positive and negative pins must have the same width, but (pins io A0) " (r"^Positive and negative pins must have the same width, but \(pins io A0\) "
"and (pins io B0 B1) do not"): r"and \(pins io B0 B1\) do not$")):
dp = DiffPairs("A0", "B0 B1") dp = DiffPairs("A0", "B0 B1")
def test_wrong_assert_width(self): def test_wrong_assert_width(self):
with self.assertRaises(AssertionError, with self.assertRaisesRegex(AssertionError,
msg="3 names are specified (0 1 2), but 4 names are expected"): r"^3 names are specified \(0 1 2\), but 4 names are expected$"):
DiffPairs("0 1 2", "3 4 5", assert_width=4) DiffPairs("0 1 2", "3 4 5", assert_width=4)
@ -137,8 +137,8 @@ class AttrsTestCase(FHDLTestCase):
self.assertEqual(repr(a), "(attrs FOO={!r})".format(fn)) self.assertEqual(repr(a), "(attrs FOO={!r})".format(fn))
def test_wrong_value(self): def test_wrong_value(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Value of attribute FOO must be None, int, str, or callable, not 1.0"): r"^Value of attribute FOO must be None, int, str, or callable, not 1\.0$"):
a = Attrs(FOO=1.0) a = Attrs(FOO=1.0)
@ -187,42 +187,42 @@ class SubsignalTestCase(FHDLTestCase):
self.assertEqual(s.clock.frequency, 1e6) self.assertEqual(s.clock.frequency, 1e6)
def test_wrong_empty_io(self): def test_wrong_empty_io(self):
with self.assertRaises(ValueError, msg="Missing I/O constraints"): with self.assertRaisesRegex(ValueError, r"^Missing I\/O constraints$"):
s = Subsignal("a") s = Subsignal("a")
def test_wrong_io(self): def test_wrong_io(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Constraint must be one of Pins, DiffPairs, Subsignal, Attrs, or Clock, " (r"^Constraint must be one of Pins, DiffPairs, Subsignal, Attrs, or Clock, "
"not 'wrong'"): r"not 'wrong'$")):
s = Subsignal("a", "wrong") s = Subsignal("a", "wrong")
def test_wrong_pins(self): def test_wrong_pins(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Pins and DiffPairs are incompatible with other location or subsignal " (r"^Pins and DiffPairs are incompatible with other location or subsignal "
"constraints, but (pins io A1) appears after (pins io A0)"): r"constraints, but \(pins io A1\) appears after \(pins io A0\)$")):
s = Subsignal("a", Pins("A0"), Pins("A1")) s = Subsignal("a", Pins("A0"), Pins("A1"))
def test_wrong_diffpairs(self): def test_wrong_diffpairs(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Pins and DiffPairs are incompatible with other location or subsignal " (r"^Pins and DiffPairs are incompatible with other location or subsignal "
"constraints, but (pins io A1) appears after (diffpairs io (p A0) (n B0))"): r"constraints, but \(pins io A1\) appears after \(diffpairs io \(p A0\) \(n B0\)\)$")):
s = Subsignal("a", DiffPairs("A0", "B0"), Pins("A1")) s = Subsignal("a", DiffPairs("A0", "B0"), Pins("A1"))
def test_wrong_subsignals(self): def test_wrong_subsignals(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Pins and DiffPairs are incompatible with other location or subsignal " (r"^Pins and DiffPairs are incompatible with other location or subsignal "
"constraints, but (pins io B0) appears after (subsignal b (pins io A0))"): r"constraints, but \(pins io B0\) appears after \(subsignal b \(pins io A0\)\)$")):
s = Subsignal("a", Subsignal("b", Pins("A0")), Pins("B0")) s = Subsignal("a", Subsignal("b", Pins("A0")), Pins("B0"))
def test_wrong_clock(self): def test_wrong_clock(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Clock constraint can only be applied to Pins or DiffPairs, not " (r"^Clock constraint can only be applied to Pins or DiffPairs, not "
"(subsignal b (pins io A0))"): r"\(subsignal b \(pins io A0\)\)$")):
s = Subsignal("a", Subsignal("b", Pins("A0")), Clock(1e6)) s = Subsignal("a", Subsignal("b", Pins("A0")), Clock(1e6))
def test_wrong_clock_many(self): def test_wrong_clock_many(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Clock constraint can be applied only once"): r"^Clock constraint can be applied only once$"):
s = Subsignal("a", Pins("A0"), Clock(1e6), Clock(1e7)) s = Subsignal("a", Pins("A0"), Clock(1e6), Clock(1e7))
@ -309,20 +309,20 @@ class ConnectorTestCase(FHDLTestCase):
self.assertEqual(c.number, "A") self.assertEqual(c.number, "A")
def test_conn_wrong_name(self): def test_conn_wrong_name(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Connector must be None or a pair of string (connector name) and " (r"^Connector must be None or a pair of string \(connector name\) and "
"integer/string (connector number), not ('foo', None)"): r"integer\/string \(connector number\), not \('foo', None\)$")):
Connector("ext", "A", "0 1 2", conn=("foo", None)) Connector("ext", "A", "0 1 2", conn=("foo", None))
def test_wrong_io(self): def test_wrong_io(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Connector I/Os must be a dictionary or a string, not []"): r"^Connector I\/Os must be a dictionary or a string, not \[\]$"):
Connector("pmod", 0, []) Connector("pmod", 0, [])
def test_wrong_dict_key_value(self): def test_wrong_dict_key_value(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Connector pin name must be a string, not 0"): r"^Connector pin name must be a string, not 0$"):
Connector("pmod", 0, {0: "A"}) Connector("pmod", 0, {0: "A"})
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Platform pin name must be a string, not 0"): r"^Platform pin name must be a string, not 0$"):
Connector("pmod", 0, {"A": 0}) Connector("pmod", 0, {"A": 0})

View file

@ -36,17 +36,17 @@ class PlatformTestCase(FHDLTestCase):
self.assertEqual(self.platform.extra_files["x.txt"], f.read()) self.assertEqual(self.platform.extra_files["x.txt"], f.read())
def test_add_file_wrong_filename(self): def test_add_file_wrong_filename(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="File name must be a string, not 1"): r"^File name must be a string, not 1$"):
self.platform.add_file(1, "") self.platform.add_file(1, "")
def test_add_file_wrong_contents(self): def test_add_file_wrong_contents(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="File contents must be str, bytes, or a file-like object, not 1"): r"^File contents must be str, bytes, or a file-like object, not 1$"):
self.platform.add_file("foo", 1) self.platform.add_file("foo", 1)
def test_add_file_wrong_duplicate(self): def test_add_file_wrong_duplicate(self):
self.platform.add_file("foo", "") self.platform.add_file("foo", "")
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="File 'foo' already exists"): r"^File 'foo' already exists$"):
self.platform.add_file("foo", "bar") self.platform.add_file("foo", "bar")

View file

@ -208,43 +208,43 @@ class ResourceManagerTestCase(FHDLTestCase):
]) ])
def test_wrong_resources(self): def test_wrong_resources(self):
with self.assertRaises(TypeError, msg="Object 'wrong' is not a Resource"): with self.assertRaisesRegex(TypeError, r"^Object 'wrong' is not a Resource$"):
self.cm.add_resources(['wrong']) self.cm.add_resources(['wrong'])
def test_wrong_resources_duplicate(self): def test_wrong_resources_duplicate(self):
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Trying to add (resource user_led 0 (pins o A1)), but " (r"^Trying to add \(resource user_led 0 \(pins o A1\)\), but "
"(resource user_led 0 (pins o A0)) has the same name and number"): r"\(resource user_led 0 \(pins o A0\)\) has the same name and number$")):
self.cm.add_resources([Resource("user_led", 0, Pins("A1", dir="o"))]) self.cm.add_resources([Resource("user_led", 0, Pins("A1", dir="o"))])
def test_wrong_connectors(self): def test_wrong_connectors(self):
with self.assertRaises(TypeError, msg="Object 'wrong' is not a Connector"): with self.assertRaisesRegex(TypeError, r"^Object 'wrong' is not a Connector$"):
self.cm.add_connectors(['wrong']) self.cm.add_connectors(['wrong'])
def test_wrong_connectors_duplicate(self): def test_wrong_connectors_duplicate(self):
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Trying to add (connector pmod 0 1=>1 2=>2), but " (r"^Trying to add \(connector pmod 0 1=>1 2=>2\), but "
"(connector pmod 0 1=>B0 2=>B1 3=>B2 4=>B3) has the same name and number"): r"\(connector pmod 0 1=>B0 2=>B1 3=>B2 4=>B3\) has the same name and number$")):
self.cm.add_connectors([Connector("pmod", 0, "1 2")]) self.cm.add_connectors([Connector("pmod", 0, "1 2")])
def test_wrong_lookup(self): def test_wrong_lookup(self):
with self.assertRaises(ResourceError, with self.assertRaisesRegex(ResourceError,
msg="Resource user_led#1 does not exist"): r"^Resource user_led#1 does not exist$"):
r = self.cm.lookup("user_led", 1) r = self.cm.lookup("user_led", 1)
def test_wrong_clock_signal(self): def test_wrong_clock_signal(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Object None is not a Signal"): r"^Object None is not a Signal$"):
self.cm.add_clock_constraint(None, 10e6) self.cm.add_clock_constraint(None, 10e6)
def test_wrong_clock_frequency(self): def test_wrong_clock_frequency(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Frequency must be a number, not None"): r"^Frequency must be a number, not None$"):
self.cm.add_clock_constraint(Signal(), None) self.cm.add_clock_constraint(Signal(), None)
def test_wrong_request_duplicate(self): def test_wrong_request_duplicate(self):
with self.assertRaises(ResourceError, with self.assertRaisesRegex(ResourceError,
msg="Resource user_led#0 has already been requested"): r"^Resource user_led#0 has already been requested$"):
self.cm.request("user_led", 0) self.cm.request("user_led", 0)
self.cm.request("user_led", 0) self.cm.request("user_led", 0)
@ -253,46 +253,46 @@ class ResourceManagerTestCase(FHDLTestCase):
Resource("clk20", 0, Pins("H1", dir="i")), Resource("clk20", 0, Pins("H1", dir="i")),
]) ])
self.cm.request("clk100", 0) self.cm.request("clk100", 0)
with self.assertRaises(ResourceError, with self.assertRaisesRegex(ResourceError,
msg="Resource component clk20_0 uses physical pin H1, but it is already " (r"^Resource component clk20_0 uses physical pin H1, but it is already "
"used by resource component clk100_0 that was requested earlier"): r"used by resource component clk100_0 that was requested earlier$")):
self.cm.request("clk20", 0) self.cm.request("clk20", 0)
def test_wrong_request_with_dir(self): def test_wrong_request_with_dir(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Direction must be one of \"i\", \"o\", \"oe\", \"io\", or \"-\", " (r"^Direction must be one of \"i\", \"o\", \"oe\", \"io\", or \"-\", "
"not 'wrong'"): r"not 'wrong'$")):
user_led = self.cm.request("user_led", 0, dir="wrong") user_led = self.cm.request("user_led", 0, dir="wrong")
def test_wrong_request_with_dir_io(self): def test_wrong_request_with_dir_io(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Direction of (pins o A0) cannot be changed from \"o\" to \"i\"; direction " (r"^Direction of \(pins o A0\) cannot be changed from \"o\" to \"i\"; direction "
"can be changed from \"io\" to \"i\", \"o\", or \"oe\", or from anything " r"can be changed from \"io\" to \"i\", \"o\", or \"oe\", or from anything "
"to \"-\""): r"to \"-\"$")):
user_led = self.cm.request("user_led", 0, dir="i") user_led = self.cm.request("user_led", 0, dir="i")
def test_wrong_request_with_dir_dict(self): def test_wrong_request_with_dir_dict(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Directions must be a dict, not 'i', because (resource i2c 0 (subsignal scl " (r"^Directions must be a dict, not 'i', because \(resource i2c 0 \(subsignal scl "
"(pins o N10)) (subsignal sda (pins io N11))) " r"\(pins o N10\)\) \(subsignal sda \(pins io N11\)\)\) "
"has subsignals"): r"has subsignals$")):
i2c = self.cm.request("i2c", 0, dir="i") i2c = self.cm.request("i2c", 0, dir="i")
def test_wrong_request_with_wrong_xdr(self): def test_wrong_request_with_wrong_xdr(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Data rate of (pins o A0) must be a non-negative integer, not -1"): r"^Data rate of \(pins o A0\) must be a non-negative integer, not -1$"):
user_led = self.cm.request("user_led", 0, xdr=-1) user_led = self.cm.request("user_led", 0, xdr=-1)
def test_wrong_request_with_xdr_dict(self): def test_wrong_request_with_xdr_dict(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Data rate must be a dict, not 2, because (resource i2c 0 (subsignal scl " r"^Data rate must be a dict, not 2, because \(resource i2c 0 \(subsignal scl "
"(pins o N10)) (subsignal sda (pins io N11))) " r"\(pins o N10\)\) \(subsignal sda \(pins io N11\)\)\) "
"has subsignals"): r"has subsignals$"):
i2c = self.cm.request("i2c", 0, xdr=2) i2c = self.cm.request("i2c", 0, xdr=2)
def test_wrong_clock_constraint_twice(self): def test_wrong_clock_constraint_twice(self):
clk100 = self.cm.request("clk100") clk100 = self.cm.request("clk100")
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Cannot add clock constraint on (sig clk100_0__i), which is already " (r"^Cannot add clock constraint on \(sig clk100_0__i\), which is already "
"constrained to 100000000.0 Hz"): r"constrained to 100000000\.0 Hz$")):
self.cm.add_clock_constraint(clk100.i, 1e6) self.cm.add_clock_constraint(clk100.i, 1e6)

View file

@ -35,18 +35,18 @@ class ShapeTestCase(FHDLTestCase):
self.assertEqual(s3.signed, True) self.assertEqual(s3.signed, True)
def test_make_wrong(self): def test_make_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Width must be a non-negative integer, not -1"): r"^Width must be a non-negative integer, not -1$"):
Shape(-1) Shape(-1)
def test_compare_wrong(self): def test_compare_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shapes may be compared with other Shapes and (int, bool) tuples, not 'hi'"): r"^Shapes may be compared with other Shapes and \(int, bool\) tuples, not 'hi'$"):
Shape(1, True) == 'hi' Shape(1, True) == 'hi'
def test_compare_tuple_wrong(self): def test_compare_tuple_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shapes may be compared with other Shapes and (int, bool) tuples, not (2, 3)"): r"^Shapes may be compared with other Shapes and \(int, bool\) tuples, not \(2, 3\)$"):
Shape(1, True) == (2, 3) Shape(1, True) == (2, 3)
def test_repr(self): def test_repr(self):
@ -84,8 +84,8 @@ class ShapeTestCase(FHDLTestCase):
self.assertEqual(s1.signed, False) self.assertEqual(s1.signed, False)
def test_cast_int_wrong(self): def test_cast_int_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Width must be a non-negative integer, not -1"): r"^Width must be a non-negative integer, not -1$"):
Shape.cast(-1) Shape.cast(-1)
def test_cast_tuple(self): def test_cast_tuple(self):
@ -98,8 +98,8 @@ class ShapeTestCase(FHDLTestCase):
def test_cast_tuple_wrong(self): def test_cast_tuple_wrong(self):
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.filterwarnings(action="ignore", category=DeprecationWarning) warnings.filterwarnings(action="ignore", category=DeprecationWarning)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Width must be a non-negative integer, not -1"): r"^Width must be a non-negative integer, not -1$"):
Shape.cast((-1, True)) Shape.cast((-1, True))
def test_cast_range(self): def test_cast_range(self):
@ -134,13 +134,13 @@ class ShapeTestCase(FHDLTestCase):
self.assertEqual(s2.signed, True) self.assertEqual(s2.signed, True)
def test_cast_enum_bad(self): def test_cast_enum_bad(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Only enumerations with integer values can be used as value shapes"): r"^Only enumerations with integer values can be used as value shapes$"):
Shape.cast(StringEnum) Shape.cast(StringEnum)
def test_cast_bad(self): def test_cast_bad(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Object 'foo' cannot be used as value shape"): r"^Object 'foo' cannot be used as value shape$"):
Shape.cast("foo") Shape.cast("foo")
@ -150,8 +150,8 @@ class ValueTestCase(FHDLTestCase):
self.assertIsInstance(Value.cast(True), Const) self.assertIsInstance(Value.cast(True), Const)
c = Const(0) c = Const(0)
self.assertIs(Value.cast(c), c) self.assertIs(Value.cast(c), c)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Object 'str' cannot be converted to an nMigen value"): r"^Object 'str' cannot be converted to an nMigen value$"):
Value.cast("str") Value.cast("str")
def test_cast_enum(self): def test_cast_enum(self):
@ -163,13 +163,13 @@ class ValueTestCase(FHDLTestCase):
self.assertEqual(e2.shape(), signed(2)) self.assertEqual(e2.shape(), signed(2))
def test_cast_enum_wrong(self): def test_cast_enum_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Only enumerations with integer values can be used as value shapes"): r"^Only enumerations with integer values can be used as value shapes$"):
Value.cast(StringEnum.FOO) Value.cast(StringEnum.FOO)
def test_bool(self): def test_bool(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Attempted to convert nMigen value to Python boolean"): r"^Attempted to convert nMigen value to Python boolean$"):
if Const(0): if Const(0):
pass pass
@ -185,8 +185,8 @@ class ValueTestCase(FHDLTestCase):
self.assertIsInstance(s2, Slice) self.assertIsInstance(s2, Slice)
self.assertEqual(s2.start, 3) self.assertEqual(s2.start, 3)
self.assertEqual(s2.stop, 4) self.assertEqual(s2.stop, 4)
with self.assertRaises(IndexError, with self.assertRaisesRegex(IndexError,
msg="Cannot index 5 bits into 4-bit value"): r"^Cannot index 5 bits into 4-bit value$"):
Const(10)[5] Const(10)[5]
def test_getitem_slice(self): def test_getitem_slice(self):
@ -211,8 +211,8 @@ class ValueTestCase(FHDLTestCase):
self.assertEqual(s3.parts[2].stop, 5) self.assertEqual(s3.parts[2].stop, 5)
def test_getitem_wrong(self): def test_getitem_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Cannot index value with 'str'"): r"^Cannot index value with 'str'$"):
Const(31)["str"] Const(31)["str"]
def test_shift_left(self): def test_shift_left(self):
@ -240,8 +240,8 @@ class ValueTestCase(FHDLTestCase):
"(s (slice (const 9'sd-256) 9:9))") "(s (slice (const 9'sd-256) 9:9))")
def test_shift_left_wrong(self): def test_shift_left_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shift amount must be an integer, not 'str'"): r"^Shift amount must be an integer, not 'str'$"):
Const(31).shift_left("str") Const(31).shift_left("str")
def test_shift_right(self): def test_shift_right(self):
@ -269,8 +269,8 @@ class ValueTestCase(FHDLTestCase):
"(s (slice (const 9'sd-256) 9:9))") "(s (slice (const 9'sd-256) 9:9))")
def test_shift_right_wrong(self): def test_shift_right_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shift amount must be an integer, not 'str'"): r"^Shift amount must be an integer, not 'str'$"):
Const(31).shift_left("str") Const(31).shift_left("str")
def test_rotate_left(self): def test_rotate_left(self):
@ -284,8 +284,8 @@ class ValueTestCase(FHDLTestCase):
"(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))") "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
def test_rotate_left_wrong(self): def test_rotate_left_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Rotate amount must be an integer, not 'str'"): r"^Rotate amount must be an integer, not 'str'$"):
Const(31).rotate_left("str") Const(31).rotate_left("str")
def test_rotate_right(self): def test_rotate_right(self):
@ -299,8 +299,8 @@ class ValueTestCase(FHDLTestCase):
"(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))") "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
def test_rotate_right_wrong(self): def test_rotate_right_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Rotate amount must be an integer, not 'str'"): r"^Rotate amount must be an integer, not 'str'$"):
Const(31).rotate_right("str") Const(31).rotate_right("str")
@ -318,8 +318,8 @@ class ConstTestCase(FHDLTestCase):
self.assertEqual(Const(0, unsigned(0)).shape(), unsigned(0)) self.assertEqual(Const(0, unsigned(0)).shape(), unsigned(0))
def test_shape_wrong(self): def test_shape_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Width must be a non-negative integer, not -1"): r"^Width must be a non-negative integer, not -1$"):
Const(1, -1) Const(1, -1)
def test_normalization(self): def test_normalization(self):
@ -413,8 +413,8 @@ class OperatorTestCase(FHDLTestCase):
self.assertEqual(v5.shape(), unsigned(4)) self.assertEqual(v5.shape(), unsigned(4))
def test_mod_wrong(self): def test_mod_wrong(self):
with self.assertRaises(NotImplementedError, with self.assertRaisesRegex(NotImplementedError,
msg="Division by a signed value is not supported"): r"^Division by a signed value is not supported$"):
Const(0, signed(4)) % Const(0, signed(6)) Const(0, signed(4)) % Const(0, signed(6))
def test_floordiv(self): def test_floordiv(self):
@ -427,8 +427,8 @@ class OperatorTestCase(FHDLTestCase):
self.assertEqual(v5.shape(), unsigned(4)) self.assertEqual(v5.shape(), unsigned(4))
def test_floordiv_wrong(self): def test_floordiv_wrong(self):
with self.assertRaises(NotImplementedError, with self.assertRaisesRegex(NotImplementedError,
msg="Division by a signed value is not supported"): r"^Division by a signed value is not supported$"):
Const(0, signed(4)) // Const(0, signed(6)) Const(0, signed(4)) // Const(0, signed(6))
def test_and(self): def test_and(self):
@ -476,11 +476,11 @@ class OperatorTestCase(FHDLTestCase):
self.assertEqual(v1.shape(), unsigned(11)) self.assertEqual(v1.shape(), unsigned(11))
def test_shl_wrong(self): def test_shl_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shift amount must be unsigned"): r"^Shift amount must be unsigned$"):
1 << Const(0, signed(6)) 1 << Const(0, signed(6))
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shift amount must be unsigned"): r"^Shift amount must be unsigned$"):
Const(1, unsigned(4)) << -1 Const(1, unsigned(4)) << -1
def test_shr(self): def test_shr(self):
@ -489,11 +489,11 @@ class OperatorTestCase(FHDLTestCase):
self.assertEqual(v1.shape(), unsigned(4)) self.assertEqual(v1.shape(), unsigned(4))
def test_shr_wrong(self): def test_shr_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shift amount must be unsigned"): r"^Shift amount must be unsigned$"):
1 << Const(0, signed(6)) 1 << Const(0, signed(6))
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Shift amount must be unsigned"): r"^Shift amount must be unsigned$"):
Const(1, unsigned(4)) << -1 Const(1, unsigned(4)) << -1
def test_lt(self): def test_lt(self):
@ -588,25 +588,25 @@ class OperatorTestCase(FHDLTestCase):
def test_matches_width_wrong(self): def test_matches_width_wrong(self):
s = Signal(4) s = Signal(4)
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Match pattern '--' must have the same width as match value (which is 4)"): r"^Match pattern '--' must have the same width as match value \(which is 4\)$"):
s.matches("--") s.matches("--")
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Match pattern '10110' is wider than match value (which has width 4); " (r"^Match pattern '10110' is wider than match value \(which has width 4\); "
"comparison will never be true"): r"comparison will never be true$")):
s.matches(0b10110) s.matches(0b10110)
def test_matches_bits_wrong(self): def test_matches_bits_wrong(self):
s = Signal(4) s = Signal(4)
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Match pattern 'abc' must consist of 0, 1, and - (don't care) bits, " (r"^Match pattern 'abc' must consist of 0, 1, and - \(don't care\) bits, "
"and may include whitespace"): r"and may include whitespace$")):
s.matches("abc") s.matches("abc")
def test_matches_pattern_wrong(self): def test_matches_pattern_wrong(self):
s = Signal(4) s = Signal(4)
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Match pattern must be an integer, a string, or an enumeration, not 1.0"): r"^Match pattern must be an integer, a string, or an enumeration, not 1\.0$"):
s.matches(1.0) s.matches(1.0)
def test_hash(self): def test_hash(self):
@ -630,23 +630,23 @@ class SliceTestCase(FHDLTestCase):
self.assertEqual((s1.start, s1.stop), (4, 7)) self.assertEqual((s1.start, s1.stop), (4, 7))
def test_start_end_wrong(self): def test_start_end_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Slice start must be an integer, not 'x'"): r"^Slice start must be an integer, not 'x'$"):
Slice(0, "x", 1) Slice(0, "x", 1)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Slice stop must be an integer, not 'x'"): r"^Slice stop must be an integer, not 'x'$"):
Slice(0, 1, "x") Slice(0, 1, "x")
def test_start_end_out_of_range(self): def test_start_end_out_of_range(self):
c = Const(0, 8) c = Const(0, 8)
with self.assertRaises(IndexError, with self.assertRaisesRegex(IndexError,
msg="Cannot start slice 10 bits into 8-bit value"): r"^Cannot start slice 10 bits into 8-bit value$"):
Slice(c, 10, 12) Slice(c, 10, 12)
with self.assertRaises(IndexError, with self.assertRaisesRegex(IndexError,
msg="Cannot stop slice 12 bits into 8-bit value"): r"^Cannot stop slice 12 bits into 8-bit value$"):
Slice(c, 0, 12) Slice(c, 0, 12)
with self.assertRaises(IndexError, with self.assertRaisesRegex(IndexError,
msg="Slice start 4 must be less than slice stop 2"): r"^Slice start 4 must be less than slice stop 2$"):
Slice(c, 4, 2) Slice(c, 4, 2)
def test_repr(self): def test_repr(self):
@ -842,8 +842,8 @@ class SignalTestCase(FHDLTestCase):
self.assertEqual(s11.shape(), unsigned(1)) self.assertEqual(s11.shape(), unsigned(1))
def test_shape_wrong(self): def test_shape_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Width must be a non-negative integer, not -10"): r"^Width must be a non-negative integer, not -10$"):
Signal(-10) Signal(-10)
def test_name(self): def test_name(self):
@ -860,20 +860,20 @@ class SignalTestCase(FHDLTestCase):
def test_reset_enum(self): def test_reset_enum(self):
s1 = Signal(2, reset=UnsignedEnum.BAR) s1 = Signal(2, reset=UnsignedEnum.BAR)
self.assertEqual(s1.reset, 2) self.assertEqual(s1.reset, 2)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Reset value has to be an int or an integral Enum" r"^Reset value has to be an int or an integral Enum$"
): ):
Signal(1, reset=StringEnum.FOO) Signal(1, reset=StringEnum.FOO)
def test_reset_narrow(self): def test_reset_narrow(self):
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Reset value 8 requires 4 bits to represent, but the signal only has 3 bits"): r"^Reset value 8 requires 4 bits to represent, but the signal only has 3 bits$"):
Signal(3, reset=8) Signal(3, reset=8)
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Reset value 4 requires 4 bits to represent, but the signal only has 3 bits"): r"^Reset value 4 requires 4 bits to represent, but the signal only has 3 bits$"):
Signal(signed(3), reset=4) Signal(signed(3), reset=4)
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Reset value -5 requires 4 bits to represent, but the signal only has 3 bits"): r"^Reset value -5 requires 4 bits to represent, but the signal only has 3 bits$"):
Signal(signed(3), reset=-5) Signal(signed(3), reset=-5)
def test_attrs(self): def test_attrs(self):
@ -928,8 +928,8 @@ class ClockSignalTestCase(FHDLTestCase):
s2 = ClockSignal("pix") s2 = ClockSignal("pix")
self.assertEqual(s2.domain, "pix") self.assertEqual(s2.domain, "pix")
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Clock domain name must be a string, not 1"): r"^Clock domain name must be a string, not 1$"):
ClockSignal(1) ClockSignal(1)
def test_shape(self): def test_shape(self):
@ -942,8 +942,8 @@ class ClockSignalTestCase(FHDLTestCase):
self.assertEqual(repr(s1), "(clk sync)") self.assertEqual(repr(s1), "(clk sync)")
def test_wrong_name_comb(self): def test_wrong_name_comb(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain 'comb' does not have a clock"): r"^Domain 'comb' does not have a clock$"):
ClockSignal("comb") ClockSignal("comb")
@ -954,8 +954,8 @@ class ResetSignalTestCase(FHDLTestCase):
s2 = ResetSignal("pix") s2 = ResetSignal("pix")
self.assertEqual(s2.domain, "pix") self.assertEqual(s2.domain, "pix")
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Clock domain name must be a string, not 1"): r"^Clock domain name must be a string, not 1$"):
ResetSignal(1) ResetSignal(1)
def test_shape(self): def test_shape(self):
@ -968,8 +968,8 @@ class ResetSignalTestCase(FHDLTestCase):
self.assertEqual(repr(s1), "(rst sync)") self.assertEqual(repr(s1), "(rst sync)")
def test_wrong_name_comb(self): def test_wrong_name_comb(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain 'comb' does not have a reset"): r"^Domain 'comb' does not have a reset$"):
ResetSignal("comb") ResetSignal("comb")
@ -1014,19 +1014,19 @@ class SampleTestCase(FHDLTestCase):
s3 = Sample(ResetSignal(), 1, "sync") s3 = Sample(ResetSignal(), 1, "sync")
def test_wrong_value_operator(self): def test_wrong_value_operator(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
"Sampled value must be a signal or a constant, not " (r"^Sampled value must be a signal or a constant, not "
"(+ (sig $signal) (const 1'd1))"): r"\(\+ \(sig \$signal\) \(const 1'd1\)\)$")):
Sample(Signal() + 1, 1, "sync") Sample(Signal() + 1, 1, "sync")
def test_wrong_clocks_neg(self): def test_wrong_clocks_neg(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
"Cannot sample a value 1 cycles in the future"): r"^Cannot sample a value 1 cycles in the future$"):
Sample(Signal(), -1, "sync") Sample(Signal(), -1, "sync")
def test_wrong_domain(self): def test_wrong_domain(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
"Domain name must be a string or None, not 0"): r"^Domain name must be a string or None, not 0$"):
Sample(Signal(), 1, 0) Sample(Signal(), 1, 0)

View file

@ -17,8 +17,8 @@ class ClockDomainTestCase(FHDLTestCase):
self.assertEqual(pix.name, "pix") self.assertEqual(pix.name, "pix")
dom = [ClockDomain("foo")][0] dom = [ClockDomain("foo")][0]
self.assertEqual(dom.name, "foo") self.assertEqual(dom.name, "foo")
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Clock domain name must be specified explicitly"): r"^Clock domain name must be specified explicitly$"):
ClockDomain() ClockDomain()
cd_reset = ClockDomain(local=True) cd_reset = ClockDomain(local=True)
self.assertEqual(cd_reset.local, True) self.assertEqual(cd_reset.local, True)
@ -32,8 +32,8 @@ class ClockDomainTestCase(FHDLTestCase):
self.assertEqual(sync.clk_edge, "neg") self.assertEqual(sync.clk_edge, "neg")
def test_edge_wrong(self): def test_edge_wrong(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain clock edge must be one of 'pos' or 'neg', not 'xxx'"): r"^Domain clock edge must be one of 'pos' or 'neg', not 'xxx'$"):
ClockDomain("sync", clk_edge="xxx") ClockDomain("sync", clk_edge="xxx")
def test_with_reset(self): def test_with_reset(self):
@ -73,6 +73,6 @@ class ClockDomainTestCase(FHDLTestCase):
self.assertEqual(sync.clk.name, "pix_clk") self.assertEqual(sync.clk.name, "pix_clk")
def test_wrong_name_comb(self): def test_wrong_name_comb(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain 'comb' may not be clocked"): r"^Domain 'comb' may not be clocked$"):
comb = ClockDomain() comb = ClockDomain()

View file

@ -20,9 +20,9 @@ class DSLTestCase(FHDLTestCase):
self.w1 = Signal(4) self.w1 = Signal(4)
def test_cant_inherit(self): def test_cant_inherit(self):
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Instead of inheriting from `Module`, inherit from `Elaboratable` and " (r"^Instead of inheriting from `Module`, inherit from `Elaboratable` and "
"return a `Module` from the `elaborate(self, platform)` method"): r"return a `Module` from the `elaborate\(self, platform\)` method$")):
class ORGate(Module): class ORGate(Module):
pass pass
@ -69,47 +69,47 @@ class DSLTestCase(FHDLTestCase):
def test_d_conflict(self): def test_d_conflict(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Driver-driver conflict: trying to drive (sig c1) from d.sync, but it " (r"^Driver-driver conflict: trying to drive \(sig c1\) from d\.sync, but it "
"is already driven from d.comb"): r"is already driven from d\.comb$")):
m.d.comb += self.c1.eq(1) m.d.comb += self.c1.eq(1)
m.d.sync += self.c1.eq(1) m.d.sync += self.c1.eq(1)
def test_d_wrong(self): def test_d_wrong(self):
m = Module() m = Module()
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Cannot assign 'd.pix' attribute; did you mean 'd.pix +='?"): r"^Cannot assign 'd\.pix' attribute; did you mean 'd.pix \+='\?$"):
m.d.pix = None m.d.pix = None
def test_d_asgn_wrong(self): def test_d_asgn_wrong(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Only assignments and property checks may be appended to d.sync"): r"^Only assignments and property checks may be appended to d\.sync$"):
m.d.sync += Switch(self.s1, {}) m.d.sync += Switch(self.s1, {})
def test_comb_wrong(self): def test_comb_wrong(self):
m = Module() m = Module()
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="'Module' object has no attribute 'comb'; did you mean 'd.comb'?"): r"^'Module' object has no attribute 'comb'; did you mean 'd\.comb'\?$"):
m.comb += self.c1.eq(1) m.comb += self.c1.eq(1)
def test_sync_wrong(self): def test_sync_wrong(self):
m = Module() m = Module()
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="'Module' object has no attribute 'sync'; did you mean 'd.sync'?"): r"^'Module' object has no attribute 'sync'; did you mean 'd\.sync'\?$"):
m.sync += self.c1.eq(1) m.sync += self.c1.eq(1)
def test_attr_wrong(self): def test_attr_wrong(self):
m = Module() m = Module()
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="'Module' object has no attribute 'nonexistentattr'"): r"^'Module' object has no attribute 'nonexistentattr'$"):
m.nonexistentattr m.nonexistentattr
def test_d_suspicious(self): def test_d_suspicious(self):
m = Module() m = Module()
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Using '<module>.d.submodules' would add statements to clock domain " (r"^Using '<module>\.d\.submodules' would add statements to clock domain "
"'submodules'; did you mean <module>.submodules instead?"): r"'submodules'; did you mean <module>\.submodules instead\?$")):
m.d.submodules += [] m.d.submodules += []
def test_clock_signal(self): def test_clock_signal(self):
@ -260,15 +260,15 @@ class DSLTestCase(FHDLTestCase):
def test_Elif_wrong(self): def test_Elif_wrong(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Elif without preceding If"): r"^Elif without preceding If$"):
with m.Elif(self.s2): with m.Elif(self.s2):
pass pass
def test_Else_wrong(self): def test_Else_wrong(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Else without preceding If/Elif"): r"^Else without preceding If\/Elif$"):
with m.Else(): with m.Else():
pass pass
@ -287,11 +287,11 @@ class DSLTestCase(FHDLTestCase):
def test_If_signed_suspicious(self): def test_If_signed_suspicious(self):
m = Module() m = Module()
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Signed values in If/Elif conditions usually result from inverting Python " (r"^Signed values in If\/Elif conditions usually result from inverting Python "
"booleans with ~, which leads to unexpected results. Replace `~flag` with " r"booleans with ~, which leads to unexpected results\. Replace `~flag` with "
"`not flag`. (If this is a false positive, silence this warning with " r"`not flag`\. \(If this is a false positive, silence this warning with "
"`m.If(x)` → `m.If(x.bool())`.)"): r"`m\.If\(x\)` → `m\.If\(x\.bool\(\)\)`\.\)$")):
with m.If(~True): with m.If(~True):
pass pass
@ -299,28 +299,28 @@ class DSLTestCase(FHDLTestCase):
m = Module() m = Module()
with m.If(0): with m.If(0):
pass pass
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Signed values in If/Elif conditions usually result from inverting Python " (r"^Signed values in If\/Elif conditions usually result from inverting Python "
"booleans with ~, which leads to unexpected results. Replace `~flag` with " r"booleans with ~, which leads to unexpected results\. Replace `~flag` with "
"`not flag`. (If this is a false positive, silence this warning with " r"`not flag`\. \(If this is a false positive, silence this warning with "
"`m.If(x)` → `m.If(x.bool())`.)"): r"`m\.If\(x\)` → `m\.If\(x\.bool\(\)\)`\.\)$")):
with m.Elif(~True): with m.Elif(~True):
pass pass
def test_if_If_Elif_Else(self): def test_if_If_Elif_Else(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="`if m.If(...):` does not work; use `with m.If(...)`"): r"^`if m\.If\(\.\.\.\):` does not work; use `with m\.If\(\.\.\.\)`$"):
if m.If(0): if m.If(0):
pass pass
with m.If(0): with m.If(0):
pass pass
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="`if m.Elif(...):` does not work; use `with m.Elif(...)`"): r"^`if m\.Elif\(\.\.\.\):` does not work; use `with m\.Elif\(\.\.\.\)`$"):
if m.Elif(0): if m.Elif(0):
pass pass
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="`if m.Else(...):` does not work; use `with m.Else(...)`"): r"^`if m\.Else\(\.\.\.\):` does not work; use `with m\.Else\(\.\.\.\)`$"):
if m.Else(): if m.Else():
pass pass
@ -414,18 +414,18 @@ class DSLTestCase(FHDLTestCase):
RED = 0b10101010 RED = 0b10101010
m = Module() m = Module()
with m.Switch(self.w1): with m.Switch(self.w1):
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Case pattern '--' must have the same width as switch value (which is 4)"): r"^Case pattern '--' must have the same width as switch value \(which is 4\)$"):
with m.Case("--"): with m.Case("--"):
pass pass
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Case pattern '10110' is wider than switch value (which has width 4); " (r"^Case pattern '10110' is wider than switch value \(which has width 4\); "
"comparison will never be true"): r"comparison will never be true$")):
with m.Case(0b10110): with m.Case(0b10110):
pass pass
with self.assertWarns(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
msg="Case pattern '10101010' (Color.RED) is wider than switch value " (r"^Case pattern '10101010' \(Color\.RED\) is wider than switch value "
"(which has width 4); comparison will never be true"): r"\(which has width 4\); comparison will never be true$")):
with m.Case(Color.RED): with m.Case(Color.RED):
pass pass
self.assertRepr(m._statements, """ self.assertRepr(m._statements, """
@ -437,33 +437,33 @@ class DSLTestCase(FHDLTestCase):
def test_Case_bits_wrong(self): def test_Case_bits_wrong(self):
m = Module() m = Module()
with m.Switch(self.w1): with m.Switch(self.w1):
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Case pattern 'abc' must consist of 0, 1, and - (don't care) bits, " (r"^Case pattern 'abc' must consist of 0, 1, and - \(don't care\) bits, "
"and may include whitespace"): r"and may include whitespace$")):
with m.Case("abc"): with m.Case("abc"):
pass pass
def test_Case_pattern_wrong(self): def test_Case_pattern_wrong(self):
m = Module() m = Module()
with m.Switch(self.w1): with m.Switch(self.w1):
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Case pattern must be an integer, a string, or an enumeration, not 1.0"): r"^Case pattern must be an integer, a string, or an enumeration, not 1\.0$"):
with m.Case(1.0): with m.Case(1.0):
pass pass
def test_Case_outside_Switch_wrong(self): def test_Case_outside_Switch_wrong(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Case is not permitted outside of Switch"): r"^Case is not permitted outside of Switch$"):
with m.Case(): with m.Case():
pass pass
def test_If_inside_Switch_wrong(self): def test_If_inside_Switch_wrong(self):
m = Module() m = Module()
with m.Switch(self.s1): with m.Switch(self.s1):
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="If is not permitted directly inside of Switch; " (r"^If is not permitted directly inside of Switch; "
"it is permitted inside of Switch Case"): r"it is permitted inside of Switch Case$")):
with m.If(self.s2): with m.If(self.s2):
pass pass
@ -577,15 +577,15 @@ class DSLTestCase(FHDLTestCase):
def test_FSM_wrong_domain(self): def test_FSM_wrong_domain(self):
m = Module() m = Module()
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="FSM may not be driven by the 'comb' domain"): r"^FSM may not be driven by the 'comb' domain$"):
with m.FSM(domain="comb"): with m.FSM(domain="comb"):
pass pass
def test_FSM_wrong_undefined(self): def test_FSM_wrong_undefined(self):
m = Module() m = Module()
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="FSM state 'FOO' is referenced but not defined"): r"^FSM state 'FOO' is referenced but not defined$"):
with m.FSM() as fsm: with m.FSM() as fsm:
fsm.ongoing("FOO") fsm.ongoing("FOO")
@ -594,21 +594,21 @@ class DSLTestCase(FHDLTestCase):
with m.FSM(): with m.FSM():
with m.State("FOO"): with m.State("FOO"):
pass pass
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="FSM state 'FOO' is already defined"): r"^FSM state 'FOO' is already defined$"):
with m.State("FOO"): with m.State("FOO"):
pass pass
def test_FSM_wrong_next(self): def test_FSM_wrong_next(self):
m = Module() m = Module()
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="Only assignment to `m.next` is permitted"): r"^Only assignment to `m\.next` is permitted$"):
m.next m.next
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="`m.next = <...>` is only permitted inside an FSM state"): r"^`m\.next = <\.\.\.>` is only permitted inside an FSM state$"):
m.next = "FOO" m.next = "FOO"
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="`m.next = <...>` is only permitted inside an FSM state"): r"^`m\.next = <\.\.\.>` is only permitted inside an FSM state$"):
with m.FSM(): with m.FSM():
m.next = "FOO" m.next = "FOO"
@ -617,9 +617,9 @@ class DSLTestCase(FHDLTestCase):
with m.FSM(): with m.FSM():
with m.State("FOO"): with m.State("FOO"):
pass pass
with self.assertRaises(SyntaxError, with self.assertRaisesRegex(SyntaxError,
msg="If is not permitted directly inside of FSM; " (r"^If is not permitted directly inside of FSM; "
"it is permitted inside of FSM State"): r"it is permitted inside of FSM State$")):
with m.If(self.s2): with m.If(self.s2):
pass pass
@ -668,18 +668,18 @@ class DSLTestCase(FHDLTestCase):
def test_submodule_wrong(self): def test_submodule_wrong(self):
m = Module() m = Module()
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Trying to add 1, which does not implement .elaborate(), as a submodule"): r"^Trying to add 1, which does not implement \.elaborate\(\), as a submodule$"):
m.submodules.foo = 1 m.submodules.foo = 1
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Trying to add 1, which does not implement .elaborate(), as a submodule"): r"^Trying to add 1, which does not implement \.elaborate\(\), as a submodule$"):
m.submodules += 1 m.submodules += 1
def test_submodule_named_conflict(self): def test_submodule_named_conflict(self):
m1 = Module() m1 = Module()
m2 = Module() m2 = Module()
m1.submodules.foo = m2 m1.submodules.foo = m2
with self.assertRaises(NameError, msg="Submodule named 'foo' already exists"): with self.assertRaisesRegex(NameError, r"^Submodule named 'foo' already exists$"):
m1.submodules.foo = m2 m1.submodules.foo = m2
def test_submodule_get(self): def test_submodule_get(self):
@ -698,9 +698,9 @@ class DSLTestCase(FHDLTestCase):
def test_submodule_get_unset(self): def test_submodule_get_unset(self):
m1 = Module() m1 = Module()
with self.assertRaises(AttributeError, msg="No submodule named 'foo' exists"): with self.assertRaisesRegex(AttributeError, r"^No submodule named 'foo' exists$"):
m2 = m1.submodules.foo m2 = m1.submodules.foo
with self.assertRaises(AttributeError, msg="No submodule named 'foo' exists"): with self.assertRaisesRegex(AttributeError, r"^No submodule named 'foo' exists$"):
m2 = m1.submodules["foo"] m2 = m1.submodules["foo"]
def test_domain_named_implicit(self): def test_domain_named_implicit(self):
@ -716,24 +716,24 @@ class DSLTestCase(FHDLTestCase):
def test_domain_add_wrong(self): def test_domain_add_wrong(self):
m = Module() m = Module()
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Only clock domains may be added to `m.domains`, not 1"): r"^Only clock domains may be added to `m\.domains`, not 1$"):
m.domains.foo = 1 m.domains.foo = 1
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Only clock domains may be added to `m.domains`, not 1"): r"^Only clock domains may be added to `m\.domains`, not 1$"):
m.domains += 1 m.domains += 1
def test_domain_add_wrong_name(self): def test_domain_add_wrong_name(self):
m = Module() m = Module()
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Clock domain name 'bar' must match name in `m.domains.foo += ...` syntax"): r"^Clock domain name 'bar' must match name in `m\.domains\.foo \+= \.\.\.` syntax$"):
m.domains.foo = ClockDomain("bar") m.domains.foo = ClockDomain("bar")
def test_domain_add_wrong_duplicate(self): def test_domain_add_wrong_duplicate(self):
m = Module() m = Module()
m.domains += ClockDomain("foo") m.domains += ClockDomain("foo")
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Clock domain named 'foo' already exists"): r"^Clock domain named 'foo' already exists$"):
m.domains += ClockDomain("foo") m.domains += ClockDomain("foo")
def test_lower(self): def test_lower(self):

View file

@ -16,14 +16,14 @@ class BadElaboratable(Elaboratable):
class FragmentGetTestCase(FHDLTestCase): class FragmentGetTestCase(FHDLTestCase):
def test_get_wrong(self): def test_get_wrong(self):
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Object None cannot be elaborated"): r"^Object None cannot be elaborated$"):
Fragment.get(None, platform=None) Fragment.get(None, platform=None)
with self.assertWarns(UserWarning, with self.assertWarnsRegex(UserWarning,
msg=".elaborate() returned None; missing return statement?"): r"^\.elaborate\(\) returned None; missing return statement\?$"):
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Object None cannot be elaborated"): r"^Object None cannot be elaborated$"):
Fragment.get(BadElaboratable(), platform=None) Fragment.get(BadElaboratable(), platform=None)
@ -41,11 +41,11 @@ class FragmentGeneratedTestCase(FHDLTestCase):
f2 = Fragment() f2 = Fragment()
f1.add_subfragment(f2, "f2") f1.add_subfragment(f2, "f2")
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="No subfragment at index #1"): r"^No subfragment at index #1$"):
f1.find_subfragment(1) f1.find_subfragment(1)
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="No subfragment with name 'fx'"): r"^No subfragment with name 'fx'$"):
f1.find_subfragment("fx") f1.find_subfragment("fx")
def test_find_generated(self): def test_find_generated(self):
@ -300,18 +300,18 @@ class FragmentPortsTestCase(FHDLTestCase):
def test_port_wrong(self): def test_port_wrong(self):
f = Fragment() f = Fragment()
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Only signals may be added as ports, not (const 1'd1)"): r"^Only signals may be added as ports, not \(const 1'd1\)$"):
f.prepare(ports=(Const(1),)) f.prepare(ports=(Const(1),))
def test_port_not_iterable(self): def test_port_not_iterable(self):
f = Fragment() f = Fragment()
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="`ports` must be either a list or a tuple, not 1"): r"^`ports` must be either a list or a tuple, not 1$"):
f.prepare(ports=1) f.prepare(ports=1)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="`ports` must be either a list or a tuple, not (const 1'd1)" + (r"^`ports` must be either a list or a tuple, not \(const 1'd1\)"
" (did you mean `ports=(<signal>,)`, rather than `ports=<signal>`?)"): r" \(did you mean `ports=\(<signal>,\)`, rather than `ports=<signal>`\?\)$")):
f.prepare(ports=Const(1)) f.prepare(ports=Const(1))
class FragmentDomainsTestCase(FHDLTestCase): class FragmentDomainsTestCase(FHDLTestCase):
@ -380,10 +380,10 @@ class FragmentDomainsTestCase(FHDLTestCase):
f.add_subfragment(fa, "a") f.add_subfragment(fa, "a")
f.add_subfragment(fb) f.add_subfragment(fb)
with self.assertRaises(DomainError, with self.assertRaisesRegex(DomainError,
msg="Domain 'sync' is defined by subfragments 'a', <unnamed #1> of fragment " (r"^Domain 'sync' is defined by subfragments 'a', <unnamed #1> of fragment "
"'top'; it is necessary to either rename subfragment domains explicitly, " r"'top'; it is necessary to either rename subfragment domains explicitly, "
"or give names to subfragments"): r"or give names to subfragments$")):
f._propagate_domains_up() f._propagate_domains_up()
def test_domain_conflict_name(self): def test_domain_conflict_name(self):
@ -398,10 +398,10 @@ class FragmentDomainsTestCase(FHDLTestCase):
f.add_subfragment(fa, "x") f.add_subfragment(fa, "x")
f.add_subfragment(fb, "x") f.add_subfragment(fb, "x")
with self.assertRaises(DomainError, with self.assertRaisesRegex(DomainError,
msg="Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some " (r"^Domain 'sync' is defined by subfragments #0, #1 of fragment 'top', some "
"of which have identical names; it is necessary to either rename subfragment " r"of which have identical names; it is necessary to either rename subfragment "
"domains explicitly, or give distinct names to subfragments"): r"domains explicitly, or give distinct names to subfragments$")):
f._propagate_domains_up() f._propagate_domains_up()
def test_domain_conflict_rename_drivers(self): def test_domain_conflict_rename_drivers(self):
@ -481,8 +481,8 @@ class FragmentDomainsTestCase(FHDLTestCase):
f1 = Fragment() f1 = Fragment()
f1.add_driver(s1, "sync") f1.add_driver(s1, "sync")
with self.assertRaises(DomainError, with self.assertRaisesRegex(DomainError,
msg="Domain 'sync' is used but not defined"): r"^Domain 'sync' is used but not defined$"):
f1._propagate_domains(missing_domain=lambda name: None) f1._propagate_domains(missing_domain=lambda name: None)
def test_propagate_create_missing(self): def test_propagate_create_missing(self):
@ -542,9 +542,9 @@ class FragmentDomainsTestCase(FHDLTestCase):
f2 = Fragment() f2 = Fragment()
f2.add_domains(ClockDomain("foo")) f2.add_domains(ClockDomain("foo"))
with self.assertRaises(DomainError, with self.assertRaisesRegex(DomainError,
msg="Fragment returned by missing domain callback does not define requested " (r"^Fragment returned by missing domain callback does not define requested "
"domain 'sync' (defines 'foo')."): r"domain 'sync' \(defines 'foo'\)\.$")):
f1._propagate_domains(missing_domain=lambda name: f2) f1._propagate_domains(missing_domain=lambda name: f2)
@ -597,16 +597,16 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
def test_conflict_self_sub_error(self): def test_conflict_self_sub_error(self):
self.setUp_self_sub() self.setUp_self_sub()
with self.assertRaises(DriverConflict, with self.assertRaisesRegex(DriverConflict,
msg="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>"): r"^Signal '\(sig s1\)' is driven from multiple fragments: top, top.<unnamed #1>$"):
self.f1._resolve_hierarchy_conflicts(mode="error") self.f1._resolve_hierarchy_conflicts(mode="error")
def test_conflict_self_sub_warning(self): def test_conflict_self_sub_warning(self):
self.setUp_self_sub() self.setUp_self_sub()
with self.assertWarns(DriverConflict, with self.assertWarnsRegex(DriverConflict,
msg="Signal '(sig s1)' is driven from multiple fragments: top, top.<unnamed #1>; " (r"^Signal '\(sig s1\)' is driven from multiple fragments: top, top.<unnamed #1>; "
"hierarchy will be flattened"): r"hierarchy will be flattened$")):
self.f1._resolve_hierarchy_conflicts(mode="warn") self.f1._resolve_hierarchy_conflicts(mode="warn")
def setUp_sub_sub(self): def setUp_sub_sub(self):
@ -691,17 +691,17 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
def test_conflict_memory_error(self): def test_conflict_memory_error(self):
self.setUp_memory() self.setUp_memory()
with self.assertRaises(DriverConflict, with self.assertRaisesRegex(DriverConflict,
msg="Memory 'm' is accessed from multiple fragments: top.<unnamed #0>, " r"^Memory 'm' is accessed from multiple fragments: top\.<unnamed #0>, "
"top.<unnamed #1>"): r"top\.<unnamed #1>$"):
self.f1._resolve_hierarchy_conflicts(mode="error") self.f1._resolve_hierarchy_conflicts(mode="error")
def test_conflict_memory_warning(self): def test_conflict_memory_warning(self):
self.setUp_memory() self.setUp_memory()
with self.assertWarns(DriverConflict, with self.assertWarnsRegex(DriverConflict,
msg="Memory 'm' is accessed from multiple fragments: top.<unnamed #0>, " (r"^Memory 'm' is accessed from multiple fragments: top.<unnamed #0>, "
"top.<unnamed #1>; hierarchy will be flattened"): r"top.<unnamed #1>; hierarchy will be flattened$")):
self.f1._resolve_hierarchy_conflicts(mode="warn") self.f1._resolve_hierarchy_conflicts(mode="warn")
def test_explicit_flatten(self): def test_explicit_flatten(self):
@ -783,16 +783,16 @@ class InstanceTestCase(FHDLTestCase):
def test_wrong_construct_arg(self): def test_wrong_construct_arg(self):
s = Signal() s = Signal()
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Instance argument ('', 's1', (sig s)) should be a tuple " (r"^Instance argument \('', 's1', \(sig s\)\) should be a tuple "
"(kind, name, value) where kind is one of \"p\", \"i\", \"o\", or \"io\""): r"\(kind, name, value\) where kind is one of \"p\", \"i\", \"o\", or \"io\"$")):
Instance("foo", ("", "s1", s)) Instance("foo", ("", "s1", s))
def test_wrong_construct_kwarg(self): def test_wrong_construct_kwarg(self):
s = Signal() s = Signal()
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Instance keyword argument x_s1=(sig s) does not start with one of " (r"^Instance keyword argument x_s1=\(sig s\) does not start with one of "
"\"p_\", \"i_\", \"o_\", or \"io_\""): r"\"p_\", \"i_\", \"o_\", or \"io_\"$")):
Instance("foo", x_s1=s) Instance("foo", x_s1=s)
def setUp_cpu(self): def setUp_cpu(self):

View file

@ -20,11 +20,11 @@ class MemoryTestCase(FHDLTestCase):
self.assertEqual(m.depth, 4) self.assertEqual(m.depth, 4)
def test_geometry_wrong(self): def test_geometry_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Memory width must be a non-negative integer, not -1"): r"^Memory width must be a non-negative integer, not -1$"):
m = Memory(width=-1, depth=4) m = Memory(width=-1, depth=4)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Memory depth must be a non-negative integer, not -1"): r"^Memory depth must be a non-negative integer, not -1$"):
m = Memory(width=8, depth=-1) m = Memory(width=8, depth=-1)
def test_init(self): def test_init(self):
@ -32,14 +32,14 @@ class MemoryTestCase(FHDLTestCase):
self.assertEqual(m.init, [0, 1, 2, 3]) self.assertEqual(m.init, [0, 1, 2, 3])
def test_init_wrong_count(self): def test_init_wrong_count(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Memory initialization value count exceed memory depth (8 > 4)"): r"^Memory initialization value count exceed memory depth \(8 > 4\)$"):
m = Memory(width=8, depth=4, init=range(8)) m = Memory(width=8, depth=4, init=range(8))
def test_init_wrong_type(self): def test_init_wrong_type(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Memory initialization value at address 1: " (r"^Memory initialization value at address 1: "
"'str' object cannot be interpreted as an integer"): r"'str' object cannot be interpreted as an integer$")):
m = Memory(width=8, depth=4, init=[1, "0"]) m = Memory(width=8, depth=4, init=[1, "0"])
def test_attrs(self): def test_attrs(self):
@ -82,8 +82,8 @@ class MemoryTestCase(FHDLTestCase):
def test_read_port_wrong(self): def test_read_port_wrong(self):
mem = Memory(width=8, depth=4) mem = Memory(width=8, depth=4)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Read port cannot be simultaneously asynchronous and non-transparent"): r"^Read port cannot be simultaneously asynchronous and non-transparent$"):
mem.read_port(domain="comb", transparent=False) mem.read_port(domain="comb", transparent=False)
def test_write_port(self): def test_write_port(self):
@ -108,14 +108,14 @@ class MemoryTestCase(FHDLTestCase):
def test_write_port_granularity_wrong(self): def test_write_port_granularity_wrong(self):
mem = Memory(width=8, depth=4) mem = Memory(width=8, depth=4)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Write port granularity must be a non-negative integer, not -1"): r"^Write port granularity must be a non-negative integer, not -1$"):
mem.write_port(granularity=-1) mem.write_port(granularity=-1)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Write port granularity must not be greater than memory width (10 > 8)"): r"^Write port granularity must not be greater than memory width \(10 > 8\)$"):
mem.write_port(granularity=10) mem.write_port(granularity=10)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Write port granularity must divide memory width evenly"): r"^Write port granularity must divide memory width evenly$"):
mem.write_port(granularity=3) mem.write_port(granularity=3)

View file

@ -72,31 +72,31 @@ class LayoutTestCase(FHDLTestCase):
"('b', Layout([('c', signed(3))]))])") "('b', Layout([('c', signed(3))]))])")
def test_wrong_field(self): def test_wrong_field(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Field (1,) has invalid layout: should be either (name, shape) or " (r"^Field \(1,\) has invalid layout: should be either \(name, shape\) or "
"(name, shape, direction)"): r"\(name, shape, direction\)$")):
Layout.cast([(1,)]) Layout.cast([(1,)])
def test_wrong_name(self): def test_wrong_name(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Field (1, 1) has invalid name: should be a string"): r"^Field \(1, 1\) has invalid name: should be a string$"):
Layout.cast([(1, 1)]) Layout.cast([(1, 1)])
def test_wrong_name_duplicate(self): def test_wrong_name_duplicate(self):
with self.assertRaises(NameError, with self.assertRaisesRegex(NameError,
msg="Field ('a', 2) has a name that is already present in the layout"): r"^Field \('a', 2\) has a name that is already present in the layout$"):
Layout.cast([("a", 1), ("a", 2)]) Layout.cast([("a", 1), ("a", 2)])
def test_wrong_direction(self): def test_wrong_direction(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Field ('a', 1, 0) has invalid direction: should be a Direction " (r"^Field \('a', 1, 0\) has invalid direction: should be a Direction "
"instance like DIR_FANIN"): r"instance like DIR_FANIN$")):
Layout.cast([("a", 1, 0)]) Layout.cast([("a", 1, 0)])
def test_wrong_shape(self): def test_wrong_shape(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Field ('a', 'x') has invalid shape: should be castable to Shape or " (r"^Field \('a', 'x'\) has invalid shape: should be castable to Shape or "
"a list of fields of a nested record"): r"a list of fields of a nested record$")):
Layout.cast([("a", "x")]) Layout.cast([("a", "x")])
@ -142,11 +142,11 @@ class RecordTestCase(FHDLTestCase):
("stb", 1), ("stb", 1),
("ack", 1), ("ack", 1),
]) ])
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Record 'r' does not have a field 'en'. Did you mean one of: stb, ack?"): r"^Record 'r' does not have a field 'en'\. Did you mean one of: stb, ack\?$"):
r["en"] r["en"]
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Record 'r' does not have a field 'en'. Did you mean one of: stb, ack?"): r"^Record 'r' does not have a field 'en'\. Did you mean one of: stb, ack\?$"):
r.en r.en
def test_wrong_field_unnamed(self): def test_wrong_field_unnamed(self):
@ -154,8 +154,8 @@ class RecordTestCase(FHDLTestCase):
("stb", 1), ("stb", 1),
("ack", 1), ("ack", 1),
])][0] ])][0]
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Unnamed record does not have a field 'en'. Did you mean one of: stb, ack?"): r"^Unnamed record does not have a field 'en'\. Did you mean one of: stb, ack\?$"):
r.en r.en
def test_construct_with_fields(self): def test_construct_with_fields(self):
@ -303,27 +303,27 @@ class ConnectTestCase(FHDLTestCase):
core = Record(self.core_layout) core = Record(self.core_layout)
periph = Record(self.periph_layout) periph = Record(self.periph_layout)
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Cannot include field 'foo' because it is not present in record 'core'"): r"^Cannot include field 'foo' because it is not present in record 'core'$"):
core.connect(periph, include={"foo": True}) core.connect(periph, include={"foo": True})
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Cannot exclude field 'foo' because it is not present in record 'core'"): r"^Cannot exclude field 'foo' because it is not present in record 'core'$"):
core.connect(periph, exclude={"foo": True}) core.connect(periph, exclude={"foo": True})
def test_wrong_direction(self): def test_wrong_direction(self):
recs = [Record([("x", 1)]) for _ in range(2)] recs = [Record([("x", 1)]) for _ in range(2)]
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Cannot connect field 'x' of unnamed record because it does not have " (r"^Cannot connect field 'x' of unnamed record because it does not have "
"a direction"): r"a direction$")):
recs[0].connect(recs[1]) recs[0].connect(recs[1])
def test_wrong_missing_field(self): def test_wrong_missing_field(self):
core = Record([("addr", 32, DIR_FANOUT)]) core = Record([("addr", 32, DIR_FANOUT)])
periph = Record([]) periph = Record([])
with self.assertRaises(AttributeError, with self.assertRaisesRegex(AttributeError,
msg="Cannot connect field 'addr' of record 'core' to subordinate record 'periph' " (r"^Cannot connect field 'addr' of record 'core' to subordinate record 'periph' "
"because the subordinate record does not have this field"): r"because the subordinate record does not have this field$")):
core.connect(periph) core.connect(periph)

View file

@ -110,13 +110,13 @@ class DomainRenamerTestCase(FHDLTestCase):
}) })
def test_rename_wrong_to_comb(self): def test_rename_wrong_to_comb(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain 'sync' may not be renamed to 'comb'"): r"^Domain 'sync' may not be renamed to 'comb'$"):
DomainRenamer("comb") DomainRenamer("comb")
def test_rename_wrong_from_comb(self): def test_rename_wrong_from_comb(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain 'comb' may not be renamed"): r"^Domain 'comb' may not be renamed$"):
DomainRenamer({"comb": "sync"}) DomainRenamer({"comb": "sync"})
@ -189,8 +189,8 @@ class DomainLowererTestCase(FHDLTestCase):
self.s.eq(ClockSignal("xxx")) self.s.eq(ClockSignal("xxx"))
) )
with self.assertRaises(DomainError, with self.assertRaisesRegex(DomainError,
msg="Signal (clk xxx) refers to nonexistent domain 'xxx'"): r"^Signal \(clk xxx\) refers to nonexistent domain 'xxx'$"):
DomainLowerer()(f) DomainLowerer()(f)
def test_lower_wrong_reset_less_domain(self): def test_lower_wrong_reset_less_domain(self):
@ -201,8 +201,8 @@ class DomainLowererTestCase(FHDLTestCase):
self.s.eq(ResetSignal("sync")) self.s.eq(ResetSignal("sync"))
) )
with self.assertRaises(DomainError, with self.assertRaisesRegex(DomainError,
msg="Signal (rst sync) refers to reset of reset-less domain 'sync'"): r"^Signal \(rst sync\) refers to reset of reset-less domain 'sync'$"):
DomainLowerer()(f) DomainLowerer()(f)

View file

@ -8,11 +8,11 @@ from ..lib.cdc import *
class FFSynchronizerTestCase(FHDLTestCase): class FFSynchronizerTestCase(FHDLTestCase):
def test_stages_wrong(self): def test_stages_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Synchronization stage count must be a positive integer, not 0"): r"^Synchronization stage count must be a positive integer, not 0$"):
FFSynchronizer(Signal(), Signal(), stages=0) FFSynchronizer(Signal(), Signal(), stages=0)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Synchronization stage count may not safely be less than 2"): r"^Synchronization stage count may not safely be less than 2$"):
FFSynchronizer(Signal(), Signal(), stages=1) FFSynchronizer(Signal(), Signal(), stages=1)
def test_basic(self): def test_basic(self):
@ -56,16 +56,16 @@ class FFSynchronizerTestCase(FHDLTestCase):
class AsyncFFSynchronizerTestCase(FHDLTestCase): class AsyncFFSynchronizerTestCase(FHDLTestCase):
def test_stages_wrong(self): def test_stages_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Synchronization stage count must be a positive integer, not 0"): r"^Synchronization stage count must be a positive integer, not 0$"):
ResetSynchronizer(Signal(), stages=0) ResetSynchronizer(Signal(), stages=0)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Synchronization stage count may not safely be less than 2"): r"^Synchronization stage count may not safely be less than 2$"):
ResetSynchronizer(Signal(), stages=1) ResetSynchronizer(Signal(), stages=1)
def test_edge_wrong(self): def test_edge_wrong(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="AsyncFFSynchronizer async edge must be one of 'pos' or 'neg', not 'xxx'"): r"^AsyncFFSynchronizer async edge must be one of 'pos' or 'neg', not 'xxx'$"):
AsyncFFSynchronizer(Signal(), Signal(), domain="sync", async_edge="xxx") AsyncFFSynchronizer(Signal(), Signal(), domain="sync", async_edge="xxx")
def test_pos_edge(self): def test_pos_edge(self):
@ -147,11 +147,11 @@ class AsyncFFSynchronizerTestCase(FHDLTestCase):
class ResetSynchronizerTestCase(FHDLTestCase): class ResetSynchronizerTestCase(FHDLTestCase):
def test_stages_wrong(self): def test_stages_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Synchronization stage count must be a positive integer, not 0"): r"^Synchronization stage count must be a positive integer, not 0$"):
ResetSynchronizer(Signal(), stages=0) ResetSynchronizer(Signal(), stages=0)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Synchronization stage count may not safely be less than 2"): r"^Synchronization stage count may not safely be less than 2$"):
ResetSynchronizer(Signal(), stages=1) ResetSynchronizer(Signal(), stages=1)
def test_basic(self): def test_basic(self):
@ -196,11 +196,11 @@ class ResetSynchronizerTestCase(FHDLTestCase):
# TODO: test with distinct clocks # TODO: test with distinct clocks
class PulseSynchronizerTestCase(FHDLTestCase): class PulseSynchronizerTestCase(FHDLTestCase):
def test_stages_wrong(self): def test_stages_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Synchronization stage count must be a positive integer, not 0"): r"^Synchronization stage count must be a positive integer, not 0$"):
PulseSynchronizer("w", "r", stages=0) PulseSynchronizer("w", "r", stages=0)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Synchronization stage count may not safely be less than 2"): r"^Synchronization stage count may not safely be less than 2$"):
PulseSynchronizer("w", "r", stages=1) PulseSynchronizer("w", "r", stages=1)
def test_smoke(self): def test_smoke(self):

View file

@ -9,11 +9,11 @@ from ..lib.fifo import *
class FIFOTestCase(FHDLTestCase): class FIFOTestCase(FHDLTestCase):
def test_depth_wrong(self): def test_depth_wrong(self):
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="FIFO width must be a non-negative integer, not -1"): r"^FIFO width must be a non-negative integer, not -1$"):
FIFOInterface(width=-1, depth=8, fwft=True) FIFOInterface(width=-1, depth=8, fwft=True)
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="FIFO depth must be a non-negative integer, not -1"): r"^FIFO depth must be a non-negative integer, not -1$"):
FIFOInterface(width=8, depth=-1, fwft=True) FIFOInterface(width=8, depth=-1, fwft=True)
def test_sync_depth(self): def test_sync_depth(self):
@ -37,9 +37,9 @@ class FIFOTestCase(FHDLTestCase):
self.assertEqual(AsyncFIFO(width=8, depth=17).depth, 32) self.assertEqual(AsyncFIFO(width=8, depth=17).depth, 32)
def test_async_depth_wrong(self): def test_async_depth_wrong(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="AsyncFIFO only supports depths that are powers of 2; " (r"^AsyncFIFO only supports depths that are powers of 2; "
"requested exact depth 15 is not"): r"requested exact depth 15 is not$")):
AsyncFIFO(width=8, depth=15, exact_depth=True) AsyncFIFO(width=8, depth=15, exact_depth=True)
def test_async_buffered_depth(self): def test_async_buffered_depth(self):
@ -54,9 +54,9 @@ class FIFOTestCase(FHDLTestCase):
self.assertEqual(AsyncFIFOBuffered(width=8, depth=18).depth, 33) self.assertEqual(AsyncFIFOBuffered(width=8, depth=18).depth, 33)
def test_async_buffered_depth_wrong(self): def test_async_buffered_depth_wrong(self):
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="AsyncFIFOBuffered only supports depths that are one higher than powers of 2; " (r"^AsyncFIFOBuffered only supports depths that are one higher than powers of 2; "
"requested exact depth 16 is not"): r"requested exact depth 16 is not$")):
AsyncFIFOBuffered(width=8, depth=16, exact_depth=True) AsyncFIFOBuffered(width=8, depth=16, exact_depth=True)
class FIFOModel(Elaboratable, FIFOInterface): class FIFOModel(Elaboratable, FIFOInterface):

View file

@ -541,8 +541,8 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
def test_add_process_wrong(self): def test_add_process_wrong(self):
with self.assertSimulation(Module()) as sim: with self.assertSimulation(Module()) as sim:
with self.assertRaises(TypeError, with self.assertRaisesRegex(TypeError,
msg="Cannot add a process 1 because it is not a generator function"): r"^Cannot add a process 1 because it is not a generator function$"):
sim.add_process(1) sim.add_process(1)
def test_add_process_wrong_generator(self): def test_add_process_wrong_generator(self):
@ -559,15 +559,15 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
m.d.sync += s.eq(0) m.d.sync += s.eq(0)
with self.assertSimulation(m) as sim: with self.assertSimulation(m) as sim:
sim.add_clock(1) sim.add_clock(1)
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain 'sync' already has a clock driving it"): r"^Domain 'sync' already has a clock driving it$"):
sim.add_clock(1) sim.add_clock(1)
def test_add_clock_wrong_missing(self): def test_add_clock_wrong_missing(self):
m = Module() m = Module()
with self.assertSimulation(m) as sim: with self.assertSimulation(m) as sim:
with self.assertRaises(ValueError, with self.assertRaisesRegex(ValueError,
msg="Domain 'sync' is not present in simulation"): r"^Domain 'sync' is not present in simulation$"):
sim.add_clock(1) sim.add_clock(1)
def test_add_clock_if_exists(self): def test_add_clock_if_exists(self):

View file

@ -28,23 +28,6 @@ class FHDLTestCase(unittest.TestCase):
return repr_str.strip() return repr_str.strip()
self.assertEqual(prepare_repr(repr(obj)), prepare_repr(repr_str)) self.assertEqual(prepare_repr(repr(obj)), prepare_repr(repr_str))
@contextmanager
def assertRaises(self, exception, msg=None):
with super().assertRaises(exception) as cm:
yield
if msg is not None:
# WTF? unittest.assertRaises is completely broken.
self.assertEqual(str(cm.exception), msg)
@contextmanager
def assertWarns(self, category, msg=None):
with warnings.catch_warnings(record=True) as warns:
yield
self.assertEqual(len(warns), 1)
self.assertEqual(warns[0].category, category)
if msg is not None:
self.assertEqual(str(warns[0].message), msg)
def assertFormal(self, spec, mode="bmc", depth=1): def assertFormal(self, spec, mode="bmc", depth=1):
caller, *_ = traceback.extract_stack(limit=2) caller, *_ = traceback.extract_stack(limit=2)
spec_root, _ = os.path.splitext(caller.filename) spec_root, _ = os.path.splitext(caller.filename)