/* * Copyright 2015 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.samples.apps.iosched.session; import android.app.LoaderManager; import android.content.Context; import android.content.CursorLoader; import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.test.suitebuilder.annotation.SmallTest; import com.google.samples.apps.iosched.BuildConfig; import com.google.samples.apps.iosched.archframework.Model; import com.google.samples.apps.iosched.model.TagMetadataTest; import com.google.samples.apps.iosched.provider.ScheduleContract; import com.google.samples.apps.iosched.settings.SettingsUtils; import com.google.samples.apps.iosched.testutils.SettingsMockContext; import com.google.samples.apps.iosched.util.LogUtils; import com.google.samples.apps.iosched.util.SessionsHelper; import com.google.samples.apps.iosched.util.TimeUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsSame.sameInstance; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(PowerMockRunner.class) @PrepareForTest({SettingsUtils.class, TimeUtils.class}) @SmallTest public class SessionDetailModelTest { private static final String FAKE_ID = "FAKE ID"; private static final String FAKE_TITLE = "FAKE TITLE"; private static final String FAKE_ROOM_ID = "FAKE ROOM ID"; private static final String FAKE_HASHTAG = "FAKE HASHTAG"; private static final String FAKE_SPEAKER_NAME = "FAKE SPEAKER NAME"; private static final String FAKE_SPEAKER_IMAGE_URL = "FAKE SPEAKER IMAGE URL"; private static final String FAKE_SPEAKER_COMPANY = "FAKE SPEAKER COMPANY"; private static final String FAKE_SPEAKER_URL = "FAKE SPEAKER URL"; private static final String FAKE_SPEAKER_ABSTRACT = "FAKE SPEAKER ABSTRACT"; private static final int FAKE_COLOR = 200; private static final long FAKE_CURRENT_TIME_OFFSET = 0l; private static final int SESSION_TITLE_COLUMN_INDEX = 1; private static final int SESSION_COLOR_COLUMN_INDEX = 2; private static final int SESSION_START_COLUMN_INDEX = 3; private static final int SESSION_END_COLUMN_INDEX = 4; private static final int SESSION_IN_MY_SCHEDULE_COLUMN_INDEX = 5; private static final int SESSION_ROOM_ID_COLUMN_INDEX = 6; private static final int SESSION_HASHTAG_COLUMN_INDEX = 7; private static final int SPEAKER_NAME_COLUMN_INDEX = 8; private static final int SPEAKER_IMAGE_URL_COLUMN_INDEX = 9; private static final int SPEAKER_COMPANY_COLUMN_INDEX = 10; private static final int SPEAKER_URL_COLUMN_INDEX = 11; private static final int SPEAKER_PLUSONE_URL_COLUMN_INDEX = 12; private static final int SPEAKER_TWITTER_URL_COLUMN_INDEX = 13; private static final int SPEAKER_ABSTRACT_COLUMN_INDEX = 14; private static final long ONE_MINUTE = 1 * 60 * 1000l; private static final long ONE_HOUR = 1 * 60 * 60 * 1000l; @Mock private Context mMockContext; @Mock private SharedPreferences mMockSharedPreferences; @Mock private Uri mMockUri; @Mock private SessionsHelper mMockSessionsHelper; @Mock private Cursor mMockCursor; @Mock private Cursor mMockEmptyCursor; @Mock private CursorLoader mMockCursorLoader; @Mock private LoaderManager mMockLoaderManager; @Mock private Model.UserActionCallback mMockUserActionCallback; private SessionDetailModel mSessionDetailModel; @Before public void setUp() { // Init mocks initMockCursors(); initMockContextWithFakeCurrentTime(); LogUtils.LOGGING_ENABLED = false; // Create an instance of the model. mSessionDetailModel = new SessionDetailModel(mMockUri, mMockContext, mMockSessionsHelper, mMockLoaderManager); } @Test public void readDataFromCursor_SessionQuery_SessionLoaded() { // Given a mock cursor with a fake session title initMockCursorWithTitle(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When ran with session query boolean success = spyModel.readDataFromCursor( mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then the model has correct session title and true is returned assertThat(spyModel.getSessionTitle(), is(FAKE_TITLE)); assertThat(success, is(true)); } @Test public void readDataFromCursor_TagMetadataQuery_TagMetadataLoaded() { // Given a mock cursor with a fake tag initMockCursorWithOneTag(mMockCursor); // When ran with tag query boolean success = mSessionDetailModel.readDataFromCursor( mMockCursor, SessionDetailModel.SessionDetailQueryEnum.TAG_METADATA); // Then the tag metadata object has been created, and true is returned assertThat(mSessionDetailModel.getTagMetadata(), not(nullValue())); assertThat(success, is(true)); } @Test public void readDataFromCursor_TagMetadataQueryWithNullCursor_ReturnsFalse() { // When ran with tag query and null cursor boolean success = mSessionDetailModel.readDataFromCursor( null, SessionDetailModel.SessionDetailQueryEnum.TAG_METADATA); // Then false is returned assertThat(success, is(false)); } @Test public void readDataFromCursor_SpeakersQueryWithOneSpeaker_SpeakerLoaded() { // Given a mock cursor with a fake speaker initMockCursorWithOneSpeaker(mMockCursor); // When ran with speakers query boolean success = mSessionDetailModel.readDataFromCursor( mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SPEAKERS); // Then the model has correct speakers size, and data, and true is returned assertThat(mSessionDetailModel.getSpeakers().size(), is(1)); assertThat(mSessionDetailModel.getSpeakers().get(0).getName(), is(FAKE_SPEAKER_NAME)); assertThat(mSessionDetailModel.getSpeakers().get(0).getImageUrl(), is(FAKE_SPEAKER_IMAGE_URL)); assertThat(mSessionDetailModel.getSpeakers().get(0).getCompany(), is(FAKE_SPEAKER_COMPANY)); assertThat(mSessionDetailModel.getSpeakers().get(0).getUrl(), is(FAKE_SPEAKER_URL)); assertThat(mSessionDetailModel.getSpeakers().get(0).getAbstract(), is(FAKE_SPEAKER_ABSTRACT)); assertThat(success, is(true)); } @Test public void readDataFromCursor_SpeakersQueryWithTwoSpeakers_SpeakersLoaded() { // Given a mock cursor with 2 fake speakers initMockCursorWithTwoSpeakers(mMockCursor); // When ran with speakers query boolean success = mSessionDetailModel.readDataFromCursor( mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SPEAKERS); // Then the model has correct speakers size, and data, and true is returned assertThat(mSessionDetailModel.getSpeakers().size(), is(2)); assertThat(mSessionDetailModel.getSpeakers().get(0).getName(), is(FAKE_SPEAKER_NAME)); assertThat(mSessionDetailModel.getSpeakers().get(0).getImageUrl(), is(FAKE_SPEAKER_IMAGE_URL)); assertThat(mSessionDetailModel.getSpeakers().get(0).getCompany(), is(FAKE_SPEAKER_COMPANY)); assertThat(mSessionDetailModel.getSpeakers().get(0).getUrl(), is(FAKE_SPEAKER_URL)); assertThat(mSessionDetailModel.getSpeakers().get(0).getAbstract(), is(FAKE_SPEAKER_ABSTRACT)); assertThat(mSessionDetailModel.getSpeakers().get(1).getName(), is(FAKE_SPEAKER_NAME)); assertThat(mSessionDetailModel.getSpeakers().get(1).getImageUrl(), is(FAKE_SPEAKER_IMAGE_URL)); assertThat(mSessionDetailModel.getSpeakers().get(1).getCompany(), is(FAKE_SPEAKER_COMPANY)); assertThat(mSessionDetailModel.getSpeakers().get(1).getUrl(), is(FAKE_SPEAKER_URL)); assertThat(mSessionDetailModel.getSpeakers().get(1).getAbstract(), is(FAKE_SPEAKER_ABSTRACT)); assertThat(success, is(true)); } @Test public void readDataFromCursor_FeedbackQueryWithFeedbackAvailable_SessionHasFeedback() { // Given a mock cursor with data when(mMockCursor.getCount()).thenReturn(1); // When ran with feedback query boolean success = mSessionDetailModel.readDataFromCursor( mMockCursor, SessionDetailModel.SessionDetailQueryEnum.FEEDBACK); // Then the session has feedback and true is returned assertThat(mSessionDetailModel.hasFeedback(), is(true)); assertThat(success, is(true)); } @Test public void readDataFromCursor_FeedbackQueryWithNoFeedbackAvailable_SessionHasNoFeedback() { // Given a mock cursor with no data when(mMockCursor.getCount()).thenReturn(0); // When ran with feedback query boolean success = mSessionDetailModel.readDataFromCursor( mMockCursor, SessionDetailModel.SessionDetailQueryEnum.FEEDBACK); // Then the session has no feedback and true is returned assertThat(mSessionDetailModel.hasFeedback(), is(false)); assertThat(success, is(true)); } @Test public void readDataFromCursor_ValidQueryWithNullCursor_ReturnsFalse() { // When ran with session query and null cursor boolean success = mSessionDetailModel.readDataFromCursor( null, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then false is returned assertThat(success, is(false)); } @Test public void readDataFromCursor_ValidQueryWithEmptyCursor_ReturnsFalse() { // When ran with session query and empty cursor boolean success = mSessionDetailModel.readDataFromCursor( mMockEmptyCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then false is returned assertThat(success, is(false)); } @Test public void readDataFromCursor_InvalidQuery_ReturnsFalse() { // When ran with invalid query and non empty cursor boolean success = mSessionDetailModel.readDataFromCursor( mMockCursor, null); // Then false is returned assertThat(success, is(false)); } @Test public void createCursorLoader_SessionQuery_ReturnsCursorLoader() { // Given a mock uri and mock cursor loader SessionDetailModel spyModel = spy( new SessionDetailModel(mMockUri, mMockContext, mMockSessionsHelper, mMockLoaderManager)); doReturn(FAKE_ID).when(spyModel).getSessionId(mMockUri); doReturn(mMockCursorLoader).when(spyModel).getCursorLoaderInstance( any(Context.class), any(Uri.class), any(String[].class), any(String.class), any(String[].class), any(String.class)); // When ran with mock uri and session query loader id CursorLoader createdCursorLoader = (CursorLoader) spyModel.createCursorLoader( SessionDetailModel.SessionDetailQueryEnum.SESSIONS, null); // Then the returned cursor loader is the mock cursor loader assertThat(createdCursorLoader, sameInstance(mMockCursorLoader)); } @Test public void createCursorLoader_TagMetadaQuery_ReturnsCursorLoader() { // Given a mock uri and mock cursor loader SessionDetailModel spyModel = spy( new SessionDetailModel(mMockUri, mMockContext, mMockSessionsHelper, mMockLoaderManager)); doReturn(mMockCursorLoader).when(spyModel).getTagMetadataLoader(); // When ran with mock uri and tag metadata query loader id CursorLoader createdCursorLoader = (CursorLoader) spyModel.createCursorLoader( SessionDetailModel.SessionDetailQueryEnum.TAG_METADATA, null); // Then the returned cursor loader is the mock cursor loader assertThat(createdCursorLoader, sameInstance(mMockCursorLoader)); } @Test public void createCursorLoader_SpeakersQuery_ReturnsCursor() { // Given a mock uri and mock cursor loader SessionDetailModel spyModel = spy( new SessionDetailModel(mMockUri, mMockContext, mMockSessionsHelper, mMockLoaderManager)); doReturn(mMockUri).when(spyModel).getSpeakersDirUri(any(String.class)); doReturn(mMockCursorLoader).when(spyModel).getCursorLoaderInstance( any(Context.class), any(Uri.class), any(String[].class), any(String.class), any(String[].class), any(String.class)); // When ran with mock uri and speakers query loader id CursorLoader createdCursorLoader = (CursorLoader) spyModel.createCursorLoader( SessionDetailModel.SessionDetailQueryEnum.SPEAKERS, null); // Then the returned cursor loader is the mock cursor loader assertThat(createdCursorLoader, sameInstance(mMockCursorLoader)); } @Test public void createCursorLoader_FeedbackQuery_ReturnsCursor() { // Given a mock uri and mock cursor loader SessionDetailModel spyModel = spy( new SessionDetailModel(mMockUri, mMockContext, mMockSessionsHelper, mMockLoaderManager)); doReturn(mMockUri).when(spyModel).getFeedbackUri(any(String.class)); doReturn(mMockCursorLoader).when(spyModel).getCursorLoaderInstance( any(Context.class), any(Uri.class), any(String[].class), any(String.class), any(String[].class), any(String.class)); // When ran with mock uri and feedback query loader id CursorLoader createdCursorLoader = (CursorLoader) spyModel.createCursorLoader( SessionDetailModel.SessionDetailQueryEnum.FEEDBACK, null); // Then the returned cursor loader is the mock cursor loader assertThat(createdCursorLoader, sameInstance(mMockCursorLoader)); } @Test public void createCursorLoader_NullQuery_ReturnsNullCursor() { // When ran with mock uri and null query loader id CursorLoader createdCursorLoader = (CursorLoader) mSessionDetailModel.createCursorLoader(null, null); // Then the returned cursor loader is null assertThat(createdCursorLoader, nullValue()); } @Test public void deliverUserAction_StarSession_Success() { // Given a loaded session not in user schedule initMockCursorWithSessionNotInSchedule(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); doNothing().when(spyModel).sendAnalyticsEvent( any(String.class), any(String.class), any(String.class)); // When ran with star user action spyModel.deliverUserAction(SessionDetailModel.SessionDetailUserActionEnum.STAR, null, mMockUserActionCallback); // Then verify the callback was called successfully verify(mMockUserActionCallback).onModelUpdated(spyModel, SessionDetailModel.SessionDetailUserActionEnum.STAR); // And the session is in user schedule and set session starred is called with true verify(mMockSessionsHelper) .setSessionStarred(eq(mMockUri), eq(true), anyString()); assertThat(spyModel.isInSchedule(), is(true)); } @Test public void deliverUserAction_UnstarSession_Success() { // Given a loaded session in user schedule initMockCursorWithSessionInSchedule(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); doNothing().when(spyModel).sendAnalyticsEvent( any(String.class), any(String.class), any(String.class)); // When ran with unstar user action spyModel.deliverUserAction(SessionDetailModel.SessionDetailUserActionEnum.UNSTAR, null, mMockUserActionCallback); // Then verify the callback was called successfully verify(mMockUserActionCallback).onModelUpdated(spyModel, SessionDetailModel.SessionDetailUserActionEnum.UNSTAR); // And the session is not in user schedule and set session starred is called with false verify(mMockSessionsHelper) .setSessionStarred(eq(mMockUri), eq(false), anyString()); assertThat(spyModel.isInSchedule(), is(false)); } @Test public void deliverUserAction_ShowMap_Success() { // Given a loaded session with a fake room id initMockCursorWithRoomId(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); doNothing().when(spyModel).sendAnalyticsEvent( any(String.class), any(String.class), any(String.class)); // When ran with show map user action spyModel.deliverUserAction(SessionDetailModel.SessionDetailUserActionEnum.SHOW_MAP, null, mMockUserActionCallback); // Then verify the callback was called successfully verify(mMockUserActionCallback).onModelUpdated(spyModel, SessionDetailModel.SessionDetailUserActionEnum.SHOW_MAP); } @Test public void deliverUserAction_ShowShare_Success() { // Given a loaded session with a fake title initMockCursorWithTitle(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // When ran with show share user action spyModel.deliverUserAction(SessionDetailModel.SessionDetailUserActionEnum.SHOW_SHARE, null, mMockUserActionCallback); // Then verify the callback was called successfully verify(mMockUserActionCallback).onModelUpdated(spyModel, SessionDetailModel.SessionDetailUserActionEnum.SHOW_SHARE); } @Test public void isSessionOngoing_OngoingSession_ReturnsTrue() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress initMockCursorWithOngoingSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.isSessionOngoing(), is(true)); } } @Test public void isSessionOngoing_SessionNotStarted_ReturnsFalse() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in future initMockCursorWithNotStartedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is not ongoing assertThat(spyModel.isSessionOngoing(), is(false)); } } @Test public void isSessionOngoing_SessionEnded_ReturnsFalse() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session that has ended initMockCursorWithEndedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is not ongoing assertThat(spyModel.isSessionOngoing(), is(false)); } } @Test public void hasSessionStarted_OnGoingSession_ReturnsTrue() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress initMockCursorWithOngoingSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session has started assertThat(spyModel.hasSessionStarted(), is(true)); } } @Test public void hasSessionStarted_SessionNotStarted_ReturnsFalse() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in future initMockCursorWithNotStartedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session has not started assertThat(spyModel.hasSessionStarted(), is(false)); } } @Test public void hasSessionStarted_SessionEnded_ReturnsTrue() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session that has ended initMockCursorWithEndedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session has started assertThat(spyModel.hasSessionStarted(), is(true)); } } @Test public void hasSessionEnded_SessionNotStarted_ReturnsFalse() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress initMockCursorWithNotStartedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session has not ended assertThat(spyModel.hasSessionEnded(), is(false)); } } @Test public void hasSessionEnded_OngoingSession_ReturnsFalse() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress initMockCursorWithOngoingSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session has not ended assertThat(spyModel.hasSessionEnded(), is(false)); } } @Test public void hasSessionEnded_SessionEnded_ReturnsTrue() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session that has ended initMockCursorWithEndedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session has ended assertThat(spyModel.hasSessionEnded(), is(true)); } } @Test public void minutesSinceSessionStarted_SessionNotStarted_ReturnsCorrectMinutes() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session not started initMockCursorWithNotStartedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.minutesSinceSessionStarted(), is(0l)); } } @Test public void minutesSinceSessionStarted_SessionStarted_ReturnsCorrectMinutes() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress that started 1 hour ago initMockCursorWithOngoingSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.minutesSinceSessionStarted(), is(60l)); } } @Test public void minutesUntilSessionStarts_SessionNotStarted_ReturnsCorrectMinutes() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session starting in 1 hour initMockCursorWithNotStartedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.minutesUntilSessionStarts(), is(60l)); } } @Test public void minutesUntilSessionStarts_SessionStarted_ReturnsCorrectMinutes() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress initMockCursorWithOngoingSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.minutesUntilSessionStarts(), is(0l)); } } @Test public void isSessionReadyForFeedback_SessionNotStarted_ReturnsFalse() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session not started initMockCursorWithNotStartedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.isSessionReadyForFeedback(), is(false)); } } @Test public void isSessionReadyForFeedback_OnGoingSessionJustStarted_ReturnsFalse() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress that started 1 minute ago and lasts // 2 hours initMockCursorWithJustStartedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.isSessionReadyForFeedback(), is(false)); } } @Test public void isSessionReadyForFeedback_OnGoingSessionNearEnd_ReturnsTrue() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session in progress that will end within feedback // allowed time initMockCursorWithSessionEndingSoon(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.isSessionReadyForFeedback(), is(true)); } } @Test public void isSessionReadyForFeedback_SessionEnded_ReturnsTrue() { // Only possible to mock current time in debug build if (BuildConfig.DEBUG) { // Given a mock cursor for a session that has ended initMockCursorWithEndedSession(mMockCursor); SessionDetailModel spyModel = setSpyModelForSessionLoading(); // When session is loaded spyModel.readDataFromCursor(mMockCursor, SessionDetailModel.SessionDetailQueryEnum.SESSIONS); // Then session is ongoing assertThat(spyModel.isSessionReadyForFeedback(), is(true)); } } private SessionDetailModel setSpyModelForSessionLoading() { SessionDetailModel spyModel = spy( new SessionDetailModel(mMockUri, mMockContext, mMockSessionsHelper, mMockLoaderManager)); doNothing().when(spyModel).formatSubtitle(); return spyModel; } private void initMockCursors() { // Set non empty cursor. when(mMockCursor.moveToFirst()).thenReturn(true); // Set session color to avoid call to mock context resources. when(mMockCursor.getColumnIndex(ScheduleContract.Sessions.SESSION_COLOR)) .thenReturn(SESSION_COLOR_COLUMN_INDEX); when(mMockCursor.getInt(SESSION_COLOR_COLUMN_INDEX)).thenReturn(FAKE_COLOR); // Set empty cursor. when(mMockEmptyCursor.moveToFirst()).thenReturn(false); } private void initMockContextWithFakeCurrentTime() { SettingsMockContext.initMockContextForCurrentTime(FAKE_CURRENT_TIME_OFFSET, mMockContext); } private void initMockCursorWithTitle(Cursor cursor) { when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_TITLE)) .thenReturn(SESSION_TITLE_COLUMN_INDEX); when(cursor.getString(SESSION_TITLE_COLUMN_INDEX)).thenReturn(FAKE_TITLE); } private void initMockCursorWithSessionNotInSchedule(Cursor cursor) { when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_IN_MY_SCHEDULE)) .thenReturn(SESSION_IN_MY_SCHEDULE_COLUMN_INDEX); when(cursor.getInt(SESSION_IN_MY_SCHEDULE_COLUMN_INDEX)).thenReturn(0); } private void initMockCursorWithSessionInSchedule(Cursor cursor) { when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_IN_MY_SCHEDULE)) .thenReturn(SESSION_IN_MY_SCHEDULE_COLUMN_INDEX); when(cursor.getInt(SESSION_IN_MY_SCHEDULE_COLUMN_INDEX)).thenReturn(1); } private void initMockCursorWithRoomId(Cursor cursor) { when(cursor.getColumnIndex(ScheduleContract.Sessions.ROOM_ID)) .thenReturn(SESSION_ROOM_ID_COLUMN_INDEX); when(cursor.getString(SESSION_ROOM_ID_COLUMN_INDEX)).thenReturn(FAKE_ROOM_ID); } private void initMockCursorWithHashTag(Cursor cursor) { when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_HASHTAG)) .thenReturn(SESSION_HASHTAG_COLUMN_INDEX); when(cursor.getString(SESSION_HASHTAG_COLUMN_INDEX)).thenReturn(FAKE_HASHTAG); } private void initMockCursorWithNotStartedSession(Cursor cursor) { // Return a fake start time in future when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_START)) .thenReturn(SESSION_START_COLUMN_INDEX); when(cursor.getLong(SESSION_START_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET + ONE_HOUR); // Return a fake end time in future when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_END)) .thenReturn(SESSION_END_COLUMN_INDEX); when(cursor.getLong(SESSION_END_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET + 2 * ONE_HOUR); } private void initMockCursorWithJustStartedSession(Cursor cursor) { // Return a fake start time 1 minute ago when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_START)) .thenReturn(SESSION_START_COLUMN_INDEX); when(cursor.getLong(SESSION_START_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET - ONE_MINUTE); // Return a fake end time in future when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_END)) .thenReturn(SESSION_END_COLUMN_INDEX); when(cursor.getLong(SESSION_END_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET + 2 * ONE_HOUR); } private void initMockCursorWithSessionEndingSoon(Cursor cursor) { // Return a fake start time in past when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_START)) .thenReturn(SESSION_START_COLUMN_INDEX); when(cursor.getLong(SESSION_START_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET - ONE_HOUR); // Return a fake end time within feedback before session allowed time when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_END)) .thenReturn(SESSION_END_COLUMN_INDEX); when(cursor.getLong(SESSION_END_COLUMN_INDEX)).thenReturn(FAKE_CURRENT_TIME_OFFSET + SessionDetailConstants.FEEDBACK_MILLIS_BEFORE_SESSION_END_MS - ONE_MINUTE); } private void initMockCursorWithOngoingSession(Cursor cursor) { // Return a fake start time in past when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_START)) .thenReturn(SESSION_START_COLUMN_INDEX); when(cursor.getLong(SESSION_START_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET - ONE_HOUR); // Return a fake end time in future when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_END)) .thenReturn(SESSION_END_COLUMN_INDEX); when(cursor.getLong(SESSION_END_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET + ONE_HOUR); } private void initMockCursorWithEndedSession(Cursor cursor) { // Return a fake start time in past when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_START)) .thenReturn(SESSION_START_COLUMN_INDEX); when(cursor.getLong(SESSION_START_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET - 2 * ONE_HOUR); // Return a fake end time in past when(cursor.getColumnIndex(ScheduleContract.Sessions.SESSION_END)) .thenReturn(SESSION_END_COLUMN_INDEX); when(cursor.getLong(SESSION_END_COLUMN_INDEX)) .thenReturn(FAKE_CURRENT_TIME_OFFSET - ONE_HOUR); } private void initMockCursorWithOneSpeaker(Cursor cursor) { // Return a count of 1 when(cursor.getCount()).thenReturn(1); when(cursor.moveToPosition(0)).thenReturn(true); // Return fake speaker details when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_NAME)) .thenReturn(SPEAKER_NAME_COLUMN_INDEX); when(cursor.getString(SPEAKER_NAME_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_NAME); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_IMAGE_URL)) .thenReturn(SPEAKER_IMAGE_URL_COLUMN_INDEX); when(cursor.getString(SPEAKER_IMAGE_URL_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_IMAGE_URL); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_COMPANY)) .thenReturn(SPEAKER_COMPANY_COLUMN_INDEX); when(cursor.getString(SPEAKER_COMPANY_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_COMPANY); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_URL)) .thenReturn(SPEAKER_URL_COLUMN_INDEX); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_PLUSONE_URL)) .thenReturn(SPEAKER_PLUSONE_URL_COLUMN_INDEX); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_TWITTER_URL)) .thenReturn(SPEAKER_TWITTER_URL_COLUMN_INDEX); when(cursor.getString(SPEAKER_URL_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_URL); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_ABSTRACT)) .thenReturn(SPEAKER_ABSTRACT_COLUMN_INDEX); when(cursor.getString(SPEAKER_ABSTRACT_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_ABSTRACT); } private void initMockCursorWithTwoSpeakers(Cursor cursor) { // Return a count of 2 when(cursor.getCount()).thenReturn(2); when(cursor.moveToPosition(0)).thenReturn(true); when(cursor.moveToPosition(1)).thenReturn(true); // Return fake speaker details when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_NAME)) .thenReturn(SPEAKER_NAME_COLUMN_INDEX); when(cursor.getString(SPEAKER_NAME_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_NAME); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_IMAGE_URL)) .thenReturn(SPEAKER_IMAGE_URL_COLUMN_INDEX); when(cursor.getString(SPEAKER_IMAGE_URL_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_IMAGE_URL); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_COMPANY)) .thenReturn(SPEAKER_COMPANY_COLUMN_INDEX); when(cursor.getString(SPEAKER_COMPANY_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_COMPANY); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_URL)) .thenReturn(SPEAKER_URL_COLUMN_INDEX); when(cursor.getString(SPEAKER_URL_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_URL); when(cursor.getColumnIndex(ScheduleContract.Speakers.SPEAKER_ABSTRACT)) .thenReturn(SPEAKER_ABSTRACT_COLUMN_INDEX); when(cursor.getString(SPEAKER_ABSTRACT_COLUMN_INDEX)).thenReturn(FAKE_SPEAKER_ABSTRACT); } private void initMockCursorWithOneTag(Cursor cursor) { TagMetadataTest.initMockCursorWithOneTag(cursor); } }