@@ -339,3 +339,268 @@ pub type LayerId = u32;
339339/// Node IDs are assigned sequentially as nodes are added during scene encoding.
340340/// They are used to reference nodes when adding edges and during execution order traversal.
341341pub type NodeId = usize ;
342+
343+ #[ cfg( test) ]
344+ mod tests {
345+ use super :: * ;
346+ use crate :: color:: AlphaColor ;
347+
348+ #[ test]
349+ fn new_creates_empty_graph ( ) {
350+ let graph = RenderGraph :: new ( ) ;
351+ assert_eq ! ( graph. nodes. len( ) , 0 ) ;
352+ assert_eq ! ( graph. edges. len( ) , 0 ) ;
353+ assert ! ( !graph. has_filters( ) ) ;
354+ assert ! ( graph. root_node. is_none( ) ) ;
355+ }
356+
357+ #[ test]
358+ fn clear_resets_to_empty_state ( ) {
359+ let mut graph = RenderGraph :: new ( ) ;
360+ graph. add_node ( RenderNodeKind :: RootLayer {
361+ layer_id : 0 ,
362+ wtile_bbox : dummy_bbox ( ) ,
363+ } ) ;
364+ graph. add_node ( RenderNodeKind :: FilterLayer {
365+ layer_id : 1 ,
366+ filter : dummy_filter ( ) ,
367+ wtile_bbox : dummy_bbox ( ) ,
368+ transform : Affine :: IDENTITY ,
369+ } ) ;
370+ graph. record_node_for_execution ( 1 ) ;
371+
372+ graph. clear ( ) ;
373+
374+ assert_eq ! ( graph. nodes. len( ) , 0 ) ;
375+ assert_eq ! ( graph. edges. len( ) , 0 ) ;
376+ assert_eq ! ( graph. next_node_id, 0 ) ;
377+ assert ! ( graph. root_node. is_none( ) ) ;
378+ assert ! ( !graph. has_filters( ) ) ;
379+ assert_eq ! ( graph. execution_order( ) . count( ) , 0 ) ;
380+ }
381+
382+ #[ test]
383+ fn clear_preserves_capacity ( ) {
384+ let mut graph = RenderGraph :: new ( ) ;
385+ let from = graph. add_node ( RenderNodeKind :: RootLayer {
386+ layer_id : 0 ,
387+ wtile_bbox : dummy_bbox ( ) ,
388+ } ) ;
389+ let to = graph. add_node ( RenderNodeKind :: RootLayer {
390+ layer_id : 1 ,
391+ wtile_bbox : dummy_bbox ( ) ,
392+ } ) ;
393+ graph. add_edge ( from, to, DependencyKind :: Sequential { layer_id : 1 } ) ;
394+
395+ let nodes_capacity = graph. nodes . capacity ( ) ;
396+ let edges_capacity = graph. edges . capacity ( ) ;
397+
398+ graph. clear ( ) ;
399+
400+ assert ! ( graph. nodes. capacity( ) >= nodes_capacity) ;
401+ assert ! ( graph. edges. capacity( ) >= edges_capacity) ;
402+ }
403+
404+ #[ test]
405+ fn add_node_returns_sequential_ids ( ) {
406+ let mut graph = RenderGraph :: new ( ) ;
407+ let id0 = graph. add_node ( RenderNodeKind :: RootLayer {
408+ layer_id : 0 ,
409+ wtile_bbox : dummy_bbox ( ) ,
410+ } ) ;
411+ let id1 = graph. add_node ( RenderNodeKind :: FilterLayer {
412+ layer_id : 1 ,
413+ filter : dummy_filter ( ) ,
414+ wtile_bbox : dummy_bbox ( ) ,
415+ transform : Affine :: IDENTITY ,
416+ } ) ;
417+
418+ assert_eq ! ( id0, 0 ) ;
419+ assert_eq ! ( id1, 1 ) ;
420+ }
421+
422+ #[ test]
423+ fn add_node_tracks_root ( ) {
424+ let mut graph = RenderGraph :: new ( ) ;
425+ let root_id = graph. add_node ( RenderNodeKind :: RootLayer {
426+ layer_id : 0 ,
427+ wtile_bbox : dummy_bbox ( ) ,
428+ } ) ;
429+
430+ assert_eq ! ( graph. root_node, Some ( root_id) ) ;
431+ }
432+
433+ #[ test]
434+ fn add_node_filter_sets_has_filters ( ) {
435+ let mut graph = RenderGraph :: new ( ) ;
436+
437+ graph. add_node ( RenderNodeKind :: FilterLayer {
438+ layer_id : 1 ,
439+ filter : dummy_filter ( ) ,
440+ wtile_bbox : dummy_bbox ( ) ,
441+ transform : Affine :: IDENTITY ,
442+ } ) ;
443+
444+ assert ! ( graph. has_filters( ) ) ;
445+ }
446+
447+ #[ test]
448+ fn add_node_root_does_not_set_has_filters ( ) {
449+ let mut graph = RenderGraph :: new ( ) ;
450+
451+ graph. add_node ( RenderNodeKind :: RootLayer {
452+ layer_id : 0 ,
453+ wtile_bbox : dummy_bbox ( ) ,
454+ } ) ;
455+
456+ assert ! ( !graph. has_filters( ) ) ;
457+ }
458+
459+ #[ test]
460+ fn add_edge_creates_dependency ( ) {
461+ let mut graph = RenderGraph :: new ( ) ;
462+ let from = graph. add_node ( RenderNodeKind :: FilterLayer {
463+ layer_id : 1 ,
464+ filter : dummy_filter ( ) ,
465+ wtile_bbox : dummy_bbox ( ) ,
466+ transform : Affine :: IDENTITY ,
467+ } ) ;
468+ let to = graph. add_node ( RenderNodeKind :: RootLayer {
469+ layer_id : 0 ,
470+ wtile_bbox : dummy_bbox ( ) ,
471+ } ) ;
472+
473+ graph. add_edge ( from, to, DependencyKind :: Sequential { layer_id : 1 } ) ;
474+
475+ assert_eq ! ( graph. edges. len( ) , 1 ) ;
476+ assert_eq ! ( graph. edges[ 0 ] . from, from) ;
477+ assert_eq ! ( graph. edges[ 0 ] . to, to) ;
478+ }
479+
480+ #[ test]
481+ fn add_edge_multiple_from_same_node ( ) {
482+ let mut graph = RenderGraph :: new ( ) ;
483+ let from = graph. add_node ( RenderNodeKind :: FilterLayer {
484+ layer_id : 1 ,
485+ filter : dummy_filter ( ) ,
486+ wtile_bbox : dummy_bbox ( ) ,
487+ transform : Affine :: IDENTITY ,
488+ } ) ;
489+ let to1 = graph. add_node ( RenderNodeKind :: FilterLayer {
490+ layer_id : 2 ,
491+ filter : dummy_filter ( ) ,
492+ wtile_bbox : dummy_bbox ( ) ,
493+ transform : Affine :: IDENTITY ,
494+ } ) ;
495+ let to2 = graph. add_node ( RenderNodeKind :: RootLayer {
496+ layer_id : 0 ,
497+ wtile_bbox : dummy_bbox ( ) ,
498+ } ) ;
499+
500+ graph. add_edge ( from, to1, DependencyKind :: Sequential { layer_id : 1 } ) ;
501+ graph. add_edge ( from, to2, DependencyKind :: Sequential { layer_id : 1 } ) ;
502+
503+ assert_eq ! ( graph. edges. len( ) , 2 ) ;
504+ }
505+
506+ #[ test]
507+ fn execution_order_includes_recorded_nodes ( ) {
508+ let mut graph = RenderGraph :: new ( ) ;
509+ let filter = graph. add_node ( RenderNodeKind :: FilterLayer {
510+ layer_id : 1 ,
511+ filter : dummy_filter ( ) ,
512+ wtile_bbox : dummy_bbox ( ) ,
513+ transform : Affine :: IDENTITY ,
514+ } ) ;
515+
516+ graph. record_node_for_execution ( filter) ;
517+
518+ let order: Vec < _ > = graph. execution_order ( ) . collect ( ) ;
519+ assert_eq ! ( order, vec![ filter] ) ;
520+ }
521+
522+ #[ test]
523+ fn execution_order_includes_only_root_when_present ( ) {
524+ let mut graph = RenderGraph :: new ( ) ;
525+ let root = graph. add_node ( RenderNodeKind :: RootLayer {
526+ layer_id : 0 ,
527+ wtile_bbox : dummy_bbox ( ) ,
528+ } ) ;
529+
530+ let order: Vec < _ > = graph. execution_order ( ) . collect ( ) ;
531+ assert_eq ! ( order, vec![ root] ) ;
532+ }
533+
534+ #[ test]
535+ fn execution_order_root_comes_last ( ) {
536+ let mut graph = RenderGraph :: new ( ) ;
537+ let filter1 = graph. add_node ( RenderNodeKind :: FilterLayer {
538+ layer_id : 1 ,
539+ filter : dummy_filter ( ) ,
540+ wtile_bbox : dummy_bbox ( ) ,
541+ transform : Affine :: IDENTITY ,
542+ } ) ;
543+ let filter2 = graph. add_node ( RenderNodeKind :: FilterLayer {
544+ layer_id : 2 ,
545+ filter : dummy_filter ( ) ,
546+ wtile_bbox : dummy_bbox ( ) ,
547+ transform : Affine :: IDENTITY ,
548+ } ) ;
549+ let root = graph. add_node ( RenderNodeKind :: RootLayer {
550+ layer_id : 0 ,
551+ wtile_bbox : dummy_bbox ( ) ,
552+ } ) ;
553+
554+ graph. record_node_for_execution ( filter2) ;
555+ graph. record_node_for_execution ( filter1) ;
556+
557+ let order: Vec < _ > = graph. execution_order ( ) . collect ( ) ;
558+ assert_eq ! ( order, vec![ filter2, filter1, root] ) ;
559+ }
560+
561+ #[ test]
562+ fn topological_sort_diamond_dependency ( ) {
563+ let mut graph = RenderGraph :: new ( ) ;
564+ let bottom = graph. add_node ( RenderNodeKind :: FilterLayer {
565+ layer_id : 3 ,
566+ filter : dummy_filter ( ) ,
567+ wtile_bbox : dummy_bbox ( ) ,
568+ transform : Affine :: IDENTITY ,
569+ } ) ;
570+ let left = graph. add_node ( RenderNodeKind :: FilterLayer {
571+ layer_id : 1 ,
572+ filter : dummy_filter ( ) ,
573+ wtile_bbox : dummy_bbox ( ) ,
574+ transform : Affine :: IDENTITY ,
575+ } ) ;
576+ let right = graph. add_node ( RenderNodeKind :: FilterLayer {
577+ layer_id : 2 ,
578+ filter : dummy_filter ( ) ,
579+ wtile_bbox : dummy_bbox ( ) ,
580+ transform : Affine :: IDENTITY ,
581+ } ) ;
582+ let top = graph. add_node ( RenderNodeKind :: RootLayer {
583+ layer_id : 0 ,
584+ wtile_bbox : dummy_bbox ( ) ,
585+ } ) ;
586+
587+ // Diamond: bottom -> left -> top, bottom -> right -> top
588+ graph. add_edge ( bottom, left, DependencyKind :: Sequential { layer_id : 3 } ) ;
589+ graph. add_edge ( bottom, right, DependencyKind :: Sequential { layer_id : 3 } ) ;
590+ graph. add_edge ( left, top, DependencyKind :: Sequential { layer_id : 1 } ) ;
591+ graph. add_edge ( right, top, DependencyKind :: Sequential { layer_id : 2 } ) ;
592+
593+ let sorted = graph. topological_sort ( ) ;
594+ assert_eq ! ( sorted, vec![ bottom, right, left, top] ) ;
595+ }
596+
597+ fn dummy_filter ( ) -> Filter {
598+ Filter :: from_primitive ( crate :: filter_effects:: FilterPrimitive :: Flood {
599+ color : AlphaColor :: from_rgba8 ( 0 , 0 , 0 , 255 ) ,
600+ } )
601+ }
602+
603+ fn dummy_bbox ( ) -> WideTilesBbox {
604+ WideTilesBbox :: new ( [ 0 , 0 , 0 , 0 ] )
605+ }
606+ }
0 commit comments