Import Vector lab project

This commit is contained in:
root
2026-06-06 18:31:55 +00:00
commit fcc22063ed
105 changed files with 31639 additions and 0 deletions
+341
View File
@@ -0,0 +1,341 @@
"""
Tests for distance_service.py
Tests the distance calculation formulas and prior probabilities
based on §9 ВЕКТОР-контекст.md specifications.
"""
import pytest
from services.distance_service import (
calculate_max_distance,
get_base_speed,
get_terrain_coefficient,
get_time_of_day_coefficient,
get_weather_coefficient,
get_distance_priors,
get_distance_zone,
get_distance_statistics
)
class TestCalculateMaxDistance:
"""Test the main distance calculation function."""
def test_boy_10_years_4_hours_forest_rain(self):
"""
Test case from requirements:
Мальчик 10 лет, 4 часа, лес, дождь → ~5 км
"""
case_data = {
'age': 10,
'elapsed_hours': 4.0,
'terrain_primary': 'лес',
'time_of_day': 'день',
'weather': 'дождь'
}
distance = calculate_max_distance(case_data)
# Expected calculation:
# Time = 4 hours
# НормС (age 10) = 4.0 km/h
# СП (лес) = 0.5
# СУТ (4 hours) = 1.0 - (0.05 * 4) = 0.8
# ВВС (день) = 1.0
# ВП (дождь) = 0.8
# Distance = 4 * 4.0 * 0.5 * 0.8 * 1.0 * 0.8 = 5.12 km
assert 4.5 <= distance <= 5.5, f"Expected ~5 km, got {distance} km"
assert distance == pytest.approx(5.12, rel=0.01)
def test_young_child_short_time(self):
"""Test for young child (3 years) with short elapsed time."""
case_data = {
'age': 3,
'elapsed_hours': 1.0,
'terrain_primary': 'лес',
'time_of_day': 'день',
'weather': 'нет'
}
distance = calculate_max_distance(case_data)
# Expected: 1 * 2.0 * 0.5 * 0.95 * 1.0 * 1.0 = 0.95 km
assert distance == pytest.approx(0.95, rel=0.01)
def test_teenager_long_time_road(self):
"""Test for teenager on road with longer elapsed time."""
case_data = {
'age': 15,
'elapsed_hours': 6.0,
'terrain_primary': 'дорога',
'time_of_day': 'день',
'weather': 'нет'
}
distance = calculate_max_distance(case_data)
# Expected: 6 * 5.0 * 0.8 * 0.7 * 1.0 * 1.0 = 16.8 km
assert distance == pytest.approx(16.8, rel=0.01)
def test_elderly_night_swamp(self):
"""Test for elderly person at night in swamp."""
case_data = {
'age': 70,
'elapsed_hours': 3.0,
'terrain_primary': 'болото',
'time_of_day': 'ночь',
'weather': 'туман'
}
distance = calculate_max_distance(case_data)
# Expected: 3 * 3.0 * 0.2 * 0.85 * 0.5 * 0.7 = 0.54 km
assert distance == pytest.approx(0.54, rel=0.01)
def test_adult_heavy_rain_field(self):
"""Test for adult in heavy rain on field."""
case_data = {
'age': 35,
'elapsed_hours': 2.0,
'terrain_primary': 'поле',
'time_of_day': 'день',
'weather': 'ливень'
}
distance = calculate_max_distance(case_data)
# Expected: 2 * 5.0 * 0.9 * 0.9 * 1.0 * 0.6 = 4.86 km
assert distance == pytest.approx(4.86, rel=0.01)
class TestBaseSpeed:
"""Test НормС (base speed) by age."""
def test_infant(self):
assert get_base_speed(1) == 1.0
assert get_base_speed(2) == 1.0
def test_preschool(self):
assert get_base_speed(3) == 2.0
assert get_base_speed(5) == 2.0
def test_young_child(self):
assert get_base_speed(6) == 3.0
assert get_base_speed(8) == 3.0
def test_preteen(self):
assert get_base_speed(10) == 4.0
assert get_base_speed(12) == 4.0
def test_teenager(self):
assert get_base_speed(13) == 5.0
assert get_base_speed(15) == 5.0
assert get_base_speed(16) == 5.5
assert get_base_speed(17) == 5.5
def test_adult(self):
assert get_base_speed(25) == 5.0
assert get_base_speed(50) == 5.0
assert get_base_speed(64) == 5.0
def test_elderly(self):
assert get_base_speed(65) == 3.0
assert get_base_speed(80) == 3.0
class TestTerrainCoefficient:
"""Test СП (terrain coefficient)."""
def test_road_terrain(self):
assert get_terrain_coefficient('дорога') == 0.8
assert get_terrain_coefficient('лесная дорога') == 0.8
assert get_terrain_coefficient('тропа') == 0.8
def test_forest_terrain(self):
assert get_terrain_coefficient('лес') == 0.5
assert get_terrain_coefficient('простой лес') == 0.5
assert get_terrain_coefficient('сложный лес') == 0.25
assert get_terrain_coefficient('густой лес') == 0.25
def test_open_terrain(self):
assert get_terrain_coefficient('поле') == 0.9
assert get_terrain_coefficient('луг') == 0.9
def test_difficult_terrain(self):
assert get_terrain_coefficient('болото') == 0.2
assert get_terrain_coefficient('горы') == 0.3
assert get_terrain_coefficient('овраг') == 0.3
def test_urban_terrain(self):
assert get_terrain_coefficient('город') == 1.0
assert get_terrain_coefficient('населённый пункт') == 1.0
def test_unknown_terrain(self):
assert get_terrain_coefficient('неизвестно') == 0.5
class TestTimeOfDayCoefficient:
"""Test ВВС (time of day coefficient)."""
def test_day(self):
assert get_time_of_day_coefficient('день') == 1.0
def test_night(self):
assert get_time_of_day_coefficient('ночь') == 0.5
def test_twilight(self):
assert get_time_of_day_coefficient('сумерки') == 0.5
assert get_time_of_day_coefficient('вечер') == 0.5
class TestWeatherCoefficient:
"""Test ВП (weather coefficient)."""
def test_clear_weather(self):
assert get_weather_coefficient('нет') == 1.0
assert get_weather_coefficient('ясно') == 1.0
def test_rain(self):
assert get_weather_coefficient('дождь') == 0.8
assert get_weather_coefficient('ливень') == 0.6
assert get_weather_coefficient('сильный дождь') == 0.6
def test_fog(self):
assert get_weather_coefficient('туман') == 0.7
def test_snow(self):
assert get_weather_coefficient('снег') == 0.6
assert get_weather_coefficient('метель') == 0.6
def test_heat(self):
assert get_weather_coefficient('жара') == 0.8
class TestDistancePriors:
"""Test get_distance_priors() - априорные вероятности зон."""
def test_young_child_priors(self):
"""Children under 8 stay close."""
priors = get_distance_priors(5)
assert priors['0_500m'] == 0.45
assert priors['500_1500m'] == 0.35
assert priors['1500_2500m'] == 0.15
assert sum(priors.values()) == pytest.approx(1.0, rel=0.01)
def test_preteen_priors(self):
"""Children 8-12 have more even distribution."""
priors = get_distance_priors(10)
assert priors['0_500m'] == 0.28
assert priors['500_1500m'] == 0.25
assert priors['1500_2500m'] == 0.22
assert sum(priors.values()) == pytest.approx(1.0, rel=0.01)
def test_teenager_priors(self):
"""Teenagers can go farther."""
priors = get_distance_priors(15)
assert priors['1500_2500m'] == 0.25
assert priors['5000_plus'] == 0.08
assert sum(priors.values()) == pytest.approx(1.0, rel=0.01)
def test_adult_priors(self):
"""Adults have highest far-distance probability."""
priors = get_distance_priors(35)
assert priors['0_500m'] == 0.12
assert priors['5000_plus'] == 0.13
assert sum(priors.values()) == pytest.approx(1.0, rel=0.01)
def test_elderly_priors(self):
"""Elderly stay closer like young children."""
priors = get_distance_priors(70)
assert priors['0_500m'] == 0.35
assert priors['5000_plus'] == 0.02
assert sum(priors.values()) == pytest.approx(1.0, rel=0.01)
class TestDistanceZone:
"""Test get_distance_zone() classification."""
def test_zone_classification(self):
assert get_distance_zone(0.3) == '0_500m'
assert get_distance_zone(0.5) == '500_1500m'
assert get_distance_zone(1.0) == '500_1500m'
assert get_distance_zone(1.5) == '1500_2500m'
assert get_distance_zone(2.5) == '2500_3500m'
assert get_distance_zone(4.0) == '3500_5000m'
assert get_distance_zone(6.0) == '5000_plus'
class TestDistanceStatistics:
"""Test get_distance_statistics() comprehensive output."""
def test_statistics_structure(self):
stats = get_distance_statistics(
age_years=10,
elapsed_hours=4.0,
terrain='лес'
)
assert 'max_distance_km' in stats
assert 'current_zone' in stats
assert 'zone_probability' in stats
assert 'all_priors' in stats
assert 'base_speed_kmh' in stats
assert 'terrain_coefficient' in stats
def test_statistics_values(self):
stats = get_distance_statistics(
age_years=10,
elapsed_hours=4.0,
terrain='лес'
)
assert stats['base_speed_kmh'] == 4.0
assert stats['terrain_coefficient'] == 0.5
assert stats['max_distance_km'] > 0
assert 0 <= stats['zone_probability'] <= 1.0
class TestFatigueCoefficient:
"""Test СУТ (fatigue coefficient) behavior."""
def test_fatigue_progression(self):
"""Fatigue increases with time (5% per hour)."""
case_1h = {
'age': 30,
'elapsed_hours': 1.0,
'terrain_primary': 'поле',
'time_of_day': 'день',
'weather': 'нет'
}
dist_1h = calculate_max_distance(case_1h)
case_5h = case_1h.copy()
case_5h['elapsed_hours'] = 5.0
dist_5h = calculate_max_distance(case_5h)
case_10h = case_1h.copy()
case_10h['elapsed_hours'] = 10.0
dist_10h = calculate_max_distance(case_10h)
assert dist_5h < dist_1h * 5
assert dist_10h < dist_5h * 2
def test_fatigue_minimum(self):
"""Fatigue coefficient has minimum of 0.3."""
case_data = {
'age': 30,
'elapsed_hours': 20.0,
'terrain_primary': 'поле',
'time_of_day': 'день',
'weather': 'нет'
}
distance = calculate_max_distance(case_data)
# 20 * 5.0 * 0.9 * 0.3 * 1.0 * 1.0 = 27.0
assert distance == pytest.approx(27.0, rel=0.01)