Skip to main content
Glama

MCP Sheet Parser

by yuqie6
MIT License
3
  • Apple
test_chart_positioning.py14.4 kB
import pytest from unittest.mock import MagicMock from src.utils.chart_positioning import ChartPositionCalculator, ChartCSSPosition from src.models.table_model import Sheet, ChartPosition @pytest.fixture def mock_sheet(): """提供一个模拟的 Sheet 对象,用于测试。""" sheet = MagicMock(spec=Sheet) sheet.column_widths = {0: 10, 1: 12, 2: 8} sheet.row_heights = {0: 20, 1: 25, 2: 18} sheet.default_column_width = 9 sheet.default_row_height = 15 return sheet @pytest.fixture def calculator(mock_sheet): """提供一个 ChartPositionCalculator 实例。""" return ChartPositionCalculator(mock_sheet) def test_initialization(calculator, mock_sheet): """测试计算器是否正确初始化。""" assert calculator.sheet == mock_sheet def test_calculate_cell_position_single_cell(calculator): """测试计算单个单元格的位置。""" # A1单元格 (0, 0) x, y = calculator._calculate_cell_position(0, 0) assert x == 0 assert y == 0 # B2单元格 (1, 1) x, y = calculator._calculate_cell_position(1, 1) expected_x = 10 * 8.45 # col 0 width expected_y = 20 # row 0 height assert abs(x - expected_x) < 1e-9 assert abs(y - expected_y) < 1e-9 @pytest.fixture def mock_chart_position(): """提供一个模拟的 ChartPosition 对象。""" pos = MagicMock(spec=ChartPosition) pos.from_row = 1 pos.from_col = 1 pos.from_row_offset = 100000 pos.from_col_offset = 50000 pos.to_row = 3 pos.to_col = 3 pos.to_row_offset = 200000 pos.to_col_offset = 150000 return pos def test_calculate_chart_width(calculator, mock_chart_position): """测试计算图表的宽度(修正版)。""" width = calculator._calculate_chart_width(mock_chart_position) # 根据源代码的逻辑重新计算期望值 start_offset_px = mock_chart_position.from_col_offset * calculator.EMU_TO_PX end_offset_px = mock_chart_position.to_col_offset * calculator.EMU_TO_PX from_col_width_px = calculator.sheet.column_widths.get(mock_chart_position.from_col, calculator.sheet.default_column_width) * calculator.EXCEL_TO_PX middle_cols_width_px = 0 for i in range(mock_chart_position.from_col + 1, mock_chart_position.to_col): middle_cols_width_px += calculator.sheet.column_widths.get(i, calculator.sheet.default_column_width) * calculator.EXCEL_TO_PX expected_width = (from_col_width_px - start_offset_px) + middle_cols_width_px + end_offset_px # 源代码中有 max(50, width) 的逻辑 assert abs(width - max(50, expected_width)) < 1e-9 def test_calculate_chart_height(calculator, mock_chart_position): """测试计算图表的高度(修正版)。""" height = calculator._calculate_chart_height(mock_chart_position) # 根据源代码的逻辑重新计算期望值 start_offset_pt = mock_chart_position.from_row_offset * calculator.EMU_TO_PT end_offset_pt = mock_chart_position.to_row_offset * calculator.EMU_TO_PT from_row_height_pt = calculator.sheet.row_heights.get(mock_chart_position.from_row, calculator.sheet.default_row_height) middle_rows_height_pt = 0 for i in range(mock_chart_position.from_row + 1, mock_chart_position.to_row): middle_rows_height_pt += calculator.sheet.row_heights.get(i, calculator.sheet.default_row_height) expected_height = (from_row_height_pt - start_offset_pt) + middle_rows_height_pt + end_offset_pt # 源代码中有 max(50, height) 的逻辑 assert abs(height - max(50, expected_height)) < 1e-9 def test_calculate_chart_css_position(calculator, mock_chart_position): """测试获取最终的CSS位置对象(修正版)。""" # 修正方法调用 css_pos = calculator.calculate_chart_css_position(mock_chart_position) assert isinstance(css_pos, ChartCSSPosition) # 验证 top 和 left 是否正确计算 start_x_base, start_y_base = calculator._calculate_cell_position(mock_chart_position.from_col, mock_chart_position.from_row) col_offset_px = mock_chart_position.from_col_offset * calculator.EMU_TO_PX row_offset_pt = mock_chart_position.from_row_offset * calculator.EMU_TO_PT expected_left = start_x_base + col_offset_px expected_top = start_y_base + row_offset_pt assert abs(css_pos.left - expected_left) < 1e-9 assert abs(css_pos.top - expected_top) < 1e-9 # 验证 width 和 height 是否与独立方法计算结果一致 expected_width = calculator._calculate_chart_width(mock_chart_position) expected_height = calculator._calculate_chart_height(mock_chart_position) assert abs(css_pos.width - expected_width) < 1e-9 assert abs(css_pos.height - expected_height) < 1e-9 def test_calculate_cell_position_multi_cell(calculator): """测试计算跨多个单元格的位置。""" # C3单元格 (2, 2) x, y = calculator._calculate_cell_position(2, 2) expected_x = (10 + 12) * 8.45 # col 0 + col 1 width expected_y = 20 + 25 # row 0 + row 1 height assert abs(x - expected_x) < 1e-9 assert abs(y - expected_y) < 1e-9 @pytest.fixture def mock_single_cell_chart_position(): """提供一个在单个单元格内的模拟 ChartPosition 对象。""" pos = MagicMock(spec=ChartPosition) pos.from_row = 1 pos.from_col = 1 pos.from_row_offset = 100000 # ~1/9th of the way in pos.from_col_offset = 50000 # ~1/18th of the way in pos.to_row = 1 # Same row pos.to_col = 1 # Same col pos.to_row_offset = 800000 pos.to_col_offset = 850000 return pos def test_calculate_chart_width_single_cell(calculator, mock_single_cell_chart_position): """测试在单个单元格内计算图表宽度。""" width = calculator._calculate_chart_width(mock_single_cell_chart_position) start_offset_px = mock_single_cell_chart_position.from_col_offset * calculator.EMU_TO_PX end_offset_px = mock_single_cell_chart_position.to_col_offset * calculator.EMU_TO_PX expected_width = end_offset_px - start_offset_px assert abs(width - max(50, expected_width)) < 1e-9 def test_calculate_chart_height_single_row(calculator, mock_single_cell_chart_position): """测试在单行内计算图表高度。""" height = calculator._calculate_chart_height(mock_single_cell_chart_position) start_offset_pt = mock_single_cell_chart_position.from_row_offset * calculator.EMU_TO_PT end_offset_pt = mock_single_cell_chart_position.to_row_offset * calculator.EMU_TO_PT expected_height = end_offset_pt - start_offset_pt assert abs(height - max(50, expected_height)) < 1e-9 def test_calculate_image_dimensions(calculator, mock_chart_position): """测试图片尺寸的计算。""" # Test width width = calculator._calculate_image_width(mock_chart_position) width_emu = mock_chart_position.to_col_offset - mock_chart_position.from_col_offset expected_width_px = width_emu * calculator.EMU_TO_PX assert abs(width - max(20, expected_width_px)) < 1e-9 # Test height height = calculator._calculate_image_height(mock_chart_position) height_emu = mock_chart_position.to_row_offset - mock_chart_position.from_row_offset expected_height_pt = height_emu * calculator.EMU_TO_PT assert abs(height - max(15, expected_height_pt)) < 1e-9 def test_generate_chart_html_with_positioning_for_image(calculator, mock_single_cell_chart_position): """测试为图片生成带定位的HTML。""" mock_chart = MagicMock() mock_chart.type = 'image' # 修正:通过参数注入 Fixture,而不是直接调用 mock_chart.position = mock_single_cell_chart_position # Mock the _calculate_image_position to return a predictable ChartCSSPosition css_pos = ChartCSSPosition(left=10, top=20, width=100, height=80) calculator._calculate_image_position = MagicMock(return_value=css_pos) chart_html = "<svg>...</svg>" positioned_html = calculator.generate_chart_html_with_positioning(mock_chart, chart_html) calculator._calculate_image_position.assert_called_once_with(mock_chart.position) assert 'left: 10.0px;' in positioned_html assert 'top: 26.7px;' in positioned_html # 20pt * 1.333 assert 'width: 100.0px;' in positioned_html assert 'height: 106.6px;' in positioned_html # 80pt * 1.333 assert chart_html in positioned_html def test_get_chart_overlay_css(calculator, mock_chart_position): """测试生成图表覆盖的CSS。""" css_string = calculator.get_chart_overlay_css(mock_chart_position, "my-container") css_pos = calculator.calculate_chart_css_position(mock_chart_position) assert '#my-container' in css_string assert f"left: {css_pos.left:.1f}px;" in css_string assert f"top: {css_pos.top:.1f}pt;" in css_string assert f"width: {css_pos.width:.1f}px;" in css_string assert f"height: {css_pos.height:.1f}pt;" in css_string def test_calculate_cell_position_with_defaults(calculator): """测试计算位置时使用默认行高和列宽。""" # E5单元格 (4, 4) x, y = calculator._calculate_cell_position(4, 4) expected_x = (10 + 12 + 8 + 9) * 8.45 # col 0, 1, 2, 3 (default) expected_y = 20 + 25 + 18 + 15 # row 0, 1, 2, 3 (default) assert abs(x - expected_x) < 1e-9 assert abs(y - expected_y) < 1e-9 class TestGenerateChartHtmlEdgeCases: """测试generate_chart_html_with_positioning的边界情况。""" def test_generate_chart_html_without_position(self, calculator): """ TDD测试:generate_chart_html_with_positioning应该处理没有定位信息的图表 这个测试覆盖第207行的代码 """ # 创建没有position的模拟图表 mock_chart = MagicMock() mock_chart.position = None mock_chart.type = 'bar' chart_html = "<div>Test Chart</div>" result = calculator.generate_chart_html_with_positioning(mock_chart, chart_html) # 验证返回原始HTML assert result == chart_html def test_generate_chart_html_with_non_image_chart(self, calculator): """ TDD测试:generate_chart_html_with_positioning应该正确处理非图片类型的图表 这个测试覆盖第215、225、235-236行的代码 """ # 创建非图片类型的模拟图表 mock_chart = MagicMock() mock_chart.type = 'bar' # 非图片类型 mock_chart.position = MagicMock() mock_chart.position.from_row = 1 mock_chart.position.from_col = 1 mock_chart.position.from_row_offset = 100000 mock_chart.position.from_col_offset = 50000 mock_chart.position.to_row = 3 mock_chart.position.to_col = 3 mock_chart.position.to_row_offset = 200000 mock_chart.position.to_col_offset = 150000 chart_html = "<div>Bar Chart</div>" result = calculator.generate_chart_html_with_positioning(mock_chart, chart_html) # 验证返回了包含定位信息的HTML assert "position: absolute" in result assert "chart-overlay" in result assert chart_html in result class TestImagePositionCalculation: """测试图片位置计算的相关方法。""" def test_calculate_image_position(self, calculator): """ TDD测试:_calculate_image_position应该正确计算图片位置 这个测试覆盖第265-278行的代码 """ # 创建模拟的图片位置 mock_position = MagicMock() mock_position.from_row = 1 mock_position.from_col = 1 mock_position.from_row_offset = 100000 mock_position.from_col_offset = 50000 mock_position.to_row_offset = 200000 mock_position.to_col_offset = 150000 result = calculator._calculate_image_position(mock_position) # 验证返回了ChartCSSPosition对象 assert isinstance(result, ChartCSSPosition) assert result.left >= 0 assert result.top >= 0 assert result.width > 0 assert result.height > 0 def test_calculate_image_width_with_default(self, calculator): """ TDD测试:_calculate_image_width应该使用默认宽度 这个测试覆盖第294行的代码 """ # 创建没有to_col_offset的模拟位置 mock_position = MagicMock() mock_position.from_col_offset = 50000 mock_position.to_col_offset = 0 # 没有结束偏移 result = calculator._calculate_image_width(mock_position) # 验证使用了默认宽度 assert result >= 20 # 最小宽度 # 默认宽度应该是914400 EMU转换后的像素值 expected_default = 914400 * calculator.EMU_TO_PX assert abs(result - expected_default) < 1 def test_calculate_image_height_with_default(self, calculator): """ TDD测试:_calculate_image_height应该使用默认高度 这个测试覆盖第308行的代码 """ # 创建没有to_row_offset的模拟位置 mock_position = MagicMock() mock_position.from_row_offset = 100000 mock_position.to_row_offset = 0 # 没有结束偏移 result = calculator._calculate_image_height(mock_position) # 验证使用了默认高度 assert result >= 10 # 最小高度 # 默认高度应该是285750 EMU转换后的点值 expected_default = 285750 * calculator.EMU_TO_PT assert abs(result - expected_default) < 1 class TestFactoryFunction: """测试工厂函数。""" def test_create_position_calculator(self, mock_sheet): """ TDD测试:create_position_calculator应该创建计算器实例 这个测试覆盖第324行的代码 """ from src.utils.chart_positioning import create_position_calculator result = create_position_calculator(mock_sheet) # 验证返回了正确的实例 assert isinstance(result, ChartPositionCalculator) assert result.sheet == mock_sheet

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yuqie6/MCP-Sheet-Parser-cot'

If you have feedback or need assistance with the MCP directory API, please join our Discord server