test_package_config.py (4569B)
1 #!/usr/bin/env python3 2 3 # This file is in the public domain. 4 5 import sys 6 import tempfile 7 import tomllib 8 import unittest 9 import stat 10 from dataclasses import replace 11 from pathlib import Path 12 13 BUILDSCRIPTS = Path(__file__).parents[1] / "buildscripts" 14 sys.path.insert(0, str(BUILDSCRIPTS)) 15 16 from package_config import ( # noqa: E402 17 ConfigError, 18 load_config, 19 parse_config, 20 serialize_config, 21 write_config, 22 ) 23 24 25 VALID_CONFIG = { 26 "repositories": { 27 "workspace": { 28 "url": "git://example.test/workspace.git", 29 "builder": "pnpm-workspace", 30 } 31 }, 32 "packages": { 33 "application": { 34 "repository": "workspace", 35 "tag": "v1.2.3", 36 "debian_path": "packages/application", 37 "dependencies": ["library"], 38 "enabled": True, 39 }, 40 "library": { 41 "repository": "workspace", 42 "tag": "v1.2.2", 43 }, 44 }, 45 } 46 47 48 class PackageConfigTests(unittest.TestCase): 49 def test_defaults_and_builder_inheritance(self): 50 config = parse_config(VALID_CONFIG) 51 52 library = config.packages["library"] 53 self.assertEqual("", library.debian_path) 54 self.assertEqual((), library.dependencies) 55 self.assertTrue(library.enabled) 56 self.assertEqual("pnpm-workspace", config.builder_for(library)) 57 58 def test_package_builder_override(self): 59 data = { 60 **VALID_CONFIG, 61 "packages": { 62 **VALID_CONFIG["packages"], 63 "library": { 64 **VALID_CONFIG["packages"]["library"], 65 "builder": "generic", 66 }, 67 }, 68 } 69 config = parse_config(data) 70 71 self.assertEqual("generic", config.builder_for(config.packages["library"])) 72 73 def test_rejects_unknown_builder(self): 74 data = { 75 **VALID_CONFIG, 76 "repositories": { 77 "workspace": { 78 **VALID_CONFIG["repositories"]["workspace"], 79 "builder": "unknown", 80 } 81 }, 82 } 83 84 with self.assertRaisesRegex(ConfigError, "builder is not supported"): 85 parse_config(data) 86 87 def test_rejects_unknown_fields_and_references(self): 88 with self.assertRaisesRegex(ConfigError, "unknown field"): 89 parse_config({**VALID_CONFIG, "surprise": {}}) 90 91 data = { 92 **VALID_CONFIG, 93 "packages": { 94 **VALID_CONFIG["packages"], 95 "library": { 96 **VALID_CONFIG["packages"]["library"], 97 "repository": "missing", 98 }, 99 }, 100 } 101 with self.assertRaisesRegex(ConfigError, "unknown repository"): 102 parse_config(data) 103 104 def test_rejects_dependency_cycles(self): 105 data = { 106 **VALID_CONFIG, 107 "packages": { 108 **VALID_CONFIG["packages"], 109 "library": { 110 **VALID_CONFIG["packages"]["library"], 111 "dependencies": ["application"], 112 }, 113 }, 114 } 115 116 with self.assertRaisesRegex(ConfigError, "application -> library -> application"): 117 parse_config(data) 118 119 def test_serializer_is_canonical_and_round_trips(self): 120 config = parse_config(VALID_CONFIG) 121 serialized = serialize_config(config) 122 123 self.assertEqual(config, parse_config(tomllib.loads(serialized))) 124 self.assertLess( 125 serialized.index('[packages."application"]'), 126 serialized.index('[packages."library"]'), 127 ) 128 self.assertEqual(serialized, serialize_config(parse_config(tomllib.loads(serialized)))) 129 130 def test_write_config_replaces_complete_document(self): 131 config = parse_config(VALID_CONFIG) 132 updated_packages = dict(config.packages) 133 updated_packages["library"] = replace( 134 updated_packages["library"], tag="v1.2.4" 135 ) 136 updated = replace(config, packages=updated_packages) 137 138 with tempfile.TemporaryDirectory() as temporary_directory: 139 path = Path(temporary_directory) / "packages.toml" 140 path.write_text("old contents\n") 141 path.chmod(0o640) 142 write_config(path, updated) 143 144 self.assertEqual(updated, load_config(path)) 145 self.assertEqual(serialize_config(updated), path.read_text()) 146 self.assertEqual(0o640, stat.S_IMODE(path.stat().st_mode)) 147 148 149 if __name__ == "__main__": 150 unittest.main()