"""
Binance Derivatives Trading Options REST API

OpenAPI Specification for the Binance Derivatives Trading Options 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
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_derivatives_trading_options.rest_api.api import MarketDataApi
from binance_sdk_derivatives_trading_options.rest_api.models import (
    CheckServerTimeResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import (
    ExchangeInformationResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import (
    HistoricalExerciseRecordsResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import (
    IndexPriceTickerResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import (
    KlineCandlestickDataResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import (
    OldTradesLookupResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import OpenInterestResponse
from binance_sdk_derivatives_trading_options.rest_api.models import (
    OptionMarkPriceResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import OrderBookResponse
from binance_sdk_derivatives_trading_options.rest_api.models import (
    RecentBlockTradesListResponse,
)
from binance_sdk_derivatives_trading_options.rest_api.models import (
    RecentTradesListResponse,
)

from binance_sdk_derivatives_trading_options.rest_api.models import (
    Ticker24hrPriceChangeStatisticsResponse,
)


class TestMarketDataApi:
    @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 = MarketDataApi(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_check_server_time_success(self):
        """Test check_server_time() successfully with required parameters only."""

        expected_response = {"serverTime": 1499827319559}

        self.set_mock_response(expected_response)

        response = self.client.check_server_time()

        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 "/eapi/v1/time" 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(CheckServerTimeResponse)

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

        assert response.data() == expected

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

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

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

    def test_exchange_information_success(self):
        """Test exchange_information() successfully with required parameters only."""

        expected_response = {
            "timezone": "UTC",
            "serverTime": 1592387337630,
            "optionContracts": [
                {
                    "baseAsset": "BTC",
                    "quoteAsset": "USDT",
                    "underlying": "BTCUSDT",
                    "settleAsset": "USDT",
                }
            ],
            "optionAssets": [{"name": "USDT"}],
            "optionSymbols": [
                {
                    "expiryDate": 1660521600000,
                    "filters": [
                        {
                            "filterType": "PRICE_FILTER",
                            "minPrice": "0.02",
                            "maxPrice": "80000.01",
                            "tickSize": "0.01",
                        },
                        {
                            "filterType": "LOT_SIZE",
                            "minQty": "0.01",
                            "maxQty": "100",
                            "stepSize": "0.01",
                        },
                    ],
                    "symbol": "BTC-220815-50000-C",
                    "side": "CALL",
                    "strikePrice": "50000",
                    "underlying": "BTCUSDT",
                    "unit": 1,
                    "makerFeeRate": "0.0002",
                    "takerFeeRate": "0.0002",
                    "liquidationFeeRate": "0.0019000",
                    "minQty": "0.01",
                    "maxQty": "100",
                    "initialMargin": "0.15",
                    "maintenanceMargin": "0.075",
                    "minInitialMargin": "0.1",
                    "minMaintenanceMargin": "0.05",
                    "priceScale": 2,
                    "quantityScale": 2,
                    "quoteAsset": "USDT",
                }
            ],
            "rateLimits": [
                {
                    "rateLimitType": "REQUEST_WEIGHT",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 2400,
                },
                {
                    "rateLimitType": "ORDERS",
                    "interval": "MINUTE",
                    "intervalNum": 1,
                    "limit": 1200,
                },
                {
                    "rateLimitType": "ORDERS",
                    "interval": "SECOND",
                    "intervalNum": 10,
                    "limit": 300,
                },
            ],
        }

        self.set_mock_response(expected_response)

        response = self.client.exchange_information()

        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 "/eapi/v1/exchangeInfo" 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(ExchangeInformationResponse)

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

        assert response.data() == expected

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

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

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

    def test_historical_exercise_records_success(self):
        """Test historical_exercise_records() successfully with required parameters only."""

        expected_response = [
            {
                "symbol": "BTC-220121-60000-P",
                "strikePrice": "60000",
                "realStrikePrice": "38844.69652571",
                "expiryDate": 1642752000000,
                "strikeResult": "REALISTIC_VALUE_STRICKEN",
            }
        ]

        self.set_mock_response(expected_response)

        response = self.client.historical_exercise_records()

        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 "/eapi/v1/exerciseHistory" 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(HistoricalExerciseRecordsResponse)

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

        assert response.data() == expected

    def test_historical_exercise_records_success_with_optional_params(self):
        """Test historical_exercise_records() successfully with optional parameters."""

        params = {
            "underlying": "underlying_example",
            "start_time": 1623319461670,
            "end_time": 1641782889000,
            "limit": 100,
        }

        expected_response = [
            {
                "symbol": "BTC-220121-60000-P",
                "strikePrice": "60000",
                "realStrikePrice": "38844.69652571",
                "expiryDate": 1642752000000,
                "strikeResult": "REALISTIC_VALUE_STRICKEN",
            }
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/eapi/v1/exerciseHistory" 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(HistoricalExerciseRecordsResponse)

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

        assert response.data() == expected

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

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

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

    def test_index_price_ticker_success(self):
        """Test index_price_ticker() successfully with required parameters only."""

        params = {"underlying": "underlying_example"}

        expected_response = {"time": 1656647305000, "indexPrice": "9200"}

        self.set_mock_response(expected_response)

        response = self.client.index_price_ticker(**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 "/eapi/v1/index" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["underlying"] == "underlying_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(IndexPriceTickerResponse)

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

        assert response.data() == expected

    def test_index_price_ticker_success_with_optional_params(self):
        """Test index_price_ticker() successfully with optional parameters."""

        params = {"underlying": "underlying_example"}

        expected_response = {"time": 1656647305000, "indexPrice": "9200"}

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/eapi/v1/index" 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(IndexPriceTickerResponse)

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

        assert response.data() == expected

    def test_index_price_ticker_missing_required_param_underlying(self):
        """Test that index_price_ticker() raises RequiredError when 'underlying' is missing."""
        params = {"underlying": "underlying_example"}
        params["underlying"] = None

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

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

        params = {"underlying": "underlying_example"}

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

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

    def test_kline_candlestick_data_success(self):
        """Test kline_candlestick_data() successfully with required parameters only."""

        params = {
            "symbol": "symbol_example",
            "interval": "interval_example",
        }

        expected_response = [
            {
                "open": "950",
                "high": "1100",
                "low": "900",
                "close": "1000",
                "volume": "100",
                "amount": "2",
                "interval": "5m",
                "tradeCount": 10,
                "takerVolume": "100",
                "takerAmount": "10000",
                "openTime": 1499040000000,
                "closeTime": 1499644799999,
            }
        ]

        self.set_mock_response(expected_response)

        response = self.client.kline_candlestick_data(**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 "/eapi/v1/klines" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "symbol_example"
        assert normalized["interval"] == "interval_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(KlineCandlestickDataResponse)

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

        assert response.data() == expected

    def test_kline_candlestick_data_success_with_optional_params(self):
        """Test kline_candlestick_data() successfully with optional parameters."""

        params = {
            "symbol": "symbol_example",
            "interval": "interval_example",
            "start_time": 1623319461670,
            "end_time": 1641782889000,
            "limit": 100,
        }

        expected_response = [
            {
                "open": "950",
                "high": "1100",
                "low": "900",
                "close": "1000",
                "volume": "100",
                "amount": "2",
                "interval": "5m",
                "tradeCount": 10,
                "takerVolume": "100",
                "takerAmount": "10000",
                "openTime": 1499040000000,
                "closeTime": 1499644799999,
            }
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/eapi/v1/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(KlineCandlestickDataResponse)

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

        assert response.data() == expected

    def test_kline_candlestick_data_missing_required_param_symbol(self):
        """Test that kline_candlestick_data() raises RequiredError when 'symbol' is missing."""
        params = {
            "symbol": "symbol_example",
            "interval": "interval_example",
        }
        params["symbol"] = None

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

    def test_kline_candlestick_data_missing_required_param_interval(self):
        """Test that kline_candlestick_data() raises RequiredError when 'interval' is missing."""
        params = {
            "symbol": "symbol_example",
            "interval": "interval_example",
        }
        params["interval"] = None

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

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

        params = {
            "symbol": "symbol_example",
            "interval": "interval_example",
        }

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

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

    def test_old_trades_lookup_success(self):
        """Test old_trades_lookup() successfully with required parameters only."""

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

        expected_response = [
            {
                "id": "1",
                "tradeId": "159244329455993",
                "price": "1000",
                "qty": "-0.1",
                "quoteQty": "-100",
                "side": -1,
                "time": 1592449455993,
            }
        ]

        self.set_mock_response(expected_response)

        response = self.client.old_trades_lookup(**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 "/eapi/v1/historicalTrades" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["symbol"] == "symbol_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(OldTradesLookupResponse)

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

        assert response.data() == expected

    def test_old_trades_lookup_success_with_optional_params(self):
        """Test old_trades_lookup() successfully with optional parameters."""

        params = {"symbol": "symbol_example", "from_id": 1, "limit": 100}

        expected_response = [
            {
                "id": "1",
                "tradeId": "159244329455993",
                "price": "1000",
                "qty": "-0.1",
                "quoteQty": "-100",
                "side": -1,
                "time": 1592449455993,
            }
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/eapi/v1/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(OldTradesLookupResponse)

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

        assert response.data() == expected

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

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

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

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

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

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

    def test_open_interest_success(self):
        """Test open_interest() successfully with required parameters only."""

        params = {
            "underlying_asset": "underlying_asset_example",
            "expiration": "expiration_example",
        }

        expected_response = [
            {
                "symbol": "ETH-221119-1175-P",
                "sumOpenInterest": "4.01",
                "sumOpenInterestUsd": "4880.2985615624",
                "timestamp": "1668754020000",
            }
        ]

        self.set_mock_response(expected_response)

        response = self.client.open_interest(**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 "/eapi/v1/openInterest" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["underlyingAsset"] == "underlying_asset_example"
        assert normalized["expiration"] == "expiration_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(OpenInterestResponse)

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

        assert response.data() == expected

    def test_open_interest_success_with_optional_params(self):
        """Test open_interest() successfully with optional parameters."""

        params = {
            "underlying_asset": "underlying_asset_example",
            "expiration": "expiration_example",
        }

        expected_response = [
            {
                "symbol": "ETH-221119-1175-P",
                "sumOpenInterest": "4.01",
                "sumOpenInterestUsd": "4880.2985615624",
                "timestamp": "1668754020000",
            }
        ]

        self.set_mock_response(expected_response)

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

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

        assert "url" in request_kwargs
        assert "/eapi/v1/openInterest" 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(OpenInterestResponse)

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

        assert response.data() == expected

    def test_open_interest_missing_required_param_underlying_asset(self):
        """Test that open_interest() raises RequiredError when 'underlying_asset' is missing."""
        params = {
            "underlying_asset": "underlying_asset_example",
            "expiration": "expiration_example",
        }
        params["underlying_asset"] = None

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

    def test_open_interest_missing_required_param_expiration(self):
        """Test that open_interest() raises RequiredError when 'expiration' is missing."""
        params = {
            "underlying_asset": "underlying_asset_example",
            "expiration": "expiration_example",
        }
        params["expiration"] = None

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

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

        params = {
            "underlying_asset": "underlying_asset_example",
            "expiration": "expiration_example",
        }

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

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

    def test_option_mark_price_success(self):
        """Test option_mark_price() successfully with required parameters only."""

        expected_response = [
            {
                "symbol": "BTC-200730-9000-C",
                "markPrice": "1343.2883",
                "bidIV": "1.40000077",
                "askIV": "1.50000153",
                "markIV": "1.45000000",
                "delta": "0.55937056",
                "theta": "3739.82509871",
                "gamma": "0.00010969",
                "vega": "978.58874732",
                "highPriceLimit": "1618.241",
                "lowPriceLimit": "1068.3356",
                "riskFreeInterest": "0.1",
            }
        ]

        self.set_mock_response(expected_response)

