GetListRow

Parses a list by header and value.

python · Common Scripts

Details

IDGetListRow
Languagepython
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10404775

README

Parses a list by header and value.

Script Data


Name Description
Script Type python3
Tags  
Cortex XSOAR Version 5.0.0

Inputs


Argument Name Description
value Value to search for. If you supply a value, you need to supply the “header” argument also.
header Header to filter lines by. If you supply a header, you need to supply the “value” argument.
list_name The list name in which to search.
parse_all If “True”, parses the entire list into the context. Can be “True” or “False”. Default is “False”.
list_separator Separator to split the list by (use \\t in case of tab separated list).

Outputs


Path Description Type
GetListRow.Header Header in which the search was performed. String
GetListRow.Value Value to search for. String
GetListRow.ListName The name of the list that was searched.. String
GetListRow.ParseAll If “True”, the entire list was parsed into the context. String
GetListRow.Results All parse results of the list. UnKnown
import pytest
from CommonServerPython import *

RETURN_ERROR_TARGET = "GetListRow.return_error"
DATA_WITH_CUSTOM_SEP = [{"Contents": "name;id\nname1;id1\nname2;id2"}]
DATA_WITH_NEW_LINE_SEP = [{"Contents": "name\nid\nname1\nid1\nname2\nid2"}]
DATA_WITH_TAB_SEP = [{"Contents": "name	id\nname1	id1\nname2	id2"}]
DATA_WITH_TAB_SEP_2 = [{"Contents": "name\tid\nname1\tid1\nname2\tid2"}]


@pytest.mark.parametrize(
    "parse_all, header, value, expected",
    [("True", "", "", 0), ("true", "", "test", 0), ("False", "", "test", 1), ("False", "", "", 1), ("False", "test", "test", 0)],
)
def test_validate_args(mocker, parse_all, header, value, expected):
    from GetListRow import validate_args

    return_error_mock = mocker.patch(RETURN_ERROR_TARGET)
    validate_args(parse_all, header, value)
    assert return_error_mock.call_count == expected


@pytest.mark.parametrize("list_result, expected", [("False", 0), ("id, name, status, title", 0), ("Item not found", 1), ("", 1)])
def test_does_list_exist(mocker, list_result, expected):
    from GetListRow import validate_list_exists

    return_error_mock = mocker.patch(RETURN_ERROR_TARGET)
    validate_list_exists(list_result)
    assert return_error_mock.call_count == expected


@pytest.mark.parametrize(
    "headers, header, expected",
    [
        (["id", "name", "title", "status"], "id", 0),
        (["id", "name", "title", "status"], "status", 0),
        (["id", "name", "title", "status"], "statu", 1),
        (["id", "name"], "title", 1),
    ],
)
def test_does_header_exist(mocker, headers, header, expected):
    from GetListRow import validate_header_exists

    return_error_mock = mocker.patch(RETURN_ERROR_TARGET)
    validate_header_exists(headers, header)
    assert return_error_mock.call_count == expected


@pytest.mark.parametrize(
    "parse_all, header, value, list_name, list_separator, expected",
    [
        ("True", "", "on", "getListRow", ",", "List Result"),
        ("False", "status", "on", "getListRow", ",", "List Result"),
        ("False", "status", "n", "getListRow", ",", "No results found"),
    ],
)
def test_parse_list(mocker, parse_all, header, value, list_name, list_separator, expected):
    from GetListRow import parse_list

    mocker.patch.object(
        demisto,
        "executeCommand",
        return_value=[
            {
                "Contents": """id,name,title,status
                                                                  1,Chanoch,junior,on
                                                                  2,Or,manager,off
                                                                  3,Chen,developer,on"""
            }
        ],
    )
    res = parse_list(parse_all, header, value, list_name, list_separator)
    assert expected in res.readable_output


@pytest.mark.parametrize(
    "data, parse_all, header, value, list_name, list_separator, expected",
    [
        (
            DATA_WITH_CUSTOM_SEP,
            "True",
            "name",
            "id",
            "getListRow",
            ";",
            [{"name": "name1", "id": "id1"}, {"name": "name2", "id": "id2"}],
        ),
        (DATA_WITH_CUSTOM_SEP, "False", "name", "name2", "getListRow", ";", [{"name": "name2", "id": "id2"}]),
    ],
)
def test_custom_list_separator(mocker, data, parse_all, header, value, list_name, list_separator, expected):
    """
    Given:
        - Data that should be split by the custom separator ';'.
    When:
        - Running the script with a custom separator arg
    Then:
        - Ensure the parsed sata was split correctly
    """
    from GetListRow import parse_list

    mocker.patch.object(demisto, "executeCommand", return_value=data)
    res = parse_list(parse_all, header, value, list_name, list_separator)
    assert res.outputs.get("Results") == expected


@pytest.mark.parametrize(
    "data, parse_all, header, value, list_name, list_separator, expected",
    [
        (
            DATA_WITH_NEW_LINE_SEP,
            "True",
            "name",
            "id",
            "getListRow",
            "\n",
            [{"name": "id"}, {"name": "name1"}, {"name": "id1"}, {"name": "name2"}, {"name": "id2"}],
        ),
        (DATA_WITH_NEW_LINE_SEP, "False", "name", "name2", "getListRow", "\n", [{"name": "name2"}]),
    ],
)
def test_custom_list_new_line_sep(mocker, data, parse_all, header, value, list_name, list_separator, expected):
    """
    Given:
        - Data that should be split by the custom separator '\n'.
    When:
        - Running the script with a custom separator arg
    Then:
        - Ensure the parsed sata was split correctly
    """
    from GetListRow import parse_list

    mocker.patch.object(demisto, "executeCommand", return_value=data)
    res = parse_list(parse_all, header, value, list_name, list_separator)
    assert res.outputs.get("Results") == expected


@pytest.mark.parametrize(
    "data, parse_all, header, value, list_name, list_separator, expected",
    [
        (
            DATA_WITH_TAB_SEP,
            "True",
            "name",
            "id",
            "getListRow",
            "\t",
            [{"name": "name1", "id": "id1"}, {"name": "name2", "id": "id2"}],
        ),
        (DATA_WITH_TAB_SEP, "False", "name", "name2", "getListRow", "	", [{"name": "name2", "id": "id2"}]),
        (
            DATA_WITH_TAB_SEP_2,
            "True",
            "name",
            "id",
            "getListRow",
            "\\t",
            [{"name": "name1", "id": "id1"}, {"name": "name2", "id": "id2"}],
        ),
        (
            DATA_WITH_TAB_SEP_2,
            "True",
            "name",
            "id",
            "getListRow",
            "\t",
            [{"name": "name1", "id": "id1"}, {"name": "name2", "id": "id2"}],
        ),
    ],
)
def test_custom_list_tab_sep(mocker, data, parse_all, header, value, list_name, list_separator, expected):
    """
    Given:
        - Data that should be split by the tab separator (' ').
    When:
        - Running the script with a custom separator arg
    Then:
        - Ensure the parsed sata was split correctly
    """
    import GetListRow

    mock_args = {
        "list_name": list_name,
        "parse_all": parse_all,
        "header": header,
        "value": value,
        "list_separator": list_separator,
    }
    mocker.patch.object(demisto, "args", return_value=mock_args)
    mocker.patch.object(demisto, "executeCommand", return_value=data)
    mocker.patch.object(GetListRow, "return_results", return_value=data)

    GetListRow.main()

    assert GetListRow.return_results.call_args[0][0].outputs.get("Results") == expected


@pytest.mark.parametrize(
    "data, parse_all, header, value, expected_context_key",
    [
        (DATA_WITH_NEW_LINE_SEP, "True", "name", "id", ["list_name", "parse_all"]),
        (DATA_WITH_NEW_LINE_SEP, "False", "name", "name2", ["list_name", "parse_all", "header", "value"]),
    ],
)
def test_context_path_are_correct(mocker, data, parse_all, header, value, expected_context_key):
    from GetListRow import parse_list

    mocker.patch.object(demisto, "executeCommand", return_value=data)
    res = parse_list(parse_all, header, value, list_name="getListRow", list_separator="\n")
    assert res.outputs_prefix == "GetListRow"
    assert res.outputs_key_field == expected_context_key


@pytest.mark.parametrize(
    "list_data, expected_headers, expected_lines",
    [
        (
            "header_a ,header_b\nline_1_item_a,line_1_item_b\nline_2_item_a,line_2_item_b",
            ["header_a ", "header_b"],
            [["line_1_item_a", "line_1_item_b"], ["line_2_item_a", "line_2_item_b"]],
        ),
        (
            "header_a ,header_b\nline\r_1_item_a,line_1_item_b\nline\r_2_item_a,line_2_item_b",
            ["header_a ", "header_b"],
            [["line\r_1_item_a", "line_1_item_b"], ["line\r_2_item_a", "line_2_item_b"]],
        ),
        (
            "header_a ,header_b\r\nline_1_item_a,line_1_item_b\r\nline_2_item_a,line_2_item_b",
            ["header_a ", "header_b"],
            [["line_1_item_a", "line_1_item_b"], ["line_2_item_a", "line_2_item_b"]],
        ),
    ],
)
def test_list_to_headers_and_lines(list_data, expected_headers, expected_lines):
    """
    Given:
        - list_data.
        - Case 1: list data without any \r.
        - Case 2: list data with \r in the middle of a line.
        - Case 3: list data with \r followed by \n at the end of each line (except for last).
    When:
        - Running list_to_headers_and_lines.
    Then:
        - Ensure that the right parts of line was parsed into headers & lines.
        - Case 1: Should split the lines by \n.
        - Case 2: Should split the lines by \n and not do anything about the \r.
        - Case 3: Should split the lines by \r\n.
    """
    from GetListRow import list_to_headers_and_lines

    headers, lines = list_to_headers_and_lines(list_data, ",")
    assert expected_headers == headers
    assert expected_lines == lines


def test_parse_list_with_new_line_at_the_end(mocker):
    """
    Given:
        - A list with a new line at the end.
    When:
        - Parsing the list.
    Then:
        - Make sure that no exception is raised and the code finished gracefully.
    """
    list_with_new_line_at_the_end = """,mapping_framework,mapping_framework_version,capability_group,capability_id
0,veris,1.3.7,action.hacking

"""
    from GetListRow import parse_list

    mocker.patch.object(demisto, "executeCommand", return_value=[{"Contents": list_with_new_line_at_the_end}])
    res = parse_list(parse_all="false", header="mapping_framework", value="veris", list_name="test_list", list_separator=",")
    assert res