Add command-line interface, test suite, and unit tests for hardware manager and recipe models
This commit is contained in:
217
python_rewrite/tests/unit/test_recipe_models.py
Normal file
217
python_rewrite/tests/unit/test_recipe_models.py
Normal file
@@ -0,0 +1,217 @@
|
||||
"""
|
||||
Unit tests for recipe models and validation.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from src.tempering_machine.shared.models.recipe import Recipe, RecipePhase
|
||||
|
||||
|
||||
class TestRecipe:
|
||||
"""Test cases for Recipe model."""
|
||||
|
||||
def test_recipe_creation(self):
|
||||
"""Test basic recipe creation."""
|
||||
recipe = Recipe(
|
||||
name="Test Recipe",
|
||||
heating_goal=46.0,
|
||||
cooling_goal=27.0,
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
|
||||
assert recipe.name == "Test Recipe"
|
||||
assert recipe.heating_goal == 46.0
|
||||
assert recipe.cooling_goal == 27.0
|
||||
assert recipe.is_active is True
|
||||
assert recipe.version == 1
|
||||
|
||||
def test_recipe_temperature_validation_valid(self):
|
||||
"""Test valid temperature parameters."""
|
||||
recipe = Recipe(
|
||||
name="Valid Recipe",
|
||||
heating_goal=50.0,
|
||||
cooling_goal=25.0,
|
||||
pouring_goal=30.0,
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
|
||||
assert recipe.validate_temperatures() is True
|
||||
|
||||
def test_recipe_temperature_validation_invalid_cooling_too_high(self):
|
||||
"""Test invalid temperature parameters - cooling goal too high."""
|
||||
recipe = Recipe(
|
||||
name="Invalid Recipe",
|
||||
heating_goal=45.0,
|
||||
cooling_goal=50.0, # Higher than heating goal
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
|
||||
assert recipe.validate_temperatures() is False
|
||||
|
||||
def test_recipe_temperature_validation_invalid_ranges(self):
|
||||
"""Test invalid temperature ranges."""
|
||||
# Heating goal too low
|
||||
recipe1 = Recipe(
|
||||
name="Invalid Recipe 1",
|
||||
heating_goal=35.0, # Below minimum of 40°C
|
||||
cooling_goal=25.0,
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
assert recipe1.validate_temperatures() is False
|
||||
|
||||
# Cooling goal too high
|
||||
recipe2 = Recipe(
|
||||
name="Invalid Recipe 2",
|
||||
heating_goal=50.0,
|
||||
cooling_goal=45.0, # Above maximum of 40°C
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
assert recipe2.validate_temperatures() is False
|
||||
|
||||
def test_recipe_pouring_goal_validation(self):
|
||||
"""Test pouring goal validation."""
|
||||
# Valid pouring goal within range
|
||||
recipe1 = Recipe(
|
||||
name="Valid Pouring",
|
||||
heating_goal=50.0,
|
||||
cooling_goal=25.0,
|
||||
pouring_goal=30.0, # Between cooling and heating
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
assert recipe1.validate_temperatures() is True
|
||||
|
||||
# Invalid pouring goal - too low
|
||||
recipe2 = Recipe(
|
||||
name="Invalid Pouring Low",
|
||||
heating_goal=50.0,
|
||||
cooling_goal=25.0,
|
||||
pouring_goal=20.0, # Below cooling goal
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
assert recipe2.validate_temperatures() is False
|
||||
|
||||
# Invalid pouring goal - too high
|
||||
recipe3 = Recipe(
|
||||
name="Invalid Pouring High",
|
||||
heating_goal=50.0,
|
||||
cooling_goal=25.0,
|
||||
pouring_goal=55.0, # Above heating goal
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
assert recipe3.validate_temperatures() is False
|
||||
|
||||
def test_get_phase_sequence(self):
|
||||
"""Test phase sequence generation."""
|
||||
recipe = Recipe(
|
||||
name="Phase Test",
|
||||
heating_goal=46.0,
|
||||
cooling_goal=27.0,
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0
|
||||
)
|
||||
|
||||
phases = recipe.get_phase_sequence()
|
||||
expected_phases = [
|
||||
RecipePhase.PREHEATING,
|
||||
RecipePhase.HEATING,
|
||||
RecipePhase.HEATING_DELAY,
|
||||
RecipePhase.COOLING,
|
||||
RecipePhase.COOLING_DELAY,
|
||||
RecipePhase.POURING
|
||||
]
|
||||
|
||||
assert phases == expected_phases
|
||||
|
||||
def test_recipe_to_dict(self):
|
||||
"""Test recipe serialization to dictionary."""
|
||||
recipe = Recipe(
|
||||
name="Serialization Test",
|
||||
description="Test description",
|
||||
heating_goal=46.0,
|
||||
cooling_goal=27.0,
|
||||
pouring_goal=30.0,
|
||||
tank_temp=45.0,
|
||||
fountain_temp=32.0,
|
||||
mixer_enabled=True,
|
||||
fountain_enabled=True,
|
||||
pedal_on_time=2.5,
|
||||
pedal_off_time=3.5
|
||||
)
|
||||
|
||||
recipe_dict = recipe.to_dict()
|
||||
|
||||
assert recipe_dict["name"] == "Serialization Test"
|
||||
assert recipe_dict["description"] == "Test description"
|
||||
assert recipe_dict["heating_goal"] == 46.0
|
||||
assert recipe_dict["cooling_goal"] == 27.0
|
||||
assert recipe_dict["pouring_goal"] == 30.0
|
||||
assert recipe_dict["mixer_enabled"] is True
|
||||
assert recipe_dict["pedal_on_time"] == 2.5
|
||||
assert recipe_dict["pedal_off_time"] == 3.5
|
||||
assert recipe_dict["version"] == 1
|
||||
assert recipe_dict["is_active"] is True
|
||||
|
||||
def test_from_csv_row(self):
|
||||
"""Test creating recipe from CSV data."""
|
||||
csv_row = {
|
||||
"ID": "1",
|
||||
"Name": "CSV Recipe",
|
||||
"HeatingGoal": "46.0",
|
||||
"CoolingGoal": "27.0",
|
||||
"PouringGoal": "30.0",
|
||||
"TankTemp": "45.0",
|
||||
"FountainTemp": "32.0",
|
||||
"Mixer": "1",
|
||||
"Fountain": "1",
|
||||
"MoldHeater": "0",
|
||||
"Vibration": "0",
|
||||
"VibHeater": "0",
|
||||
"Pedal": "1",
|
||||
"PedalOnTime": "2.0",
|
||||
"PedalOffTime": "3.0"
|
||||
}
|
||||
|
||||
recipe = Recipe.from_csv_row(csv_row)
|
||||
|
||||
assert recipe.id == 1
|
||||
assert recipe.name == "CSV Recipe"
|
||||
assert recipe.heating_goal == 46.0
|
||||
assert recipe.cooling_goal == 27.0
|
||||
assert recipe.pouring_goal == 30.0
|
||||
assert recipe.mixer_enabled is True
|
||||
assert recipe.mold_heater_enabled is False
|
||||
assert recipe.pedal_on_time == 2.0
|
||||
|
||||
|
||||
class TestRecipePhase:
|
||||
"""Test cases for RecipePhase enum."""
|
||||
|
||||
def test_recipe_phase_values(self):
|
||||
"""Test recipe phase enum values."""
|
||||
assert RecipePhase.PREHEATING.value == "preheating"
|
||||
assert RecipePhase.HEATING.value == "heating"
|
||||
assert RecipePhase.HEATING_DELAY.value == "heating_delay"
|
||||
assert RecipePhase.COOLING.value == "cooling"
|
||||
assert RecipePhase.COOLING_DELAY.value == "cooling_delay"
|
||||
assert RecipePhase.POURING.value == "pouring"
|
||||
assert RecipePhase.COMPLETED.value == "completed"
|
||||
assert RecipePhase.STOPPED.value == "stopped"
|
||||
assert RecipePhase.ERROR.value == "error"
|
||||
|
||||
def test_recipe_phase_membership(self):
|
||||
"""Test recipe phase enum membership."""
|
||||
assert RecipePhase.PREHEATING in RecipePhase
|
||||
assert RecipePhase.HEATING in RecipePhase
|
||||
assert RecipePhase.COMPLETED in RecipePhase
|
||||
|
||||
# Test string conversion
|
||||
assert str(RecipePhase.HEATING) == "RecipePhase.HEATING"
|
||||
Reference in New Issue
Block a user