From e7ea8fff4dbeac970542d5addabd3716f3d184de Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson <oscar.gustafsson@gmail.com>
Date: Thu, 19 Jan 2023 13:23:37 +0100
Subject: [PATCH] Change some asserts and test for specific exceptions

---
 b_asic/port.py                      | 10 ++++------
 b_asic/scheduler_gui/main_window.py |  6 +++---
 b_asic/signal.py                    |  8 ++++++--
 b_asic/signal_flow_graph.py         | 12 +++++++-----
 test/test_inputport.py              |  2 +-
 test/test_outputport.py             |  2 +-
 test/test_sfg.py                    |  8 ++++----
 test/test_signal.py                 |  8 ++++----
 8 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/b_asic/port.py b/b_asic/port.py
index 7b750451..f2a25328 100644
--- a/b_asic/port.py
+++ b/b_asic/port.py
@@ -172,9 +172,8 @@ class InputPort(AbstractPort):
         return [] if self._source_signal is None else [self._source_signal]
 
     def add_signal(self, signal: Signal) -> None:
-        assert (
-            self._source_signal is None
-        ), "Input port may have only one signal added."
+        if self._source_signal is not None:
+            raise ValueError("Cannot add to already connected input port.")
         assert (
             signal is not self._source_signal
         ), "Attempted to add already connected signal."
@@ -207,9 +206,8 @@ class InputPort(AbstractPort):
         Connect the provided signal source to this input port by creating a new signal.
         Returns the new signal.
         """
-        assert (
-            self._source_signal is None
-        ), "Attempted to connect already connected input port."
+        if self._source_signal is not None:
+            raise ValueError("Cannot connect already connected input port.")
         # self._source_signal is set by the signal constructor.
         return Signal(source=src.source, destination=self, name=name)
 
diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py
index 6d834b0b..7e3f1e2d 100644
--- a/b_asic/scheduler_gui/main_window.py
+++ b/b_asic/scheduler_gui/main_window.py
@@ -210,10 +210,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
             module = SourceFileLoader(
                 module_name, abs_path_filename
             ).load_module()
-        except:
+        except Exception as e:
             log.exception(
-                "Exception occurred. Could not load module from file '{}'."
-                .format(abs_path_filename)
+                "Exception occurred. Could not load module from file '{}'.\n\n{}"
+                .format(abs_path_filename, e)
             )
             return
 
diff --git a/b_asic/signal.py b/b_asic/signal.py
index 867f7ba7..63914c00 100644
--- a/b_asic/signal.py
+++ b/b_asic/signal.py
@@ -138,6 +138,10 @@ class Signal(AbstractGraphComponent):
         should truncate received values to.
         None = unlimited.
         """
-        if bits is not None and bits < 0:
-            raise ValueError("Bits cannot be negative")
+        if bits is not None:
+            if not isinstance(bits, int):
+                raise TypeError(
+                    f"Bits must be an int, not {type(bits)}: {bits!r}")
+            if bits < 0:
+                raise ValueError("Bits cannot be negative")
         self.set_param("bits", bits)
diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py
index 8e87c71a..37baeca8 100644
--- a/b_asic/signal_flow_graph.py
+++ b/b_asic/signal_flow_graph.py
@@ -624,12 +624,14 @@ class SFG(AbstractOperation):
         if output_comp is None:
             return None
 
-        assert not isinstance(
+        if isinstance(
             output_comp, Output
-        ), "Source operation can not be an output operation."
-        assert len(output_comp.output_signals) == component.input_count, (
-            "Source operation output count does not match input count for"
-            " component."
+        ):
+            raise TypeError("Source operation cannot be an output operation.")
+        if len(output_comp.output_signals) != component.input_count:
+            raise TypeError(
+            f"Source operation output count ({len(output_comp.output_signals)})"
+            f" does not match input count for component ({component.input_count})."
         )
         assert len(output_comp.output_signals) == component.output_count, (
             "Destination operation input count does not match output for"
diff --git a/test/test_inputport.py b/test/test_inputport.py
index 3d3e057c..a94bbb7d 100644
--- a/test/test_inputport.py
+++ b/test/test_inputport.py
@@ -27,7 +27,7 @@ def test_connect_then_disconnect(input_port, output_port):
 def test_connect_used_port_to_new_port(input_port, output_port, output_port2):
     """Multiple connections to an input port should throw an error."""
     input_port.connect(output_port)
-    with pytest.raises(Exception):
+    with pytest.raises(ValueError):
         input_port.connect(output_port2)
 
 
diff --git a/test/test_outputport.py b/test/test_outputport.py
index 8548cbbe..3480c2eb 100644
--- a/test/test_outputport.py
+++ b/test/test_outputport.py
@@ -17,7 +17,7 @@ class TestConnect:
     def test_same_port(self, output_port, input_port):
         """Check error handing."""
         input_port.connect(output_port)
-        with pytest.raises(Exception):
+        with pytest.raises(ValueError):
             input_port.connect(output_port)
 
         assert output_port.signal_count == 1
diff --git a/test/test_sfg.py b/test/test_sfg.py
index ac73cf3f..30040995 100644
--- a/test/test_sfg.py
+++ b/test/test_sfg.py
@@ -250,7 +250,7 @@ class TestEvaluateOutput:
 
     def test_evaluate_output_cycle(self, operation_graph_with_cycle):
         sfg = SFG(outputs=[Output(operation_graph_with_cycle)])
-        with pytest.raises(Exception):
+        with pytest.raises(RuntimeError, match="Direct feedback loop detected"):
             sfg.evaluate_output(0, [])
 
 
@@ -501,7 +501,7 @@ class TestInsertComponent:
 
         # Should raise an exception for not matching input count to output count.
         add4 = Addition()
-        with pytest.raises(Exception):
+        with pytest.raises(TypeError, match="Source operation output count"):
             sfg.insert_operation(add4, "c1")
 
     def test_insert_at_output(self, large_operation_tree):
@@ -509,7 +509,7 @@ class TestInsertComponent:
 
         # Should raise an exception for trying to insert an operation after an output.
         sqrt = SquareRoot()
-        with pytest.raises(Exception):
+        with pytest.raises(TypeError, match="Source operation cannot be an"):
             _ = sfg.insert_operation(sqrt, "out1")
 
     def test_insert_multiple_output_ports(self, butterfly_operation_tree):
@@ -1324,7 +1324,7 @@ class TestSaveLoadSFG:
 
     def test_load_invalid_path(self):
         path_ = self.get_path(existing=False)
-        with pytest.raises(Exception):
+        with pytest.raises(FileNotFoundError):
             python_to_sfg(path_)
 
 
diff --git a/test/test_signal.py b/test/test_signal.py
index 295cbb79..30186fd1 100644
--- a/test/test_signal.py
+++ b/test/test_signal.py
@@ -62,7 +62,7 @@ def test_signal_creation_and_disconnction_and_connection_changing():
     assert s.destination is in_port
 
 
-class Bits:
+class TestBits:
     def test_pos_int(self, signal):
         signal.bits = 10
         assert signal.bits == 10
@@ -72,15 +72,15 @@ class Bits:
         assert signal.bits == 0
 
     def test_bits_neg_int(self, signal):
-        with pytest.raises(Exception):
+        with pytest.raises(ValueError):
             signal.bits = -10
 
     def test_bits_complex(self, signal):
-        with pytest.raises(Exception):
+        with pytest.raises(TypeError):
             signal.bits = 2 + 4j
 
     def test_bits_float(self, signal):
-        with pytest.raises(Exception):
+        with pytest.raises(TypeError):
             signal.bits = 3.2
 
     def test_bits_pos_then_none(self, signal):
-- 
GitLab