"""Tests for weather system.""" import random from mudlib.weather import ( WeatherCondition, WeatherState, advance_weather, get_weather_description, ) def test_weather_condition_enum(): assert WeatherCondition.clear.value == "clear" assert WeatherCondition.cloudy.value == "cloudy" assert WeatherCondition.rain.value == "rain" assert WeatherCondition.storm.value == "storm" assert WeatherCondition.snow.value == "snow" assert WeatherCondition.fog.value == "fog" def test_weather_state_dataclass(): state = WeatherState(condition=WeatherCondition.rain, intensity=0.5) assert state.condition == WeatherCondition.rain assert state.intensity == 0.5 def test_get_weather_description_returns_non_empty(): state = WeatherState(condition=WeatherCondition.clear, intensity=0.5) description = get_weather_description(state) assert isinstance(description, str) assert len(description) > 0 def test_get_weather_description_varies_by_condition(): clear = get_weather_description( WeatherState(condition=WeatherCondition.clear, intensity=0.5) ) rain = get_weather_description( WeatherState(condition=WeatherCondition.rain, intensity=0.5) ) snow = get_weather_description( WeatherState(condition=WeatherCondition.snow, intensity=0.5) ) # Different conditions should produce different descriptions assert clear != rain assert rain != snow assert clear != snow def test_get_weather_description_varies_by_intensity(): light_rain = get_weather_description( WeatherState(condition=WeatherCondition.rain, intensity=0.2) ) heavy_rain = get_weather_description( WeatherState(condition=WeatherCondition.rain, intensity=0.9) ) # Different intensities should produce different descriptions assert light_rain != heavy_rain def test_advance_weather_returns_new_state(): current = WeatherState(condition=WeatherCondition.clear, intensity=0.5) rng = random.Random(42) new_state = advance_weather(current, season="summer", rng=rng) assert isinstance(new_state, WeatherState) assert isinstance(new_state.condition, WeatherCondition) assert 0.0 <= new_state.intensity <= 1.0 def test_advance_weather_is_deterministic_with_seed(): current = WeatherState(condition=WeatherCondition.clear, intensity=0.5) rng1 = random.Random(42) state1 = advance_weather(current, season="summer", rng=rng1) rng2 = random.Random(42) state2 = advance_weather(current, season="summer", rng=rng2) assert state1.condition == state2.condition assert state1.intensity == state2.intensity def test_advance_weather_transitions_naturally(): # Clear can become cloudy rng = random.Random(42) for _ in range(100): current = WeatherState(condition=WeatherCondition.clear, intensity=0.5) new_state = advance_weather(current, season="summer", rng=rng) if new_state.condition == WeatherCondition.cloudy: break else: raise AssertionError("clear never transitioned to cloudy in 100 iterations") # Cloudy can become rain or clear rng = random.Random(43) found_rain = False found_clear = False for _ in range(100): current = WeatherState(condition=WeatherCondition.cloudy, intensity=0.5) new_state = advance_weather(current, season="summer", rng=rng) if new_state.condition == WeatherCondition.rain: found_rain = True if new_state.condition == WeatherCondition.clear: found_clear = True if found_rain and found_clear: break assert found_rain or found_clear def test_storm_transitions_to_rain_or_cloudy(): # Storm should always transition away (doesn't last) rng = random.Random(44) found_non_storm = False for _ in range(50): current = WeatherState(condition=WeatherCondition.storm, intensity=0.8) new_state = advance_weather(current, season="summer", rng=rng) if new_state.condition in (WeatherCondition.rain, WeatherCondition.cloudy): found_non_storm = True break assert found_non_storm, "storm should transition to rain or cloudy" def test_snow_only_in_winter_autumn(): # Snow in winter rng = random.Random(45) found_snow = False for _ in range(200): current = WeatherState(condition=WeatherCondition.cloudy, intensity=0.5) new_state = advance_weather(current, season="winter", rng=rng) if new_state.condition == WeatherCondition.snow: found_snow = True break assert found_snow, "snow should be possible in winter" # Snow should be rare or impossible in summer rng = random.Random(46) for _ in range(100): current = WeatherState(condition=WeatherCondition.cloudy, intensity=0.5) new_state = advance_weather(current, season="summer", rng=rng) # Should not produce snow in summer assert new_state.condition != WeatherCondition.snow def test_climate_temperate_default(): current = WeatherState(condition=WeatherCondition.clear, intensity=0.5) rng = random.Random(47) # Should work without climate parameter (defaults to temperate) new_state = advance_weather(current, season="summer", rng=rng) assert isinstance(new_state, WeatherState) def test_climate_arid_favors_clear(): # Arid should heavily favor clear weather rng = random.Random(48) clear_count = 0 for _ in range(100): current = WeatherState(condition=WeatherCondition.clear, intensity=0.5) new_state = advance_weather(current, season="summer", rng=rng, climate="arid") if new_state.condition == WeatherCondition.clear: clear_count += 1 # Arid should stay clear most of the time assert clear_count > 70, f"arid should favor clear, got {clear_count}/100" def test_climate_arid_no_snow(): # Arid should never produce snow rng = random.Random(49) for _ in range(100): current = WeatherState(condition=WeatherCondition.cloudy, intensity=0.5) new_state = advance_weather(current, season="winter", rng=rng, climate="arid") assert new_state.condition != WeatherCondition.snow def test_climate_arctic_favors_snow_fog_cloudy(): # Arctic should produce snow, fog, or cloudy frequently rng = random.Random(50) arctic_conditions = 0 for _ in range(100): current = WeatherState(condition=WeatherCondition.cloudy, intensity=0.5) new_state = advance_weather(current, season="winter", rng=rng, climate="arctic") if new_state.condition in ( WeatherCondition.snow, WeatherCondition.fog, WeatherCondition.cloudy, ): arctic_conditions += 1 # Arctic should heavily favor snow/fog/cloudy assert arctic_conditions > 70, ( f"arctic should favor snow/fog/cloudy, got {arctic_conditions}/100" ) def test_advance_weather_accepts_all_seasons(): current = WeatherState(condition=WeatherCondition.clear, intensity=0.5) rng = random.Random(51) for season in ["spring", "summer", "autumn", "winter"]: new_state = advance_weather(current, season=season, rng=rng) assert isinstance(new_state, WeatherState)