@@ -336,8 +336,8 @@ def test_resolve_dictionary_keeps_compatible_mapping(example_plain_env):
336336 assert resolved is gfs_mapping
337337
338338
339- def test_resolve_dictionary_falls_back_to_legacy_mapping (example_plain_env ):
340- """Fallback to a compatible built-in mapping for legacy NOMADS -style files."""
339+ def test_resolve_dictionary_falls_back_to_first_compatible_mapping (example_plain_env ):
340+ """Fallback to the first compatible built-in mapping for legacy-style files."""
341341 thredds_gfs_mapping = example_plain_env ._Environment__weather_model_map .get ("GFS" )
342342 dataset = _DummyDataset (
343343 [
@@ -356,7 +356,6 @@ def test_resolve_dictionary_falls_back_to_legacy_mapping(example_plain_env):
356356 thredds_gfs_mapping , dataset
357357 )
358358
359- # Explicit legacy mappings should be preferred over unrelated model mappings.
360359 assert resolved == example_plain_env ._Environment__weather_model_map .get (
361360 "GFS_LEGACY"
362361 )
@@ -602,3 +601,51 @@ def test_set_atmospheric_model_raises_for_unknown_model_type(example_plain_env):
602601 # Act / Assert
603602 with pytest .raises (ValueError , match = "Unknown model type" ):
604603 environment .set_atmospheric_model (type = "unknown_type" )
604+
605+
606+ @pytest .mark .parametrize ("shortcut_name" , ["AIGFS" , "HRRR" ])
607+ def test_forecast_shortcut_and_dictionary_are_case_insensitive (
608+ monkeypatch , shortcut_name
609+ ):
610+ """Ensure forecast shortcuts and built-in dictionaries ignore input casing."""
611+ # Arrange
612+ env = Environment (date = (2026 , 3 , 17 , 12 ), latitude = 32.99 , longitude = - 106.97 )
613+
614+ sentinel_dataset = object ()
615+ env ._Environment__atm_type_file_to_function_map ["forecast" ][shortcut_name ] = (
616+ lambda : sentinel_dataset
617+ )
618+
619+ captured = {}
620+
621+ def fake_process_forecast_reanalysis (file , dictionary ):
622+ captured ["file" ] = file
623+ captured ["dictionary" ] = dictionary
624+
625+ monkeypatch .setattr (
626+ env , "process_forecast_reanalysis" , fake_process_forecast_reanalysis
627+ )
628+ monkeypatch .setattr (env , "calculate_density_profile" , lambda : None )
629+ monkeypatch .setattr (env , "calculate_speed_of_sound_profile" , lambda : None )
630+ monkeypatch .setattr (env , "calculate_dynamic_viscosity" , lambda : None )
631+
632+ # Act
633+ env .set_atmospheric_model (
634+ type = "forecast" ,
635+ file = shortcut_name .lower (),
636+ dictionary = shortcut_name .lower (),
637+ )
638+
639+ # Assert
640+ expected_dictionary = env ._Environment__weather_model_map .get (shortcut_name )
641+ assert captured ["file" ] is sentinel_dataset
642+ assert captured ["dictionary" ] == expected_dictionary
643+ assert env .atmospheric_model_file == shortcut_name
644+ assert env .atmospheric_model_dict == expected_dictionary
645+
646+
647+ def test_weather_model_mapping_get_is_case_insensitive ():
648+ """Ensure built-in mapping names are resolved regardless of casing."""
649+ mapping = WeatherModelMapping ()
650+ assert mapping .get ("aigfs" ) == mapping .get ("AIGFS" )
651+ assert mapping .get ("ecmwf_v0" ) == mapping .get ("ECMWF_v0" )
0 commit comments