1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.deskclock.timer;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.text.format.DateUtils;
22 import android.view.View;
23 import android.widget.Button;
24 import android.widget.ImageView;
25 import android.widget.TextView;
26 
27 import androidx.test.InstrumentationRegistry;
28 import androidx.test.core.app.ApplicationProvider;
29 import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
30 import androidx.test.rule.ActivityTestRule;
31 import androidx.viewpager.widget.PagerAdapter;
32 import androidx.viewpager.widget.ViewPager;
33 
34 import com.android.deskclock.DeskClock;
35 import com.android.deskclock.R;
36 import com.android.deskclock.data.DataModel;
37 import com.android.deskclock.data.Timer;
38 import com.android.deskclock.widget.MockFabContainer;
39 
40 import org.junit.After;
41 import org.junit.BeforeClass;
42 import org.junit.Rule;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.List;
49 import java.util.concurrent.TimeUnit;
50 
51 import static org.junit.Assert.assertEquals;
52 import static org.junit.Assert.assertNotNull;
53 import static org.junit.Assert.assertSame;
54 import static org.junit.Assert.fail;
55 
56 @RunWith(AndroidJUnit4ClassRunner.class)
57 public class TimerFragmentTest {
58 
59     private static int LIGHT;
60     private static int DARK;
61     private static int TOP;
62     private static int BOTTOM;
63 
64     private static final int GONE = 0;
65 
66     private TimerFragment fragment;
67     private View timersView;
68     private View timerSetupView;
69     private ViewPager viewPager;
70     private TimerPagerAdapter adapter;
71 
72     private ImageView fab;
73     private Button leftButton;
74     private Button rightButton;
75 
76     @Rule
77     public ActivityTestRule<DeskClock> rule = new ActivityTestRule<>(DeskClock.class, true);
78 
79     @BeforeClass
staticSetUp()80     public static void staticSetUp() {
81         LIGHT = R.drawable.ic_swipe_circle_light;
82         DARK = R.drawable.ic_swipe_circle_dark;
83         TOP = R.drawable.ic_swipe_circle_top;
84         BOTTOM = R.drawable.ic_swipe_circle_bottom;
85     }
86 
setUpSingleTimer()87     private void setUpSingleTimer() {
88         Runnable addTimerRunnable = () -> {
89             DataModel.getDataModel().addTimer(60000L, null, false);
90         };
91         InstrumentationRegistry.getInstrumentation().runOnMainSync(addTimerRunnable);
92         setUpFragment();
93     }
94 
setUpTwoTimers()95     private void setUpTwoTimers() {
96         Runnable addTimerRunnable = () -> {
97             DataModel.getDataModel().addTimer(60000L, null, false);
98             DataModel.getDataModel().addTimer(90000L, null, false);
99         };
100         InstrumentationRegistry.getInstrumentation().runOnMainSync(addTimerRunnable);
101         setUpFragment();
102     }
103 
setUpFragment()104     private void setUpFragment() {
105         Runnable setUpFragmentRunnable = () -> {
106             ViewPager deskClockPager =
107                     (ViewPager) rule.getActivity().findViewById(R.id.desk_clock_pager);
108             PagerAdapter tabPagerAdapter = (PagerAdapter) deskClockPager.getAdapter();
109             fragment = (TimerFragment) tabPagerAdapter.instantiateItem(deskClockPager, 2);
110             fragment.onStart();
111             fragment.selectTab();
112             final MockFabContainer fabContainer =
113                     new MockFabContainer(fragment, ApplicationProvider.getApplicationContext());
114             fragment.setFabContainer(fabContainer);
115 
116             final View view = fragment.getView();
117             assertNotNull(view);
118 
119             timersView = view.findViewById(R.id.timer_view);
120             timerSetupView = view.findViewById(R.id.timer_setup);
121             viewPager = view.findViewById(R.id.vertical_view_pager);
122             adapter = (TimerPagerAdapter) viewPager.getAdapter();
123 
124             fab = fabContainer.getFab();
125             leftButton = fabContainer.getLeftButton();
126             rightButton = fabContainer.getRightButton();
127         };
128         InstrumentationRegistry.getInstrumentation().runOnMainSync(setUpFragmentRunnable);
129     }
130 
131     @After
tearDown()132     public void tearDown() {
133         clearTimers();
134         fragment = null;
135         fab = null;
136         timerSetupView = null;
137         timersView = null;
138         adapter = null;
139         viewPager = null;
140         leftButton = null;
141         rightButton = null;
142     }
143 
clearTimers()144     private void clearTimers() {
145         Runnable clearTimersRunnable = () -> {
146             final List<Timer> timers = new ArrayList<>(DataModel.getDataModel().getTimers());
147             for (Timer timer : timers) {
148                 DataModel.getDataModel().removeTimer(timer);
149             }
150         };
151         InstrumentationRegistry.getInstrumentation().runOnMainSync(clearTimersRunnable);
152     }
153 
154     @Test
initialStateNoTimers()155     public void initialStateNoTimers() {
156         setUpFragment();
157         assertEquals(View.VISIBLE, timerSetupView.getVisibility());
158         assertEquals(View.GONE, timersView.getVisibility());
159         assertAdapter(0);
160     }
161 
162     @Test
initialStateOneTimer()163     public void initialStateOneTimer() {
164         setUpSingleTimer();
165         assertEquals(View.VISIBLE, timersView.getVisibility());
166         assertEquals(View.GONE, timerSetupView.getVisibility());
167         assertAdapter(1);
168     }
169 
170     @Test
initialStateTwoTimers()171     public void initialStateTwoTimers() {
172         setUpTwoTimers();
173         assertEquals(View.VISIBLE, timersView.getVisibility());
174         assertEquals(View.GONE, timerSetupView.getVisibility());
175         assertAdapter(2);
176     }
177 
178     @Test
timeClick_startsTimer()179     public void timeClick_startsTimer() {
180         setUpSingleTimer();
181 
182         setCurrentItem(0);
183         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(0);
184         final TextView timeText = timerItem.findViewById(R.id.timer_time_text);
185         assertStateEquals(Timer.State.RESET, 0);
186         clickView(timeText);
187         assertStateEquals(Timer.State.RUNNING, 0);
188     }
189 
190     @Test
timeClick_startsSecondTimer()191     public void timeClick_startsSecondTimer() {
192         setUpTwoTimers();
193 
194         setCurrentItem(1);
195         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(1);
196         final TextView timeText = timerItem.findViewById(R.id.timer_time_text);
197         assertStateEquals(Timer.State.RESET, 1);
198         assertStateEquals(Timer.State.RESET, 0);
199         clickView(timeText);
200         assertStateEquals(Timer.State.RUNNING, 1);
201         assertStateEquals(Timer.State.RESET, 0);
202     }
203 
204     @Test
timeClick_pausesTimer()205     public void timeClick_pausesTimer() {
206         setUpSingleTimer();
207 
208         setCurrentItem(0);
209         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(0);
210         final TextView timeText = timerItem.findViewById(R.id.timer_time_text);
211         assertStateEquals(Timer.State.RESET, 0);
212         clickView(timeText);
213         assertStateEquals(Timer.State.RUNNING, 0);
214         clickView(timeText);
215         assertStateEquals(Timer.State.PAUSED, 0);
216     }
217 
218     @Test
timeClick_pausesSecondTimer()219     public void timeClick_pausesSecondTimer() {
220         setUpTwoTimers();
221 
222         setCurrentItem(1);
223         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(1);
224         final TextView timeText = timerItem.findViewById(R.id.timer_time_text);
225         assertStateEquals(Timer.State.RESET, 1);
226         assertStateEquals(Timer.State.RESET, 0);
227         clickView(timeText);
228         assertStateEquals(Timer.State.RUNNING, 1);
229         assertStateEquals(Timer.State.RESET, 0);
230         clickView(timeText);
231         assertStateEquals(Timer.State.PAUSED, 1);
232         assertStateEquals(Timer.State.RESET, 0);
233     }
234 
235     @Test
timeClick_restartsTimer()236     public void timeClick_restartsTimer() {
237         setUpSingleTimer();
238 
239         setCurrentItem(0);
240         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(0);
241         final TextView timeText = timerItem.findViewById(R.id.timer_time_text);
242         assertStateEquals(Timer.State.RESET, 0);
243         clickView(timeText);
244         assertStateEquals(Timer.State.RUNNING, 0);
245         clickView(timeText);
246         assertStateEquals(Timer.State.PAUSED, 0);
247         clickView(timeText);
248         assertStateEquals(Timer.State.RUNNING, 0);
249     }
250 
251     @Test
timeClick_restartsSecondTimer()252     public void timeClick_restartsSecondTimer() {
253         setUpTwoTimers();
254 
255         setCurrentItem(1);
256         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(1);
257         final TextView timeText = timerItem.findViewById(R.id.timer_time_text);
258         assertStateEquals(Timer.State.RESET, 1);
259         assertStateEquals(Timer.State.RESET, 0);
260         clickView(timeText);
261         assertStateEquals(Timer.State.RUNNING, 1);
262         assertStateEquals(Timer.State.RESET, 0);
263         clickView(timeText);
264         assertStateEquals(Timer.State.PAUSED, 1);
265         assertStateEquals(Timer.State.RESET, 0);
266         clickView(timeText);
267         assertStateEquals(Timer.State.RUNNING, 1);
268         assertStateEquals(Timer.State.RESET, 0);
269     }
270 
271     @Test
fabClick_startsTimer()272     public void fabClick_startsTimer() {
273         setUpSingleTimer();
274 
275         assertStateEquals(Timer.State.RESET, 0);
276         clickFab();
277         assertStateEquals(Timer.State.RUNNING, 0);
278     }
279 
280     @Test
fabClick_startsSecondTimer()281     public void fabClick_startsSecondTimer() {
282         setUpTwoTimers();
283 
284         setCurrentItem(1);
285         assertStateEquals(Timer.State.RESET, 1);
286         assertStateEquals(Timer.State.RESET, 0);
287         clickFab();
288         assertStateEquals(Timer.State.RUNNING, 1);
289         assertStateEquals(Timer.State.RESET, 0);
290     }
291 
292     @Test
fabClick_pausesTimer()293     public void fabClick_pausesTimer() {
294         setUpSingleTimer();
295 
296         assertStateEquals(Timer.State.RESET, 0);
297         clickFab();
298         assertStateEquals(Timer.State.RUNNING, 0);
299         clickFab();
300         assertStateEquals(Timer.State.PAUSED, 0);
301     }
302 
303     @Test
fabClick_pausesSecondTimer()304     public void fabClick_pausesSecondTimer() {
305         setUpTwoTimers();
306 
307         setCurrentItem(1);
308         assertStateEquals(Timer.State.RESET, 1);
309         assertStateEquals(Timer.State.RESET, 0);
310         clickFab();
311         assertStateEquals(Timer.State.RUNNING, 1);
312         assertStateEquals(Timer.State.RESET, 0);
313         clickFab();
314         assertStateEquals(Timer.State.PAUSED, 1);
315         assertStateEquals(Timer.State.RESET, 0);
316     }
317 
318     @Test
fabClick_restartsTimer()319     public void fabClick_restartsTimer() {
320         setUpSingleTimer();
321 
322         setCurrentItem(0);
323         assertStateEquals(Timer.State.RESET, 0);
324         clickFab();
325         assertStateEquals(Timer.State.RUNNING, 0);
326         clickFab();
327         assertStateEquals(Timer.State.PAUSED, 0);
328         clickFab();
329         assertStateEquals(Timer.State.RUNNING, 0);
330     }
331 
332     @Test
fabClick_restartsSecondTimer()333     public void fabClick_restartsSecondTimer() {
334         setUpTwoTimers();
335 
336         setCurrentItem(1);
337         assertStateEquals(Timer.State.RESET, 1);
338         assertStateEquals(Timer.State.RESET, 0);
339         clickFab();
340         assertStateEquals(Timer.State.RUNNING, 1);
341         assertStateEquals(Timer.State.RESET, 0);
342         clickFab();
343         assertStateEquals(Timer.State.PAUSED, 1);
344         assertStateEquals(Timer.State.RESET, 0);
345         clickFab();
346         assertStateEquals(Timer.State.RUNNING, 1);
347         assertStateEquals(Timer.State.RESET, 0);
348     }
349 
350     @Test
fabClick_resetsTimer()351     public void fabClick_resetsTimer() {
352         setUpSingleTimer();
353 
354         assertStateEquals(Timer.State.RESET, 0);
355         clickFab();
356         assertStateEquals(Timer.State.RUNNING, 0);
357         final Context context = fab.getContext();
358         Runnable expireTimerRunnable = () -> {
359             DataModel.getDataModel().expireTimer(null, DataModel.getDataModel().getTimers().get(0));
360         };
361         InstrumentationRegistry.getInstrumentation().runOnMainSync(expireTimerRunnable);
362         clickFab();
363         assertStateEquals(Timer.State.RESET, 0);
364     }
365 
366     @Test
fabClick_resetsSecondTimer()367     public void fabClick_resetsSecondTimer() {
368         setUpTwoTimers();
369 
370         setCurrentItem(1);
371         assertStateEquals(Timer.State.RESET, 1);
372         assertStateEquals(Timer.State.RESET, 0);
373         clickFab();
374         assertStateEquals(Timer.State.RUNNING, 1);
375         assertStateEquals(Timer.State.RESET, 0);
376         final Context context = fab.getContext();
377         Runnable expireTimerRunnable = () -> {
378             DataModel.getDataModel().expireTimer(null, DataModel.getDataModel().getTimers().get(1));
379         };
380         InstrumentationRegistry.getInstrumentation().runOnMainSync(expireTimerRunnable);
381         clickFab();
382         assertStateEquals(Timer.State.RESET, 1);
383         assertStateEquals(Timer.State.RESET, 0);
384     }
385 
386     @Test
clickAdd_addsOneMinuteToTimer()387     public void clickAdd_addsOneMinuteToTimer() {
388         setUpSingleTimer();
389 
390         setCurrentItem(0);
391         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(0);
392         final Button addMinute = timerItem.findViewById(R.id.reset_add);
393         assertStateEquals(Timer.State.RESET, 0);
394         clickFab();
395         assertStateEquals(Timer.State.RUNNING, 0);
396         Runnable getTimersRunnable = () -> {
397             long remainingTime1 = DataModel.getDataModel().getTimers().get(0).getRemainingTime();
398             addMinute.performClick();
399             long remainingTime2 = DataModel.getDataModel().getTimers().get(0).getRemainingTime();
400             assertSame(Timer.State.RUNNING, DataModel.getDataModel().getTimers().get(0).getState());
401             long expectedSeconds =
402                     TimeUnit.MILLISECONDS.toSeconds(remainingTime1 + DateUtils.MINUTE_IN_MILLIS);
403             long observedSeconds = TimeUnit.MILLISECONDS.toSeconds(remainingTime2);
404             assertEquals(expectedSeconds, observedSeconds);
405         };
406         InstrumentationRegistry.getInstrumentation().runOnMainSync(getTimersRunnable);
407     }
408 
409     @Test
clickAdd_addsOneMinuteToSecondTimer()410     public void clickAdd_addsOneMinuteToSecondTimer() {
411         setUpTwoTimers();
412 
413         setCurrentItem(1);
414         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(1);
415         final Button addMinute = timerItem.findViewById(R.id.reset_add);
416         assertStateEquals(Timer.State.RESET, 1);
417         assertStateEquals(Timer.State.RESET, 0);
418         clickFab();
419         assertStateEquals(Timer.State.RUNNING, 1);
420         assertStateEquals(Timer.State.RESET, 0);
421         Runnable getTimersRunnable = () -> {
422             long remainingTime1 = DataModel.getDataModel().getTimers().get(1).getRemainingTime();
423             addMinute.performClick();
424             long remainingTime2 = DataModel.getDataModel().getTimers().get(1).getRemainingTime();
425             assertSame(Timer.State.RUNNING, DataModel.getDataModel().getTimers().get(1).getState());
426             assertSame(Timer.State.RESET, DataModel.getDataModel().getTimers().get(0).getState());
427             long expectedSeconds =
428                     TimeUnit.MILLISECONDS.toSeconds(remainingTime1 + DateUtils.MINUTE_IN_MILLIS);
429             long observedSeconds = TimeUnit.MILLISECONDS.toSeconds(remainingTime2);
430             assertEquals(expectedSeconds, observedSeconds);
431         };
432         InstrumentationRegistry.getInstrumentation().runOnMainSync(getTimersRunnable);
433     }
434 
435     @Test
clickReset_resetsTimer()436     public void clickReset_resetsTimer() {
437         setUpSingleTimer();
438 
439         setCurrentItem(0);
440         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(0);
441         final Button reset = timerItem.findViewById(R.id.reset_add);
442         assertStateEquals(Timer.State.RESET, 0);
443         clickFab();
444         assertStateEquals(Timer.State.RUNNING, 0);
445         clickFab();
446         assertStateEquals(Timer.State.PAUSED, 0);
447         clickView(reset);
448         assertStateEquals(Timer.State.RESET, 0);
449     }
450 
451     @Test
clickReset_resetsSecondTimer()452     public void clickReset_resetsSecondTimer() {
453         setUpTwoTimers();
454 
455         setCurrentItem(1);
456         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(1);
457         final Button reset = timerItem.findViewById(R.id.reset_add);
458         assertStateEquals(Timer.State.RESET, 1);
459         assertStateEquals(Timer.State.RESET, 0);
460         clickFab();
461         assertStateEquals(Timer.State.RUNNING, 1);
462         assertStateEquals(Timer.State.RESET, 0);
463         clickFab();
464         assertStateEquals(Timer.State.PAUSED, 1);
465         assertStateEquals(Timer.State.RESET, 0);
466         clickView(reset);
467         assertStateEquals(Timer.State.RESET, 1);
468         assertStateEquals(Timer.State.RESET, 0);
469     }
470 
471     @Test
labelClick_opensLabel()472     public void labelClick_opensLabel() {
473         setUpSingleTimer();
474 
475         setCurrentItem(0);
476         final TimerItem timerItem = (TimerItem) viewPager.getChildAt(0);
477         final TextView label = timerItem.findViewById(R.id.timer_label);
478         assertStateEquals(Timer.State.RESET, 0);
479         clickView(label);
480     }
481 
482     //
483     // 3 Indicators
484     //
485 
486     @Test
verify3Indicators0Pages()487     public void verify3Indicators0Pages() {
488         assertIndicatorsEquals(0, 3, 0, GONE, GONE, GONE);
489     }
490 
491     @Test
verify3Indicators1Page()492     public void verify3Indicators1Page() {
493         assertIndicatorsEquals(0, 3, 1, GONE, GONE, GONE);
494     }
495 
496     @Test
verify3Indicators2Pages()497     public void verify3Indicators2Pages() {
498         assertIndicatorsEquals(0, 3, 2, LIGHT, DARK, GONE);
499         assertIndicatorsEquals(1, 3, 2, DARK, LIGHT, GONE);
500     }
501 
502     @Test
verify3Indicators3Pages()503     public void verify3Indicators3Pages() {
504         assertIndicatorsEquals(0, 3, 3, LIGHT, DARK, DARK);
505         assertIndicatorsEquals(1, 3, 3, DARK, LIGHT, DARK);
506         assertIndicatorsEquals(2, 3, 3, DARK, DARK, LIGHT);
507     }
508 
509     @Test
verify3Indicators4Pages()510     public void verify3Indicators4Pages() {
511         assertIndicatorsEquals(0, 3, 4, LIGHT, DARK, BOTTOM);
512         assertIndicatorsEquals(1, 3, 4, DARK, LIGHT, BOTTOM);
513         assertIndicatorsEquals(2, 3, 4, TOP, LIGHT, DARK);
514         assertIndicatorsEquals(3, 3, 4, TOP, DARK, LIGHT);
515     }
516 
517     @Test
verify3Indicators5Pages()518     public void verify3Indicators5Pages() {
519         assertIndicatorsEquals(0, 3, 5, LIGHT, DARK, BOTTOM);
520         assertIndicatorsEquals(1, 3, 5, DARK, LIGHT, BOTTOM);
521         assertIndicatorsEquals(2, 3, 5, TOP, LIGHT, BOTTOM);
522         assertIndicatorsEquals(3, 3, 5, TOP, LIGHT, DARK);
523         assertIndicatorsEquals(4, 3, 5, TOP, DARK, LIGHT);
524     }
525 
526     @Test
verify3Indicators6Pages()527     public void verify3Indicators6Pages() {
528         assertIndicatorsEquals(0, 3, 6, LIGHT, DARK, BOTTOM);
529         assertIndicatorsEquals(1, 3, 6, DARK, LIGHT, BOTTOM);
530         assertIndicatorsEquals(2, 3, 6, TOP, LIGHT, BOTTOM);
531         assertIndicatorsEquals(3, 3, 6, TOP, LIGHT, BOTTOM);
532         assertIndicatorsEquals(4, 3, 6, TOP, LIGHT, DARK);
533         assertIndicatorsEquals(5, 3, 6, TOP, DARK, LIGHT);
534     }
535 
536     @Test
verify3Indicators7Pages()537     public void verify3Indicators7Pages() {
538         assertIndicatorsEquals(0, 3, 7, LIGHT, DARK, BOTTOM);
539         assertIndicatorsEquals(1, 3, 7, DARK, LIGHT, BOTTOM);
540         assertIndicatorsEquals(2, 3, 7, TOP, LIGHT, BOTTOM);
541         assertIndicatorsEquals(3, 3, 7, TOP, LIGHT, BOTTOM);
542         assertIndicatorsEquals(4, 3, 7, TOP, LIGHT, BOTTOM);
543         assertIndicatorsEquals(5, 3, 7, TOP, LIGHT, DARK);
544         assertIndicatorsEquals(6, 3, 7, TOP, DARK, LIGHT);
545     }
546 
547     //
548     // 4 Indicators
549     //
550 
551     @Test
verify4Indicators0Pages()552     public void verify4Indicators0Pages() {
553         assertIndicatorsEquals(0, 4, 0, GONE, GONE, GONE, GONE);
554     }
555 
556     @Test
verify4Indicators1Page()557     public void verify4Indicators1Page() {
558         assertIndicatorsEquals(0, 4, 1, GONE, GONE, GONE, GONE);
559     }
560 
561     @Test
verify4Indicators2Pages()562     public void verify4Indicators2Pages() {
563         assertIndicatorsEquals(0, 4, 2, LIGHT, DARK, GONE, GONE);
564         assertIndicatorsEquals(1, 4, 2, DARK, LIGHT, GONE, GONE);
565     }
566 
567     @Test
verify4Indicators3Pages()568     public void verify4Indicators3Pages() {
569         assertIndicatorsEquals(0, 4, 3, LIGHT, DARK, DARK, GONE);
570         assertIndicatorsEquals(1, 4, 3, DARK, LIGHT, DARK, GONE);
571         assertIndicatorsEquals(2, 4, 3, DARK, DARK, LIGHT, GONE);
572     }
573 
574     @Test
verify4Indicators4Pages()575     public void verify4Indicators4Pages() {
576         assertIndicatorsEquals(0, 4, 4, LIGHT, DARK, DARK, DARK);
577         assertIndicatorsEquals(1, 4, 4, DARK, LIGHT, DARK, DARK);
578         assertIndicatorsEquals(2, 4, 4, DARK, DARK, LIGHT, DARK);
579         assertIndicatorsEquals(3, 4, 4, DARK, DARK, DARK, LIGHT);
580     }
581 
582     @Test
verify4Indicators5Pages()583     public void verify4Indicators5Pages() {
584         assertIndicatorsEquals(0, 4, 5, LIGHT, DARK, DARK, BOTTOM);
585         assertIndicatorsEquals(1, 4, 5, DARK, LIGHT, DARK, BOTTOM);
586         assertIndicatorsEquals(2, 4, 5, DARK, DARK, LIGHT, BOTTOM);
587         assertIndicatorsEquals(3, 4, 5, TOP, DARK, LIGHT, DARK);
588         assertIndicatorsEquals(4, 4, 5, TOP, DARK, DARK, LIGHT);
589     }
590 
591     @Test
verify4Indicators6Pages()592     public void verify4Indicators6Pages() {
593         assertIndicatorsEquals(0, 4, 6, LIGHT, DARK, DARK, BOTTOM);
594         assertIndicatorsEquals(1, 4, 6, DARK, LIGHT, DARK, BOTTOM);
595         assertIndicatorsEquals(2, 4, 6, DARK, DARK, LIGHT, BOTTOM);
596         assertIndicatorsEquals(3, 4, 6, TOP, DARK, LIGHT, BOTTOM);
597         assertIndicatorsEquals(4, 4, 6, TOP, DARK, LIGHT, DARK);
598         assertIndicatorsEquals(5, 4, 6, TOP, DARK, DARK, LIGHT);
599     }
600 
601     @Test
verify4Indicators7Pages()602     public void verify4Indicators7Pages() {
603         assertIndicatorsEquals(0, 4, 7, LIGHT, DARK, DARK, BOTTOM);
604         assertIndicatorsEquals(1, 4, 7, DARK, LIGHT, DARK, BOTTOM);
605         assertIndicatorsEquals(2, 4, 7, DARK, DARK, LIGHT, BOTTOM);
606         assertIndicatorsEquals(3, 4, 7, TOP, DARK, LIGHT, BOTTOM);
607         assertIndicatorsEquals(4, 4, 7, TOP, DARK, LIGHT, BOTTOM);
608         assertIndicatorsEquals(5, 4, 7, TOP, DARK, LIGHT, DARK);
609         assertIndicatorsEquals(6, 4, 7, TOP, DARK, DARK, LIGHT);
610     }
611 
612     @Test
showTimerSetupView_fromIntent()613     public void showTimerSetupView_fromIntent() {
614         setUpSingleTimer();
615 
616         assertEquals(View.VISIBLE, timersView.getVisibility());
617         assertEquals(View.GONE, timerSetupView.getVisibility());
618 
619         final Intent intent = TimerFragment.createTimerSetupIntent(fragment.getContext());
620         rule.getActivity().onNewIntent(intent);
621         restartFragment();
622 
623         assertEquals(View.GONE, timersView.getVisibility());
624         assertEquals(View.VISIBLE, timerSetupView.getVisibility());
625     }
626 
627     @Test
showTimerSetupView_usesLabel_fromIntent()628     public void showTimerSetupView_usesLabel_fromIntent() {
629         setUpSingleTimer();
630 
631         assertEquals(View.VISIBLE, timersView.getVisibility());
632         assertEquals(View.GONE, timerSetupView.getVisibility());
633 
634         final Intent intent = TimerFragment.createTimerSetupIntent(fragment.getContext());
635         rule.getActivity().onNewIntent(intent);
636         restartFragment();
637 
638         assertEquals(View.GONE, timersView.getVisibility());
639         assertEquals(View.VISIBLE, timerSetupView.getVisibility());
640         clickView(timerSetupView.findViewById(R.id.timer_setup_digit_3));
641 
642         clickFab();
643     }
644 
645     @Test
showTimer_fromIntent()646     public void showTimer_fromIntent() {
647         setUpTwoTimers();
648 
649         assertEquals(View.VISIBLE, timersView.getVisibility());
650         assertEquals(View.GONE, timerSetupView.getVisibility());
651         assertEquals(0, viewPager.getCurrentItem());
652 
653         final Intent intent =
654                 new Intent(ApplicationProvider.getApplicationContext(), TimerService.class)
655                         .setAction(TimerService.ACTION_SHOW_TIMER)
656                         .putExtra(TimerService.EXTRA_TIMER_ID, 0);
657         rule.getActivity().onNewIntent(intent);
658         restartFragment();
659 
660         assertEquals(View.VISIBLE, timersView.getVisibility());
661         assertEquals(View.GONE, timerSetupView.getVisibility());
662         assertEquals(1, viewPager.getCurrentItem());
663     }
664 
assertIndicatorsEquals( int page, int indicatorCount, int pageCount, int... expected)665     private void assertIndicatorsEquals(
666             int page, int indicatorCount, int pageCount, int... expected) {
667         int[] actual = TimerFragment.computePageIndicatorStates(page, indicatorCount, pageCount);
668         if (!Arrays.equals(expected, actual)) {
669             final String expectedString = Arrays.toString(expected);
670             final String actualString = Arrays.toString(actual);
671             fail(String.format("Expected %s, found %s", expectedString, actualString));
672         }
673     }
674 
assertStateEquals(Timer.State expectedState, int index)675     private void assertStateEquals(Timer.State expectedState, int index) {
676         Runnable timerRunnable = () -> {
677             final Timer.State actualState =
678                     DataModel.getDataModel().getTimers().get(index).getState();
679             assertSame(expectedState, actualState);
680         };
681         InstrumentationRegistry.getInstrumentation().runOnMainSync(timerRunnable);
682     }
683 
assertAdapter(int count)684     private void assertAdapter(int count) {
685         Runnable assertRunnable = () -> {
686             assertEquals(count, adapter.getCount());
687         };
688         InstrumentationRegistry.getInstrumentation().runOnMainSync(assertRunnable);
689     }
690 
restartFragment()691     private void restartFragment() {
692         Runnable onStartRunnable = () -> {
693             fragment.onStart();
694         };
695         InstrumentationRegistry.getInstrumentation().runOnMainSync(onStartRunnable);
696     }
697 
setCurrentItem(int position)698     private void setCurrentItem(int position) {
699         Runnable setCurrentItemRunnable = () -> {
700             viewPager.setCurrentItem(position);
701         };
702         InstrumentationRegistry.getInstrumentation().runOnMainSync(setCurrentItemRunnable);
703     }
704 
clickView(View view)705     private void clickView(View view) {
706         Runnable clickRunnable = () -> {
707             view.performClick();
708         };
709         InstrumentationRegistry.getInstrumentation().runOnMainSync(clickRunnable);
710     }
711 
clickFab()712     private void clickFab() {
713         Runnable clickRunnable = () -> {
714             fab.performClick();
715         };
716         InstrumentationRegistry.getInstrumentation().runOnMainSync(clickRunnable);
717     }
718 }
719