mirror of
https://github.com/crewAIInc/crewAI.git
synced 2025-12-16 04:18:35 +00:00
- Replace type(NOT_SPECIFIED) with Any in type annotations to fix Pydantic schema generation errors - Fix test_process_config_with_empty_config to expect empty config to remain (early return behavior) - Fix test_process_config_with_dict_merge to test the actual behavior (config only overrides None/NOT_SPECIFIED) All 19 tests now pass locally. Co-Authored-By: João <joao@crewai.com>
201 lines
5.9 KiB
Python
201 lines
5.9 KiB
Python
"""Tests for utilities.config.process_config function."""
|
|
|
|
import pytest
|
|
from typing import Any
|
|
from pydantic import BaseModel, Field
|
|
|
|
from crewai.utilities.config import process_config
|
|
from crewai.utilities.constants import NOT_SPECIFIED
|
|
|
|
|
|
class TestProcessConfig:
|
|
"""Test suite for process_config function."""
|
|
|
|
def test_process_config_with_none_overrides_not_specified(self):
|
|
"""Test that config with None value overrides NOT_SPECIFIED sentinel."""
|
|
|
|
class TestModel(BaseModel):
|
|
context: Any = Field(default=NOT_SPECIFIED)
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"context": NOT_SPECIFIED,
|
|
"description": "test",
|
|
"config": {"context": None}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["context"] is None
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_with_none_overrides_none(self):
|
|
"""Test that config with None value can override existing None."""
|
|
|
|
class TestModel(BaseModel):
|
|
context: list[str] | None = None
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"context": None,
|
|
"description": "test",
|
|
"config": {"context": None}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["context"] is None
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_preserves_explicit_values(self):
|
|
"""Test that config does not override explicitly set non-None values."""
|
|
|
|
class TestModel(BaseModel):
|
|
context: list[str] | None = None
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"context": ["task1", "task2"],
|
|
"description": "test",
|
|
"config": {"context": None}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["context"] == ["task1", "task2"]
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_with_empty_list_from_config(self):
|
|
"""Test that config with empty list is preserved."""
|
|
|
|
class TestModel(BaseModel):
|
|
context: Any = Field(default=NOT_SPECIFIED)
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"context": NOT_SPECIFIED,
|
|
"description": "test",
|
|
"config": {"context": []}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["context"] == []
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_does_not_override_false(self):
|
|
"""Test that config does not override explicit False value."""
|
|
|
|
class TestModel(BaseModel):
|
|
flag: bool = True
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"flag": False,
|
|
"description": "test",
|
|
"config": {"flag": True}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["flag"] is False
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_does_not_override_zero(self):
|
|
"""Test that config does not override explicit 0 value."""
|
|
|
|
class TestModel(BaseModel):
|
|
count: int = 10
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"count": 0,
|
|
"description": "test",
|
|
"config": {"count": 5}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["count"] == 0
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_does_not_override_empty_string(self):
|
|
"""Test that config does not override explicit empty string value."""
|
|
|
|
class TestModel(BaseModel):
|
|
name: str = "default"
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"name": "",
|
|
"description": "test",
|
|
"config": {"name": "new_name"}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["name"] == ""
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_with_dict_merge(self):
|
|
"""Test that config properly merges dict values when current is None or NOT_SPECIFIED."""
|
|
|
|
class TestModel(BaseModel):
|
|
settings: dict[str, str] | None = None
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"settings": None,
|
|
"description": "test",
|
|
"config": {"settings": {"key2": "value2"}}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["settings"] == {"key2": "value2"}
|
|
assert result["description"] == "test"
|
|
assert "config" not in result
|
|
|
|
def test_process_config_with_no_config(self):
|
|
"""Test that process_config handles missing config gracefully."""
|
|
|
|
class TestModel(BaseModel):
|
|
context: list[str] | None = None
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"context": None,
|
|
"description": "test"
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["context"] is None
|
|
assert result["description"] == "test"
|
|
|
|
def test_process_config_with_empty_config(self):
|
|
"""Test that process_config handles empty config gracefully."""
|
|
|
|
class TestModel(BaseModel):
|
|
context: list[str] | None = None
|
|
description: str = "default"
|
|
|
|
values = {
|
|
"context": None,
|
|
"description": "test",
|
|
"config": {}
|
|
}
|
|
|
|
result = process_config(values, TestModel)
|
|
|
|
assert result["context"] is None
|
|
assert result["description"] == "test"
|
|
assert result["config"] == {}
|