Coverage for tests/tool_version_constraints_test.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-17 19:08 +0000

1# 

2# -------------------------------------------------------------------------------- 

3# SPDX-FileCopyrightText: 2024-2026 Martin Jan Köhler and Harald Pretl 

4# Johannes Kepler University, Institute for Integrated Circuits. 

5# 

6# This file is part of KPEX  

7# (see https://github.com/iic-jku/klayout-pex). 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21# SPDX-License-Identifier: GPL-3.0-or-later 

22# -------------------------------------------------------------------------------- 

23# 

24 

25from __future__ import annotations 

26 

27import unittest 

28 

29import allure 

30from packaging.specifiers import SpecifierSet 

31from packaging.version import Version 

32 

33from klayout_pex.pdk_config import PDK 

34from klayout_pex.tool_version_constraints import ( 

35 TOOL_VERSION_CONSTRAINTS, 

36 Severity, 

37 Tool, 

38 ToolVersionConstraint, 

39 applicable_constraints, 

40 effective_version_range, 

41) 

42 

43 

44@allure.parent_suite('Unit Tests') 

45@allure.tag('Tool Versions', 'Version Constraints') 

46class Test(unittest.TestCase): 

47 def test_magic_reports_its_patch_level_as_a_revision(self): 

48 # the banner every MAGIC run prints, and what 'magic --version' gives 

49 assert Tool.MAGIC.parse_version( 

50 'Magic 8.3 revision 681 - Compiled on Di. 11 Aug. 2026 15:53:45 CEST.' 

51 ) == Version('8.3.681') 

52 assert Tool.MAGIC.parse_version('8.3.681') == Version('8.3.681') 

53 assert Tool.MAGIC.parse_version('no version in here') is None 

54 

55 def test_a_packaging_release_is_not_part_of_the_tool_version(self): 

56 assert Tool.KLAYOUT.parse_version('KLayout 0.30.4') == Version('0.30.4') 

57 assert Tool.KLAYOUT.parse_version('klayout_0.30.4-1_amd64') == Version('0.30.4') 

58 assert Tool.FASTERCAP.parse_version('FasterCap 6.0.9') == Version('6.0.9') 

59 

60 def test_constraints_compile_to_one_effective_range(self): 

61 assert effective_version_range(Tool.KLAYOUT) == SpecifierSet('>=0.30.1,>=0.30.2,>=0.30.3') 

62 assert effective_version_range(Tool.KLAYOUT).contains(Version('0.30.4')) 

63 assert not effective_version_range(Tool.KLAYOUT).contains(Version('0.30.2')) 

64 

65 def test_a_pdk_constraint_is_part_of_that_pdk_s_range(self): 

66 for_sky130a = effective_version_range(Tool.MAGIC, pdk=PDK.SKY130A) 

67 assert for_sky130a == effective_version_range(Tool.MAGIC) 

68 assert {c.tool for c in applicable_constraints(Tool.MAGIC, PDK.SKY130A)} == {Tool.MAGIC} 

69 

70 def test_an_excluded_version_is_the_only_one_rejected(self): 

71 constraint = ToolVersionConstraint( 

72 id='TEST_EXCLUSION', tool=Tool.KLAYOUT, specifier='!= 0.30.5', 

73 reason="a hypothetical regression") 

74 assert constraint.is_satisfied_by(Version('0.30.4')) 

75 assert not constraint.is_satisfied_by(Version('0.30.5')) 

76 assert constraint.is_satisfied_by(Version('0.30.6')) 

77 

78 def test_a_pdk_constraint_applies_only_to_that_pdk(self): 

79 constraint = ToolVersionConstraint( 

80 id='TEST_PDK_SCOPED', tool=Tool.MAGIC, specifier='>= 8.3.540', 

81 reason="a PDK-specific requirement", pdk=PDK.SKY130A) 

82 assert constraint.applies_to(PDK.SKY130A) 

83 assert not constraint.applies_to(PDK.IHP_SG13G2) 

84 assert not constraint.applies_to(None) 

85 

86 def test_every_declared_constraint_is_well_formed(self): 

87 ids = [c.id for c in TOOL_VERSION_CONSTRAINTS] 

88 assert len(ids) == len(set(ids)), "constraint IDs have to be unique" 

89 for constraint in TOOL_VERSION_CONSTRAINTS: 

90 with self.subTest(constraint=constraint.id): 

91 assert constraint.id.isupper() 

92 assert constraint.reason, "a constraint has to say why it exists" 

93 assert constraint.severity in (Severity.ERROR, Severity.WARNING) 

94 assert str(constraint.specifier_set) != ''