From 535e5e33d5bae0c4440a7ed1570c8c72c636804a Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Sun, 17 Mar 2024 12:39:06 +0100 Subject: [PATCH] Worked on scripts and tests --- ACKNOWLEDGEMENTS | 3 + AUTHORS | 11 ++++ MANIFEST.in | 12 ++++ scripts/extract.py | 19 +++--- scripts/generate_docs.py | 2 +- scripts/generate_source.py | 4 +- scripts/resolve_names.py | 2 +- test_data/properties.yaml | 21 +++++++ tests/yaml_definitions_file.py | 98 +++++++++++++++++++++++++++++++ winspsrc/yaml_definitions_file.py | 10 ++-- 10 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 ACKNOWLEDGEMENTS create mode 100644 AUTHORS create mode 100644 MANIFEST.in create mode 100644 test_data/properties.yaml create mode 100644 tests/yaml_definitions_file.py diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS new file mode 100644 index 0000000..7090f59 --- /dev/null +++ b/ACKNOWLEDGEMENTS @@ -0,0 +1,3 @@ +Acknowledgements: winsps-kb + +Copyright (c) 2023-2024, Joachim Metz diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..5817ed8 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,11 @@ +# Names should be added to this file with this pattern: +# +# For individuals: +# Name (email address) +# +# For organizations: +# Organization (fnmatch pattern) +# +# See python fnmatch module documentation for more information. + +Joachim Metz (joachim.metz@gmail.com) diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..e6780d1 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,12 @@ +include ACKNOWLEDGEMENTS AUTHORS LICENSE README +include dependencies.ini run_tests.py utils/dependencies.py +include utils/check_dependencies.py +include requirements.txt test_requirements.txt +exclude .gitignore +exclude *.pyc +recursive-exclude winspsrc *.pyc +recursive-include test_data * +# The test scripts are not required in a binary distribution package they +# are considered source distribution files and excluded in find_package() +# in setup.py. +recursive-include tests *.py diff --git a/scripts/extract.py b/scripts/extract.py index 7e88021..104ada5 100755 --- a/scripts/extract.py +++ b/scripts/extract.py @@ -8,8 +8,8 @@ import sys import yaml -from dfimagetools.helpers import command_line as dfimagetools_command_line - +from dfvfs.helpers import command_line as dfvfs_command_line +from dfvfs.helpers import volume_scanner as dfvfs_volume_scanner from dfvfs.lib import errors as dfvfs_errors import winspsrc @@ -36,11 +36,8 @@ def Main(): dest='windows_version', action='store', metavar='Windows XP', default=None, help='string that identifies the Windows version.') - dfimagetools_command_line.AddStorageMediaImageCLIArguments(argument_parser) - argument_parser.add_argument( - 'source', nargs='?', action='store', metavar='/mnt/c/', - default=None, help=( + 'source', nargs='?', action='store', metavar='PATH', default=None, help=( 'path of the volume containing C:\\Windows or the filename of ' 'a storage media image containing the C:\\Windows directory.')) @@ -64,7 +61,7 @@ def Main(): logging.basicConfig( level=logging.INFO, format='[%(levelname)s] %(message)s') - definitions_file = yaml_definitions_file.YAMLPropertyDefinitionsFile() + definitions_file = yaml_definitions_file.YAMLPropertiesDefinitionsFile() data_path = os.path.join(os.path.dirname(winspsrc.__file__), 'data') @@ -89,8 +86,12 @@ def Main(): if lookup_key not in third_party_property_definitions: third_party_property_definitions[lookup_key] = property_definition - mediator, volume_scanner_options = ( - dfimagetools_command_line.ParseStorageMediaImageCLIArguments(options)) + mediator = dfvfs_command_line.CLIVolumeScannerMediator() + + volume_scanner_options = dfvfs_volume_scanner.VolumeScannerOptions() + volume_scanner_options.partitions = ['all'] + volume_scanner_options.snapshots = ['none'] + volume_scanner_options.volumes = ['none'] serialized_properties = {} defined_serialized_properties = {} diff --git a/scripts/generate_docs.py b/scripts/generate_docs.py index 75b109f..c1503d0 100755 --- a/scripts/generate_docs.py +++ b/scripts/generate_docs.py @@ -136,7 +136,7 @@ def Main(): logging.basicConfig( level=logging.INFO, format='[%(levelname)s] %(message)s') - definitions_file = yaml_definitions_file.YAMLPropertyDefinitionsFile() + definitions_file = yaml_definitions_file.YAMLPropertiesDefinitionsFile() property_definitions = {} diff --git a/scripts/generate_source.py b/scripts/generate_source.py index 16f439f..0c48720 100755 --- a/scripts/generate_source.py +++ b/scripts/generate_source.py @@ -27,7 +27,7 @@ def Main(): options = argument_parser.parse_args() - if options.format not in ('c', 'python'): + if options.format not in ('c_header', 'c_source', 'python'): print('Unsupported format.') print('') argument_parser.print_help() @@ -37,7 +37,7 @@ def Main(): logging.basicConfig( level=logging.INFO, format='[%(levelname)s] %(message)s') - definitions_file = yaml_definitions_file.YAMLPropertyDefinitionsFile() + definitions_file = yaml_definitions_file.YAMLPropertiesDefinitionsFile() property_definitions = {} diff --git a/scripts/resolve_names.py b/scripts/resolve_names.py index 09625bc..f563aa2 100755 --- a/scripts/resolve_names.py +++ b/scripts/resolve_names.py @@ -109,7 +109,7 @@ def Main(): logging.basicConfig( level=logging.INFO, format='[%(levelname)s] %(message)s') - definitions_file = yaml_definitions_file.YAMLPropertyDefinitionsFile() + definitions_file = yaml_definitions_file.YAMLPropertiesDefinitionsFile() property_definitions = {} diff --git a/test_data/properties.yaml b/test_data/properties.yaml new file mode 100644 index 0000000..38e23e8 --- /dev/null +++ b/test_data/properties.yaml @@ -0,0 +1,21 @@ +# winsps-kb property definitions. +--- +format_identifier: 00000000-0000-0000-0000-000000000000 +name: System.Null +property_identifier: 0 +shell_property_key: PKEY_Null +value_type: VT_NULL +--- +format_identifier: 7d683fc9-d155-45a8-bb1f-89d19bcb792f +name: System.Identity.DisplayName +property_identifier: 100 +shell_property_key: PKEY_Identity_DisplayName +value_type: VT_LPWSTR +--- +alias: PIDSI_TITLE +format_class: FMTID_SummaryInformation +format_identifier: f29f85e0-4ff9-1068-ab91-08002b27b3d9 +name: System.Title +property_identifier: 2 +shell_property_key: PKEY_Title +value_type: VT_LPWSTR diff --git a/tests/yaml_definitions_file.py b/tests/yaml_definitions_file.py new file mode 100644 index 0000000..38131c7 --- /dev/null +++ b/tests/yaml_definitions_file.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Tests for the YAML-based properties definitions file.""" + +import unittest + +from winspsrc import yaml_definitions_file + +from tests import test_lib + + +class YAMLPropertiesDefinitionsFileTest(test_lib.BaseTestCase): + """Tests for the YAML-based properties definitions file.""" + + # pylint: disable=protected-access + + _TEST_YAML = { + 'format_class': 'FMTID_IntSite', + 'format_identifier': '000214a1-0000-0000-c000-000000000046', + 'name': 'System.Status', + 'property_identifier': 9, + 'shell_property_key': 'PKEY_Status', + 'value_type': 'VT_LPWSTR'} + + def testReadPropertyDefinition(self): + """Tests the _ReadPropertyDefinition function.""" + test_definitions_file = ( + yaml_definitions_file.YAMLPropertiesDefinitionsFile()) + + definitions = test_definitions_file._ReadPropertyDefinition(self._TEST_YAML) + + self.assertIsNotNone(definitions) + self.assertEqual(definitions.format_class, 'FMTID_IntSite') + self.assertEqual( + definitions.format_identifier, '000214a1-0000-0000-c000-000000000046') + self.assertEqual(definitions.names, set(['System.Status'])) + self.assertEqual(definitions.property_identifier, 9) + self.assertEqual(definitions.shell_property_keys, set(['PKEY_Status'])) + self.assertEqual(definitions.value_types, set(['VT_LPWSTR'])) + + with self.assertRaises(RuntimeError): + test_definitions_file._ReadPropertyDefinition({}) + + with self.assertRaises(RuntimeError): + test_definitions_file._ReadPropertyDefinition({ + 'format_class': 'FMTID_IntSite', + 'name': 'System.Status', + 'property_identifier': 9, + 'shell_property_key': 'PKEY_Status', + 'value_type': 'VT_LPWSTR'}) + + with self.assertRaises(RuntimeError): + test_definitions_file._ReadPropertyDefinition({ + 'format_class': 'FMTID_IntSite', + 'format_identifier': '000214a1-0000-0000-c000-000000000046', + 'name': 'System.Status', + 'shell_property_key': 'PKEY_Status', + 'value_type': 'VT_LPWSTR'}) + + with self.assertRaises(RuntimeError): + test_definitions_file._ReadPropertyDefinition({ + 'bogus': 'test'}) + + def testReadFromFileObject(self): + """Tests the _ReadFromFileObject function.""" + test_file_path = self._GetTestFilePath(['properties.yaml']) + self._SkipIfPathNotExists(test_file_path) + + test_definitions_file = ( + yaml_definitions_file.YAMLPropertiesDefinitionsFile()) + + with open(test_file_path, 'r', encoding='utf-8') as file_object: + definitions = list(test_definitions_file._ReadFromFileObject(file_object)) + + self.assertEqual(len(definitions), 3) + + def testReadFromFile(self): + """Tests the ReadFromFile function.""" + test_file_path = self._GetTestFilePath(['properties.yaml']) + self._SkipIfPathNotExists(test_file_path) + + test_definitions_file = ( + yaml_definitions_file.YAMLPropertiesDefinitionsFile()) + + definitions = list(test_definitions_file.ReadFromFile(test_file_path)) + + self.assertEqual(len(definitions), 3) + + self.assertEqual( + definitions[0].format_identifier, + '00000000-0000-0000-0000-000000000000') + self.assertEqual( + definitions[2].format_identifier, + 'f29f85e0-4ff9-1068-ab91-08002b27b3d9') + + +if __name__ == '__main__': + unittest.main() diff --git a/winspsrc/yaml_definitions_file.py b/winspsrc/yaml_definitions_file.py index 33a1405..43da84e 100644 --- a/winspsrc/yaml_definitions_file.py +++ b/winspsrc/yaml_definitions_file.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- -"""YAML-based property definitions file.""" +"""YAML-based properties definitions file.""" import yaml from winspsrc import resources -class YAMLPropertyDefinitionsFile(object): - """YAML-based property definitions file. +class YAMLPropertiesDefinitionsFile(object): + """YAML-based properties definitions file. - A YAML-based property definitions file contains one or more property + A YAML-based properties definitions file contains one or more property definitions. A property definition consists of: format_identifier: 00000000-0000-0000-0000-000000000000 @@ -68,7 +68,7 @@ def _ReadPropertyDefinition(self, yaml_property_definition): property_identifier = yaml_property_definition.get( 'property_identifier', None) - if not format_identifier: + if property_identifier is None: raise RuntimeError( 'Invalid property definition missing property identifier.')