@@ -1101,3 +1101,128 @@ def test_extract_az_cli_error_message_skips_warnings():
11011101 output = 'WARNING: This is deprecated\n ERROR: Real error here'
11021102 result = az ._extract_az_cli_error_message (output )
11031103 assert result == 'Real error here'
1104+
1105+
1106+ def test_extract_az_cli_error_message_with_ansi_codes ():
1107+ """Test _extract_az_cli_error_message strips ANSI codes."""
1108+ output = '\x1b [31mERROR: Resource failed\x1b [0m'
1109+ result = az ._extract_az_cli_error_message (output )
1110+ assert result == 'Resource failed'
1111+
1112+
1113+ def test_extract_az_cli_error_message_finds_first_non_empty_line ():
1114+ """Test _extract_az_cli_error_message returns first meaningful line."""
1115+ output = '\n \n \n Some error occurred\n More details'
1116+ result = az ._extract_az_cli_error_message (output )
1117+ assert result == 'Some error occurred'
1118+
1119+
1120+ def test_looks_like_json_with_valid_json ():
1121+ """Test _looks_like_json identifies JSON strings."""
1122+ assert az ._looks_like_json ('{"key": "value"}' ) is True
1123+ assert az ._looks_like_json ('[1, 2, 3]' ) is True
1124+
1125+
1126+ def test_looks_like_json_with_non_json ():
1127+ """Test _looks_like_json rejects non-JSON strings."""
1128+ assert az ._looks_like_json ('plain text' ) is False
1129+ assert az ._looks_like_json ('' ) is False
1130+
1131+
1132+ def test_strip_ansi_removes_codes ():
1133+ """Test _strip_ansi removes ANSI escape codes."""
1134+ text = '\x1b [31mRed text\x1b [0m normal'
1135+ result = az ._strip_ansi (text )
1136+ assert '\x1b ' not in result
1137+ assert 'Red text' in result
1138+ assert 'normal' in result
1139+
1140+
1141+ def test_is_az_command_recognizes_az_commands ():
1142+ """Test _is_az_command identifies az CLI commands."""
1143+ assert az ._is_az_command ('az group list' ) is True
1144+ assert az ._is_az_command (' az account show ' ) is True
1145+ assert az ._is_az_command ('az' ) is True
1146+
1147+
1148+ def test_is_az_command_rejects_non_az_commands ():
1149+ """Test _is_az_command rejects non-az commands."""
1150+ assert az ._is_az_command ('echo hello' ) is False
1151+ assert az ._is_az_command ('python script.py' ) is False
1152+ assert az ._is_az_command ('azurecli' ) is False
1153+
1154+
1155+ def test_run_with_exception_in_subprocess ():
1156+ """Test run() handles subprocess exceptions gracefully."""
1157+ with patch ('azure_resources.subprocess.run' ) as mock_subprocess :
1158+ mock_subprocess .side_effect = Exception ('Subprocess failed' )
1159+
1160+ result = az .run ('az group list' )
1161+
1162+ assert result .success is False
1163+ assert 'Subprocess failed' in result .text
1164+
1165+
1166+ def test_run_with_stderr_only ():
1167+ """Test run() handles commands that only output to stderr."""
1168+ with patch ('azure_resources.subprocess.run' ) as mock_subprocess :
1169+ mock_process = Mock ()
1170+ mock_process .returncode = 0
1171+ mock_process .stdout = ''
1172+ mock_process .stderr = 'Some warning message'
1173+ mock_subprocess .return_value = mock_process
1174+
1175+ result = az .run ('az group list' )
1176+
1177+ assert result .success is True
1178+
1179+
1180+ def test_run_with_az_debug_flag_already_present ():
1181+ """Test run() doesn't duplicate --debug flag."""
1182+ with patch ('azure_resources.is_debug_enabled' , return_value = True ):
1183+ with patch ('azure_resources.subprocess.run' ) as mock_subprocess :
1184+ mock_process = Mock ()
1185+ mock_process .returncode = 0
1186+ mock_process .stdout = '[]'
1187+ mock_process .stderr = ''
1188+ mock_subprocess .return_value = mock_process
1189+
1190+ az .run ('az group list --debug' )
1191+
1192+ # Check that --debug appears only once in the command
1193+ called_command = mock_subprocess .call_args [0 ][0 ]
1194+ assert called_command .count ('--debug' ) == 1
1195+
1196+
1197+ def test_run_with_json_output_success ():
1198+ """Test run() with successful JSON output."""
1199+ with patch ('azure_resources.subprocess.run' ) as mock_subprocess :
1200+ mock_process = Mock ()
1201+ mock_process .returncode = 0
1202+ mock_process .stdout = '{"result": "success"}'
1203+ mock_process .stderr = ''
1204+ mock_subprocess .return_value = mock_process
1205+
1206+ result = az .run ('az group show --name test-rg' )
1207+
1208+ assert result .success is True
1209+ assert '{"result": "success"}' in result .text
1210+
1211+
1212+ def test_run_with_complex_shell_expression ():
1213+ """Test run() handles complex shell expressions with operators."""
1214+ with patch ('azure_resources.is_debug_enabled' , return_value = True ):
1215+ with patch ('azure_resources.subprocess.run' ) as mock_subprocess :
1216+ mock_process = Mock ()
1217+ mock_process .returncode = 0
1218+ mock_process .stdout = 'output'
1219+ mock_process .stderr = ''
1220+ mock_subprocess .return_value = mock_process
1221+
1222+ az .run ('az group list || echo "failed"' )
1223+
1224+ # --debug should be inserted before the ||
1225+ called_command = mock_subprocess .call_args [0 ][0 ]
1226+ debug_pos = called_command .find ('--debug' )
1227+ pipe_pos = called_command .find ('||' )
1228+ assert debug_pos < pipe_pos
0 commit comments