"""
Binance Spot REST API

OpenAPI Specifications for the Binance Spot REST API

API documents:
  - [Github rest-api documentation file](https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md)
  - [General API information for rest-api on website](https://developers.binance.com/docs/binance-spot-api-docs/rest-api/general-api-information)

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
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_spot.rest_api.api import MarketApi
from binance_sdk_spot.rest_api.models import AggTradesResponse
from binance_sdk_spot.rest_api.models import AvgPriceResponse
from binance_sdk_spot.rest_api.models import DepthResponse
from binance_sdk_spot.rest_api.models import GetTradesResponse
from binance_sdk_spot.rest_api.models import HistoricalTradesResponse
from binance_sdk_spot.rest_api.models import KlinesResponse
from binance_sdk_spot.rest_api.models import TickerResponse
from binance_sdk_spot.rest_api.models import Ticker24hrResponse
from binance_sdk_spot.rest_api.models import TickerBookTickerResponse
from binance_sdk_spot.rest_api.models import TickerPriceResponse
from binance_sdk_spot.rest_api.models import TickerTradingDayResponse
from binance_sdk_spot.rest_api.models import UiKlinesResponse


from binance_sdk_spot.rest_api.models import DepthSymbolStatusEnum
from binance_sdk_spot.rest_api.models import KlinesIntervalEnum
from binance_sdk_spot.rest_api.models import TickerWindowSizeEnum
from binance_sdk_spot.rest_api.models import TickerTypeEnum
from binance_sdk_spot.rest_api.models import TickerSymbolStatusEnum
from binance_sdk_spot.rest_api.models import Ticker24hrTypeEnum
from binance_sdk_spot.rest_api.models import Ticker24hrSymbolStatusEnum
from binance_sdk_spot.rest_api.models import TickerBookTickerSymbolStatusEnum
from binance_sdk_spot.rest_api.models import TickerPriceSymbolStatusEnum
from binance_sdk_spot.rest_api.models import TickerTradingDayTypeEnum
from binance_sdk_spot.rest_api.models import TickerTradingDaySymbolStatusEnum
from binance_sdk_spot.rest_api.models import UiKlinesIntervalEnum


class TestMarketApi:
    @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 = MarketApi(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

    def test_agg_trades_success(self):
        """Test agg_trades() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
        }

        expected_response = [
            {
                "a": 26129,
                "p": "0.01633102",
                "q": "4.70443515",
                "f": 27781,
                "l": 27781,
                "T": 1498793709153,
                "m": True,
                "M": True,
            }
        ]

        self.set_mock_response(expected_response)

        response = self.client.agg_trades(**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()

        assert "url" in request_kwargs
        assert "/api/v3/aggTrades" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "BNBUSDT"

        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(AggTradesResponse)

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

        assert response.data() == expected

    def test_agg_trades_success_with_optional_params(self):
        """Test agg_trades() successfully with optional parameters."""

        params = {
            "symbol": "BNBUSDT",
            "from_id": 1,
            "start_time": 1735693200000,
            "end_time": 1735693200000,
            "limit": 500,
        }

        expected_response = [
            {
                "a": 26129,
                "p": "0.01633102",
                "q": "4.70443515",
                "f": 27781,
                "l": 27781,
                "T": 1498793709153,
                "m": True,
                "M": True,
            }
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/api/v3/aggTrades" 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(AggTradesResponse)

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

        assert response.data() == expected

    def test_agg_trades_missing_required_param_symbol(self):
        """Test that agg_trades() raises RequiredError when 'symbol' is missing."""
        params = {
            "symbol": "BNBUSDT",
        }
        params["symbol"] = None

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

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

        params = {
            "symbol": "BNBUSDT",
        }

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

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

    def test_avg_price_success(self):
        """Test avg_price() successfully with required parameters only."""

        params = {"symbol": "BNBUSDT"}

        expected_response = {
            "mins": 5,
            "price": "9.35751834",
            "closeTime": 1694061154503,
        }

        self.set_mock_response(expected_response)

        response = self.client.avg_price(**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()

        assert "url" in request_kwargs
        assert "/api/v3/avgPrice" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "BNBUSDT"

        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(AvgPriceResponse)

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

        assert response.data() == expected

    def test_avg_price_success_with_optional_params(self):
        """Test avg_price() successfully with optional parameters."""

        params = {"symbol": "BNBUSDT"}

        expected_response = {
            "mins": 5,
            "price": "9.35751834",
            "closeTime": 1694061154503,
        }

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/api/v3/avgPrice" 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(AvgPriceResponse)

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

        assert response.data() == expected

    def test_avg_price_missing_required_param_symbol(self):
        """Test that avg_price() raises RequiredError when 'symbol' is missing."""
        params = {"symbol": "BNBUSDT"}
        params["symbol"] = None

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

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

        params = {"symbol": "BNBUSDT"}

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

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

    def test_depth_success(self):
        """Test depth() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
        }

        expected_response = {
            "lastUpdateId": 1027024,
            "bids": [["4.00000000", "431.00000000"]],
            "asks": [["4.00000200", "12.00000000"]],
        }

        self.set_mock_response(expected_response)

        response = self.client.depth(**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()

        assert "url" in request_kwargs
        assert "/api/v3/depth" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "BNBUSDT"

        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(DepthResponse)

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

        assert response.data() == expected

    def test_depth_success_with_optional_params(self):
        """Test depth() successfully with optional parameters."""

        params = {
            "symbol": "BNBUSDT",
            "limit": 500,
            "symbol_status": DepthSymbolStatusEnum["TRADING"].value,
        }

        expected_response = {
            "lastUpdateId": 1027024,
            "bids": [["4.00000000", "431.00000000"]],
            "asks": [["4.00000200", "12.00000000"]],
        }

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/api/v3/depth" 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(DepthResponse)

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

        assert response.data() == expected

    def test_depth_missing_required_param_symbol(self):
        """Test that depth() raises RequiredError when 'symbol' is missing."""
        params = {
            "symbol": "BNBUSDT",
        }
        params["symbol"] = None

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

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

        params = {
            "symbol": "BNBUSDT",
        }

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

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

    def test_get_trades_success(self):
        """Test get_trades() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
        }

        expected_response = [
            {
                "id": 28457,
                "price": "4.00000100",
                "qty": "12.00000000",
                "quoteQty": "48.000012",
                "time": 1499865549590,
                "isBuyerMaker": True,
                "isBestMatch": True,
            }
        ]

        self.set_mock_response(expected_response)

        response = self.client.get_trades(**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()

        assert "url" in request_kwargs
        assert "/api/v3/trades" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "BNBUSDT"

        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(GetTradesResponse)

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

        assert response.data() == expected

    def test_get_trades_success_with_optional_params(self):
        """Test get_trades() successfully with optional parameters."""

        params = {"symbol": "BNBUSDT", "limit": 500}

        expected_response = [
            {
                "id": 28457,
                "price": "4.00000100",
                "qty": "12.00000000",
                "quoteQty": "48.000012",
                "time": 1499865549590,
                "isBuyerMaker": True,
                "isBestMatch": True,
            }
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/api/v3/trades" 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(GetTradesResponse)

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

        assert response.data() == expected

    def test_get_trades_missing_required_param_symbol(self):
        """Test that get_trades() raises RequiredError when 'symbol' is missing."""
        params = {
            "symbol": "BNBUSDT",
        }
        params["symbol"] = None

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

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

        params = {
            "symbol": "BNBUSDT",
        }

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

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

    def test_historical_trades_success(self):
        """Test historical_trades() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
        }

        expected_response = [
            {
                "id": 28457,
                "price": "4.00000100",
                "qty": "12.00000000",
                "quoteQty": "48.000012",
                "time": 1499865549590,
                "isBuyerMaker": True,
                "isBestMatch": True,
            }
        ]

        self.set_mock_response(expected_response)

        response = self.client.historical_trades(**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()

        assert "url" in request_kwargs
        assert "/api/v3/historicalTrades" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "BNBUSDT"

        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(HistoricalTradesResponse)

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

        assert response.data() == expected

    def test_historical_trades_success_with_optional_params(self):
        """Test historical_trades() successfully with optional parameters."""

        params = {"symbol": "BNBUSDT", "limit": 500, "from_id": 1}

        expected_response = [
            {
                "id": 28457,
                "price": "4.00000100",
                "qty": "12.00000000",
                "quoteQty": "48.000012",
                "time": 1499865549590,
                "isBuyerMaker": True,
                "isBestMatch": True,
            }
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/api/v3/historicalTrades" 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(HistoricalTradesResponse)

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

        assert response.data() == expected

    def test_historical_trades_missing_required_param_symbol(self):
        """Test that historical_trades() raises RequiredError when 'symbol' is missing."""
        params = {
            "symbol": "BNBUSDT",
        }
        params["symbol"] = None

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

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

        params = {
            "symbol": "BNBUSDT",
        }

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

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

    def test_klines_success(self):
        """Test klines() successfully with required parameters only."""

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
        }

        expected_response = [
            [
                1499040000000,
                "0.01634790",
                "0.80000000",
                "0.01575800",
                "0.01577100",
                "148976.11427815",
                1499644799999,
                "2434.19055334",
                308,
                "1756.87402397",
                "28.46694368",
                "0",
            ]
        ]

        self.set_mock_response(expected_response)

        response = self.client.klines(**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()

        assert "url" in request_kwargs
        assert "/api/v3/klines" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "BNBUSDT"
        assert normalized["interval"] == KlinesIntervalEnum["INTERVAL_1s"].value

        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(KlinesResponse)

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

        assert response.data() == expected

    def test_klines_success_with_optional_params(self):
        """Test klines() successfully with optional parameters."""

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
            "start_time": 1735693200000,
            "end_time": 1735693200000,
            "time_zone": "time_zone_example",
            "limit": 500,
        }

        expected_response = [
            [
                1499040000000,
                "0.01634790",
                "0.80000000",
                "0.01575800",
                "0.01577100",
                "148976.11427815",
                1499644799999,
                "2434.19055334",
                308,
                "1756.87402397",
                "28.46694368",
                "0",
            ]
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/api/v3/klines" 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(KlinesResponse)

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

        assert response.data() == expected

    def test_klines_missing_required_param_symbol(self):
        """Test that klines() raises RequiredError when 'symbol' is missing."""
        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
        }
        params["symbol"] = None

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

    def test_klines_missing_required_param_interval(self):
        """Test that klines() raises RequiredError when 'interval' is missing."""
        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
        }
        params["interval"] = None

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

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

        params = {
            "symbol": "BNBUSDT",
            "interval": KlinesIntervalEnum["INTERVAL_1s"].value,
        }

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

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

    def test_ticker_success(self):
        """Test ticker() successfully with required parameters only."""

        expected_response = {
            "symbol": "LTCBTC",
            "priceChange": "-8.00000000",
            "priceChangePercent": "-88.889",
            "weightedAvgPrice": "2.60427807",
            "openPrice": "0.10000000",
            "highPrice": "2.00000000",
            "lowPrice": "0.10000000",
            "lastPrice": "2.00000000",
            "volume": "39.00000000",
            "quoteVolume": "13.40000000",
            "openTime": 1656986580000,
            "closeTime": 1657001016795,
            "firstId": 0,
            "lastId": 34,
            "count": 35,
        }

        self.set_mock_response(expected_response)

        response = self.client.ticker()

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

        self.mock_session.request.assert_called_once()

        assert "url" in request_kwargs
        assert "/api/v3/ticker" 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(TickerResponse)

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

        assert response.data() == expected

    def test_ticker_success_with_optional_params(self):
        """Test ticker() successfully with optional parameters."""

        params = {
            "symbol": "BNBUSDT",
            "symbols": [""],
            "window_size": TickerWindowSizeEnum["WINDOW_SIZE_1m"].value,
            "type": TickerTypeEnum["FULL"].value,
            "symbol_status": TickerSymbolStatusEnum["TRADING"].value,
        }

        expected_response = {
            "symbol": "LTCBTC",
            "priceChange": "-8.00000000",
            "priceChangePercent": "-88.889",
            "weightedAvgPrice": "2.60427807",
            "openPrice": "0.10000000",
            "highPrice": "2.00000000",
            "lowPrice": "0.10000000",
            "lastPrice": "2.00000000",
            "volume": "39.00000000",
            "quoteVolume": "13.40000000",
            "openTime": 1656986580000,
            "closeTime": 1657001016795,
            "firstId": 0,
            "lastId": 34,
            "count": 35,
        }

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/api/v3/ticker" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"

        self.mock_session.request.assert_called_once()
        assert response is not None
