@@ -671,3 +671,100 @@ fn test_execute_recurring_without_window_allows_late_execution() {
671671 client. execute_recurring ( & id) ;
672672 assert ! ( client. is_recurring_active( & id) ) ;
673673}
674+
675+ // ── #737: cancel_recurring_batch tests ───────────────────────────────────────
676+
677+ #[ test]
678+ fn test_cancel_recurring_batch_all_succeed ( ) {
679+ use soroban_sdk:: { testutils:: Address as _, Address } ;
680+ let e = Env :: default ( ) ;
681+ e. mock_all_auths ( ) ;
682+
683+ let contract_id = e. register_contract ( None , crate :: contract:: VeriTixPay ) ;
684+ let client = crate :: contract:: VeriTixPayClient :: new ( & e, & contract_id) ;
685+
686+ let payer = Address :: generate ( & e) ;
687+ let payee = Address :: generate ( & e) ;
688+ let token = e. register_stellar_asset_contract ( Address :: generate ( & e) ) ;
689+ soroban_sdk:: token:: StellarAssetClient :: new ( & e, & token) . mint ( & payer, & 10_000 ) ;
690+
691+ let id1 = client. setup_recurring ( & payer, & payee, & token, & 100 , & 100 , & 5 ) ;
692+ let id2 = client. setup_recurring ( & payer, & payee, & token, & 100 , & 100 , & 5 ) ;
693+ assert ! ( client. is_recurring_active( & id1) ) ;
694+ assert ! ( client. is_recurring_active( & id2) ) ;
695+
696+ client. cancel_recurring_batch ( & payer, & soroban_sdk:: vec![ & e, id1, id2] ) ;
697+ assert ! ( !client. is_recurring_active( & id1) ) ;
698+ assert ! ( !client. is_recurring_active( & id2) ) ;
699+ }
700+
701+ #[ test]
702+ #[ should_panic( expected = "not the payer for recurring" ) ]
703+ fn test_cancel_recurring_batch_one_wrong_payer_reverts_all ( ) {
704+ use soroban_sdk:: { testutils:: Address as _, Address } ;
705+ let e = Env :: default ( ) ;
706+ e. mock_all_auths ( ) ;
707+
708+ let contract_id = e. register_contract ( None , crate :: contract:: VeriTixPay ) ;
709+ let client = crate :: contract:: VeriTixPayClient :: new ( & e, & contract_id) ;
710+
711+ let payer = Address :: generate ( & e) ;
712+ let intruder = Address :: generate ( & e) ;
713+ let payee = Address :: generate ( & e) ;
714+ let token = e. register_stellar_asset_contract ( Address :: generate ( & e) ) ;
715+ soroban_sdk:: token:: StellarAssetClient :: new ( & e, & token) . mint ( & payer, & 10_000 ) ;
716+ soroban_sdk:: token:: StellarAssetClient :: new ( & e, & token) . mint ( & intruder, & 10_000 ) ;
717+
718+ let id1 = client. setup_recurring ( & payer, & payee, & token, & 100 , & 100 , & 5 ) ;
719+ let id2 = client. setup_recurring ( & payer, & payee, & token, & 100 , & 100 , & 5 ) ;
720+
721+ // An intruder trying to cancel a batch containing a payer-owned id fails.
722+ client. cancel_recurring_batch ( & intruder, & soroban_sdk:: vec![ & e, id1, id2] ) ;
723+ }
724+
725+ #[ test]
726+ #[ should_panic( expected = "batch size cannot exceed 20" ) ]
727+ fn test_cancel_recurring_batch_over_limit_panics ( ) {
728+ use soroban_sdk:: { testutils:: Address as _, Address } ;
729+ let e = Env :: default ( ) ;
730+ e. mock_all_auths ( ) ;
731+
732+ let contract_id = e. register_contract ( None , crate :: contract:: VeriTixPay ) ;
733+ let client = crate :: contract:: VeriTixPayClient :: new ( & e, & contract_id) ;
734+
735+ let payer = Address :: generate ( & e) ;
736+ let payee = Address :: generate ( & e) ;
737+ let token = e. register_stellar_asset_contract ( Address :: generate ( & e) ) ;
738+ soroban_sdk:: token:: StellarAssetClient :: new ( & e, & token) . mint ( & payer, & 10_000 ) ;
739+
740+ let mut ids: soroban_sdk:: Vec < u32 > = soroban_sdk:: Vec :: new ( & e) ;
741+ for _ in 0 ..25 {
742+ ids. push_back ( client. setup_recurring ( & payer, & payee, & token, & 100 , & 100 , & 5 ) ) ;
743+ }
744+ client. cancel_recurring_batch ( & payer, & ids) ;
745+ }
746+
747+ #[ test]
748+ fn test_cancel_recurring_batch_removes_all_from_payer_index ( ) {
749+ use soroban_sdk:: { testutils:: Address as _, Address } ;
750+ let e = Env :: default ( ) ;
751+ e. mock_all_auths ( ) ;
752+
753+ let contract_id = e. register_contract ( None , crate :: contract:: VeriTixPay ) ;
754+ let client = crate :: contract:: VeriTixPayClient :: new ( & e, & contract_id) ;
755+
756+ let payer = Address :: generate ( & e) ;
757+ let payee = Address :: generate ( & e) ;
758+ let token = e. register_stellar_asset_contract ( Address :: generate ( & e) ) ;
759+ soroban_sdk:: token:: StellarAssetClient :: new ( & e, & token) . mint ( & payer, & 10_000 ) ;
760+
761+ let id1 = client. setup_recurring ( & payer, & payee, & token, & 100 , & 100 , & 5 ) ;
762+ let id2 = client. setup_recurring ( & payer, & payee, & token, & 100 , & 100 , & 5 ) ;
763+ let list_before = client. get_recurring_by_payer ( & payer) ;
764+ assert_eq ! ( list_before. len( ) , 2 ) ;
765+
766+ client. cancel_recurring_batch ( & payer, & soroban_sdk:: vec![ & e, id1, id2] ) ;
767+ // Every recurring the payer owned is now inactive.
768+ assert ! ( !client. is_recurring_active( & id1) ) ;
769+ assert ! ( !client. is_recurring_active( & id2) ) ;
770+ }
0 commit comments