Files
create-linux-swapfile/tests/unit/test_cli.py
Kevin Veen-Birkenbach 02760e5864 feat: package as pip-installable distribution
Turns the loose main.py into the 'swap-forge' distribution with a src layout, shipping both the swap-forge and the older swafo command.

A failing swap command no longer produces a traceback: CalledProcessError is caught and reported as "'mkswap' failed with exit code 1" at exit 1, a missing binary as exit 127. Required binaries are declared per filesystem path so an ext4 host is never asked for btrfs tooling.

The fstab entry is still written last, after swapon, so a failed activation leaves /etc/fstab untouched. The e2e suite proves that byte for byte across a create, a same-size rerun and a resize cycle, with real fallocate, chmod and file sizes.

Adds unit, integration and container-based e2e tests, ruff and markdown/mermaid linting, CodeQL and Dependabot, and pins the core metadata to 2.4 so twine accepts the artifacts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 14:28:08 +02:00

64 lines
2.2 KiB
Python

import unittest
from pathlib import Path
from subprocess import CalledProcessError
from unittest import mock
from swap_forge.cli import main
class TestMain(unittest.TestCase):
def _run(self, argv, fs="ext4", old_size=0):
with (
mock.patch("swap_forge.cli.detect_root_fs", return_value=fs),
mock.patch("swap_forge.cli.swap_path_for", return_value=Path("/swapfile")),
mock.patch("swap_forge.cli.get_swap_size", return_value=old_size),
mock.patch("swap_forge.cli.remove_swap") as remove,
mock.patch("swap_forge.cli.create_swap") as create,
):
exit_code = main(argv)
return exit_code, remove, create
def test_creates_a_missing_swapfile(self):
exit_code, remove, create = self._run(["2048M"])
remove.assert_not_called()
create.assert_called_once_with(Path("/swapfile"), 2048, "ext4")
self.assertEqual(exit_code, 0)
def test_matching_size_is_left_alone(self):
exit_code, remove, create = self._run(["2048M"], old_size=2048)
remove.assert_not_called()
create.assert_not_called()
self.assertEqual(exit_code, 0)
def test_wrong_size_is_recreated(self):
exit_code, remove, create = self._run(["4G"], old_size=2048)
remove.assert_called_once_with(Path("/swapfile"))
create.assert_called_once_with(Path("/swapfile"), 4096, "ext4")
self.assertEqual(exit_code, 0)
def test_failing_command_reports_cleanly(self):
with (
mock.patch("swap_forge.cli.detect_root_fs", return_value="ext4"),
mock.patch("swap_forge.cli.swap_path_for", return_value=Path("/swapfile")),
mock.patch("swap_forge.cli.get_swap_size", return_value=0),
mock.patch("swap_forge.cli.create_swap") as create,
):
create.side_effect = CalledProcessError(255, ["swapon", "/swapfile"])
exit_code = main(["2048M"])
self.assertEqual(exit_code, 1)
def test_invalid_size_exits_non_zero(self):
with mock.patch("swap_forge.cli.detect_root_fs") as detect:
exit_code = main(["64T"])
detect.assert_not_called()
self.assertEqual(exit_code, 1)
if __name__ == "__main__":
unittest.main()