(Init): Added shit
This commit is contained in:
162
tests/test_state.py
Normal file
162
tests/test_state.py
Normal file
@@ -0,0 +1,162 @@
|
||||
"""Unit tests for the AppState manager.
|
||||
|
||||
Tests state initialization, dirty tracking, undo/redo integration,
|
||||
commit_save, discard, and node serialization helpers — without requiring
|
||||
a live GTK session or filesystem access.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from nirimod.kdl_parser import KdlNode, KdlRawString, parse_kdl, write_kdl
|
||||
from nirimod.state import AppState
|
||||
|
||||
|
||||
class TestAppStateInit(unittest.TestCase):
|
||||
"""AppState starts in a clean, non-dirty state."""
|
||||
|
||||
def test_initial_state(self):
|
||||
state = AppState()
|
||||
self.assertEqual(state.nodes, [])
|
||||
self.assertEqual(state.saved_kdl, "")
|
||||
self.assertFalse(state.is_dirty)
|
||||
self.assertFalse(state.niri_running)
|
||||
self.assertFalse(state.has_touchpad)
|
||||
|
||||
def test_initial_undo_empty(self):
|
||||
state = AppState()
|
||||
self.assertFalse(state.undo.can_undo())
|
||||
self.assertFalse(state.undo.can_redo())
|
||||
|
||||
|
||||
class TestDirtyTracking(unittest.TestCase):
|
||||
def test_mark_dirty(self):
|
||||
state = AppState()
|
||||
self.assertFalse(state.is_dirty)
|
||||
state.mark_dirty()
|
||||
self.assertTrue(state.is_dirty)
|
||||
|
||||
def test_mark_clean(self):
|
||||
state = AppState()
|
||||
state.mark_dirty()
|
||||
state.mark_clean()
|
||||
self.assertFalse(state.is_dirty)
|
||||
|
||||
|
||||
class TestUndoRedo(unittest.TestCase):
|
||||
def _make_state_with_nodes(self, kdl: str) -> AppState:
|
||||
state = AppState()
|
||||
state.nodes = parse_kdl(kdl)
|
||||
state._saved_kdl = kdl
|
||||
return state
|
||||
|
||||
def test_push_and_apply_undo(self):
|
||||
state = self._make_state_with_nodes("gaps 8\n")
|
||||
before = "gaps 8\n"
|
||||
after = "gaps 16\n"
|
||||
state.push_undo("change gaps", before, after)
|
||||
self.assertTrue(state.undo.can_undo())
|
||||
|
||||
entry = state.apply_undo()
|
||||
self.assertIsNotNone(entry)
|
||||
self.assertEqual(state.nodes[0].get_child("gaps") if state.nodes and state.nodes[0].children else None, None)
|
||||
# After undo, nodes should be from the 'before' snapshot
|
||||
kdl_out = write_kdl(state.nodes)
|
||||
self.assertIn("8", kdl_out)
|
||||
|
||||
def test_apply_undo_empty_returns_none(self):
|
||||
state = AppState()
|
||||
result = state.apply_undo()
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_apply_redo_empty_returns_none(self):
|
||||
state = AppState()
|
||||
result = state.apply_redo()
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_undo_sets_dirty(self):
|
||||
state = self._make_state_with_nodes("gaps 8\n")
|
||||
state.push_undo("x", "gaps 16\n", "gaps 24\n")
|
||||
state.apply_undo()
|
||||
self.assertTrue(state.is_dirty)
|
||||
|
||||
def test_redo_after_undo(self):
|
||||
state = self._make_state_with_nodes("gaps 8\n")
|
||||
state.push_undo("x", "gaps 8\n", "gaps 16\n")
|
||||
state.apply_undo()
|
||||
self.assertTrue(state.undo.can_redo())
|
||||
entry = state.apply_redo()
|
||||
self.assertIsNotNone(entry)
|
||||
kdl_out = write_kdl(state.nodes)
|
||||
self.assertIn("16", kdl_out)
|
||||
|
||||
|
||||
class TestCommitSave(unittest.TestCase):
|
||||
def test_commit_save_clears_undo_and_dirty(self):
|
||||
state = AppState()
|
||||
state.push_undo("x", "a", "b")
|
||||
state.mark_dirty()
|
||||
state.commit_save("new kdl\n")
|
||||
self.assertEqual(state.saved_kdl, "new kdl\n")
|
||||
self.assertFalse(state.is_dirty)
|
||||
self.assertFalse(state.undo.can_undo())
|
||||
|
||||
|
||||
class TestDiscard(unittest.TestCase):
|
||||
def test_discard_restores_saved_kdl(self):
|
||||
state = AppState()
|
||||
state._saved_kdl = "gaps 8\n"
|
||||
state.nodes = parse_kdl("gaps 16\n")
|
||||
state.mark_dirty()
|
||||
state.push_undo("x", "gaps 8\n", "gaps 16\n")
|
||||
|
||||
state.discard()
|
||||
|
||||
self.assertFalse(state.is_dirty)
|
||||
self.assertFalse(state.undo.can_undo())
|
||||
kdl_out = write_kdl(state.nodes)
|
||||
self.assertIn("8", kdl_out)
|
||||
|
||||
def test_discard_empty_saved_kdl(self):
|
||||
state = AppState()
|
||||
state._saved_kdl = ""
|
||||
state.discard()
|
||||
self.assertEqual(state.nodes, [])
|
||||
|
||||
|
||||
class TestWriteCurrentKdl(unittest.TestCase):
|
||||
def test_write_current_kdl(self):
|
||||
state = AppState()
|
||||
state.nodes = [KdlNode("prefer-no-csd")]
|
||||
out = state.write_current_kdl()
|
||||
self.assertIn("prefer-no-csd", out)
|
||||
|
||||
def test_write_raw_string(self):
|
||||
# A string containing a double-quote forces the hash-delimited raw form
|
||||
node = KdlNode("env", args=[KdlRawString('has "double" quotes')])
|
||||
out = write_kdl([node])
|
||||
self.assertIn('r#"', out)
|
||||
|
||||
|
||||
class TestLoad(unittest.TestCase):
|
||||
def test_load_detects_runtime(self):
|
||||
state = AppState()
|
||||
# state.py does: from nirimod import niri_ipc
|
||||
# We patch at the canonical module location so all references see the mock.
|
||||
with (
|
||||
patch("nirimod.niri_ipc.is_niri_running", return_value=True),
|
||||
patch("nirimod.niri_ipc.has_touchpad", return_value=True),
|
||||
patch("nirimod.kdl_parser.NIRI_CONFIG") as mock_cfg,
|
||||
):
|
||||
mock_cfg.exists.return_value = False
|
||||
state.load()
|
||||
|
||||
self.assertTrue(state.niri_running)
|
||||
self.assertTrue(state.has_touchpad)
|
||||
self.assertFalse(state.is_dirty)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user