@@ -148,18 +148,8 @@ def run_next_break(
148148 was already called.
149149 """
150150 on_update_next_break = mock .Mock ()
151- on_pre_break = mock .Mock (return_value = True )
152- on_start_break = mock .Mock (return_value = True )
153- start_break = mock .Mock ()
154- on_count_down = mock .Mock ()
155- on_stop_break = mock .Mock ()
156151
157152 safe_eyes_core .on_update_next_break += on_update_next_break
158- safe_eyes_core .on_pre_break += on_pre_break
159- safe_eyes_core .on_start_break += on_start_break
160- safe_eyes_core .start_break += start_break
161- safe_eyes_core .on_count_down += on_count_down
162- safe_eyes_core .on_stop_break += on_stop_break
163153
164154 if initial :
165155 safe_eyes_core .start ()
@@ -175,6 +165,36 @@ def run_next_break(
175165 assert on_update_next_break .call_args [0 ][0 ].name == break_name_translated
176166 on_update_next_break .reset_mock ()
177167
168+ self .run_next_break_from_waiting_state (
169+ sequential_threading_handle ,
170+ safe_eyes_core ,
171+ context ,
172+ break_duration ,
173+ break_name_translated ,
174+ )
175+
176+ def run_next_break_from_waiting_state (
177+ self ,
178+ sequential_threading_handle : SafeEyesCoreHandle ,
179+ safe_eyes_core : core .SafeEyesCore ,
180+ context ,
181+ break_duration : int ,
182+ break_name_translated : str ,
183+ ) -> None :
184+ on_pre_break = mock .Mock (return_value = True )
185+ on_start_break = mock .Mock (return_value = True )
186+ start_break = mock .Mock ()
187+ on_count_down = mock .Mock ()
188+ on_stop_break = mock .Mock ()
189+
190+ safe_eyes_core .on_pre_break += on_pre_break
191+ safe_eyes_core .on_start_break += on_start_break
192+ safe_eyes_core .start_break += start_break
193+ safe_eyes_core .on_count_down += on_count_down
194+ safe_eyes_core .on_stop_break += on_stop_break
195+
196+ assert context ["state" ] == model .State .WAITING
197+
178198 # continue after condvar
179199 sequential_threading_handle .next ()
180200 # end of __scheduler_job
@@ -547,3 +567,300 @@ def test_long_duration_is_bigger_than_short_interval(
547567 safe_eyes_core .stop ()
548568
549569 assert context ["state" ] == model .State .STOPPED
570+
571+ def test_idle (
572+ self ,
573+ sequential_threading : SequentialThreadingFixture ,
574+ time_machine : TimeMachineFixture ,
575+ ):
576+ """Test idling for short amount of time."""
577+ context : dict [str , typing .Any ] = {
578+ "session" : {},
579+ }
580+ short_break_duration = 15 # seconds
581+ short_break_interval = 15 # minutes
582+ pre_break_warning_time = 10 # seconds
583+ long_break_duration = 60 # seconds
584+ long_break_interval = 75 # minutes
585+ config = model .Config (
586+ user_config = {
587+ "short_breaks" : [
588+ {"name" : "break 1" },
589+ {"name" : "break 2" },
590+ {"name" : "break 3" },
591+ {"name" : "break 4" },
592+ ],
593+ "long_breaks" : [
594+ {"name" : "long break 1" },
595+ {"name" : "long break 2" },
596+ {"name" : "long break 3" },
597+ ],
598+ "short_break_interval" : short_break_interval ,
599+ "long_break_interval" : long_break_interval ,
600+ "long_break_duration" : long_break_duration ,
601+ "short_break_duration" : short_break_duration ,
602+ "pre_break_warning_time" : pre_break_warning_time ,
603+ "random_order" : False ,
604+ "postpone_duration" : 5 ,
605+ },
606+ system_config = {},
607+ )
608+
609+ self .assert_datetime ("2024-08-25T13:00:00" )
610+
611+ safe_eyes_core = core .SafeEyesCore (context )
612+
613+ sequential_threading_handle = sequential_threading (safe_eyes_core )
614+
615+ safe_eyes_core .initialize (config )
616+
617+ self .run_next_break (
618+ sequential_threading_handle ,
619+ time_machine ,
620+ safe_eyes_core ,
621+ context ,
622+ short_break_duration ,
623+ "translated!: break 1" ,
624+ initial = True ,
625+ )
626+
627+ # Time passed: 15min 25s
628+ # 15min short_break_interval, 10 seconds pre_break_warning_time,
629+ # 15 seconds short_break_duration
630+ self .assert_datetime ("2024-08-25T13:15:25" )
631+
632+ # idle, simulate behaviour of smartpause plugin
633+ idle_seconds = 30
634+ idle_period = datetime .timedelta (seconds = idle_seconds )
635+
636+ safe_eyes_core .stop (is_resting = True )
637+
638+ assert context ["state" ] == model .State .RESTING
639+
640+ time_machine .shift (delta = idle_period )
641+
642+ assert safe_eyes_core .scheduled_next_break_time is not None
643+ next_break = safe_eyes_core .scheduled_next_break_time + idle_period
644+
645+ safe_eyes_core .start (next_break_time = next_break .timestamp ())
646+
647+ self .assert_datetime ("2024-08-25T13:15:55" )
648+
649+ self .run_next_break_from_waiting_state (
650+ sequential_threading_handle ,
651+ safe_eyes_core ,
652+ context ,
653+ short_break_duration ,
654+ "translated!: break 2" ,
655+ )
656+
657+ self .assert_datetime ("2024-08-25T13:31:20" )
658+
659+ self .run_next_break (
660+ sequential_threading_handle ,
661+ time_machine ,
662+ safe_eyes_core ,
663+ context ,
664+ short_break_duration ,
665+ "translated!: break 3" ,
666+ )
667+
668+ self .assert_datetime ("2024-08-25T13:46:45" )
669+
670+ self .run_next_break (
671+ sequential_threading_handle ,
672+ time_machine ,
673+ safe_eyes_core ,
674+ context ,
675+ short_break_duration ,
676+ "translated!: break 4" ,
677+ )
678+
679+ self .assert_datetime ("2024-08-25T14:02:10" )
680+
681+ self .run_next_break (
682+ sequential_threading_handle ,
683+ time_machine ,
684+ safe_eyes_core ,
685+ context ,
686+ long_break_duration ,
687+ "translated!: long break 1" ,
688+ )
689+
690+ # Time passed: 16min 10s
691+ # 15min short_break_interval (from previous, as long_break_interval must be
692+ # multiple)
693+ # 10 seconds pre_break_warning_time, 1 minute long_break_duration
694+ self .assert_datetime ("2024-08-25T14:18:20" )
695+
696+ self .run_next_break (
697+ sequential_threading_handle ,
698+ time_machine ,
699+ safe_eyes_core ,
700+ context ,
701+ short_break_duration ,
702+ "translated!: break 1" ,
703+ )
704+
705+ # Time passed: 15min 25s
706+ # 15min short_break_interval, 10 seconds pre_break_warning_time,
707+ # 15 seconds short_break_duration
708+ self .assert_datetime ("2024-08-25T14:33:45" )
709+
710+ safe_eyes_core .stop ()
711+
712+ assert context ["state" ] == model .State .STOPPED
713+
714+ def test_idle_skip_long (
715+ self ,
716+ sequential_threading : SequentialThreadingFixture ,
717+ time_machine : TimeMachineFixture ,
718+ ):
719+ """Test idling for longer than long break time."""
720+ context : dict [str , typing .Any ] = {
721+ "session" : {},
722+ }
723+ short_break_duration = 15 # seconds
724+ short_break_interval = 15 # minutes
725+ pre_break_warning_time = 10 # seconds
726+ long_break_duration = 60 # seconds
727+ long_break_interval = 75 # minutes
728+ config = model .Config (
729+ user_config = {
730+ "short_breaks" : [
731+ {"name" : "break 1" },
732+ {"name" : "break 2" },
733+ {"name" : "break 3" },
734+ {"name" : "break 4" },
735+ ],
736+ "long_breaks" : [
737+ {"name" : "long break 1" },
738+ {"name" : "long break 2" },
739+ {"name" : "long break 3" },
740+ ],
741+ "short_break_interval" : short_break_interval ,
742+ "long_break_interval" : long_break_interval ,
743+ "long_break_duration" : long_break_duration ,
744+ "short_break_duration" : short_break_duration ,
745+ "pre_break_warning_time" : pre_break_warning_time ,
746+ "random_order" : False ,
747+ "postpone_duration" : 5 ,
748+ },
749+ system_config = {},
750+ )
751+
752+ self .assert_datetime ("2024-08-25T13:00:00" )
753+
754+ safe_eyes_core = core .SafeEyesCore (context )
755+
756+ sequential_threading_handle = sequential_threading (safe_eyes_core )
757+
758+ safe_eyes_core .initialize (config )
759+
760+ self .run_next_break (
761+ sequential_threading_handle ,
762+ time_machine ,
763+ safe_eyes_core ,
764+ context ,
765+ short_break_duration ,
766+ "translated!: break 1" ,
767+ initial = True ,
768+ )
769+
770+ # Time passed: 15min 25s
771+ # 15min short_break_interval, 10 seconds pre_break_warning_time,
772+ # 15 seconds short_break_duration
773+ self .assert_datetime ("2024-08-25T13:15:25" )
774+
775+ # idle, simulate behaviour of smartpause plugin
776+ idle_seconds = 65
777+ idle_period = datetime .timedelta (seconds = idle_seconds )
778+
779+ safe_eyes_core .stop (is_resting = True )
780+
781+ assert context ["state" ] == model .State .RESTING
782+
783+ time_machine .shift (delta = idle_period )
784+
785+ assert safe_eyes_core .scheduled_next_break_time is not None
786+ next_break = safe_eyes_core .scheduled_next_break_time + idle_period
787+
788+ safe_eyes_core .start (next_break_time = next_break .timestamp ())
789+
790+ self .assert_datetime ("2024-08-25T13:16:30" )
791+
792+ self .run_next_break_from_waiting_state (
793+ sequential_threading_handle ,
794+ safe_eyes_core ,
795+ context ,
796+ short_break_duration ,
797+ "translated!: break 2" ,
798+ )
799+
800+ self .assert_datetime ("2024-08-25T13:31:55" )
801+
802+ self .run_next_break (
803+ sequential_threading_handle ,
804+ time_machine ,
805+ safe_eyes_core ,
806+ context ,
807+ short_break_duration ,
808+ "translated!: break 3" ,
809+ )
810+
811+ self .assert_datetime ("2024-08-25T13:47:20" )
812+
813+ self .run_next_break (
814+ sequential_threading_handle ,
815+ time_machine ,
816+ safe_eyes_core ,
817+ context ,
818+ short_break_duration ,
819+ "translated!: break 4" ,
820+ )
821+
822+ self .assert_datetime ("2024-08-25T14:02:45" )
823+
824+ self .run_next_break (
825+ sequential_threading_handle ,
826+ time_machine ,
827+ safe_eyes_core ,
828+ context ,
829+ short_break_duration ,
830+ "translated!: break 1" ,
831+ )
832+
833+ self .assert_datetime ("2024-08-25T14:18:10" )
834+
835+ self .run_next_break (
836+ sequential_threading_handle ,
837+ time_machine ,
838+ safe_eyes_core ,
839+ context ,
840+ long_break_duration ,
841+ "translated!: long break 1" ,
842+ )
843+
844+ # Time passed: 16min 10s
845+ # 15min short_break_interval (from previous, as long_break_interval must be
846+ # multiple)
847+ # 10 seconds pre_break_warning_time, 1 minute long_break_duration
848+ self .assert_datetime ("2024-08-25T14:34:20" )
849+
850+ self .run_next_break (
851+ sequential_threading_handle ,
852+ time_machine ,
853+ safe_eyes_core ,
854+ context ,
855+ short_break_duration ,
856+ "translated!: break 2" ,
857+ )
858+
859+ # Time passed: 15min 25s
860+ # 15min short_break_interval, 10 seconds pre_break_warning_time,
861+ # 15 seconds short_break_duration
862+ self .assert_datetime ("2024-08-25T14:49:45" )
863+
864+ safe_eyes_core .stop ()
865+
866+ assert context ["state" ] == model .State .STOPPED
0 commit comments