@@ -411,6 +411,112 @@ test_ff_epoll_wait_ev_eof_write_with_fflags(void **state)
411411 assert_ptr_equal (events [0 ].data .ptr , (void * )(intptr_t )0xDEAD );
412412}
413413
414+ /* ------------------------------------------------------------------------ */
415+ /* Stage-7 Phase-5 (FU-S7-EPOLL-*): branch-coverage boost */
416+ /* ------------------------------------------------------------------------ */
417+
418+ /* TC-S7-EPOLL-01: EPOLL_CTL_ADD with EPOLLOUT-only events leaves the */
419+ /* read kevent in EV_DISABLE state (covers BRDA L89 br=1, the false leg */
420+ /* of `if (event->events & EPOLLIN)`). */
421+ static void
422+ test_ff_epoll_ctl_add_writeonly_only_epollout (void * * state )
423+ {
424+ (void )state ;
425+ int epfd = ff_epoll_create (1 );
426+ struct epoll_event ev ;
427+ memset (& ev , 0 , sizeof (ev ));
428+ ev .events = EPOLLOUT ; /* deliberately NOT EPOLLIN */
429+ ev .data .fd = 7 ;
430+
431+ int rc = ff_epoll_ctl (epfd , EPOLL_CTL_ADD , 7 , & ev );
432+ assert_int_equal (rc , 0 );
433+ assert_int_equal (g_kev_cap .last_nchanges , 2 );
434+ /* read kevent: EV_DISABLE is preserved (EPOLLIN absent) */
435+ assert_true ((g_kev_cap .captured [0 ].flags & EV_DISABLE ) != 0 );
436+ /* write kevent: EV_ENABLE is set (EPOLLOUT present) */
437+ assert_true ((g_kev_cap .captured [1 ].flags & EV_ENABLE ) != 0 );
438+ }
439+
440+ /* TC-S7-EPOLL-02: a synthesized kevent with an unknown filter (e.g. */
441+ /* EVFILT_TIMER) translates to events=0 -- covers BRDA L116 br=1. */
442+ static void
443+ test_ff_epoll_wait_unknown_filter_yields_zero_events (void * * state )
444+ {
445+ (void )state ;
446+ g_synth_kev .ident = 33 ;
447+ g_synth_kev .filter = EVFILT_TIMER ; /* not READ, not WRITE */
448+ g_synth_kev .flags = 0 ;
449+ g_synth_kev .data = 1 ;
450+ g_synth_kev .udata = NULL ;
451+ g_synth_count = 1 ;
452+
453+ struct epoll_event events [1 ];
454+ int n = ff_epoll_wait (42 , events , 1 , 0 );
455+ assert_int_equal (n , 1 );
456+ assert_int_equal (events [0 ].events , 0 ); /* no EPOLL* bits set */
457+ }
458+
459+ /* TC-S7-EPOLL-03: EV_EOF with an unknown filter still yields EPOLLHUP */
460+ /* (without EPOLLERR or EPOLLIN/OUT) -- covers BRDA L133 br=1. */
461+ static void
462+ test_ff_epoll_wait_eof_unknown_filter_only_hup (void * * state )
463+ {
464+ (void )state ;
465+ g_synth_kev .ident = 44 ;
466+ g_synth_kev .filter = EVFILT_TIMER ; /* unknown */
467+ g_synth_kev .flags = EV_EOF ;
468+ g_synth_kev .fflags = 0 ;
469+ g_synth_kev .data = 0 ;
470+ g_synth_kev .udata = NULL ;
471+ g_synth_count = 1 ;
472+
473+ struct epoll_event events [1 ];
474+ int n = ff_epoll_wait (42 , events , 1 , 0 );
475+ assert_int_equal (n , 1 );
476+ /* EPOLLHUP set, EPOLLERR/IN/OUT not set */
477+ assert_true (events [0 ].events & EPOLLHUP );
478+ assert_false (events [0 ].events & EPOLLIN );
479+ assert_false (events [0 ].events & EPOLLOUT );
480+ }
481+
482+ /* TC-S7-EPOLL-04: events!=NULL but maxevents=0 still rejects with -1 */
483+ /* / errno=EINVAL (covers BRDA L152 br=2, the maxevents<1 leg with */
484+ /* events being valid). */
485+ static void
486+ test_ff_epoll_wait_zero_maxevents_returns_einval (void * * state )
487+ {
488+ (void )state ;
489+ struct epoll_event events [1 ];
490+ errno = 0 ;
491+ int n = ff_epoll_wait (42 , events , /*maxevents*/ 0 , 0 );
492+ assert_int_equal (n , -1 );
493+ assert_int_equal (errno , EINVAL );
494+ }
495+
496+ /* TC-S7-EPOLL-05: EVFILT_READ with data=0 and EV_EOF set still produces */
497+ /* EPOLLIN via the EV_EOF branch (covers BRDA L113 br=2 partial leg). */
498+ static void
499+ test_ff_epoll_wait_evfilt_read_eof_data_zero_yields_in_hup (void * * state )
500+ {
501+ (void )state ;
502+ g_synth_kev .ident = 55 ;
503+ g_synth_kev .filter = EVFILT_READ ;
504+ g_synth_kev .flags = EV_EOF ; /* EOF set, data=0 */
505+ g_synth_kev .data = 0 ;
506+ g_synth_kev .fflags = 0 ;
507+ g_synth_kev .udata = NULL ;
508+ g_synth_count = 1 ;
509+
510+ struct epoll_event events [1 ];
511+ int n = ff_epoll_wait (42 , events , 1 , 0 );
512+ assert_int_equal (n , 1 );
513+ /* The L113 branch (data=0 && !EV_EOF) is FALSE (because EV_EOF=1) so */
514+ /* the first block sets nothing; the EV_EOF block then sets EPOLLHUP */
515+ /* and (filter==READ) sets EPOLLIN. */
516+ assert_true (events [0 ].events & EPOLLHUP );
517+ assert_true (events [0 ].events & EPOLLIN );
518+ }
519+
414520/* ------------------------------------------------------------------------ */
415521/* Main runner */
416522/* ------------------------------------------------------------------------ */
@@ -434,6 +540,12 @@ main(void)
434540 cmocka_unit_test_setup_teardown (test_ff_epoll_wait_ev_error_to_epollerr , test_setup , NULL ),
435541 cmocka_unit_test_setup_teardown (test_ff_epoll_wait_ev_eof_read_to_hup_in , test_setup , NULL ),
436542 cmocka_unit_test_setup_teardown (test_ff_epoll_wait_ev_eof_write_with_fflags , test_setup , NULL ),
543+ /* Stage-7 Phase-5 branch-coverage boost (FU-S7-EPOLL-*) */
544+ cmocka_unit_test_setup_teardown (test_ff_epoll_ctl_add_writeonly_only_epollout , test_setup , NULL ),
545+ cmocka_unit_test_setup_teardown (test_ff_epoll_wait_unknown_filter_yields_zero_events , test_setup , NULL ),
546+ cmocka_unit_test_setup_teardown (test_ff_epoll_wait_eof_unknown_filter_only_hup , test_setup , NULL ),
547+ cmocka_unit_test_setup_teardown (test_ff_epoll_wait_zero_maxevents_returns_einval , test_setup , NULL ),
548+ cmocka_unit_test_setup_teardown (test_ff_epoll_wait_evfilt_read_eof_data_zero_yields_in_hup , test_setup , NULL ),
437549 };
438550 return cmocka_run_group_tests (tests , NULL , NULL );
439551}
0 commit comments