import pytest from unittest.mock import AsyncMock, MagicMock, patch from datetime import date from room_cal.mcp import mcp, convert_price, run_action def test_mcp_is_fastmcp(): from fastmcp import FastMCP assert isinstance(mcp, FastMCP) @pytest.mark.asyncio async def test_convert_price_from_net(): result = await convert_price('net_to_list', 'airbnb', 100) assert set(result.keys()) == {'net', 'list', 'retail'} assert result['net'] == 100 assert result['list'] > result['net'] @pytest.mark.asyncio async def test_convert_price_from_list(): result = await convert_price('list_to_net', 'airbnb', 150) assert set(result.keys()) == {'net', 'list', 'retail'} assert result['list'] == 150 assert result['net'] < result['list'] @pytest.mark.asyncio async def test_convert_price_from_retail(): result = await convert_price('retail_to_list', 'airbnb', 200) assert set(result.keys()) == {'net', 'list', 'retail'} assert result['retail'] == 200 @pytest.mark.asyncio async def test_convert_price_unknown_transformation(): with pytest.raises(ValueError, match='Unknown transformation'): await convert_price('bad_transform', 'airbnb', 100) @pytest.mark.asyncio async def test_run_action_unknown_raises(): with pytest.raises(ValueError, match='Unknown action'): await run_action('bad-action', '2026-01-01') @pytest.mark.asyncio async def test_run_action_end_date_defaults_to_start(): mock_fn = AsyncMock(return_value=[]) mock_mod = MagicMock() mock_mod.fetch_prices = mock_fn with patch('importlib.import_module', return_value=mock_mod): await run_action('fetch-prices', '2026-01-15') mock_fn.assert_called_once_with(date(2026, 1, 15), date(2026, 1, 15)) @pytest.mark.asyncio async def test_run_action_kwargs_filtering_allows_allowed_keys(): mock_fn = AsyncMock(return_value=[]) mock_mod = MagicMock() mock_mod.fetch_feed = mock_fn with patch('importlib.import_module', return_value=mock_mod): # fetch-feed allows feed_name and title, but not service await run_action('fetch-feed', '2026-01-15', end_date='2026-01-20', feed_name='Fire', title='T', service='airbnb') mock_fn.assert_called_once_with(date(2026, 1, 15), date(2026, 1, 20), feed_name='Fire', title='T') @pytest.mark.asyncio async def test_run_action_kwargs_filtering_excludes_none(): mock_fn = AsyncMock(return_value=[]) mock_mod = MagicMock() mock_mod.fetch_feed = mock_fn with patch('importlib.import_module', return_value=mock_mod): # feed_name=None should be excluded even though it's in allowed_keys await run_action('fetch-feed', '2026-01-15', feed_name=None) mock_fn.assert_called_once_with(date(2026, 1, 15), date(2026, 1, 15))