@@ -444,22 +444,23 @@ def test_index_max_hops_honored(engine, hop_kw):
444444
445445
446446@pytest .mark .parametrize ("engine" , ENGINES )
447- def test_index_bounded_range_min_one_hops_none (engine ):
447+ @pytest .mark .parametrize ("max_hops" , [1 , 2 , 3 ])
448+ def test_index_bounded_range_min_one_hops_none (engine , max_hops ):
448449 """A bounded [1,max] hop is a depth union, not exactly max hops."""
449450 from graphistry .compute .gfql .index import index_trace
450451
451452 edf = pd .DataFrame ({"src" : [0 , 1 , 2 ], "dst" : [1 , 2 , 3 ]})
452453 g = graphistry .edges (edf , "src" , "dst" ).materialize_nodes ()
453454 seeds = pd .DataFrame ({"id" : [0 ]})
454- kwargs = dict (hops = None , min_hops = 1 , max_hops = 2 , direction = "forward" )
455+ kwargs = dict (hops = None , min_hops = 1 , max_hops = max_hops , direction = "forward" )
455456 base = g .hop (nodes = seeds , engine = engine , ** kwargs )
456457 with index_trace () as steps :
457458 idx = _force (g , engine ).hop (nodes = seeds , engine = engine , ** kwargs )
458459 assert _sig (base ) == _sig (idx ), "range-hop index must equal scan"
459460 assert any (step ["path" ] == "index" for step in steps ), steps
460461
461462
462- def test_index_coverability_rejects_invalid_bounded_ranges ():
463+ def test_index_coverability_bounded_range_boundaries ():
463464 """Planner declines invalid direct-hop ranges before index traversal."""
464465 from graphistry .compute .gfql .index .api import _hop_is_index_coverable
465466
@@ -486,6 +487,25 @@ def test_index_coverability_rejects_invalid_bounded_ranges():
486487 )
487488 assert not _hop_is_index_coverable (** dict (common , max_hops = 0 ))
488489 assert not _hop_is_index_coverable (** dict (common , min_hops = 0 ))
490+ assert _hop_is_index_coverable (** dict (common , max_hops = 1 ))
491+ assert _hop_is_index_coverable (** dict (common , hops = 5 , max_hops = 2 ))
492+ assert not _hop_is_index_coverable (** dict (common , max_hops = None ))
493+ assert not _hop_is_index_coverable (** dict (common , min_hops = 2 ))
494+ assert not _hop_is_index_coverable (** dict (common , min_hops = 3 , max_hops = 2 ))
495+ assert not _hop_is_index_coverable (** dict (common , nodes = None ))
496+
497+ def test_index_min_two_bounded_range_scans_pandas (graph ):
498+ """Unsupported [2,2] ranges scan without entering the indexed traversal."""
499+ from graphistry .compute .gfql .index import index_trace
500+
501+ seeds = pd .DataFrame ({"id" : [0 , 1 ]})
502+ kwargs = dict (hops = None , min_hops = 2 , max_hops = 2 , direction = "forward" )
503+ base = graph .hop (nodes = seeds , engine = "pandas" , ** kwargs )
504+ with index_trace () as steps :
505+ indexed = _force (graph , "pandas" ).hop (nodes = seeds , engine = "pandas" , ** kwargs )
506+ assert _sig (base ) == _sig (indexed )
507+ assert not any (step ["path" ] == "index" for step in steps ), steps
508+ assert any (step ["decision_reason" ] == "query not index-coverable" for step in steps ), steps
489509
490510@pytest .mark .parametrize ("engine" , ENGINES )
491511def test_index_duplicate_node_ids (engine ):
0 commit comments