|
13 | 13 | from circuit_maintenance_parser.parsers.att import HtmlParserATT1, XlsxParserATT1 |
14 | 14 | from circuit_maintenance_parser.parsers.aws import SubjectParserAWS1, TextParserAWS1 |
15 | 15 | from circuit_maintenance_parser.parsers.bso import HtmlParserBSO1 |
16 | | -from circuit_maintenance_parser.parsers.cogent import HtmlParserCogent1 |
| 16 | +from circuit_maintenance_parser.parsers.cogent import HtmlParserCogent1, SubjectParserCogent1 |
17 | 17 | from circuit_maintenance_parser.parsers.colt import CsvParserColt1, SubjectParserColt1, SubjectParserColt2 |
18 | 18 | from circuit_maintenance_parser.parsers.crowncastle import HtmlParserCrownCastle1 |
19 | 19 | from circuit_maintenance_parser.parsers.equinix import HtmlParserEquinix, SubjectParserEquinix |
@@ -252,6 +252,11 @@ def default(self, o): |
252 | 252 | Path(dir_path, "data", "cogent", "cogent2.html"), |
253 | 253 | Path(dir_path, "data", "cogent", "cogent2_result.json"), |
254 | 254 | ), |
| 255 | + ( |
| 256 | + SubjectParserCogent1, |
| 257 | + Path(dir_path, "data", "cogent", "cogent3.eml"), |
| 258 | + Path(dir_path, "data", "cogent", "cogent3_subject_result.json"), |
| 259 | + ), |
255 | 260 | # Colt |
256 | 261 | ( |
257 | 262 | CsvParserColt1, |
@@ -844,3 +849,108 @@ def test_parser_no_data(parser_class): |
844 | 849 | """Test parser with no data.""" |
845 | 850 | with pytest.raises(ParserError): |
846 | 851 | parser_class().parse(b"", parser_class.get_data_types()[0]) # pylint: disable=protected-access |
| 852 | + |
| 853 | + |
| 854 | +def test_openai_parser_import_error(): |
| 855 | + """Test OpenAI parser raises ImportError when openai package is not available.""" |
| 856 | + from unittest.mock import patch |
| 857 | + |
| 858 | + from circuit_maintenance_parser.parsers.openai import OpenAIParser |
| 859 | + |
| 860 | + # Mock the absence of openai package |
| 861 | + with patch("circuit_maintenance_parser.parsers.openai._HAS_OPENAI", False): |
| 862 | + parser = OpenAIParser() |
| 863 | + with pytest.raises(ImportError, match="openai extra is required"): |
| 864 | + parser.get_llm_response("test content") |
| 865 | + |
| 866 | + |
| 867 | +def test_openai_parser_api_success(): |
| 868 | + """Test OpenAI parser with successful API response.""" |
| 869 | + import sys |
| 870 | + from unittest.mock import MagicMock, patch |
| 871 | + |
| 872 | + from circuit_maintenance_parser.parsers.openai import OpenAIParser |
| 873 | + |
| 874 | + # Mock successful API response |
| 875 | + mock_response = MagicMock() |
| 876 | + mock_response.usage.total_tokens = 100 |
| 877 | + mock_response.choices = [MagicMock()] |
| 878 | + mock_response.choices[0].message.content = '{"test": "data"}' |
| 879 | + |
| 880 | + mock_client = MagicMock() |
| 881 | + mock_client.chat.completions.create.return_value = mock_response |
| 882 | + |
| 883 | + # Mock the OpenAI module |
| 884 | + mock_openai_module = MagicMock() |
| 885 | + mock_openai_module.OpenAI.return_value = mock_client |
| 886 | + |
| 887 | + with patch.dict(sys.modules, {"openai": mock_openai_module}): |
| 888 | + with patch("circuit_maintenance_parser.parsers.openai._HAS_OPENAI", True): |
| 889 | + # Re-import to get the mocked OpenAI |
| 890 | + from circuit_maintenance_parser.parsers import openai as openai_parser |
| 891 | + |
| 892 | + openai_parser.OpenAI = mock_openai_module.OpenAI |
| 893 | + |
| 894 | + parser = OpenAIParser() |
| 895 | + result = parser.get_llm_response("test content") |
| 896 | + |
| 897 | + assert result == {"test": "data"} |
| 898 | + assert parser.tokens_used == 100 |
| 899 | + |
| 900 | + |
| 901 | +def test_openai_parser_api_exception(): |
| 902 | + """Test OpenAI parser handles API exceptions.""" |
| 903 | + import sys |
| 904 | + from unittest.mock import MagicMock, patch |
| 905 | + |
| 906 | + from circuit_maintenance_parser.parsers.openai import OpenAIParser |
| 907 | + |
| 908 | + mock_client = MagicMock() |
| 909 | + mock_client.chat.completions.create.side_effect = Exception("API Error") |
| 910 | + |
| 911 | + # Mock the OpenAI module |
| 912 | + mock_openai_module = MagicMock() |
| 913 | + mock_openai_module.OpenAI.return_value = mock_client |
| 914 | + |
| 915 | + with patch.dict(sys.modules, {"openai": mock_openai_module}): |
| 916 | + with patch("circuit_maintenance_parser.parsers.openai._HAS_OPENAI", True): |
| 917 | + from circuit_maintenance_parser.parsers import openai as openai_parser |
| 918 | + |
| 919 | + openai_parser.OpenAI = mock_openai_module.OpenAI |
| 920 | + |
| 921 | + parser = OpenAIParser() |
| 922 | + result = parser.get_llm_response("test content") |
| 923 | + |
| 924 | + assert result is None |
| 925 | + |
| 926 | + |
| 927 | +def test_openai_parser_invalid_json(): |
| 928 | + """Test OpenAI parser handles invalid JSON response.""" |
| 929 | + import sys |
| 930 | + from unittest.mock import MagicMock, patch |
| 931 | + |
| 932 | + from circuit_maintenance_parser.parsers.openai import OpenAIParser |
| 933 | + |
| 934 | + # Mock API response with invalid JSON |
| 935 | + mock_response = MagicMock() |
| 936 | + mock_response.usage.total_tokens = 50 |
| 937 | + mock_response.choices = [MagicMock()] |
| 938 | + mock_response.choices[0].message.content = "not valid json" |
| 939 | + |
| 940 | + mock_client = MagicMock() |
| 941 | + mock_client.chat.completions.create.return_value = mock_response |
| 942 | + |
| 943 | + # Mock the OpenAI module |
| 944 | + mock_openai_module = MagicMock() |
| 945 | + mock_openai_module.OpenAI.return_value = mock_client |
| 946 | + |
| 947 | + with patch.dict(sys.modules, {"openai": mock_openai_module}): |
| 948 | + with patch("circuit_maintenance_parser.parsers.openai._HAS_OPENAI", True): |
| 949 | + from circuit_maintenance_parser.parsers import openai as openai_parser |
| 950 | + |
| 951 | + openai_parser.OpenAI = mock_openai_module.OpenAI |
| 952 | + |
| 953 | + parser = OpenAIParser() |
| 954 | + result = parser.get_llm_response("test content") |
| 955 | + |
| 956 | + assert result is None |
0 commit comments