import json import os import sys import tempfile import unittest sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import config class TestConfig(unittest.TestCase): def setUp(self): self.dir = tempfile.mkdtemp() self.path = os.path.join(self.dir, "config.json") def test_missing_file_returns_default(self): cfg = config.load_config(self.path) self.assertEqual(cfg, config.default_config()) self.assertEqual(cfg["buttons"], []) self.assertIsNone(cfg["output_device"]) def test_corrupt_file_returns_default(self): with open(self.path, "w") as fh: fh.write("{not valid json") self.assertEqual(config.load_config(self.path), config.default_config()) def test_round_trip(self): cfg = config.default_config() cfg["output_device"] = "CABLE Input" cfg["volume"] = 55 cfg["buttons"] = [{"id": "btn_001", "label": "Air Horn", "file_path": "/x/a.mp3"}] config.save_config(self.path, cfg) loaded = config.load_config(self.path) self.assertEqual(loaded, cfg) def test_save_is_atomic_no_tmp_left(self): config.save_config(self.path, config.default_config()) self.assertFalse(os.path.exists(self.path + ".tmp")) self.assertTrue(os.path.exists(self.path)) def test_volume_clamped(self): with open(self.path, "w") as fh: json.dump({"volume": 999}, fh) self.assertEqual(config.load_config(self.path)["volume"], 100) def test_malformed_buttons_dropped(self): with open(self.path, "w") as fh: json.dump( { "buttons": [ {"id": "btn_001", "label": "ok", "file_path": "/a"}, {"id": "btn_002", "label": "missing path"}, "not a dict", {"id": 5, "label": "bad id type", "file_path": "/b"}, ] }, fh, ) buttons = config.load_config(self.path)["buttons"] self.assertEqual(len(buttons), 1) self.assertEqual(buttons[0]["id"], "btn_001") if __name__ == "__main__": unittest.main()