@@ -59,3 +59,114 @@ where
5959 . retain ( |( task_round, _) , _| task_round > finalized_round) ;
6060 }
6161}
62+
63+ #[ cfg( test) ]
64+ mod tests {
65+ use super :: * ;
66+ use crate :: types:: { Epoch , View } ;
67+ use commonware_cryptography:: { sha256:: Digest as Sha256Digest , Hasher , Sha256 } ;
68+
69+ type D = Sha256Digest ;
70+
71+ fn round ( view : u64 ) -> Round {
72+ Round :: new ( Epoch :: zero ( ) , View :: new ( view) )
73+ }
74+
75+ fn pending_task ( ) -> oneshot:: Receiver < bool > {
76+ let ( _tx, rx) = oneshot:: channel ( ) ;
77+ rx
78+ }
79+
80+ #[ test]
81+ fn test_insert_and_take_returns_task ( ) {
82+ let tasks = VerificationTasks :: < D > :: new ( ) ;
83+ let digest = Sha256 :: hash ( b"block" ) ;
84+ tasks. insert ( round ( 1 ) , digest, pending_task ( ) ) ;
85+
86+ assert ! ( tasks. take( round( 1 ) , digest) . is_some( ) ) ;
87+ assert ! (
88+ tasks. take( round( 1 ) , digest) . is_none( ) ,
89+ "taking twice should yield None"
90+ ) ;
91+ }
92+
93+ #[ test]
94+ fn test_take_absent_key_is_none ( ) {
95+ let tasks = VerificationTasks :: < D > :: new ( ) ;
96+ assert ! ( tasks. take( round( 1 ) , Sha256 :: hash( b"missing" ) ) . is_none( ) ) ;
97+ }
98+
99+ #[ test]
100+ fn test_take_distinguishes_rounds_and_digests ( ) {
101+ let tasks = VerificationTasks :: < D > :: new ( ) ;
102+ let digest_a = Sha256 :: hash ( b"a" ) ;
103+ let digest_b = Sha256 :: hash ( b"b" ) ;
104+ tasks. insert ( round ( 1 ) , digest_a, pending_task ( ) ) ;
105+ tasks. insert ( round ( 2 ) , digest_a, pending_task ( ) ) ;
106+ tasks. insert ( round ( 1 ) , digest_b, pending_task ( ) ) ;
107+
108+ assert ! ( tasks. take( round( 1 ) , digest_a) . is_some( ) ) ;
109+ assert ! ( tasks. take( round( 2 ) , digest_a) . is_some( ) ) ;
110+ assert ! ( tasks. take( round( 1 ) , digest_b) . is_some( ) ) ;
111+ }
112+
113+ #[ test]
114+ fn test_retain_after_drops_at_and_below_boundary ( ) {
115+ let tasks = VerificationTasks :: < D > :: new ( ) ;
116+ let digest = Sha256 :: hash ( b"block" ) ;
117+ tasks. insert ( round ( 1 ) , digest, pending_task ( ) ) ;
118+ tasks. insert ( round ( 2 ) , digest, pending_task ( ) ) ;
119+ tasks. insert ( round ( 3 ) , digest, pending_task ( ) ) ;
120+
121+ tasks. retain_after ( & round ( 2 ) ) ;
122+
123+ assert ! (
124+ tasks. take( round( 1 ) , digest) . is_none( ) ,
125+ "tasks strictly below boundary should be dropped"
126+ ) ;
127+ assert ! (
128+ tasks. take( round( 2 ) , digest) . is_none( ) ,
129+ "tasks at boundary should be dropped"
130+ ) ;
131+ assert ! (
132+ tasks. take( round( 3 ) , digest) . is_some( ) ,
133+ "tasks strictly above boundary should be retained"
134+ ) ;
135+ }
136+
137+ #[ test]
138+ fn test_retain_after_spans_epochs ( ) {
139+ let tasks = VerificationTasks :: < D > :: new ( ) ;
140+ let digest = Sha256 :: hash ( b"block" ) ;
141+ let early = Round :: new ( Epoch :: zero ( ) , View :: new ( 100 ) ) ;
142+ let late = Round :: new ( Epoch :: new ( 1 ) , View :: zero ( ) ) ;
143+ tasks. insert ( early, digest, pending_task ( ) ) ;
144+ tasks. insert ( late, digest, pending_task ( ) ) ;
145+
146+ tasks. retain_after ( & early) ;
147+
148+ assert ! (
149+ tasks. take( early, digest) . is_none( ) ,
150+ "task at boundary must be dropped"
151+ ) ;
152+ assert ! (
153+ tasks. take( late, digest) . is_some( ) ,
154+ "task in later epoch must outlive an earlier boundary"
155+ ) ;
156+ }
157+
158+ #[ test]
159+ fn test_retain_after_empty_map_is_noop ( ) {
160+ let tasks = VerificationTasks :: < D > :: new ( ) ;
161+ tasks. retain_after ( & round ( 5 ) ) ;
162+ assert ! ( tasks. take( round( 5 ) , Sha256 :: hash( b"x" ) ) . is_none( ) ) ;
163+ }
164+
165+ #[ test]
166+ fn test_default_matches_new ( ) {
167+ let default = <VerificationTasks < D > as Default >:: default ( ) ;
168+ let digest = Sha256 :: hash ( b"block" ) ;
169+ default. insert ( round ( 1 ) , digest, pending_task ( ) ) ;
170+ assert ! ( default . take( round( 1 ) , digest) . is_some( ) ) ;
171+ }
172+ }
0 commit comments