"""
Binance Convert REST API

OpenAPI Specification for the Binance Convert REST API
The version of the OpenAPI document: 1.0.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""

import json
import pytest
import requests

from unittest.mock import MagicMock, patch
from urllib.parse import parse_qs

from binance_common.configuration import ConfigurationRestAPI
from binance_common.errors import RequiredError
from binance_common.utils import normalize_query_values, is_one_of_model, snake_to_camel

from binance_sdk_convert.rest_api.api import TradeApi
from binance_sdk_convert.rest_api.models import AcceptQuoteResponse
from binance_sdk_convert.rest_api.models import CancelLimitOrderResponse
from binance_sdk_convert.rest_api.models import GetConvertTradeHistoryResponse
from binance_sdk_convert.rest_api.models import OrderStatusResponse
from binance_sdk_convert.rest_api.models import PlaceLimitOrderResponse
from binance_sdk_convert.rest_api.models import QueryLimitOpenOrdersResponse
from binance_sdk_convert.rest_api.models import SendQuoteRequestResponse


class TestTradeApi:
    @pytest.fixture(autouse=True)
    def setup_client(self):
        """Setup a client instance with mocked session before each test method."""
        self.mock_session = MagicMock(spec=requests.Session)
        config = ConfigurationRestAPI(
            api_key="test-api-key",
            api_secret="test-api-secret",
        )
        self.client = TradeApi(configuration=config, session=self.mock_session)

    def set_mock_response(self, data: dict = {}, status_code=200, headers=None):
        """Helper method to setup mock response for the client's session request."""
        if headers is None:
            headers = {}

        mock_response = MagicMock()
        mock_response.status_code = status_code
        mock_response.json.return_value = data
        mock_response.text = json.dumps(data)
        mock_response.headers = headers

        self.mock_session.request.return_value = mock_response

    @patch("binance_common.utils.get_signature")
    def test_accept_quote_success(self, mock_get_signature):
        """Test accept_quote() successfully with required parameters only."""

        params = {
            "quote_id": "1",
        }

        expected_response = {
            "orderId": "933256278426274426",
            "createTime": 1623381330472,
            "orderStatus": "PROCESS",
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.accept_quote(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/acceptQuote" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"
        assert normalized["quoteId"] == "1"

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(AcceptQuoteResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(AcceptQuoteResponse, "from_dict"):
            expected = AcceptQuoteResponse.from_dict(expected_response)
        else:
            expected = AcceptQuoteResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_accept_quote_success_with_optional_params(self, mock_get_signature):
        """Test accept_quote() successfully with optional parameters."""

        params = {"quote_id": "1", "recv_window": 5000}

        expected_response = {
            "orderId": "933256278426274426",
            "createTime": 1623381330472,
            "orderStatus": "PROCESS",
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.accept_quote(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/acceptQuote" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(AcceptQuoteResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(AcceptQuoteResponse, "from_dict"):
            expected = AcceptQuoteResponse.from_dict(expected_response)
        else:
            expected = AcceptQuoteResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    def test_accept_quote_missing_required_param_quote_id(self):
        """Test that accept_quote() raises RequiredError when 'quote_id' is missing."""
        params = {
            "quote_id": "1",
        }
        params["quote_id"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'quote_id'"
        ):
            self.client.accept_quote(**params)

    def test_accept_quote_server_error(self):
        """Test that accept_quote() raises an error when the server returns an error."""

        params = {
            "quote_id": "1",
        }

        mock_error = Exception("ResponseError")
        self.client.accept_quote = MagicMock(side_effect=mock_error)

        with pytest.raises(Exception, match="ResponseError"):
            self.client.accept_quote(**params)

    @patch("binance_common.utils.get_signature")
    def test_cancel_limit_order_success(self, mock_get_signature):
        """Test cancel_limit_order() successfully with required parameters only."""

        params = {
            "order_id": 1,
        }

        expected_response = {"orderId": 1603680255057330400, "status": "CANCELED"}
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.cancel_limit_order(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/limit/cancelOrder" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"
        assert normalized["orderId"] == 1

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(CancelLimitOrderResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(CancelLimitOrderResponse, "from_dict"):
            expected = CancelLimitOrderResponse.from_dict(expected_response)
        else:
            expected = CancelLimitOrderResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_cancel_limit_order_success_with_optional_params(self, mock_get_signature):
        """Test cancel_limit_order() successfully with optional parameters."""

        params = {"order_id": 1, "recv_window": 5000}

        expected_response = {"orderId": 1603680255057330400, "status": "CANCELED"}
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.cancel_limit_order(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/limit/cancelOrder" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(CancelLimitOrderResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(CancelLimitOrderResponse, "from_dict"):
            expected = CancelLimitOrderResponse.from_dict(expected_response)
        else:
            expected = CancelLimitOrderResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    def test_cancel_limit_order_missing_required_param_order_id(self):
        """Test that cancel_limit_order() raises RequiredError when 'order_id' is missing."""
        params = {
            "order_id": 1,
        }
        params["order_id"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'order_id'"
        ):
            self.client.cancel_limit_order(**params)

    def test_cancel_limit_order_server_error(self):
        """Test that cancel_limit_order() raises an error when the server returns an error."""

        params = {
            "order_id": 1,
        }

        mock_error = Exception("ResponseError")
        self.client.cancel_limit_order = MagicMock(side_effect=mock_error)

        with pytest.raises(Exception, match="ResponseError"):
            self.client.cancel_limit_order(**params)

    @patch("binance_common.utils.get_signature")
    def test_get_convert_trade_history_success(self, mock_get_signature):
        """Test get_convert_trade_history() successfully with required parameters only."""

        params = {
            "start_time": 1623319461670,
            "end_time": 1641782889000,
        }

        expected_response = {
            "list": [
                {
                    "quoteId": "f3b91c525b2644c7bc1e1cd31b6e1aa6",
                    "orderId": 940708407462087200,
                    "orderStatus": "SUCCESS",
                    "fromAsset": "USDT",
                    "fromAmount": "20",
                    "toAsset": "BNB",
                    "toAmount": "0.06154036",
                    "ratio": "0.00307702",
                    "inverseRatio": "324.99",
                    "createTime": 1624248872184,
                }
            ],
            "startTime": 1623824139000,
            "endTime": 1626416139000,
            "limit": 100,
            "moreData": False,
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.get_convert_trade_history(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/tradeFlow" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["startTime"] == 1623319461670
        assert normalized["endTime"] == 1641782889000

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(GetConvertTradeHistoryResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof or is_list or hasattr(GetConvertTradeHistoryResponse, "from_dict")
        ):
            expected = GetConvertTradeHistoryResponse.from_dict(expected_response)
        else:
            expected = GetConvertTradeHistoryResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_get_convert_trade_history_success_with_optional_params(
        self, mock_get_signature
    ):
        """Test get_convert_trade_history() successfully with optional parameters."""

        params = {
            "start_time": 1623319461670,
            "end_time": 1641782889000,
            "limit": 100,
            "recv_window": 5000,
        }

        expected_response = {
            "list": [
                {
                    "quoteId": "f3b91c525b2644c7bc1e1cd31b6e1aa6",
                    "orderId": 940708407462087200,
                    "orderStatus": "SUCCESS",
                    "fromAsset": "USDT",
                    "fromAmount": "20",
                    "toAsset": "BNB",
                    "toAmount": "0.06154036",
                    "ratio": "0.00307702",
                    "inverseRatio": "324.99",
                    "createTime": 1624248872184,
                }
            ],
            "startTime": 1623824139000,
            "endTime": 1626416139000,
            "limit": 100,
            "moreData": False,
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.get_convert_trade_history(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/tradeFlow" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(GetConvertTradeHistoryResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof or is_list or hasattr(GetConvertTradeHistoryResponse, "from_dict")
        ):
            expected = GetConvertTradeHistoryResponse.from_dict(expected_response)
        else:
            expected = GetConvertTradeHistoryResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    def test_get_convert_trade_history_missing_required_param_start_time(self):
        """Test that get_convert_trade_history() raises RequiredError when 'start_time' is missing."""
        params = {
            "start_time": 1623319461670,
            "end_time": 1641782889000,
        }
        params["start_time"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'start_time'"
        ):
            self.client.get_convert_trade_history(**params)

    def test_get_convert_trade_history_missing_required_param_end_time(self):
        """Test that get_convert_trade_history() raises RequiredError when 'end_time' is missing."""
        params = {
            "start_time": 1623319461670,
            "end_time": 1641782889000,
        }
        params["end_time"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'end_time'"
        ):
            self.client.get_convert_trade_history(**params)

    def test_get_convert_trade_history_server_error(self):
        """Test that get_convert_trade_history() raises an error when the server returns an error."""

        params = {
            "start_time": 1623319461670,
            "end_time": 1641782889000,
        }

        mock_error = Exception("ResponseError")
        self.client.get_convert_trade_history = MagicMock(side_effect=mock_error)

        with pytest.raises(Exception, match="ResponseError"):
            self.client.get_convert_trade_history(**params)

    @patch("binance_common.utils.get_signature")
    def test_order_status_success(self, mock_get_signature):
        """Test order_status() successfully with required parameters only."""

        expected_response = {
            "orderId": 933256278426274400,
            "orderStatus": "SUCCESS",
            "fromAsset": "BTC",
            "fromAmount": "0.00054414",
            "toAsset": "USDT",
            "toAmount": "20",
            "ratio": "36755",
            "inverseRatio": "0.00002721",
            "createTime": 1623381330472,
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.order_status()

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/orderStatus" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(OrderStatusResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(OrderStatusResponse, "from_dict"):
            expected = OrderStatusResponse.from_dict(expected_response)
        else:
            expected = OrderStatusResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_order_status_success_with_optional_params(self, mock_get_signature):
        """Test order_status() successfully with optional parameters."""

        params = {"order_id": "1", "quote_id": "1"}

        expected_response = {
            "orderId": 933256278426274400,
            "orderStatus": "SUCCESS",
            "fromAsset": "BTC",
            "fromAmount": "0.00054414",
            "toAsset": "USDT",
            "toAmount": "20",
            "ratio": "36755",
            "inverseRatio": "0.00002721",
            "createTime": 1623381330472,
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.order_status(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/orderStatus" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(OrderStatusResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(OrderStatusResponse, "from_dict"):
            expected = OrderStatusResponse.from_dict(expected_response)
        else:
            expected = OrderStatusResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    def test_order_status_server_error(self):
        """Test that order_status() raises an error when the server returns an error."""

        mock_error = Exception("ResponseError")
        self.client.order_status = MagicMock(side_effect=mock_error)

        with pytest.raises(Exception, match="ResponseError"):
            self.client.order_status()

    @patch("binance_common.utils.get_signature")
    def test_place_limit_order_success(self, mock_get_signature):
        """Test place_limit_order() successfully with required parameters only."""

        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
        }

        expected_response = {
            "quoteId": "12415572564",
            "ratio": "38163.7",
            "inverseRatio": "0.0000262",
            "validTimestamp": 1623319461670,
            "toAmount": "3816.37",
            "fromAmount": "0.1",
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.place_limit_order(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/limit/placeOrder" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"
        assert normalized["baseAsset"] == "base_asset_example"
        assert normalized["quoteAsset"] == "quote_asset_example"
        assert normalized["limitPrice"] == 1.0
        assert normalized["side"] == "BUY"
        assert normalized["expiredType"] == "expired_type_example"

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(PlaceLimitOrderResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(PlaceLimitOrderResponse, "from_dict"):
            expected = PlaceLimitOrderResponse.from_dict(expected_response)
        else:
            expected = PlaceLimitOrderResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_place_limit_order_success_with_optional_params(self, mock_get_signature):
        """Test place_limit_order() successfully with optional parameters."""

        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
            "base_amount": 1.0,
            "quote_amount": 1.0,
            "wallet_type": "",
            "recv_window": 5000,
        }

        expected_response = {
            "quoteId": "12415572564",
            "ratio": "38163.7",
            "inverseRatio": "0.0000262",
            "validTimestamp": 1623319461670,
            "toAmount": "3816.37",
            "fromAmount": "0.1",
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.place_limit_order(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/limit/placeOrder" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(PlaceLimitOrderResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(PlaceLimitOrderResponse, "from_dict"):
            expected = PlaceLimitOrderResponse.from_dict(expected_response)
        else:
            expected = PlaceLimitOrderResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    def test_place_limit_order_missing_required_param_base_asset(self):
        """Test that place_limit_order() raises RequiredError when 'base_asset' is missing."""
        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
        }
        params["base_asset"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'base_asset'"
        ):
            self.client.place_limit_order(**params)

    def test_place_limit_order_missing_required_param_quote_asset(self):
        """Test that place_limit_order() raises RequiredError when 'quote_asset' is missing."""
        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
        }
        params["quote_asset"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'quote_asset'"
        ):
            self.client.place_limit_order(**params)

    def test_place_limit_order_missing_required_param_limit_price(self):
        """Test that place_limit_order() raises RequiredError when 'limit_price' is missing."""
        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
        }
        params["limit_price"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'limit_price'"
        ):
            self.client.place_limit_order(**params)

    def test_place_limit_order_missing_required_param_side(self):
        """Test that place_limit_order() raises RequiredError when 'side' is missing."""
        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
        }
        params["side"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'side'"):
            self.client.place_limit_order(**params)

    def test_place_limit_order_missing_required_param_expired_type(self):
        """Test that place_limit_order() raises RequiredError when 'expired_type' is missing."""
        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
        }
        params["expired_type"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'expired_type'"
        ):
            self.client.place_limit_order(**params)

    def test_place_limit_order_server_error(self):
        """Test that place_limit_order() raises an error when the server returns an error."""

        params = {
            "base_asset": "base_asset_example",
            "quote_asset": "quote_asset_example",
            "limit_price": 1.0,
            "side": "BUY",
            "expired_type": "expired_type_example",
        }

        mock_error = Exception("ResponseError")
        self.client.place_limit_order = MagicMock(side_effect=mock_error)

        with pytest.raises(Exception, match="ResponseError"):
            self.client.place_limit_order(**params)

    @patch("binance_common.utils.get_signature")
    def test_query_limit_open_orders_success(self, mock_get_signature):
        """Test query_limit_open_orders() successfully with required parameters only."""

        expected_response = {
            "list": [
                {
                    "quoteId": "18sdf87kh9df",
                    "orderId": 1150901289839,
                    "orderStatus": "SUCCESS",
                    "fromAsset": "BNB",
                    "fromAmount": "10",
                    "toAsset": "USDT",
                    "toAmount": "2317.89",
                    "ratio": "231.789",
                    "inverseRatio": "0.00431427",
                    "createTime": 1614089498000,
                    "expiredTimestamp": 1614099498000,
                }
            ]
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.query_limit_open_orders()

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/convert/limit/queryOpenOrders" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(QueryLimitOpenOrdersResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif is_oneof or is_list or hasattr(QueryLimitOpenOrdersResponse, "from_dict"):
            expected = QueryLimitOpenOrdersResponse.from_dict(expected_response)
        else:
            expected = QueryLimitOpenOrdersResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_query_limit_open_orders_success_with_optional_params(
        self, mock_get_signature
    ):
        """Test query_limit_open_orders() successfully with optional parameters."""

        params = {"recv_window": 5000}

        expected_response = {
            "list": [
                {
                    "quoteId": "18sdf87kh9df",
                    "orderId": 1150901289839,
                    "orderStatus": "SUCCESS",
                    "fromAsset": "BNB",
                    "fromAmount": "10",
