TCPDashboard/tests/test_indicator_schema.py
Vasily.onl d71cb763bc 3.4 - 3.0 Strategy Configuration System
Implement comprehensive chart configuration and validation system

- Introduced a modular chart configuration system in `components/charts/config/` to manage indicator definitions, default configurations, and strategy-specific setups.
- Added new modules for error handling and validation, enhancing user guidance and error reporting capabilities.
- Implemented detailed schema validation for indicators and strategies, ensuring robust configuration management.
- Created example strategies and default configurations to facilitate user onboarding and usage.
- Enhanced documentation to provide clear guidelines on the configuration system, validation rules, and usage examples.
- Added unit tests for all new components to ensure functionality and reliability across the configuration system.
2025-06-03 14:33:25 +08:00

316 lines
10 KiB
Python

"""
Tests for Indicator Schema Validation System
Tests the new indicator definition schema and validation functionality
to ensure robust parameter validation and error handling.
"""
import pytest
from typing import Dict, Any
from components.charts.config.indicator_defs import (
IndicatorType,
DisplayType,
LineStyle,
IndicatorParameterSchema,
IndicatorSchema,
ChartIndicatorConfig,
INDICATOR_SCHEMAS,
validate_indicator_configuration,
create_indicator_config,
get_indicator_schema,
get_available_indicator_types,
get_indicator_parameter_info,
validate_parameters_for_type,
create_configuration_from_json
)
class TestIndicatorParameterSchema:
"""Test individual parameter schema validation."""
def test_required_parameter_validation(self):
"""Test validation of required parameters."""
schema = IndicatorParameterSchema(
name="period",
type=int,
required=True,
min_value=1,
max_value=100
)
# Valid value
is_valid, error = schema.validate(20)
assert is_valid
assert error == ""
# Missing required parameter
is_valid, error = schema.validate(None)
assert not is_valid
assert "required" in error.lower()
# Wrong type
is_valid, error = schema.validate("20")
assert not is_valid
assert "type" in error.lower()
# Out of range
is_valid, error = schema.validate(0)
assert not is_valid
assert ">=" in error
is_valid, error = schema.validate(101)
assert not is_valid
assert "<=" in error
def test_optional_parameter_validation(self):
"""Test validation of optional parameters."""
schema = IndicatorParameterSchema(
name="price_column",
type=str,
required=False,
default="close"
)
# Valid value
is_valid, error = schema.validate("high")
assert is_valid
# None is valid for optional
is_valid, error = schema.validate(None)
assert is_valid
class TestIndicatorSchema:
"""Test complete indicator schema validation."""
def test_sma_schema_validation(self):
"""Test SMA indicator schema validation."""
schema = INDICATOR_SCHEMAS[IndicatorType.SMA]
# Valid parameters
params = {"period": 20, "price_column": "close"}
is_valid, errors = schema.validate_parameters(params)
assert is_valid
assert len(errors) == 0
# Missing required parameter
params = {"price_column": "close"}
is_valid, errors = schema.validate_parameters(params)
assert not is_valid
assert any("period" in error and "required" in error for error in errors)
# Invalid parameter value
params = {"period": 0, "price_column": "close"}
is_valid, errors = schema.validate_parameters(params)
assert not is_valid
assert any(">=" in error for error in errors)
# Unknown parameter
params = {"period": 20, "unknown_param": "test"}
is_valid, errors = schema.validate_parameters(params)
assert not is_valid
assert any("unknown" in error.lower() for error in errors)
def test_macd_schema_validation(self):
"""Test MACD indicator schema validation."""
schema = INDICATOR_SCHEMAS[IndicatorType.MACD]
# Valid parameters
params = {
"fast_period": 12,
"slow_period": 26,
"signal_period": 9,
"price_column": "close"
}
is_valid, errors = schema.validate_parameters(params)
assert is_valid
# Missing required parameters
params = {"fast_period": 12}
is_valid, errors = schema.validate_parameters(params)
assert not is_valid
assert len(errors) >= 2 # Missing slow_period and signal_period
class TestChartIndicatorConfig:
"""Test chart indicator configuration validation."""
def test_valid_config_validation(self):
"""Test validation of a valid configuration."""
config = ChartIndicatorConfig(
name="SMA (20)",
indicator_type="sma",
parameters={"period": 20, "price_column": "close"},
display_type="overlay",
color="#007bff",
line_style="solid",
line_width=2,
opacity=1.0,
visible=True
)
is_valid, errors = config.validate()
assert is_valid
assert len(errors) == 0
def test_invalid_indicator_type(self):
"""Test validation with invalid indicator type."""
config = ChartIndicatorConfig(
name="Invalid Indicator",
indicator_type="invalid_type",
parameters={},
display_type="overlay",
color="#007bff"
)
is_valid, errors = config.validate()
assert not is_valid
assert any("unsupported indicator type" in error.lower() for error in errors)
def test_invalid_display_properties(self):
"""Test validation of display properties."""
config = ChartIndicatorConfig(
name="SMA (20)",
indicator_type="sma",
parameters={"period": 20},
display_type="invalid_display",
color="#007bff",
line_style="invalid_style",
line_width=-1,
opacity=2.0
)
is_valid, errors = config.validate()
assert not is_valid
# Check for multiple validation errors
error_text = " ".join(errors).lower()
assert "display_type" in error_text
assert "line_style" in error_text
assert "line_width" in error_text
assert "opacity" in error_text
class TestUtilityFunctions:
"""Test utility functions for indicator management."""
def test_create_indicator_config(self):
"""Test creating indicator configuration."""
config, errors = create_indicator_config(
name="SMA (20)",
indicator_type="sma",
parameters={"period": 20},
color="#007bff"
)
assert config is not None
assert len(errors) == 0
assert config.name == "SMA (20)"
assert config.indicator_type == "sma"
assert config.parameters["period"] == 20
assert config.parameters["price_column"] == "close" # Default filled in
def test_create_indicator_config_invalid(self):
"""Test creating invalid indicator configuration."""
config, errors = create_indicator_config(
name="Invalid SMA",
indicator_type="sma",
parameters={"period": 0}, # Invalid period
color="#007bff"
)
assert config is None
assert len(errors) > 0
assert any(">=" in error for error in errors)
def test_get_indicator_schema(self):
"""Test getting indicator schema."""
schema = get_indicator_schema("sma")
assert schema is not None
assert schema.indicator_type == IndicatorType.SMA
schema = get_indicator_schema("invalid_type")
assert schema is None
def test_get_available_indicator_types(self):
"""Test getting available indicator types."""
types = get_available_indicator_types()
assert "sma" in types
assert "ema" in types
assert "rsi" in types
assert "macd" in types
assert "bollinger_bands" in types
def test_get_indicator_parameter_info(self):
"""Test getting parameter information."""
info = get_indicator_parameter_info("sma")
assert "period" in info
assert info["period"]["type"] == "int"
assert info["period"]["required"]
assert "price_column" in info
assert not info["price_column"]["required"]
def test_validate_parameters_for_type(self):
"""Test parameter validation for specific type."""
is_valid, errors = validate_parameters_for_type("sma", {"period": 20})
assert is_valid
is_valid, errors = validate_parameters_for_type("sma", {"period": 0})
assert not is_valid
is_valid, errors = validate_parameters_for_type("invalid_type", {})
assert not is_valid
def test_create_configuration_from_json(self):
"""Test creating configuration from JSON."""
json_data = {
"name": "SMA (20)",
"indicator_type": "sma",
"parameters": {"period": 20},
"color": "#007bff"
}
config, errors = create_configuration_from_json(json_data)
assert config is not None
assert len(errors) == 0
# Test with JSON string
import json
json_string = json.dumps(json_data)
config, errors = create_configuration_from_json(json_string)
assert config is not None
assert len(errors) == 0
# Test with missing fields
invalid_json = {"name": "SMA"}
config, errors = create_configuration_from_json(invalid_json)
assert config is None
assert len(errors) > 0
class TestIndicatorSchemaIntegration:
"""Test integration with existing indicator system."""
def test_schema_matches_built_in_indicators(self):
"""Test that schemas match built-in indicator definitions."""
from components.charts.config.indicator_defs import INDICATOR_DEFINITIONS
for indicator_name, config in INDICATOR_DEFINITIONS.items():
# Validate each built-in configuration
is_valid, errors = config.validate()
if not is_valid:
print(f"Validation errors for {indicator_name}: {errors}")
assert is_valid, f"Built-in indicator {indicator_name} failed validation: {errors}"
def test_parameter_schema_completeness(self):
"""Test that all indicator types have complete schemas."""
for indicator_type in IndicatorType:
schema = INDICATOR_SCHEMAS.get(indicator_type)
assert schema is not None, f"Missing schema for {indicator_type.value}"
assert schema.indicator_type == indicator_type
assert len(schema.required_parameters) > 0 or len(schema.optional_parameters) > 0
if __name__ == "__main__":
pytest.main([__file__])