Skip to content

Commit

Permalink
bug: Add improved support for single arguments in get_list_args funct…
Browse files Browse the repository at this point in the history
…ion (#3589)
  • Loading branch information
TommyE123 authored Jun 13, 2024
1 parent 3849cb0 commit 46f129b
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Note: Can be used with `oxsecurity/megalinter@beta` in your GitHub Action mega-l
- [syft](https://github.com/anchore/syft) use `scan` instead of deprecated `packages` arg
- [Powershell](https://github.com/PowerShell/PSScriptAnalyzer#readme) Error table truncation improvements
- [yamllint](https://github.com/adrienverge/yamllint) fix error/warning count to work with different log output formats
- Improve support for single argument in `get_list_args` function

- Doc

Expand Down
27 changes: 21 additions & 6 deletions megalinter/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,15 +222,30 @@ def get_list(request_id, config_var, default=None):
return default


# Retrieve a configuration variable as a list of arguments, handling various input formats.
def get_list_args(request_id, config_var, default=None):
# Retrieve the variable from the configuration
var = get(request_id, config_var, None)
if var is not None:
if isinstance(var, list):
return var
if var == "":

match var:
# None return the default value
case None:
return default
# Blank or whitespace-only strings return empty list
case "" | str() if var.strip() == "":
return []
return shlex.split(var)
return default
# Integer or a Decimal return it as a list
case int() | float():
return [str(var)]
# If already a list just return it
case list():
return var
# If string does not contain spaces, return it as a list
case str() if " " not in var.strip():
return [var]
# Otherwise, split the string using shlex and return the result
case _:
return shlex.split(var)


def set_value(request_id, config_var, val):
Expand Down
110 changes: 110 additions & 0 deletions megalinter/tests/test_megalinter/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from megalinter.constants import ML_REPO
from megalinter.MegaLinter import Megalinter
from megalinter.utils import REPO_HOME_DEFAULT
from unittest.mock import patch


class config_test(unittest.TestCase):
Expand Down Expand Up @@ -481,3 +482,112 @@ def get_repository(self):

def get_branch(self):
return os.environ.get("GITHUB_BRANCH", "main")

def test_get_list_args(self):
# This is a test to check the functionality of the get_list_args method.
# It mocks the behavior of the get method within this method and asserts the expected output.
scenarios = [
("01", "none_value", None, None),
("02", "single_boolean_true", True, ['True']),
("03", "single_boolean_false", False, ['False']),
("04", "integer_value", 42, ['42']),
("05", "float_value", 3.14, ['3.14']),
("06", "empty_list", [], []),
("07", "empty_string", "", []),
("08", "single_space", ' ', []),
("09", "double_space", ' ', []),
("10", "empty_quoted_string", '""', ['""']),
("11", "non_empty_list", ["item1", "item2"], ['item1', 'item2']),
("12", "single_quoted_string", "'single_quoted_string'", ["'single_quoted_string'"]),
("13", "space_separated_items", 'item1 item2', ['item1', 'item2']),
("14", "multiple_single_quoted_strings", "'string1' 'string2' 'string3'",
['string1', 'string2', 'string3']),
("15", "mixed_single_and_double_quotes", '"double quoted" \'single quoted\'',
['double quoted', 'single quoted']),
("16", "three_space_separated_items", "item1 item2 item3", ['item1', 'item2', 'item3']),
("17", "four_space_separated_items", "item1 item2 item3 item4", ['item1', 'item2', 'item3', 'item4']),
("18", "five_space_separated_items", "item1 item2 item3 item4 item5",
['item1', 'item2', 'item3', 'item4', 'item5']),
("19", "single_quoted_with_spaces", "' single quoted with spaces '", [" single quoted with spaces "]),
("20", " quoted_with_leading_space", '" leading space"', [" leading space"]),
("21", "quoted_with_trailing_space", '"trailing space "', ["trailing space "]),
("22", "quoted_with_leading_and_trailing_spaces", '" leading and trailing spaces "',
[" leading and trailing spaces "]),
("23", "multiple_quoted_strings_with_spaces", '" string1 " "string2 " " string3 "',
[" string1 ", "string2 ", " string3 "]),
("24", "paths_with_nested_folders", "./nested/folder/file.txt", ['./nested/folder/file.txt']),
("25", "paths_with_parent_directory", "../parent/file.txt", ['../parent/file.txt']),
("26", "paths_with_tilde_home", "~/home/user/file.txt", ['~/home/user/file.txt']),
("27", "paths_with_url_files", "http://example.com/file.txt", ['http://example.com/file.txt']),
("28", "multiple_spaces_between_paths", 'path1 path2', ['path1', 'path2']),
("29", "relative_paths", "./relative/path ./another/relative/path",
['./relative/path', './another/relative/path']),
("30", "paths_with_file_extensions", "./file.txt ./folder/file.py", ['./file.txt', './folder/file.py']),
("31", "paths_with_hidden_files", "./folder/.file.sln ./folder/.hidden",
['./folder/.file.sln', './folder/.hidden']),
("32", "absolute_unix_paths", "/root/path /another/root/path", ['/root/path', '/another/root/path']),
("33", "quoted_paths_with_spaces", '"quoted path/with spaces" "another/quoted path"',
['quoted path/with spaces', 'another/quoted path']),
("34", "paths_with_url_and_local_files", "http://example.com/file.txt ./local/file.txt",
['http://example.com/file.txt', './local/file.txt']),
("35", "mixed_quotes_and_spaces", '"quoted item1" item2 \'quoted item3\' item4',
['quoted item1', 'item2', 'quoted item3', 'item4']),
("36", "command_with_options", 'command --option="value with spaces" --flag',
['command', '--option=value with spaces', "--flag"]),
("37", "list_with_spaces_in_elements", ["item 1", "item 2"], ['item 1', 'item 2']),
("38", "list_with_single_element", ["single_item"], ['single_item']),
("39", "list_with_single_element_with_spaces", ["single item"], ['single item']),
("40", "list_with_spaces_and_quotes", ['"item 1"', "'item 2'"], ['"item 1"', "'item 2'"]),
("41", "list_with_single_quoted_element_with_spaces", ['"single item"'], ['"single item"']),
("42", "list_with_single_element_and_spaces", [" single item "], [" single item "]),
("43", "list_with_single_quoted_element_and_spaces", [' "single item" '], [' "single item" ']),
("44", "list_with_comma_separated_items", "item1,item2,item3", ['item1,item2,item3']),
("45", "list_with_comma_and_space_separated_items", "item1, item2, item3", ['item1,', 'item2,', 'item3']),
("46", "list_with_semicolon_separated_items", "item1;item2;item3", ['item1;item2;item3']),
("47", "list_with_semicolon_and_space_separated_items", "item1; item2; item3", ['item1;', 'item2;', 'item3']),
("48", "list_with_multiple_elements", ["item1", "item2", "item3", "item4"], ['item1', 'item2', 'item3', 'item4']),
("49", "list_with_multiple_elements_with_spaces", ["item 1", "item 2", "item 3", "item 4"],
['item 1', 'item 2', 'item 3', 'item 4']),
("50", "list_with_multiple_quoted_elements_with_spaces", ['"item 1"', '"item 2"', '"item 3"', '"item 4"'],
['"item 1"', '"item 2"', '"item 3"', '"item 4"']),
("51", "list_with_multiple_elements_and_spaces", [" item1 ", " item2 ", " item3 ", " item4 "],
[" item1 ", " item2 ", " item3 ", " item4 "]),
("52", "list_with_multiple_quoted_elements_and_spaces", [' "item1" ', ' "item2" ', ' "item3" ', ' "item4" '],
[' "item1" ', ' "item2" ', ' "item3" ', ' "item4" ']),
("53", "list_with_comma_separated_multiple_items", "item1,item2;item3,item4", ['item1,item2;item3,item4']),
("54", "list_with_comma_and_space_separated_multiple_items", "item1, item2, item3, item4",
['item1,', 'item2,', 'item3,', 'item4']),
("55", "list_with_semicolon_separated_multiple_items", "item1;item2,item3;item4",['item1;item2,item3;item4']),
("56", "list_with_semicolon_and_space_separated_multiple_items", "item1; item2; item3; item4",
['item1;', 'item2;', 'item3;', 'item4']),
("57", "single_windows_path", "C:\\path\\to\\file.txt", ['C:\\path\\to\\file.txt']),
("58", "windows_path_with_spaces", '"C:\\path to\\file.txt"', ['C:\\path to\\file.txt']),
("59", "list_of_two_windows_paths", ["C:\\path\\to\\file1.txt", "C:\\path\\to\\file2.txt"],
['C:\\path\\to\\file1.txt', 'C:\\path\\to\\file2.txt']),
("60", "list_of_two_windows_paths_with_spaces", ['"C:\\path to\\file1.txt"', '"C:\\path to\\file2.txt"'],
['"C:\\path to\\file1.txt"', '"C:\\path to\\file2.txt"']),
("61", "network_share", "\\\\server\\share", ["\\\\server\\share"]),
("62", "network_share_with_spaces", "'\\\\server\\share\\path with spaces\\file.txt'", ['\\\\server\\share\\path with spaces\\file.txt']),
("63", "relative_path", ".\\path\\to\\file.txt", [".\\path\\to\\file.txt"]),
("64", "relative_path_with_spaces", '".\\path to\\file.txt"', ['.\\path to\\file.txt']),
("65", "list_of_two_network_shares", ["\\\\server1\\share\\file1.txt", "\\\\server2\\share\\file2.txt"],
["\\\\server1\\share\\file1.txt", "\\\\server2\\share\\file2.txt"]),
("66", "list_of_two_relative_paths", [".\\path1\\file1.txt", ".\\path2\\file2.txt"], [".\\path1\\file1.txt", ".\\path2\\file2.txt"])

# Commented out cases due to shlex.split removing the /
# ("67", "absolute_windows_paths", "C:\\absolute\\path C:\\another\\absolute\\path",
# ['C:\\absolute\\path', 'C:\\another\\absolute\\path']),
# ("68", "paths_with_environment_variables", "$HOME/file.txt $USERPROFILE\\file1.txt",
# ['$HOME/file.txt', '$USERPROFILE\\file1.txt']),
# ("69", "path_with_mixed_separators", "path/to/file path\\to\\another\\file",
# ['path/to/file', 'path\\to\\another\\file']),
# ("70", "complex_paths_and_files", 'file1 "complex path/file2" file3\\with\\backslashes',
# ['file1', 'complex path/file2', 'file3\\with\\backslashes'])
]

for scenario_number, scenario_name, return_value, expected_result in scenarios:
with self.subTest(scenario_number=scenario_number, scenario_name=scenario_name):
with patch.object(config, 'get', return_value=return_value):
result = config.get_list_args('dummy_request_id', scenario_name)
self.assertEqual(result, expected_result,
f"Failed on result scenario {scenario_number}: {scenario_name}")

0 comments on commit 46f129b

Please sign in to comment.