from SearchIndicatorAgentix import ( escape_special_characters, build_query_for_indicator_values, prepare_query, KEYS_TO_EXCLUDE_FROM_QUERY, build_query_excluding_indicator_values, search_indicators, ) import json import pytest def test_escape_special_characters_backslash(): """ Given: A value containing backslash characters When: escape_special_characters is called Then: Returns value with backslashes properly escaped """ value = "test\\path\\file" expected = "test\\\\path\\\\file" result = escape_special_characters(value) assert result == expected def test_escape_special_characters_quotes(): """ Given: A value containing double quotes When: escape_special_characters is called Then: Returns value with quotes properly escaped """ value = 'This is a "quoted" string' expected = 'This\\ is\\ a\\ \\"quoted\\"\\ string' result = escape_special_characters(value) assert result == expected def test_escape_special_characters_newlines_and_tabs(): """ Given: A value containing newlines, tabs, and carriage returns When: escape_special_characters is called Then: Returns value with whitespace characters properly escaped """ value = "line1\nline2\tcolumn\rreturn" expected = "line1\\nline2\\tcolumn\\rreturn" result = escape_special_characters(value) assert result == expected def test_escape_special_characters_colon_and_caret(): """ Given: A value containing colons and caret characters When: escape_special_characters is called Then: Returns value with special query characters properly escaped """ value = "field:value^boost" expected = "field\\:value\\^boost" result = escape_special_characters(value) assert result == expected def test_escape_special_characters_spaces(): """ Given: A value containing spaces When: escape_special_characters is called Then: Returns value with spaces properly escaped """ value = "hello world test" expected = "hello\\ world\\ test" result = escape_special_characters(value) assert result == expected def test_escape_special_characters_mixed_special_chars(): """ Given: A value containing multiple different special characters When: escape_special_characters is called Then: Returns value with all special characters properly escaped """ value = 'path\\file:"value" test\nline^boost' expected = 'path\\\\file\\:\\"value\\"\\ test\\nline\\^boost' result = escape_special_characters(value) assert result == expected def test_escape_special_characters_empty_string(): """ Given: An empty string When: escape_special_characters is called Then: Returns empty string unchanged """ value = "" expected = "" result = escape_special_characters(value) assert result == expected def test_escape_special_characters_no_special_chars(): """ Given: A value containing no special characters When: escape_special_characters is called Then: Returns the original value unchanged """ value = "normaltext123" expected = "normaltext123" result = escape_special_characters(value) assert result == expected def test_escape_special_characters_only_special_chars(): """ Given: A value containing only special characters When: escape_special_characters is called Then: Returns all characters properly escaped """ value = '\\ \n\t\r"^:' expected = '\\\\\\ \\n\\t\\r\\"\\^\\:' result = escape_special_characters(value) assert result == expected def test_escape_special_characters_repeated_chars(): """ Given: A value with repeated special characters When: escape_special_characters is called Then: Returns value with each occurrence properly escaped """ value = "test::value^^boost space" expected = "test\\:\\:value\\^\\^boost\\ \\ space" result = escape_special_characters(value) assert result == expected @pytest.mark.parametrize( "n,expected_chunks", [ (0, 0), # empty -> [] (50, 1), # <100 -> one chunk (100, 1), # exactly 100 -> one chunk (110, 2), # 100 + 10 -> two chunks (250, 3), # 100 + 100 + 50 -> three chunks ], ) def test_build_query_for_indicator_values_chunk_counts(n, expected_chunks): # build n indicator values values = [f"v{i}" for i in range(n)] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) # Check number of chunk queries returned assert isinstance(result, list) assert len(result) == expected_chunks # Optionally, verify each chunk's size by counting " OR " occurrences (+1 = items in chunk) # because our stub joins values with " OR " and build_query wraps with parentheses. remaining = n for chunk_str in result: # strip outer parentheses added in build_query_for_indicator_values inner = chunk_str[1:-1] items_in_chunk = 0 if inner == "" else inner.count(" OR ") + 1 expected_size = min(100, remaining) assert items_in_chunk == expected_size remaining -= expected_size assert remaining == 0 def test_build_query_for_values_empty_args(): """ Given: Empty arguments dictionary When: build_query_for_values is called Then: Returns empty list """ args = {} result = build_query_for_indicator_values(args) assert result == [] def test_build_query_for_values_no_value_key(): """ Given: Arguments without 'value' key When: build_query_for_values is called Then: Returns empty list """ args = {"type": "Domain", "verdict": "Malicious"} result = build_query_for_indicator_values(args) assert result == [] def test_build_query_for_values_empty_value_list(): """ Given: Arguments with empty value list When: build_query_for_values is called Then: Returns empty list """ args = {"value": []} result = build_query_for_indicator_values(args) assert result == [] def test_build_query_for_values_single_value(): """ Given: Arguments with single value in JSON string format When: build_query_for_values is called Then: Returns list with one properly formatted query """ args = {"value": json.dumps(["example"])} result = build_query_for_indicator_values(args) assert len(result) == 1 assert 'value:"example"' in result[0] def test_build_query_for_values_multiple_values_under_100(): """ Given: Arguments with multiple values under 100 limit When: build_query_for_values is called Then: Returns list with one query containing OR operators """ values = ["example", "test", "sample"] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 1 for value in values: assert f'value:"{value}"' in result[0] assert " OR " in result[0] def test_build_query_for_values_exactly_100_values(): """ Given: Arguments with exactly 100 values When: build_query_for_values is called Then: Returns list with one query containing all values """ values = [f"example{i}" for i in range(100)] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 1 assert "example0" in result[0] assert "example99" in result[0] def test_build_query_for_values_over_100_values(): """ Given: Arguments with over 100 values When: build_query_for_values is called Then: Returns multiple queries with chunked values """ values = [f"example{i}" for i in range(150)] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 2 assert "example0" in result[0] assert "example99" in result[0] assert "example100" in result[1] assert "example149" in result[1] def test_build_query_for_values_exactly_101_values(): """ Given: Arguments with exactly 101 values When: build_query_for_values is called Then: Returns two queries with 100 and 1 values respectively """ values = [f"test{i}" for i in range(101)] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 2 assert "test0" in result[0] assert "test99" in result[0] assert "test100" in result[1] assert " OR " not in result[1] def test_build_query_for_values_with_special_characters(): """ Given: Arguments with values containing special characters When: build_query_for_values is called Then: Returns queries with properly escaped special characters """ values = ["test with spaces", 'test"quotes', "test\\backslash"] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 1 assert "test\\ with\\ spaces" in result[0] assert 'test\\"quotes' in result[0] assert "test\\\\backslash" in result[0] def test_build_query_for_values_with_whitespace(): """ Given: Arguments with values containing leading/trailing whitespace When: build_query_for_values is called Then: Returns queries with whitespace stripped from values """ values = [" example ", "\ttest\n", " sample "] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert 'value:"test"' in result[0] assert 'value:"sample"' in result[0] def test_build_query_for_values_mixed_data_types(): """ Given: Arguments with values of mixed data types (strings, numbers) When: build_query_for_values is called Then: Returns queries with all values converted to strings """ values = ["example", 192168001001, True, None] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert 'value:"192168001001"' in result[0] assert 'value:"True"' in result[0] assert 'value:"None"' in result[0] def test_build_query_for_values_large_chunk_boundary(): """ Given: Arguments with 250 values (tests multiple chunks) When: build_query_for_values is called Then: Returns three queries with proper chunk distribution """ values = [f"domain{i}.example" for i in range(250)] args = {"value": json.dumps(values)} result = build_query_for_indicator_values(args) assert len(result) == 3 assert "domain0.example" in result[0] assert "domain99.example" in result[0] assert "domain100.example" in result[1] assert "domain199.example" in result[1] assert "domain200.example" in result[2] assert "domain249.example" in result[2] def test_prepare_query_empty_args(): """ Given: Empty arguments dictionary When: prepare_query is called Then: Returns empty list """ args = {} result = prepare_query(args) assert result == [] def test_prepare_query_only_value_filters(): """ Given: Arguments with only value filters When: prepare_query is called Then: Returns queries containing only value filters """ args = {"value": json.dumps(["example", "test"])} result = prepare_query(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert 'value:"test"' in result[0] assert " OR " in result[0] assert " AND " not in result[0] def test_prepare_query_only_field_filters(): """ Given: Arguments with only field filters (no values) When: prepare_query is called Then: Returns empty list as no value filters exist """ args = {"type": "Domain", "verdict": "Malicious"} result = prepare_query(args) assert result == ['(type:"Domain") AND (verdict:"Malicious")'] def test_prepare_query_value_and_field_filters(): """ Given: Arguments with both value and field filters When: prepare_query is called Then: Returns queries combining value and field filters with AND """ args = {"value": json.dumps(["example"]), "type": json.dumps(["Domain"]), "verdict": json.dumps(["Malicious"])} result = prepare_query(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert "type:" in result[0] assert "verdict:" in result[0] assert "Domain" in result[0] assert "Malicious" in result[0] assert " AND " in result[0] def test_prepare_query_multiple_value_chunks(): """ Given: Arguments with over 100 values requiring chunking When: prepare_query is called Then: Returns multiple queries each combined with field filters """ values = [f"example{i}" for i in range(150)] args = {"value": json.dumps(values), "type": json.dumps(["Domain"])} result = prepare_query(args) assert len(result) == 2 for query in result: assert "type:" in query assert "Domain" in query assert " AND " in query def test_prepare_query_single_value_with_fields(): """ Given: Arguments with single value and multiple field filters When: prepare_query is called Then: Returns single query with value and all field filters """ args = { "value": json.dumps(["test.example"]), "type": json.dumps(["Domain"]), "verdict": json.dumps(["Malicious"]), "score": json.dumps(["High"]), } result = prepare_query(args) assert len(result) == 1 assert 'value:"test.example"' in result[0] assert "type:" in result[0] assert "verdict:" in result[0] assert "score:" in result[0] assert result[0].count(" AND ") == 3 def test_prepare_query_empty_value_list(): """ Given: Arguments with empty value list and field filters When: prepare_query is called Then: Returns empty list """ args = {"value": "[]", "type": "Domain"} result = prepare_query(args) assert result == ['(type:"Domain")'] def test_prepare_query_values_with_special_characters(): """ Given: Arguments with values containing special characters and field filters When: prepare_query is called Then: Returns queries with properly escaped values combined with fields """ args = {"value": json.dumps(["test with spaces", 'test"quotes']), "type": "Domain"} result = prepare_query(args) assert len(result) == 1 assert "test\\ with\\ spaces" in result[0] assert 'test\\"quotes' in result[0] assert "type:" in result[0] assert " AND " in result[0] def test_prepare_query_excluded_keys_ignored(): """ Given: Arguments with value filters, valid fields, and excluded keys When: prepare_query is called Then: Returns queries excluding the excluded keys but including valid fields """ excluded_key = KEYS_TO_EXCLUDE_FROM_QUERY[0] if KEYS_TO_EXCLUDE_FROM_QUERY else "dummy" args = {"value": json.dumps(["example"]), "type": "Domain", excluded_key: json.dumps(["excluded_value"])} result = prepare_query(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert "type:" in result[0] assert f"{excluded_key}:" not in result[0] def test_prepare_query_issues_ids_transformation(): """ Given: Arguments with IssuesIDs field and value filters When: prepare_query is called Then: Returns queries with IssuesIDs transformed to investigationIDs """ args = {"value": json.dumps(["example"]), "IssuesIDs": "123,456"} result = prepare_query(args) assert len(result) == 1 assert "investigationIDs:" in result[0] assert "IssuesIDs:" not in result[0] assert "123" in result[0] assert "456" in result[0] def test_prepare_query_empty_fields_ignored(): """ Given: Arguments with value filters and empty field values When: prepare_query is called Then: Returns queries containing only value filters as empty fields are ignored """ args = {"value": json.dumps(["example"]), "type": "", "verdict": ""} result = prepare_query(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert "type:" not in result[0] assert "verdict:" not in result[0] assert " AND " not in result[0] def test_prepare_query_large_value_set_with_complex_fields(): """ Given: Arguments with 250 values and multiple complex field filters When: prepare_query is called Then: Returns three queries each combined with all field filters """ values = [f"domain{i}.example" for i in range(250)] args = { "value": json.dumps(values), "type": json.dumps(["Domain", "IP"]), "verdict": json.dumps(["Malicious"]), "score": json.dumps(["High", "Medium"]), } result = prepare_query(args) assert len(result) == 3 for query in result: assert "type:" in query assert "verdict:" in query assert "score:" in query assert query.count(" AND ") == 3 def test_prepare_query_mixed_data_types_in_values(): """ Given: Arguments with mixed data types in values and field filters When: prepare_query is called Then: Returns queries with all values converted to strings and combined with fields """ args = {"value": json.dumps(["example", 192168001001, True]), "type": "Domain"} result = prepare_query(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert 'value:"192168001001"' in result[0] assert 'value:"True"' in result[0] assert "type:" in result[0] assert " AND " in result[0] def test_prepare_query_whitespace_stripped_from_values(): """ Given: Arguments with values containing whitespace and field filters When: prepare_query is called Then: Returns queries with whitespace stripped from values """ args = {"value": json.dumps([" example ", "\ttest.org\n"]), "type": "Domain"} result = prepare_query(args) assert len(result) == 1 assert 'value:"example"' in result[0] assert 'value:"test.org"' in result[0] assert "type:" in result[0] assert " AND " in result[0] def test_build_query_excluding_indicator_values_empty_args(): """ Given: Empty arguments dictionary When: build_query_excluding_indicator_values is called Then: Returns empty string """ args = {} result = build_query_excluding_indicator_values(args) assert result == "" def test_build_query_excluding_indicator_values_only_value_key(): """ Given: Arguments containing only 'value' key When: build_query_excluding_indicator_values is called Then: Returns empty string as value key is excluded """ args = {"value": json.dumps(["example", "test"])} result = build_query_excluding_indicator_values(args) assert result == "" def test_build_query_excluding_indicator_values_single_field(): """ Given: Arguments with single field excluding value When: build_query_excluding_indicator_values is called Then: Returns query string with single field condition in parentheses """ args = {"type": "Domain"} result = build_query_excluding_indicator_values(args) assert result == '(type:"Domain")' def test_build_query_excluding_indicator_values_multiple_fields(): """ Given: Arguments with multiple fields excluding value When: build_query_excluding_indicator_values is called Then: Returns query string with multiple field conditions joined by AND """ args = {"type": json.dumps(["Domain"]), "verdict": "Malicious"} result = build_query_excluding_indicator_values(args) assert "(type:" in result assert "(verdict:" in result assert "Domain" in result assert "Malicious" in result assert " AND " in result def test_build_query_excluding_indicator_values_with_value_field_mixed(): """ Given: Arguments with value field and other fields When: build_query_excluding_indicator_values is called Then: Returns query string excluding value field but including other fields """ args = {"value": json.dumps(["example"]), "type": "Domain", "verdict": "Malicious"} result = build_query_excluding_indicator_values(args) assert "value:" not in result assert "type:" in result assert "verdict:" in result assert " AND " in result def test_build_query_excluding_indicator_values_issues_ids_transformation(): """ Given: Arguments with IssuesIDs field When: build_query_excluding_indicator_values is called Then: Returns query string with IssuesIDs transformed to investigationIDs """ args = {"IssuesIDs": "123,456"} result = build_query_excluding_indicator_values(args) assert "investigationIDs:" in result assert "IssuesIDs:" not in result assert "123" in result assert "456" in result def test_build_query_excluding_indicator_values_excluded_keys_ignored(): """ Given: Arguments with fields in KEYS_TO_EXCLUDE_FROM_QUERY When: build_query_excluding_indicator_values is called Then: Returns query string excluding the excluded keys """ excluded_key = KEYS_TO_EXCLUDE_FROM_QUERY[0] if KEYS_TO_EXCLUDE_FROM_QUERY else "dummy" args = {"type": "Domain", excluded_key: "excluded_value"} result = build_query_excluding_indicator_values(args) assert "type:" in result assert f"{excluded_key}:" not in result def test_build_query_excluding_indicator_values_empty_field_values(): """ Given: Arguments with empty field values When: build_query_excluding_indicator_values is called Then: Returns empty string as empty fields are ignored """ args = {"type": [], "verdict": "", "score": None} result = build_query_excluding_indicator_values(args) assert result == "" def test_build_query_excluding_indicator_values_mixed_empty_and_valid_fields(): """ Given: Arguments with mix of empty and valid field values When: build_query_excluding_indicator_values is called Then: Returns query string containing only valid fields """ args = {"type": "Domain", "verdict": "", "score": "High"} result = build_query_excluding_indicator_values(args) assert "type:" in result assert "score:" in result assert "verdict:" not in result assert " AND " in result def test_build_query_excluding_indicator_values_multiple_values_in_field(): """ Given: Arguments with field containing multiple values When: build_query_excluding_indicator_values is called Then: Returns query string with OR operators between multiple values """ args = {"type": "Domain,IP,URL"} result = build_query_excluding_indicator_values(args) assert "(type:" in result assert "Domain" in result assert "IP" in result assert "URL" in result assert " OR " in result def test_build_query_excluding_indicator_values_single_value_no_or(): """ Given: Arguments with field containing single value When: build_query_excluding_indicator_values is called Then: Returns query string without OR operators """ args = {"type": "Domain"} result = build_query_excluding_indicator_values(args) assert "(type:" in result assert "Domain" in result assert " OR " not in result def test_build_query_excluding_indicator_values_complex_multiple_fields(): """ Given: Arguments with multiple fields each having multiple values When: build_query_excluding_indicator_values is called Then: Returns query string with proper AND/OR structure """ args = { "type": "Domain,IP", "verdict": "Malicious,Suspicious", "score": "High", } result = build_query_excluding_indicator_values(args) assert result.count("(") == 3 assert result.count(")") == 3 assert result.count(" AND ") == 2 assert "type:" in result assert "verdict:" in result assert "score:" in result def test_build_query_excluding_indicator_values_non_json_string_values(): """ Given: Arguments with field values as plain strings (not JSON) When: build_query_excluding_indicator_values is called Then: Returns query string treating plain strings as single values """ args = {"type": "Domain", "verdict": "Malicious"} result = build_query_excluding_indicator_values(args) assert "type:" in result assert "verdict:" in result assert "Domain" in result assert "Malicious" in result assert " AND " in result def test_build_query_excluding_indicator_values_mixed_json_and_plain_values(): """ Given: Arguments with mix of JSON and plain string field values When: build_query_excluding_indicator_values is called Then: Returns query string handling both value types correctly """ args = {"type": "Domain,IP", "verdict": "Malicious", "score": "High"} result = build_query_excluding_indicator_values(args) assert "type:" in result assert "verdict:" in result assert "score:" in result assert " OR " in result assert " AND " in result def test_build_query_excluding_indicator_values_issues_ids_with_other_fields(): """ Given: Arguments with IssuesIDs and other fields When: build_query_excluding_indicator_values is called Then: Returns query string with IssuesIDs transformed and combined with other fields """ args = {"IssuesIDs": "123,456", "type": "Domain"} result = build_query_excluding_indicator_values(args) assert "investigationIDs:" in result assert "type:" in result assert "IssuesIDs:" not in result assert " AND " in result def test_build_query_excluding_indicator_values_value_field_at_different_positions(): """ Given: Arguments with value field at beginning, middle, and end positions When: build_query_excluding_indicator_values is called Then: Returns query string excluding value field regardless of position """ args = {"value": json.dumps(["test"]), "type": "Domain", "verdict": "Malicious"} result = build_query_excluding_indicator_values(args) assert "value:" not in result assert "type:" in result assert "verdict:" in result def test_search_indicators_empty_args(): """ Given: Empty arguments dictionary When: search_indicators is called Then: Returns empty markdown and empty list as no queries are generated """ args = {} markdown, filtered_indicators = search_indicators(args) assert filtered_indicators == [] assert "Indicators Found" in markdown def test_search_indicators_no_results(mocker): """ Given: Valid arguments that generate queries but find no indicators When: search_indicators is called Then: Returns empty results with proper markdown formatting """ args = {"value": json.dumps(["nonexistent"])} mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{"Contents": []}] mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert filtered_indicators == [] assert "Indicators Found" in markdown def test_search_indicators_single_query_single_result(mocker): """ Given: Arguments that generate single query and return single indicator When: search_indicators is called Then: Returns properly formatted indicator with all required fields """ args = {"value": json.dumps(["example.com"])} mock_indicator = { "id": "123", "indicator_type": "Domain", "value": "example", "score": 3, "expirationStatus": "Active", "investigationIDs": ["inv1"], "lastSeen": "2023-01-01", } mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{"Contents": [mock_indicator]}] mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert len(filtered_indicators) == 1 assert filtered_indicators[0]["id"] == "123" assert filtered_indicators[0]["verdict"] == "Malicious" assert "example" in markdown def test_search_indicators_multiple_queries_multiple_results(mocker): """ Given: Arguments generating multiple queries each returning indicators When: search_indicators is called Then: Returns combined results from all queries """ values = [f"example{i}.com" for i in range(150)] args = {"value": json.dumps(values)} mock_indicator1 = { "id": "123", "indicator_type": "Domain", "value": "example1.com", "score": 2, "expirationStatus": "Active", "investigationIDs": [], "lastSeen": "2023-01-01", } mock_indicator2 = { "id": "456", "indicator_type": "Domain", "value": "example2.com", "score": 1, "expirationStatus": "Expired", "investigationIDs": ["inv2"], "lastSeen": "2023-01-02", } mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.side_effect = [[{"Contents": [mock_indicator1]}], [{"Contents": [mock_indicator2]}]] mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert len(filtered_indicators) == 2 assert filtered_indicators[0]["id"] == "123" assert filtered_indicators[1]["id"] == "456" assert mock_demisto.executeCommand.call_count == 2 def test_search_indicators_missing_fields_with_custom_fields(mocker): """ Given: Indicator with missing standard fields but present in CustomFields When: search_indicators is called Then: Returns indicator with fields populated from CustomFields """ args = {"value": json.dumps(["example"])} mock_indicator = { "id": "123", "value": "example", "CustomFields": { "indicator_type": "Domain", "score": 2, "expirationStatus": "Active", "investigationIDs": ["inv1"], "lastSeen": "2023-01-01", }, } mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{"Contents": [mock_indicator]}] mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert len(filtered_indicators) == 1 assert filtered_indicators[0]["indicator_type"] == "Domain" assert filtered_indicators[0]["score"] == 2 def test_search_indicators_with_size_parameter(mocker): """ Given: Arguments with size parameter to limit results When: search_indicators is called Then: Passes size parameter to executeCommand """ args = {"value": json.dumps(["example.com"]), "size": 50} mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{"Contents": []}] mock_demisto.debug.return_value = None search_indicators(args) mock_demisto.executeCommand.assert_called() call_args = mock_demisto.executeCommand.call_args[0][1] assert call_args["size"] == 50 def test_search_indicators_no_size_parameter(mocker): """ Given: Arguments without size parameter When: search_indicators is called Then: Passes None as size to executeCommand """ args = {"value": json.dumps(["example"])} mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{"Contents": []}] mock_demisto.debug.return_value = None search_indicators(args) mock_demisto.executeCommand.assert_called() call_args = mock_demisto.executeCommand.call_args[0][1] assert call_args["size"] is None def test_search_indicators_execute_command_returns_none(mocker): """ Given: executeCommand returns None When: search_indicators is called Then: Handles None result gracefully and returns empty results """ args = {"value": json.dumps(["example"])} mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = None mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert filtered_indicators == [] def test_search_indicators_execute_command_empty_result(mocker): """ Given: executeCommand returns empty result structure When: search_indicators is called Then: Handles empty result gracefully """ args = {"value": json.dumps(["example.com"])} mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{}] mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert filtered_indicators == [] def test_search_indicators_score_to_reputation_conversion(mocker): """ Given: Indicators with different score values When: search_indicators is called Then: Returns indicators with correct verdict based on score """ args = {"value": json.dumps(["example"])} mock_indicators = [ {"id": "2", "score": 1, "value": "unknown"}, {"id": "3", "score": 2, "value": "suspicious"}, {"id": "4", "score": 3, "value": "bad"}, ] mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{"Contents": mock_indicators}] mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert len(filtered_indicators) == 3 assert filtered_indicators[0]["verdict"] == "Benign" assert filtered_indicators[1]["verdict"] == "Suspicious" assert filtered_indicators[2]["verdict"] == "Malicious" def test_search_indicators_mixed_field_sources(mocker): """ Given: Indicators with fields from both standard and CustomFields locations When: search_indicators is called Then: Returns indicators with proper field precedence (standard over CustomFields) """ args = {"value": json.dumps(["example."])} mock_indicator = { "id": "123", "indicator_type": "Domain", "value": "example.", "score": 2, "CustomFields": { "indicator_type": "IP", "score": 3, "expirationStatus": "Expired", "investigationIDs": ["custom_inv"], "lastSeen": "2022-01-01", }, } mock_demisto = mocker.patch("SearchIndicatorAgentix.demisto") mock_demisto.executeCommand.return_value = [{"Contents": [mock_indicator]}] mock_demisto.debug.return_value = None markdown, filtered_indicators = search_indicators(args) assert len(filtered_indicators) == 1 assert filtered_indicators[0]["indicator_type"] == "Domain" assert filtered_indicators[0]["score"] == 2 assert filtered_indicators[0]["expirationStatus"] == "Expired"