diff --git a/checkout_sdk/exception.py b/checkout_sdk/exception.py index 32c5aee..4c0419b 100644 --- a/checkout_sdk/exception.py +++ b/checkout_sdk/exception.py @@ -7,6 +7,8 @@ class CheckoutException(Exception): def __init__(self, message=None): + if message is None: + message = "" super().__init__(message) @@ -37,8 +39,15 @@ class CheckoutApiException(CheckoutException): def __init__(self, response): self.http_metadata = map_to_http_metadata(response) if response.text: - payload = response.json() - self.error_details = payload['error_codes'] if 'error_codes' in payload else None - self.error_type = payload['error_type'] if 'error_type' in payload else None + try: + payload = response.json() + self.error_details = payload.get('error_codes') + self.error_type = payload.get('error_type') + except ValueError: + self.error_details = None + self.error_type = None + else: + self.error_details = None + self.error_type = None super().__init__('The API response status code ({}) does not indicate success.' .format(response.status_code)) diff --git a/tests/exception_test.py b/tests/exception_test.py index c81213d..33ef0bf 100644 --- a/tests/exception_test.py +++ b/tests/exception_test.py @@ -7,21 +7,35 @@ CheckoutApiException ) from checkout_sdk.authorization_type import AuthorizationType +from checkout_sdk.utils import map_to_http_metadata def test_checkout_exception(): - with pytest.raises(CheckoutException): + with pytest.raises(CheckoutException) as exc_info: raise CheckoutException("Test message") + exception = exc_info.value + assert str(exception) == "Test message" def test_checkout_argument_exception(): - with pytest.raises(CheckoutArgumentException): + with pytest.raises(CheckoutArgumentException) as exc_info: raise CheckoutArgumentException("Argument error occurred") + exception = exc_info.value + assert str(exception) == "Argument error occurred" + + +def test_checkout_argument_exception_no_message(): + with pytest.raises(CheckoutArgumentException) as exc_info: + raise CheckoutArgumentException() + exception = exc_info.value + assert str(exception) == "" # Después de modificar CheckoutException def test_checkout_authorization_exception(): - with pytest.raises(CheckoutAuthorizationException): + with pytest.raises(CheckoutAuthorizationException) as exc_info: raise CheckoutAuthorizationException("Authorization error occurred") + exception = exc_info.value + assert str(exception) == "Authorization error occurred" def test_invalid_authorization(): @@ -38,6 +52,14 @@ def test_invalid_key(): CheckoutAuthorizationException.invalid_key(key_type) +@pytest.mark.parametrize("auth_type_name", ["SECRET_KEY", "PUBLIC_KEY", "CUSTOM_KEY"]) +def test_invalid_authorization_various_types(auth_type_name): + auth_type = Mock(spec=AuthorizationType) + auth_type.name = auth_type_name + with pytest.raises(CheckoutAuthorizationException, match=f"{auth_type_name} authorization type"): + CheckoutAuthorizationException.invalid_authorization(auth_type) + + def test_checkout_api_exception(): response = Mock() response.status_code = 400 @@ -56,3 +78,118 @@ def test_checkout_api_exception(): assert exception.http_metadata.status_code == 400 assert exception.error_type == "request_invalid" assert exception.error_details == ["invalid_field"] + + +def test_checkout_api_exception_without_error_details(): + response = Mock() + response.status_code = 500 + response.text = '{"message": "Internal Server Error"}' + response.json.return_value = { + "message": "Internal Server Error" + } + + exception_instance = CheckoutApiException(response) + + with pytest.raises(CheckoutApiException) as exc_info: + raise exception_instance + + exception = exc_info.value + assert exception.http_metadata.status_code == 500 + assert exception.error_type is None + assert exception.error_details is None + + +def test_checkout_api_exception_empty_response(): + response = Mock() + response.status_code = 404 + response.text = '' + response.json.return_value = {} + + exception_instance = CheckoutApiException(response) + + with pytest.raises(CheckoutApiException) as exc_info: + raise exception_instance + + exception = exc_info.value + assert exception.http_metadata.status_code == 404 + assert exception.error_type is None + assert exception.error_details is None + + +def test_checkout_api_exception_non_json_response(): + response = Mock() + response.status_code = 502 + response.text = 'Bad Gateway' + response.json.side_effect = ValueError("No JSON object could be decoded") + + exception_instance = CheckoutApiException(response) + + with pytest.raises(CheckoutApiException) as exc_info: + raise exception_instance + + exception = exc_info.value + assert exception.http_metadata.status_code == 502 + assert exception.error_type is None + assert exception.error_details is None + + +@pytest.mark.parametrize("status_code", [400, 401, 403, 404, 500]) +def test_checkout_api_exception_various_status_codes(status_code): + response = Mock() + response.status_code = status_code + response.text = '' + response.json.return_value = {} + + exception_instance = CheckoutApiException(response) + + with pytest.raises(CheckoutApiException) as exc_info: + raise exception_instance + + exception = exc_info.value + assert exception.http_metadata.status_code == status_code + + +def test_map_to_http_metadata(): + response = Mock() + response.status_code = 200 + response.headers = {'Content-Type': 'application/json'} + + metadata = map_to_http_metadata(response) + assert metadata.status_code == 200 + assert metadata.headers == {'Content-Type': 'application/json'} + + +def test_checkout_api_exception_message(): + response = Mock() + response.status_code = 400 + response.text = '{"error_type": "invalid_request", "error_codes": ["bad_request"]}' + response.json.return_value = { + "error_type": "invalid_request", + "error_codes": ["bad_request"] + } + + exception_instance = CheckoutApiException(response) + + with pytest.raises(CheckoutApiException) as exc_info: + raise exception_instance + + exception = exc_info.value + expected_message = "The API response status code (400) does not indicate success." + assert str(exception) == expected_message + + +def test_checkout_api_exception_no_response_text(): + response = Mock() + response.status_code = 400 + response.text = None + response.json.return_value = {} + + exception_instance = CheckoutApiException(response) + + with pytest.raises(CheckoutApiException) as exc_info: + raise exception_instance + + exception = exc_info.value + assert exception.http_metadata.status_code == 400 + assert exception.error_type is None + assert exception.error_details is None