aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-08 13:55:04 +0200
committerDanilo M. <danix@danix.xyz>2026-09-08 13:55:04 +0200
commitb491b772b9f68c0c61a62597a972b6cc7848466e (patch)
treeb0e80c555af102430cd45cb5180d58c20f156fd3 /tests
parentab8be8e3d58a5c2dd8b351110822063b482311e1 (diff)
downloadabusectl-b491b772b9f68c0c61a62597a972b6cc7848466e.tar.gz
abusectl-b491b772b9f68c0c61a62597a972b6cc7848466e.zip
feat: read and validate the config
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KphFXTc2QajxXsHWyvGJ4R
Diffstat (limited to 'tests')
-rw-r--r--tests/test_config.py88
1 files changed, 88 insertions, 0 deletions
diff --git a/tests/test_config.py b/tests/test_config.py
new file mode 100644
index 0000000..c0a9ac4
--- /dev/null
+++ b/tests/test_config.py
@@ -0,0 +1,88 @@
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+"""Tests for reading and validating ~/.config/abusectl/config.toml."""
+
+import os
+import pathlib
+import tempfile
+import unittest
+from unittest import mock
+
+from abusectl import config
+
+
+class TestConfig(unittest.TestCase):
+ def setUp(self):
+ self._tmp = tempfile.TemporaryDirectory()
+ self.root = pathlib.Path(self._tmp.name)
+
+ def tearDown(self):
+ self._tmp.cleanup()
+
+ def _write(self, text: str) -> pathlib.Path:
+ path = self.root / "config.toml"
+ path.write_text(text, encoding="utf-8")
+ return path
+
+ def test_trusted_relays_and_cases_are_read(self):
+ path = self._write(
+ "[general]\n"
+ 'cases = "~/cases"\n'
+ 'trusted_relays = ["192.0.2.0/24"]\n'
+ )
+ loaded = config.load(path)
+ self.assertEqual(loaded.trusted_relays, ["192.0.2.0/24"])
+ self.assertEqual(loaded.cases, pathlib.Path.home() / "cases")
+
+ def test_a_missing_file_is_reported_as_not_configured(self):
+ with self.assertRaises(config.NotConfigured):
+ config.load(self.root / "absent.toml")
+
+ def test_an_empty_relay_list_is_not_configured(self):
+ # Present but empty is the same as absent: parse must refuse either
+ # way rather than guess, so they are one error.
+ path = self._write("[general]\ntrusted_relays = []\n")
+ with self.assertRaises(config.NotConfigured):
+ config.load(path)
+
+ def test_a_malformed_cidr_is_rejected_at_load(self):
+ # Reported against the file that holds the typo, not later against a
+ # message that did nothing wrong.
+ path = self._write('[general]\ntrusted_relays = ["not-a-network"]\n')
+ with self.assertRaises(ValueError):
+ config.load(path)
+
+ def test_the_cases_path_has_a_default(self):
+ path = self._write('[general]\ntrusted_relays = ["192.0.2.0/24"]\n')
+ self.assertEqual(config.load(path).cases, config.DEFAULT_CASES)
+
+ def test_malformed_toml_is_not_reported_as_not_configured(self):
+ # A syntax error is a broken file, which is a different problem from
+ # an absent one and must not be answered with "run abusectl init".
+ path = self._write("[general\ntrusted_relays = [")
+ with self.assertRaises(Exception) as caught:
+ config.load(path)
+ self.assertNotIsInstance(caught.exception, config.NotConfigured)
+
+ def test_the_config_path_follows_xdg_config_home(self):
+ with mock.patch.dict(os.environ, {"XDG_CONFIG_HOME": "/tmp/xdg-probe"}):
+ self.assertEqual(
+ config.path(),
+ pathlib.Path("/tmp/xdg-probe/abusectl/config.toml"),
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()