Skip to main content
Glama

mcp-optimizer

test_knapsack.pyโ€ข14.9 kB
"""Tests for knapsack problem tools.""" from unittest.mock import MagicMock, patch from mcp_optimizer.tools.knapsack import register_knapsack_tools, solve_knapsack_problem class TestKnapsackTools: """Tests for knapsack problem solving tools.""" def test_solve_knapsack_problem_success(self): """Test successful knapsack problem solving.""" items = [ {"name": "item1", "value": 10, "weight": 5}, {"name": "item2", "value": 20, "weight": 10}, ] capacity = 15 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" assert isinstance(result["total_value"], (int, float)) assert isinstance(result["selected_items"], list) assert "execution_time" in result assert "solver_info" in result def test_solve_knapsack_problem_empty_items(self): """Test knapsack with empty items list.""" result = solve_knapsack_problem([], 10) assert result["status"] == "error" assert result["error_message"] == "No items provided" assert result["total_value"] is None assert result["selected_items"] == [] def test_solve_knapsack_problem_zero_capacity(self): """Test knapsack with zero capacity.""" items = [{"name": "item1", "value": 10, "weight": 5}] result = solve_knapsack_problem(items, 0) assert result["status"] == "error" assert result["error_message"] == "Capacity must be positive" def test_solve_knapsack_problem_negative_capacity(self): """Test knapsack with negative capacity.""" items = [{"name": "item1", "value": 10, "weight": 5}] result = solve_knapsack_problem(items, -5) assert result["status"] == "error" assert result["error_message"] == "Capacity must be positive" def test_solve_knapsack_problem_with_volume(self): """Test knapsack with volume constraints.""" items = [ {"name": "item1", "value": 10, "weight": 5, "volume": 3}, {"name": "item2", "value": 20, "weight": 8, "volume": 4}, ] capacity = 15 volume_capacity = 6 result = solve_knapsack_problem(items, capacity, volume_capacity) assert result["status"] in ["optimal", "infeasible"] assert "solver_info" in result if result["status"] == "optimal": assert result["solver_info"]["algorithm"] == "Branch and Bound" def test_solve_knapsack_problem_large_items(self): """Test knapsack where all items are larger than capacity.""" items = [ {"name": "item1", "value": 10, "weight": 20}, {"name": "item2", "value": 15, "weight": 25}, ] capacity = 10 result = solve_knapsack_problem(items, capacity) assert result["status"] in ["optimal", "infeasible"] if result["status"] == "optimal": assert result["total_value"] == 0.0 def test_solve_knapsack_problem_single_item(self): """Test knapsack with single item.""" items = [{"name": "item1", "value": 10, "weight": 5}] capacity = 10 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" assert result["total_value"] == 10.0 assert len(result["selected_items"]) == 1 assert result["selected_items"][0]["name"] == "item1" def test_solve_knapsack_problem_invalid_item_type(self): """Test knapsack with invalid item type.""" items = ["invalid_item"] capacity = 10 result = solve_knapsack_problem(items, capacity) assert result["status"] == "error" assert "Item 0 must be a dictionary" in result["error_message"] def test_solve_knapsack_problem_missing_item_fields(self): """Test knapsack with missing item fields.""" items = [{"name": "item1"}] # Missing value and weight capacity = 10 result = solve_knapsack_problem(items, capacity) assert result["status"] == "error" assert "missing required field: value" in result["error_message"] def test_solve_knapsack_problem_negative_item_values(self): """Test knapsack with negative item values.""" items = [{"name": "item1", "value": -10, "weight": 5}] capacity = 10 result = solve_knapsack_problem(items, capacity) assert result["status"] == "error" assert "value and weight must be non-negative" in result["error_message"] def test_solve_knapsack_problem_unbounded(self): """Test unbounded knapsack problem.""" items = [ {"name": "item1", "value": 10, "weight": 5}, {"name": "item2", "value": 15, "weight": 8}, ] capacity = 20 result = solve_knapsack_problem(items, capacity, knapsack_type="unbounded") assert result["status"] in ["optimal", "infeasible"] if result["status"] == "optimal": assert isinstance(result["total_value"], (int, float)) def test_solve_knapsack_problem_bounded(self): """Test bounded knapsack problem.""" items = [ {"name": "item1", "value": 10, "weight": 5, "quantity": 2}, {"name": "item2", "value": 15, "weight": 8, "quantity": 1}, ] capacity = 20 result = solve_knapsack_problem( items, capacity, knapsack_type="bounded", max_items_per_type=3 ) assert result["status"] in ["optimal", "infeasible"] if result["status"] == "optimal": assert isinstance(result["total_value"], (int, float)) def test_solve_knapsack_problem_with_volume_no_volume_data(self): """Test knapsack with volume capacity but no volume data in items.""" items = [ {"name": "item1", "value": 10, "weight": 5}, # No volume field {"name": "item2", "value": 15, "weight": 8}, ] capacity = 20 volume_capacity = 10 result = solve_knapsack_problem(items, capacity, volume_capacity) assert result["status"] in ["optimal", "infeasible"] # Should use dynamic programming since no volume constraints are active if result["status"] == "optimal": assert result["solver_info"]["algorithm"] == "Dynamic Programming" def test_solve_knapsack_problem_no_feasible_solution(self): """Test knapsack with no feasible solution.""" with patch("ortools.algorithms.python.knapsack_solver.KnapsackSolver") as mock_solver_class: mock_solver = MagicMock() mock_solver.solve.return_value = 0 # No solution found mock_solver_class.return_value = mock_solver items = [{"name": "item1", "value": 10, "weight": 5}] capacity = 10 result = solve_knapsack_problem(items, capacity) assert result["status"] == "infeasible" assert result["total_value"] == 0.0 assert result["selected_items"] == [] def test_solve_knapsack_problem_with_optimal_solution(self): """Test knapsack with optimal solution and proper item selection.""" items = [ {"name": "item1", "value": 60, "weight": 10}, {"name": "item2", "value": 100, "weight": 20}, {"name": "item3", "value": 120, "weight": 30}, ] capacity = 50 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" assert result["total_value"] > 0 assert len(result["selected_items"]) > 0 # Verify selected items structure for item in result["selected_items"]: assert "name" in item assert "quantity" in item assert "value" in item assert "weight" in item assert "total_value" in item assert "total_weight" in item def test_solve_knapsack_problem_with_volume_constraints_active(self): """Test knapsack with active volume constraints.""" items = [ {"name": "item1", "value": 60, "weight": 10, "volume": 5}, {"name": "item2", "value": 100, "weight": 20, "volume": 8}, ] capacity = 50 volume_capacity = 10 result = solve_knapsack_problem(items, capacity, volume_capacity) assert result["status"] in ["optimal", "infeasible"] if result["status"] == "optimal": # Check that volume constraints are respected for item in result["selected_items"]: assert "total_volume" in item if item["total_volume"] is not None: assert item["total_volume"] >= 0 class TestKnapsackToolsValidation: """Tests for knapsack tools validation.""" def test_knapsack_tool_empty_items_validation(self): """Test knapsack tool validation with empty items.""" result = solve_knapsack_problem([], 10) assert result["status"] == "error" def test_knapsack_tool_zero_capacity_validation(self): """Test knapsack tool validation with zero capacity.""" items = [{"name": "item1", "value": 10, "weight": 5}] result = solve_knapsack_problem(items, 0) assert result["status"] == "error" def test_knapsack_tool_invalid_item_format_validation(self): """Test knapsack tool validation with invalid item format.""" items = [42] # Invalid item format result = solve_knapsack_problem(items, 10) assert result["status"] == "error" def test_knapsack_tool_missing_fields_validation(self): """Test knapsack tool validation with missing item fields.""" items = [{"name": "item1"}] # Missing value and weight result = solve_knapsack_problem(items, 10) assert result["status"] == "error" def test_knapsack_tool_negative_values_validation(self): """Test knapsack tool validation with negative values.""" items = [{"name": "item1", "value": -10, "weight": 5}] result = solve_knapsack_problem(items, 10) assert result["status"] == "error" class TestKnapsackSolverTypes: """Tests for different knapsack solver types.""" def test_dynamic_programming_solver(self): """Test dynamic programming solver selection.""" items = [ {"name": "item1", "value": 10, "weight": 5}, {"name": "item2", "value": 20, "weight": 8}, ] capacity = 15 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" assert result["solver_info"]["algorithm"] == "Dynamic Programming" def test_brute_force_solver(self): """Test solver behavior with small item count (uses dynamic programming).""" items = [{"name": "item1", "value": 10, "weight": 5}] capacity = 10 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" assert result["solver_info"]["solver_name"] == "OR-Tools KnapsackSolver" def test_64items_solver(self): """Test solver with larger item count.""" # Create more items to test solver behavior items = [] for i in range(10): items.append( { "name": f"item{i}", "value": 10 + i, "weight": 5 + i, } ) capacity = 50 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" assert result["solver_info"]["items_count"] == 10 class TestRegisterKnapsackTools: """Tests for knapsack tools registration.""" def test_register_knapsack_tools(self): """Test registration of knapsack tools with MCP server.""" # Mock FastMCP instance mock_mcp = MagicMock() mock_tool_decorator = MagicMock() mock_mcp.tool.return_value = mock_tool_decorator # Register tools register_knapsack_tools(mock_mcp) # Verify tool decorator was called mock_mcp.tool.assert_called() def test_knapsack_tool_wrapper(self): """Test the wrapped knapsack tool function.""" # Mock FastMCP instance mock_mcp = MagicMock() # Register tools register_knapsack_tools(mock_mcp) # Verify tool decorator was called mock_mcp.tool.assert_called() class TestKnapsackEdgeCases: """Tests for knapsack edge cases and error conditions.""" def test_fractional_values_and_weights(self): """Test knapsack with fractional values and weights.""" items = [ {"name": "item1", "value": 10.5, "weight": 5.2}, {"name": "item2", "value": 20.8, "weight": 8.3}, ] capacity = 15.5 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" assert isinstance(result["total_value"], (int, float)) def test_large_capacity(self): """Test knapsack with very large capacity.""" items = [ {"name": "item1", "value": 10, "weight": 5}, {"name": "item2", "value": 20, "weight": 8}, ] capacity = 1000000 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" # All items should be selected assert result["total_value"] == sum(item["value"] for item in items) def test_exact_capacity_match(self): """Test knapsack where selected items exactly match capacity.""" items = [ {"name": "item1", "value": 10, "weight": 5}, {"name": "item2", "value": 20, "weight": 10}, ] capacity = 15 # Exact match for both items result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" total_weight = sum(item["total_weight"] for item in result["selected_items"]) assert total_weight <= capacity def test_zero_value_items(self): """Test knapsack with zero-value items.""" items = [ {"name": "item1", "value": 0, "weight": 5}, {"name": "item2", "value": 20, "weight": 8}, ] capacity = 15 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" # Should prefer non-zero value items assert result["total_value"] >= 0 def test_zero_weight_items(self): """Test knapsack with zero-weight items.""" items = [ {"name": "item1", "value": 10, "weight": 0}, {"name": "item2", "value": 20, "weight": 8}, ] capacity = 15 result = solve_knapsack_problem(items, capacity) assert result["status"] == "optimal" # Zero-weight items should always be selected assert result["total_value"] >= 10

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/dmitryanchikov/mcp-optimizer'

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