package es.jonatantierno.scrumdailytimer;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
import roboguice.RoboGuice;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.MediaPlayer;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import com.google.inject.AbstractModule;
import com.google.inject.util.Modules;
@RunWith(RobolectricTestRunner.class)
@Config(manifest = "../ScrumDailyTimer/AndroidManifest.xml")
public class ChronoFragmentTest {
ChronoFragment out;
ShadowActivity shadowOut;
ScrumTimer mockTimer;
Provider mockPlayerProvider;
MediaPlayer mockHornPlayer;
MediaPlayer mockTickPlayer;
View wholeLayout;
SharedPreferences mockPreferences;
Editor mockEditor;
SlotSeekBarController mockSeekBarController;
TextView mParticipantTextView;
TextView mTapForNextTextView;
TextView mCountDownTextView;
TextView mTotalTimeTextView;
SeekBar mSeekBar;
public class TestModule extends AbstractModule {
@Override
protected void configure() {
mockTimer = Mockito.mock(ScrumTimer.class);
mockHornPlayer = Mockito.mock(MediaPlayer.class);
mockTickPlayer = Mockito.mock(MediaPlayer.class);
mockPlayerProvider = Mockito.mock(Provider.class);
mockSeekBarController = Mockito.mock(SlotSeekBarController.class);
when(mockPlayerProvider.getAlarmPlayer(Mockito.any(Context.class))).thenReturn(mockHornPlayer);
when(mockPlayerProvider.getTickPlayer(Mockito.any(Context.class))).thenReturn(mockTickPlayer);
bind(ScrumTimer.class).toInstance(mockTimer);
bind(Provider.class).toInstance(mockPlayerProvider);
bind(SlotSeekBarController.class).toInstance(mockSeekBarController);
}
}
@Before
public void setUp() throws Exception {
RoboGuice.setBaseApplicationInjector(Robolectric.application, RoboGuice.DEFAULT_STAGE,
Modules.override(RoboGuice.newDefaultRoboModule(Robolectric.application)).with(new TestModule()));
mockEditor = mock(Editor.class);
mockPreferences = Mockito.mock(SharedPreferences.class);
when(mockPreferences.edit()).thenReturn(mockEditor);
when(mockPreferences.getInt(ChronoFragment.TIME_SLOT_LENGTH, -1)).thenReturn(60);
out = new ChronoFragment() {
@Override
SharedPreferences getSharedPreferences() {
return mockPreferences;
}
};
FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).create().start().resume().get();
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(out, null);
fragmentTransaction.commit();
shadowOut = Robolectric.shadowOf(activity);
wholeLayout = out.getView().findViewById(R.id.wholeLayout);
mParticipantTextView = (TextView) out.getView().findViewById(R.id.participantTextView);
mTapForNextTextView = (TextView) out.getView().findViewById(R.id.tapForNextTextView);
mCountDownTextView = (TextView) out.getView().findViewById(R.id.countDownTextView);
mTotalTimeTextView = (TextView) out.getView().findViewById(R.id.totalTimeTextView);
mSeekBar = (SeekBar) out.getView().findViewById(R.id.seekBar1);
}
@Test
public void shouldLoadViews() {
assertNotNull(mTapForNextTextView);
}
@Test
public void onStartShouldStartTimer() {
verify(mockTimer).configure(out);
// Test
verify(mockTimer).startTimer();
assertEquals(out.getString(R.string.tap_for_first_participant), mTapForNextTextView.getText().toString());
}
@Test
public void whenTapAgainShouldStartCountDown() {
// Fixture
// Execute.
// Start timer
// Start first countdown
wholeLayout.performClick();
// Test
assertEquals("Participant:1", mParticipantTextView.getText().toString());
assertEquals(View.VISIBLE, mParticipantTextView.getVisibility());
assertEquals(out.getString(R.string.tap_for_next), mTapForNextTextView.getText().toString());
}
/**
* Tests that timer and countdown are properly displayed
*/
@Test
public void shouldDisplayTime() {
// Execute.
// Start timer
out.setDailyTimer("00:00");
assertEquals("Total meeting time:00:00", mTotalTimeTextView.getText().toString());
// Start first participant 1/5
wholeLayout.performClick();
out.setDailyTimer("01:00");
assertEquals("Total meeting time:01:00", mTotalTimeTextView.getText().toString());
out.setCountDown("12:34");
assertEquals("12:34", mCountDownTextView.getText().toString());
}
/**
* When time is over, go to next participant
*/
@Test
public void whenCountDownOverThenAlarm() {
// Execute.
// Start timer
// Start first participant 1
wholeLayout.performClick();
assertEquals("Participant:1", mParticipantTextView.getText().toString());
out.timeOut();
verify(mockHornPlayer).start();
verify(mockTickPlayer).start();
}
@Test
public void whenResetCountDownThenUndoTimeout() {
// Execute.
when(mockTickPlayer.isPlaying()).thenReturn(true);
// Start timer
// Start first participant
wholeLayout.performClick();
assertEquals("Participant:1", mParticipantTextView.getText().toString());
out.timeOut();
// Start first participant 2
wholeLayout.performClick();
verify(mockTickPlayer).isPlaying();
verify(mockTickPlayer).pause();
assertFalse(0xFFFF0000 == Robolectric.shadowOf(wholeLayout).getBackgroundColor());
}
/**
* Number of participants and time slot length stored in settings.
*/
@Test
public void shouldObtainParametersFromSettings() {
verify(mockPreferences).getInt(ChronoFragment.TIME_SLOT_LENGTH, -1);
verify(mockTimer).setTimeSlotLength(60);
assertEquals(60, mSeekBar.getProgress());
}
/**
* Default value is 60 seconds
*/
@Test
public void whenTimeSlotLengthNotSetThenDefaultValue() {
// Fixture
when(mockPreferences.getInt(ChronoFragment.TIME_SLOT_LENGTH, -1)).thenReturn(-1);
when(mockTimer.getPrettyTime(60)).thenReturn("01:00");
// Execute
out.onResume();
assertEquals(SlotSeekBarController.DEFAULT_VALUE, mSeekBar.getProgress());
assertEquals("01:00", mCountDownTextView.getText());
}
/**
* Hide SeekBar when meeting starts.
*/
@Test
public void whenFirstParticipantThenSeekBarShoulDissapear() {
assertEquals(View.VISIBLE, mSeekBar.getVisibility());
wholeLayout.performClick();
assertEquals(View.GONE, mSeekBar.getVisibility());
}
/**
* when seekbar value changes, update chrono
*/
@Test
public void whenSeekBarValueChangesThenUpdateChrono() {
when(mockTimer.getPrettyTime(40)).thenReturn("00:30");
out.setTime(40);
assertEquals("00:30", mCountDownTextView.getText());
}
/**
* Configure seekbar with controller.
*/
@Test
public void shouldSetSeekbarController() {
verify(mockSeekBarController).configure(mSeekBar, out);
}
/**
* Store value from seekbar in settings
*/
@Test
public void whenPauseThenStoreValueFromSeekBar() {
mSeekBar.setProgress(90);
out.onStop();
verify(mockEditor).putInt(ChronoFragment.TIME_SLOT_LENGTH, 90);
verify(mockEditor).commit();
}
/**
* Store value from seekbar when tap
*/
@Test
public void whenTapThenStoreValueFromSeekBar() {
mSeekBar.setProgress(90);
wholeLayout.performClick();
verify(mockEditor).putInt(ChronoFragment.TIME_SLOT_LENGTH, 90);
verify(mockEditor).commit();
}
/**
* when start, Store value from seekbar in settings. Also, set countdown
*/
@Test
public void whenStartMeetingThenStoreValueFromSeekBarAndSetTimer() {
mSeekBar.setProgress(90);
wholeLayout.performClick();
verify(mockEditor).putInt(ChronoFragment.TIME_SLOT_LENGTH, 90);
verify(mockEditor).commit();
}
/**
* When long click, pause countdown
*/
@Test
public void whenLongClickThenPauseCountDown() {
wholeLayout.performClick();
wholeLayout.performLongClick();
verify(mockTimer).pauseCountDown();
}
/**
* While pressing (pause), don't process taps to increment number of participants.
*/
@Test
public void whenInPauseDoNotGoToNextParticipant() {
wholeLayout.performClick();
wholeLayout.performLongClick();
when(mockTimer.isCountDownPaused()).thenReturn(true);
// This click will be ignored.
wholeLayout.performClick();
assertEquals(1, out.getNumberOfParticipants());
}
/**
* Don't pause if countdown has not started yet.
*/
@Test
public void shouldNotPauseBeforeFirstParticipant() {
wholeLayout.performLongClick();
verify(mockTimer, times(0)).pauseCountDown();
}
/**
* If pause in timeout, then pause tick.
*/
@Test
public void whenPauseInTimeoutThenPauseTickSound() {
// Start first participant 1
wholeLayout.performClick();
out.timeOut();
verify(mockTickPlayer).start();
when(mockTickPlayer.isPlaying()).thenReturn(true);
wholeLayout.performLongClick();
when(mockTimer.isCountDownPaused()).thenReturn(true);
verify(mockTickPlayer).pause();
out.endPause();
verify(mockTickPlayer, times(2)).start();
}
}