From ddc6b775ae58b8d54e7ebc7d34452cfc25ce6658 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Sat, 1 Oct 2022 12:24:50 +0200
Subject: [PATCH] Abstract instruction tests - repr()

---
 tests/test_instruction.py | 94 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 tests/test_instruction.py

diff --git a/tests/test_instruction.py b/tests/test_instruction.py
new file mode 100644
index 0000000..1d9dd92
--- /dev/null
+++ b/tests/test_instruction.py
@@ -0,0 +1,94 @@
+"""Tests for the instruction base class."""
+import pytest
+from unittest import mock
+
+from . import reconstructed
+
+
+class _Instruction(reconstructed.RcInstruction):
+    """An instruction with fake implementations for abstract methods."""
+
+    def parse_action(self, record):
+        pass
+
+    def execute_action(self, host_name, variables):
+        pass
+
+
+_ACTION_NAME = "this-is-a-test"
+"""Name of the test action."""
+
+_INSTR_REPR = _ACTION_NAME + "()"
+"""Expected representation of the instruction without flow control."""
+
+
+@pytest.fixture
+def instr():
+    """Create a mock instruction suitable for testing."""
+    return _Instruction(
+        mock.MagicMock(), mock.MagicMock(), mock.MagicMock(), _ACTION_NAME
+    )
+
+
+class TestRepr:
+    """Tests for the ``__repr__`` method."""
+
+    def test_default_repr_instruction_only(self, instr: _Instruction):
+        """Default representation returns action followed by ``()``."""
+        rv = instr.repr_instruction_only()
+        assert rv == _INSTR_REPR
+
+    def test_repr_no_flow(self, instr: _Instruction):
+        """``repr()`` returns default representation if there is no flow \
+                control or variables."""
+        rv = repr(instr)
+        assert rv == _INSTR_REPR
+
+    def test_repr_condition(self, instr: _Instruction):
+        """``repr()`` includes the condition's string if it is defined."""
+        instr._condition = "test"
+        rv = repr(instr)
+        assert rv == "{when=" + repr(instr._condition) + "}" + _INSTR_REPR
+
+    def test_repr_loop(self, instr: _Instruction):
+        """``repr()`` includes information about the loop's data and variable \
+                name if they are defined."""
+        instr._loop = [1, 2, 3]
+        instr._loop_var = "test"
+        rv = repr(instr)
+        assert rv == (
+            "{loop="
+            + repr(instr._loop)
+            + ", loop_var="
+            + repr(instr._loop_var)
+            + "}"
+            + _INSTR_REPR
+        )
+
+    def test_repr_vars(self, instr: _Instruction):
+        """``repr()`` includes information about variables if at least one \
+                variable is defined."""
+        instr._vars = {"a": 1}
+        rv = repr(instr)
+        assert rv == "{vars=" + repr(instr._vars) + "}" + _INSTR_REPR
+
+    @pytest.mark.parametrize("eo_value", (True, False))
+    def test_repr_runonce(self, instr: _Instruction, eo_value: bool):
+        """``repr()`` includes information about ``run_once``."""
+        instr._executed_once = eo_value
+        rv = repr(instr)
+        assert rv == "{run_once}" + _INSTR_REPR
+
+    def test_repr_everything(self, instr: _Instruction):
+        """``repr()`` includes information about all flow controls and \
+                variables."""
+        instr._executed_once = True
+        instr._loop = [1]
+        instr._loop_var = "test"
+        instr._condition = "test"
+        instr._vars = {"a": 1}
+        rv = repr(instr)
+        assert rv.startswith("{")
+        assert rv.endswith("}" + _INSTR_REPR)
+        for what in ("when=", "loop=", "loop_var=", "run_once", "vars="):
+            assert "{" + what in rv or ", " + what in rv, f"element '{what}' not found"