diff --git a/src/aws_encryption_sdk_cli/internal/arg_parsing.py b/src/aws_encryption_sdk_cli/internal/arg_parsing.py index 89e04ca..aa118cf 100644 --- a/src/aws_encryption_sdk_cli/internal/arg_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/arg_parsing.py @@ -15,6 +15,7 @@ from collections import defaultdict, OrderedDict import copy import logging +import platform import shlex from typing import Any, Dict, List, Optional, Sequence, Tuple, Union # noqa pylint: disable=unused-import @@ -41,6 +42,7 @@ def __init__(self, *args, **kwargs): # I would rather not duplicate the typeshed's effort keeping it up to date. # https://github.com/python/typeshed/blob/master/stdlib/2and3/argparse.pyi#L27-L39 self.__dummy_arguments = [] + self.__is_posix = not any(platform.win32_ver()) super(CommentIgnoringArgumentParser, self).__init__(*args, **kwargs) def add_dummy_redirect_argument(self, expected_name): @@ -82,7 +84,7 @@ def convert_arg_line_to_args(self, arg_line): drops both full-line and in-line comments. """ converted_line = [] - for arg in shlex.split(str(arg_line)): + for arg in shlex.split(str(arg_line), posix=self.__is_posix): arg = arg.strip() if arg.startswith('#'): break diff --git a/test/unit/test_arg_parsing.py b/test/unit/test_arg_parsing.py index 512bfa4..8c23ecd 100644 --- a/test/unit/test_arg_parsing.py +++ b/test/unit/test_arg_parsing.py @@ -11,6 +11,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Unit testing suite for ``aws_encryption_sdk_cli.internal.arg_parsing``.""" +import platform import shlex import aws_encryption_sdk @@ -23,6 +24,12 @@ from aws_encryption_sdk_cli.internal import arg_parsing, identifiers, metadata +@pytest.fixture +def patch_platform_win32_ver(mocker): + mocker.patch.object(arg_parsing.platform, 'win32_ver') + return arg_parsing.platform.win32_ver + + @pytest.yield_fixture def patch_build_parser(mocker): mocker.patch.object(arg_parsing, '_build_parser') @@ -87,6 +94,42 @@ def test_comment_ignoring_argument_parser_convert_arg_line_to_args(arg_line, lin assert line_args == parsed_line +POSIX_FILEPATH = ('-i test/file/path', ['-i', 'test/file/path']) +NON_POSIX_FILEPATH = ('-i test\\file\\path', ['-i', 'test\\file\\path']) + + +@pytest.mark.parametrize('win32_version, expected_transform', ( + (('', '', ''), POSIX_FILEPATH), + (('10', '10.0.0', 'SP0', 'Multiprocessor Free'), NON_POSIX_FILEPATH) +)) +def test_comment_ignoring_argument_parser_convert_filename(patch_platform_win32_ver, win32_version, expected_transform): + patch_platform_win32_ver.return_value = win32_version + parser = arg_parsing.CommentIgnoringArgumentParser() + + if any(win32_version): + assert not parser._CommentIgnoringArgumentParser__is_posix + else: + assert parser._CommentIgnoringArgumentParser__is_posix + + parsed_line = [arg for arg in parser.convert_arg_line_to_args(expected_transform[0])] + assert expected_transform[1] == parsed_line + + +def test_f_comment_ignoring_argument_parser_convert_filename(): + # Actually checks against the current local system + parser = arg_parsing.CommentIgnoringArgumentParser() + + if any(platform.win32_ver()): + assert not parser._CommentIgnoringArgumentParser__is_posix + expected_transform = NON_POSIX_FILEPATH + else: + assert parser._CommentIgnoringArgumentParser__is_posix + expected_transform = POSIX_FILEPATH + + parsed_line = [arg for arg in parser.convert_arg_line_to_args(expected_transform[0])] + assert expected_transform[1] == parsed_line + + def test_unique_store_action_first_call(): mock_parser = MagicMock() mock_namespace = MagicMock(special_attribute=None) @@ -134,7 +177,6 @@ def build_expected_good_args(): # pylint: disable=too-many-locals mkp_2 = ' -m provider=ex_provider_2 key=ex_mk_id_2' mkp_2_parsed = {'provider': 'ex_provider_2', 'key': ['ex_mk_id_2']} default_encrypt = encrypt + suppress_metadata + valid_io + mkp_1 - default_decrypt = decrypt + suppress_metadata + valid_io good_args = [] # encrypt/decrypt