From 2d598cff6adc136ba1fd606bc457e61b74cee284 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 30 Aug 2024 10:34:20 +0200 Subject: [PATCH] add test for typo --- src/schema/rules/checks/mri.yaml | 4 +- .../bidsschematools/tests/test_expressions.py | 52 ++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/schema/rules/checks/mri.yaml b/src/schema/rules/checks/mri.yaml index e2efc0216d..91a1520179 100644 --- a/src/schema/rules/checks/mri.yaml +++ b/src/schema/rules/checks/mri.yaml @@ -109,9 +109,9 @@ BolusCutOffDelayTimeNotMonotonicallyIncreasing: level: error selectors: - modality == "mri" - - sidecar.BolusCutoffDelayTime != null + - sidecar.BolusCutOffDelayTime != null checks: - - allequal(sorted(sidecar.BolusCutoffDelayTime), sidecar.BolusCutoffDelayTime) + - allequal(sorted(sidecar.BolusCutOffDelayTime), sidecar.BolusCutOffDelayTime) # 201 RepetitionTimePreparationNotConsistent: diff --git a/tools/schemacode/bidsschematools/tests/test_expressions.py b/tools/schemacode/bidsschematools/tests/test_expressions.py index 5532ef38ba..6370468453 100644 --- a/tools/schemacode/bidsschematools/tests/test_expressions.py +++ b/tools/schemacode/bidsschematools/tests/test_expressions.py @@ -1,7 +1,7 @@ import pytest from pyparsing.exceptions import ParseException -from ..expressions import ASTNode, expression +from ..expressions import Array, ASTNode, BinOp, Function, Property, expression def test_schema_expressions(schema_obj): @@ -77,3 +77,53 @@ def test_checks(schema_obj): def test_expected_failures(expr): with pytest.raises(ParseException): expression.parse_string(expr) + + +def test_valid_sidecar_field(schema_obj): + """Check sidecar fields actually exist in the metadata listed in the schema. + + Test failures are usually due to typos. + """ + for rules, level in ((schema_obj.rules.checks, 3),): + keys = (key for key in rules.keys(level=level) if key.endswith("selectors")) + check_fields(schema_obj, rules, keys) + + keys = (key for key in rules.keys(level=level) if key.endswith("checks")) + check_fields(schema_obj, rules, keys) + + +def check_fields(schema_obj, rules, keys): + for key in keys: + for rule in rules[key]: + ast = expression.parse_string(rule)[0] + if isinstance(ast, BinOp): + for half in [ast.lh, ast.rh]: + if isinstance(half, Function): + check_function(schema_obj, half) + elif isinstance(ast, Function): + check_function(schema_obj, ast) + elif isinstance(ast, Property): + check_property(schema_obj, ast) + + +def check_function(schema_obj, function): + for x in function.args: + if isinstance(x, Property): + check_property(schema_obj, x) + elif isinstance(x, Function): + check_function(schema_obj, x) + elif isinstance(x, Array): + check_array(schema_obj, x) + + +def check_array(schema_obj, array): + ( + check_property(schema_obj, element) + for element in array.elements + if isinstance(element, Property) + ) + + +def check_property(schema_obj, property): + if property.name == "sidecar": + assert property.field in schema_obj.objects.metadata