Skip to main content
Glama
puran-water

Corrosion Engineering MCP Server

by puran-water
test_csv_loaders.py9.59 kB
""" Unit tests for CSV data loaders Tests that CSV loaders correctly load authoritative data from CSV files. Validates data integrity, caching, and error handling. """ import pytest from data.csv_loaders import ( load_materials_from_csv, load_cpt_data_from_csv, load_galvanic_series_from_csv, load_orr_diffusion_limits_from_csv, load_chloride_thresholds_from_csv, load_temperature_coefficients_from_csv, clear_caches, MaterialComposition, ) class TestMaterialsCSVLoader: """Test materials_compositions.csv loader""" def test_load_materials_returns_dict(self): """Test that loader returns a dictionary""" materials = load_materials_from_csv() assert isinstance(materials, dict) assert len(materials) > 0 def test_material_composition_dataclass(self): """Test that loaded materials are MaterialComposition instances""" materials = load_materials_from_csv() sample_material = next(iter(materials.values())) assert isinstance(sample_material, MaterialComposition) def test_316L_composition(self): """Test specific 316L composition from CSV""" materials = load_materials_from_csv() assert "316L" in materials ss316L = materials["316L"] assert ss316L.UNS == "S31603" assert 16.0 <= ss316L.Cr_wt_pct <= 18.0 # ASTM A240 range assert 10.0 <= ss316L.Ni_wt_pct <= 14.0 assert 2.0 <= ss316L.Mo_wt_pct <= 3.0 assert ss316L.Fe_bal is True assert ss316L.grade_type == "austenitic" def test_duplex_2507_composition(self): """Test duplex 2507 composition from CSV""" materials = load_materials_from_csv() assert "2507" in materials duplex = materials["2507"] assert duplex.UNS == "S32750" assert 24.0 <= duplex.Cr_wt_pct <= 26.0 assert 3.0 <= duplex.Mo_wt_pct <= 5.0 assert duplex.grade_type == "super_duplex" def test_caching(self): """Test that repeated calls use cache""" clear_caches() # Clear cache first materials1 = load_materials_from_csv() materials2 = load_materials_from_csv() # Should return same object (cached) assert materials1 is materials2 def test_cache_clear(self): """Test cache clearing""" materials1 = load_materials_from_csv() clear_caches() materials2 = load_materials_from_csv() # After clear, should reload (different object) assert materials1 is not materials2 # But content should be identical assert materials1.keys() == materials2.keys() class TestCPTDataCSVLoader: """Test astm_g48_cpt_data.csv loader""" def test_load_cpt_data_returns_dict(self): """Test that loader returns a dictionary""" cpt_data = load_cpt_data_from_csv() assert isinstance(cpt_data, dict) assert len(cpt_data) > 0 def test_316L_cpt(self): """Test 316L CPT from ASTM G48""" cpt_data = load_cpt_data_from_csv() assert "316L" in cpt_data cpt = cpt_data["316L"]["CPT_C"] # Per ASTM G48-11, 316L CPT typically 5-15°C assert 0 <= cpt <= 20 def test_2507_cpt(self): """Test super duplex 2507 CPT""" cpt_data = load_cpt_data_from_csv() if "2507" in cpt_data: cpt = cpt_data["2507"]["CPT_C"] # Super duplex should have high CPT (>40°C) assert cpt > 40 class TestGalvanicSeriesCSVLoader: """Test astm_g82_galvanic_series.csv loader""" def test_load_galvanic_series_returns_dict(self): """Test that loader returns a dictionary""" galvanic = load_galvanic_series_from_csv() assert isinstance(galvanic, dict) assert len(galvanic) > 0 def test_316_stainless_potential(self): """Test 316 stainless steel galvanic potential""" galvanic = load_galvanic_series_from_csv() # 316 stainless should be in the data found_316 = False for key in galvanic.keys(): if "316" in key: potential = galvanic[key] # Should be noble (negative potential in SCE) assert -0.5 <= potential <= 0.0 found_316 = True break assert found_316, "316 stainless steel not found in galvanic series" def test_zinc_potential(self): """Test zinc galvanic potential (active metal)""" galvanic = load_galvanic_series_from_csv() # Zinc should be active (more negative potential) found_zinc = False for key in galvanic.keys(): if "zinc" in key.lower() or "Zn" in key: potential = galvanic[key] # Zinc is active: -0.8 to -1.1 V SCE assert -1.2 <= potential <= -0.6 found_zinc = True break assert found_zinc, "Zinc not found in galvanic series" class TestORRDiffusionLimitsCSVLoader: """Test orr_diffusion_limits.csv loader""" def test_load_orr_limits_returns_dict(self): """Test that loader returns a dictionary""" orr_limits = load_orr_diffusion_limits_from_csv() assert isinstance(orr_limits, dict) assert len(orr_limits) > 0 def test_seawater_25C_limit(self): """Test ORR limit in seawater at 25°C""" orr_limits = load_orr_diffusion_limits_from_csv() assert "seawater_25C" in orr_limits i_lim = orr_limits["seawater_25C"] # Typical ORR diffusion limit in seawater: 3-7 A/m² assert 2.0 <= i_lim <= 10.0 def test_seawater_40C_higher_than_25C(self): """Test that ORR limit increases with temperature""" orr_limits = load_orr_diffusion_limits_from_csv() if "seawater_25C" in orr_limits and "seawater_40C" in orr_limits: i_lim_25C = orr_limits["seawater_25C"] i_lim_40C = orr_limits["seawater_40C"] # Higher temperature → higher diffusion limit assert i_lim_40C > i_lim_25C class TestChlorideThresholdsCSVLoader: """Test iso18070_chloride_thresholds.csv loader""" def test_load_chloride_thresholds_returns_dict(self): """Test that loader returns a dictionary""" thresholds = load_chloride_thresholds_from_csv() assert isinstance(thresholds, dict) assert len(thresholds) > 0 def test_304_threshold(self): """Test 304 stainless steel chloride threshold""" thresholds = load_chloride_thresholds_from_csv() assert "304" in thresholds threshold = thresholds["304"] # 304 has low pitting resistance: 10-100 mg/L assert 10 <= threshold <= 150 def test_316L_higher_than_304(self): """Test that 316L has higher chloride threshold than 304""" thresholds = load_chloride_thresholds_from_csv() if "304" in thresholds and "316L" in thresholds: threshold_304 = thresholds["304"] threshold_316L = thresholds["316L"] # 316L (Mo-bearing) should have higher threshold assert threshold_316L > threshold_304 def test_2507_super_duplex_threshold(self): """Test super duplex 2507 chloride threshold""" thresholds = load_chloride_thresholds_from_csv() if "2507" in thresholds: threshold = thresholds["2507"] # Super duplex: extreme resistance (>1000 mg/L) assert threshold > 500 class TestTemperatureCoefficientsCSVLoader: """Test iso18070_temperature_coefficients.csv loader""" def test_load_temp_coefficients_returns_dict(self): """Test that loader returns a dictionary""" coeffs = load_temperature_coefficients_from_csv() assert isinstance(coeffs, dict) assert len(coeffs) > 0 def test_austenitic_coefficient(self): """Test austenitic temperature coefficient""" coeffs = load_temperature_coefficients_from_csv() assert "austenitic" in coeffs coeff = coeffs["austenitic"] # Per ISO 18070: austenitic ~0.05 /°C assert 0.04 <= coeff <= 0.06 def test_duplex_lower_than_austenitic(self): """Test that duplex has lower temp coefficient than austenitic""" coeffs = load_temperature_coefficients_from_csv() if "austenitic" in coeffs and "duplex" in coeffs: coeff_austenitic = coeffs["austenitic"] coeff_duplex = coeffs["duplex"] # Duplex more stable → lower coefficient assert coeff_duplex < coeff_austenitic class TestCacheManagement: """Test cache clearing functionality""" def test_clear_caches_resets_all_caches(self): """Test that clear_caches resets all loader caches""" # Load all data materials1 = load_materials_from_csv() cpt1 = load_cpt_data_from_csv() galvanic1 = load_galvanic_series_from_csv() # Clear caches clear_caches() # Reload materials2 = load_materials_from_csv() cpt2 = load_cpt_data_from_csv() galvanic2 = load_galvanic_series_from_csv() # All should be different objects (reloaded) assert materials1 is not materials2 assert cpt1 is not cpt2 assert galvanic1 is not galvanic2 # But content should be identical assert materials1.keys() == materials2.keys() assert cpt1.keys() == cpt2.keys() assert galvanic1.keys() == galvanic2.keys() if __name__ == "__main__": pytest.main([__file__, "-v"])

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/puran-water/corrosion-engineering-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server