@@ -268,3 +268,35 @@ def test_target_values():
268268 unique = set (np .unique (out [np .isfinite (out )]))
269269 assert 3.0 not in unique
270270 assert {1.0 , 2.0 } == unique
271+
272+
273+ @pytest .mark .skipif (da is None , reason = "dask not installed" )
274+ def test_balanced_allocation_memory_guard ():
275+ """Memory guard should raise before computing N cost surfaces."""
276+ from unittest .mock import patch
277+
278+ data = np .zeros ((100 , 100 ))
279+ data [10 , 10 ] = 1.0
280+ data [90 , 90 ] = 2.0
281+
282+ raster = _make_raster (data , backend = 'dask+numpy' , chunks = (50 , 50 ))
283+ friction = _make_raster (np .ones ((100 , 100 )), backend = 'dask+numpy' , chunks = (50 , 50 ))
284+
285+ # Mock available memory to 1 KB so the guard trips
286+ with patch ('xrspatial.zonal._available_memory_bytes' , return_value = 1024 ):
287+ with pytest .raises (MemoryError , match = "balanced_allocation with 2 sources" ):
288+ balanced_allocation (raster , friction )
289+
290+
291+ @pytest .mark .skipif (da is None , reason = "dask not installed" )
292+ def test_extract_sources_dask_no_materialize ():
293+ """_extract_sources should use da.unique, not materialize the full array."""
294+ from xrspatial .balanced_allocation import _extract_sources
295+
296+ data = np .zeros ((50 , 50 ))
297+ data [10 , 10 ] = 1.0
298+ data [40 , 40 ] = 2.0
299+ raster = _make_raster (data , backend = 'dask+numpy' , chunks = (25 , 25 ))
300+
301+ ids = _extract_sources (raster , target_values = [])
302+ np .testing .assert_array_equal (ids , [1.0 , 2.0 ])
0 commit comments