tests/subfiles.py

changeset 24
f8080ffceaa9
parent 23
1b9645b7ddb0
child 26
7c263b864371
--- a/tests/subfiles.py	Mon Jan 22 18:23:25 2018 +0200
+++ b/tests/subfiles.py	Mon Jan 22 21:00:45 2018 +0200
@@ -1,18 +1,90 @@
-from testsuite import error
+from testsuite import warning, error
+from geometry import *
+from os.path import dirname
+from pathlib import Path
+from configparser import ConfigParser
+ini_path = Path(dirname(__file__)) / 'library-standards.ini'
+library_standards = ConfigParser()
+
+with open(ini_path) as file:
+    library_standards.read_file(file)
 
 def determinant_test(model):
-    yield from [
+    yield from (
         error(subfile_reference, 'zero-determinant')
         for subfile_reference in model.subfile_references
         if abs(subfile_reference.matrix.determinant() - 0) < 1e-15
-    ]
+    )
+
+def scaling_description(scaling, axes = 'xyz'):
+    '''
+        Returns a pretty description of a scaling vector. The axes parameter
+        controls what axes are printed and can be used to filter away
+        uninteresting values.
+    '''
+    return ', '.join(
+        str.format('{} = {}', letter, getattr(scaling, letter))
+        for letter in axes
+    )
+
+def check_scaling(scaling, axes):
+    ''' Returns whether all given axes on the given scaling vector are 1. '''
+    return all(
+        abs(getattr(scaling, axis) - 1) < 1e-5
+        for axis in axes
+    )
+
+# Restriction to checking function mapping.
+restriction_tests = {
+    'no scaling': lambda scaling: check_scaling(scaling, 'xyz'),
+    'y-scaling only': lambda scaling: check_scaling(scaling, 'xz'),
+    'stud3-like scaling': lambda scaling: all([
+        check_scaling(scaling, 'xz'),
+        # check if y-scaling is 1 or -1
+        abs(abs(scaling.y) - 1) < 1e-5,
+    ]),
+}
+
+def scaling_legality_test(model):
+    from fnmatch import fnmatch
+    scaling_restrictions = library_standards['scaling restrictions']
+    for subfile_reference in model.subfile_references:
+        primitive = subfile_reference.subfile_path.lower()
+        scaling = subfile_reference.matrix.scaling_vector()
+        # Find all restrictions that apply to this subfile reference.
+        restrictions = {
+            restriction
+            for pattern, restriction in scaling_restrictions.items()
+            if fnmatch(primitive, pattern)
+        }
+        # Check restrictions against the subfile. If any restrictions were
+        # found then the scaling vector must pass at least one of them.
+        if restrictions and not any(
+            restriction_tests[restriction](scaling)
+            for restriction in restrictions
+        ):
+            interesting_axes = ''.join(
+                axis
+                for axis in 'xyz'
+                if abs(getattr(scaling, axis) - 1) > 1e-5
+            )
+            yield warning(subfile_reference, 'illegal-scaling',
+                primitive = primitive,
+                axes = interesting_axes,
+                scaling = scaling)
 
 manifest = {
     'tests': {
         'determinant': determinant_test,
+        'scaling-legality': scaling_legality_test,
     },
     'messages': {
         'zero-determinant': 'matrix determinant is zero '
             '(row or column all zero)',
+        'illegal-scaling': lambda primitive, scaling, axes:
+            str.format('scaling of unscalable primitive {} ({})',
+                primitive,
+                scaling_description(scaling, axes),
+            ),
     },
 }

mercurial