From 46c5e20e8daf098d751a4e15f5e507333f422767 Mon Sep 17 00:00:00 2001 From: Lou DeGenaro Date: Tue, 10 Oct 2023 09:04:06 -0400 Subject: [PATCH] fix: improve bad property error message by including csv row number Signed-off-by: Lou DeGenaro --- tests/trestle/tasks/csv_to_oscal_cd_test.py | 66 +++++++++++++++++ trestle/tasks/csv_to_oscal_cd.py | 80 +++++++++++++++++---- 2 files changed, 134 insertions(+), 12 deletions(-) diff --git a/tests/trestle/tasks/csv_to_oscal_cd_test.py b/tests/trestle/tasks/csv_to_oscal_cd_test.py index 78a264a13..48c9da994 100644 --- a/tests/trestle/tasks/csv_to_oscal_cd_test.py +++ b/tests/trestle/tasks/csv_to_oscal_cd_test.py @@ -1138,3 +1138,69 @@ def test_execute_validation(tmp_path: pathlib.Path) -> None: assert component.props[2].name == 'Check_Description' assert component.props[2].value == 'validation-check-description' assert len(component.control_implementations) == 0 + + +def test_row_property_builder(tmp_path): + """Test row property builder.""" + # valid + prop = csv_to_oscal_cd.row_property_builder( + row=0, + name='name', + value='value', + ns='https://www.ibm.com', + class_='class', + remarks='remarks', + ) + assert prop + # missing name + try: + prop = csv_to_oscal_cd.row_property_builder( + row=0, + name=None, + value='value', + ns='https://www.ibm.com', + class_='class', + remarks='remarks', + ) + raise AssertionError('missing name OK?') + except Exception: + assert prop + # missing value + try: + prop = csv_to_oscal_cd.row_property_builder( + row=0, + name='name', + value=None, + ns='https://www.ibm.com', + class_='class', + remarks='remarks', + ) + raise AssertionError('missing value OK?') + except Exception: + assert prop + # invalid ns + try: + prop = csv_to_oscal_cd.row_property_builder( + row=0, + name='name', + value='value', + ns='foobar', + class_='class', + remarks='remarks', + ) + raise AssertionError('invalid ns OK?') + except Exception: + assert prop + # invalid class + try: + prop = csv_to_oscal_cd.row_property_builder( + row=0, + name='name', + value='value', + ns='https://www.ibm.com', + class_='\n', + remarks='remarks', + ) + raise AssertionError('invalid class OK?') + except Exception: + assert prop diff --git a/trestle/tasks/csv_to_oscal_cd.py b/trestle/tasks/csv_to_oscal_cd.py index 39a07ca7d..3f5f5afe1 100644 --- a/trestle/tasks/csv_to_oscal_cd.py +++ b/trestle/tasks/csv_to_oscal_cd.py @@ -82,6 +82,65 @@ def derive_part_id(control_mapping: str) -> str: return rval +def etype(target: str) -> str: + """Get etype.""" + if target: + return 'invalid' + else: + return 'missing' + + +def row_property_builder(row: int, name: str, value, ns: str, class_: str, remarks: str) -> Property: + """Row property builder.""" + # name + try: + Property( + name=name, + value='value', + ) + except Exception: + text = f'property for row: {row} name: {name} is {etype(name)}' + raise RuntimeError(text) + # value + try: + Property( + name=name, + value=value, + ) + except Exception: + text = f'property for row: {row} value: {value} is {etype(value)}' + raise RuntimeError(text) + # ns + try: + Property( + name=name, + value=value, + ns=ns, + ) + except Exception: + text = f'property for row: {row} ns: {ns} is {etype(ns)}' + raise RuntimeError(text) + # class + try: + Property( + name=name, + value=value, + class_=class_, + ) + except Exception: + text = f'property for row: {row} class: {class_} is {etype(class_)}' + raise RuntimeError(text) + # prop + prop = Property( + name=name, + value=value, + ns=ns, + class_=class_, + remarks=remarks, + ) + return prop + + class CsvToOscalComponentDefinition(TaskBase): """ Task to create OSCAL ComponentDefinition json. @@ -911,18 +970,15 @@ def __init__(self, row_number: int, rule_set: str) -> None: def add_prop(self, name: str, value: str, ns: str, class_: str) -> None: """Add prop.""" if value is not None and len(value): - try: - prop = Property( - name=name, - value=value, - ns=ns, - class_=class_, - remarks=self._rule_set, - ) - self._props[name] = prop - except Exception: - text = f'Invalid property name: {name} value: {value} remarks: {self._rule_set}' - raise RuntimeError(text) + prop = row_property_builder( + row=self._row_number, + name=name, + value=value, + ns=ns, + class_=class_, + remarks=self._rule_set, + ) + self._props[name] = prop def get_props(self) -> List[Property]: """Get props."""