From 36363bc611788af2d4f494ce620100bf4e49175c Mon Sep 17 00:00:00 2001 From: Daniil Mordanov Date: Fri, 7 Aug 2026 13:01:46 +0700 Subject: [PATCH] Validate fixed-size parameter defaults Signed-off-by: Daniil Mordanov --- .../parse_yaml.py | 45 ++++++++++++++++- .../test/YAML_parse_error_test.py | 48 ++++++++++++++++++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/generate_parameter_library_py/generate_parameter_library_py/parse_yaml.py b/generate_parameter_library_py/generate_parameter_library_py/parse_yaml.py index 24429913..baad2178 100644 --- a/generate_parameter_library_py/generate_parameter_library_py/parse_yaml.py +++ b/generate_parameter_library_py/generate_parameter_library_py/parse_yaml.py @@ -103,6 +103,46 @@ def validation_base_name(function_name: str): return function_name.replace('<>', '') +@typechecked +def validate_fixed_default_size( + param_name: str, + defined_type: str, + default_value: Any, + validations_dict: dict, +): + capacity = fixed_type_size(defined_type) + if capacity is None or default_value is None: + return + if array_type(defined_type) and not isinstance(default_value, list): + return + if not array_type(defined_type) and not isinstance(default_value, str): + return + + default_size = len(default_value) + if default_size > capacity: + raise compile_error( + 'Parameter {} has a default value of size {}, which exceeds ' + "the capacity of type '{}' ({}).".format( + param_name, default_size, defined_type, capacity + ) + ) + + for function_name, arguments in validations_dict.items(): + if validation_base_name(function_name) != 'fixed_size': + continue + + expected_size = arguments + if isinstance(arguments, list) and len(arguments) == 1: + expected_size = arguments[0] + if isinstance(expected_size, int) and default_size != expected_size: + raise compile_error( + 'Parameter {} has a default value of size {}, but its ' + "'fixed_size' validation requires {}.".format( + param_name, default_size, expected_size + ) + ) + + @typechecked def validate_validator_combinations(param_name: str, validations_dict: dict): validation_names = {validation_base_name(name) for name in validations_dict} @@ -776,6 +816,10 @@ def preprocess_inputs(language, name, value, nested_name_list): # optional attributes default_value = value.get('default_value', None) + validations_dict = value.get('validation', {}) + validate_fixed_default_size( + param_name, defined_type, default_value, validations_dict + ) if not is_fixed_type(defined_type): code_gen_variable = CodeGenVariable( language, name, param_name, defined_type, default_value @@ -789,7 +833,6 @@ def preprocess_inputs(language, name, value, nested_name_list): read_only = bool(value.get('read_only', False)) validations = [] additional_constraints = value.get('additional_constraints', '') - validations_dict = value.get('validation', {}) if is_fixed_type(defined_type): validations_dict['size_lt<>'] = fixed_type_size(defined_type) + 1 diff --git a/generate_parameter_library_py/generate_parameter_library_py/test/YAML_parse_error_test.py b/generate_parameter_library_py/generate_parameter_library_py/test/YAML_parse_error_test.py index 28007666..9c12caec 100644 --- a/generate_parameter_library_py/generate_parameter_library_py/test/YAML_parse_error_test.py +++ b/generate_parameter_library_py/generate_parameter_library_py/test/YAML_parse_error_test.py @@ -21,7 +21,10 @@ from generate_parameter_library_py.generate_cpp_header import run as run_cpp from generate_parameter_library_py.generate_python_module import run as run_python from generate_parameter_library_py.generate_markdown import run as run_md -from generate_parameter_library_py.parse_yaml import YAMLSyntaxError +from generate_parameter_library_py.parse_yaml import ( + YAMLSyntaxError, + preprocess_inputs, +) from generate_parameter_library_py.generate_cpp_header import parse_args @@ -100,3 +103,46 @@ def test_parse_valid_parameter_files(yaml_test_file): set_up(yaml_test_file) except Exception as e: assert False, f'failed to parse valid file, reason:{e}' + + +@pytest.mark.parametrize( + 'defined_type,default_value', + [ + ('int_array_fixed_03', [101, 102, 103, 104]), + ('double_array_fixed_03', [1.0, 2.0, 3.0, 4.0]), + ('string_array_fixed_03', ['a', 'b', 'c', 'd']), + ('string_fixed_03', 'abcd'), + ], +) +def test_fixed_default_cannot_exceed_capacity(defined_type, default_value): + with pytest.raises(YAMLSyntaxError, match='exceeds the capacity'): + preprocess_inputs( + 'cpp', + 'test_param', + {'type': defined_type, 'default_value': default_value}, + ['test_namespace'], + ) + + +def test_fixed_default_must_satisfy_fixed_size_validator(): + with pytest.raises(YAMLSyntaxError, match="'fixed_size' validation requires 3"): + preprocess_inputs( + 'cpp', + 'test_param', + { + 'type': 'int_array_fixed_03', + 'default_value': [101, 102], + 'validation': {'fixed_size<>': 3}, + }, + ['test_namespace'], + ) + + +@pytest.mark.parametrize('default_value', [[101, 102], [101, 102, 103]]) +def test_fixed_default_at_or_below_capacity_is_valid(default_value): + preprocess_inputs( + 'cpp', + 'test_param', + {'type': 'int_array_fixed_03', 'default_value': default_value}, + ['test_namespace'], + )