Belle II Software  release-05-01-25
test_registry.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 from importlib import import_module
5 from inspect import getmembers, isclass
6 from pathlib import Path
7 import unittest
8 
9 from basf2 import find_file
10 from skim.registry import Registry
11 from skimExpertFunctions import BaseSkim
12 
13 __authors__ = ["Sam Cunliffe", "Phil Grace"]
14 
15 
16 class TestSkimCodes(unittest.TestCase):
17  """Test case for skim registry."""
18 
19  ExistentModulePaths = Path(find_file("skim/scripts/skim")).glob("*.py")
20  ExistentModules = [
21  module.stem
22  for module in ExistentModulePaths
23  if module.stem not in ["__init__", "registry"]
24  ]
25 
26  def assertIsSubclass(self, cls, parent_cls, msg=None):
27  """Fail if `cls` is not a subclass of `parent_cls`."""
28  if not issubclass(cls, parent_cls):
29  standardMsg = "%r is not a subclass of %r" % (cls, parent_cls)
30  self.fail(self._formatMessage(msg, standardMsg))
31 
32  def test_code_format(self):
33  """Check the codes are the correct format (8 digits)."""
34  # https://confluence.desy.de/x/URdYBQ
35  for code in Registry.codes:
36  self.assertEqual(len(code), 8, "Incorrect length skim code")
37  self.assertTrue(code.isdigit(), "Must consist of digits")
38 
39  def test_unique_codes(self):
40  """Check that there aren't two skims registered with the same code."""
41  self.assertEqual(
42  len(Registry.codes), len(set(Registry.codes)), "Duplicated skim code"
43  )
44 
45  def test_unique_names(self):
46  """Check that there aren't two skims registered with the same name."""
47  self.assertEqual(
48  len(Registry.names), len(set(Registry.names)), "Duplicated skim name"
49  )
50 
51  def test_invalid_names(self):
52  """Check that that no registered skims have invalid names."""
53  for name in Registry.names:
54  self.assertFalse(
55  name.startswith("Base"),
56  (
57  f"Invalid skim name in registry: {name}. Registed skim names cannot"
58  " begin with 'Base'; this word is reserved for subclassing purposes."
59  ),
60  )
61 
62  def test_encode(self):
63  """Check that we raise a LookupError if the skim name doesn't exist."""
64  with self.assertRaises(LookupError):
65  Registry.encode_skim_name("SomeNonExistentSkimName")
66 
67  def test_decode(self):
68  """Check that we raise a LookupError if the skim code doesn't exist."""
69  with self.assertRaises(LookupError):
70  Registry.decode_skim_code("1337")
71 
72  def test_modules_exist(self):
73  """Check that all modules listed in registry exist in skim/scripts/skim/."""
74  for module in Registry.modules:
75  self.assertIn(
76  module,
77  self.ExistentModules,
78  (
79  f"Module {module} listed in registry, but does not exist in "
80  "skim/scripts/skim/."
81  ),
82  )
83 
85  """Check that there is no overlap between skim and module names."""
86  duplicates = set(Registry.modules).intersection(Registry.names)
87  self.assertEqual(
88  set(), duplicates, f"Name used for both a skim and a module: {', '.join(duplicates)}"
89  )
90 
91  def test_skims_exist(self):
92  """Check that the registry is correct about the location of every skim.
93 
94  This test uses the information from the registry, and checks for missing skims
95  in the modules.
96  """
97  for ModuleName in Registry.modules:
98  SkimModule = import_module(f"skim.{ModuleName}")
99  for SkimName in Registry.get_skims_in_module(ModuleName):
100  # Check the skim is defined in the module
101  self.assertIn(
102  SkimName,
103  SkimModule.__dict__.keys(),
104  (
105  f"Registry lists {SkimName} as existing in skim.{ModuleName}, "
106  "but no such skim found!"
107  ),
108  )
109 
110  # Check that it is defined as a subclass of BaseSkim
111  SkimClass = getattr(SkimModule, SkimName)
112  self.assertIsSubclass(
113  SkimClass,
114  BaseSkim,
115  f"Skim {SkimName} must be defined as a subclass of BaseSkim.",
116  )
117 
119  """Check that every skim defined in a module is listed in the registry.
120 
121  This test uses the information from the modules, and checks for missing or
122  incorrect skim information in the registry.
123  """
124  for ModuleName in self.ExistentModules:
125  SkimModule = import_module(f"skim.{ModuleName}")
126 
127  # Inspect the module, and find all BaseSkim subclasses
128  SkimNames = [
129  obj[0]
130  for obj in getmembers(SkimModule, isclass)
131  if (
132  issubclass(obj[1], BaseSkim)
133  and obj[1] is not BaseSkim
134  and obj[0] != "CombinedSkim"
135  # Allow "Base" at beginning of skims, for subclassing
136  and not obj[0].startswith("Base")
137  )
138  ]
139 
140  # Check the skim is listed in the registry with the same name
141  for SkimName in SkimNames:
142  self.assertIn(
143  SkimName,
144  Registry.names,
145  (
146  f"Skim {SkimName} defined in skim/scripts/skim/{ModuleName}.py, "
147  "but not listed in registry."
148  ),
149  )
150 
151  # Check the module we found the skim in is the module listed in the registry
152  for SkimName in SkimNames:
153  ExpectedModuleName = Registry.get_skim_module(SkimName)
154  self.assertEqual(
155  ExpectedModuleName,
156  ModuleName,
157  (
158  f"Skim {SkimName} defined in "
159  f"skim/scripts/skim/{ModuleName}.py, but listed in registry as "
160  f"belonging to skim/scripts/skim/{ExpectedModuleName}.py."
161  ),
162  )
163 
164 
165 if __name__ == "__main__":
166  unittest.main()
test_registry.TestSkimCodes.ExistentModules
list ExistentModules
Definition: test_registry.py:20
test_registry.TestSkimCodes.test_clashing_skim_and_module_names
def test_clashing_skim_and_module_names(self)
Definition: test_registry.py:84
test_registry.TestSkimCodes.test_unique_codes
def test_unique_codes(self)
Definition: test_registry.py:39
test_registry.TestSkimCodes.assertIsSubclass
def assertIsSubclass(self, cls, parent_cls, msg=None)
Definition: test_registry.py:26
test_registry.TestSkimCodes
Definition: test_registry.py:16
test_registry.TestSkimCodes.test_decode
def test_decode(self)
Definition: test_registry.py:67
skim.registry
Definition: registry.py:1
test_registry.TestSkimCodes.test_modules_exist
def test_modules_exist(self)
Definition: test_registry.py:72
test_registry.TestSkimCodes.test_invalid_names
def test_invalid_names(self)
Definition: test_registry.py:51
test_registry.TestSkimCodes.test_code_format
def test_code_format(self)
Definition: test_registry.py:32
test_registry.TestSkimCodes.test_skims_exist
def test_skims_exist(self)
Definition: test_registry.py:91
test_registry.TestSkimCodes.test_encode
def test_encode(self)
Definition: test_registry.py:62
test_registry.TestSkimCodes.test_undocumented_skims
def test_undocumented_skims(self)
Definition: test_registry.py:118
test_registry.TestSkimCodes.test_unique_names
def test_unique_names(self)
Definition: test_registry.py:45