package com.quran.labs.androidquran.model.bookmark;
import com.quran.labs.androidquran.dao.RecentPage;
import com.quran.labs.androidquran.data.Constants;
import com.quran.labs.androidquran.database.BookmarksDBAdapter;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.reactivex.Single;
import io.reactivex.android.plugins.RxAndroidPlugins;
import io.reactivex.observers.TestObserver;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.schedulers.TestScheduler;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class RecentPageModelTest {
private static final List<RecentPage> SAMPLE_RECENT_PAGES = new ArrayList<>();
@Mock private BookmarksDBAdapter bookmarksAdapter;
@BeforeClass
public static void setup() {
RxAndroidPlugins.setInitMainThreadSchedulerHandler(schedulerCallable -> Schedulers.io());
// sample recent pages
long timestamp = System.currentTimeMillis();
SAMPLE_RECENT_PAGES.add(new RecentPage(49, timestamp));
SAMPLE_RECENT_PAGES.add(new RecentPage(100, timestamp - 10000));
}
@Before
public void setupTest() {
MockitoAnnotations.initMocks(RecentPageModelTest.this);
}
@Test
public void testEmptyRecentPages() {
when(bookmarksAdapter.getRecentPages()).thenReturn(new ArrayList<>());
RecentPageModel recentPageModel = new RecentPageModel(bookmarksAdapter);
TestObserver<Integer> testObserver = new TestObserver<>();
recentPageModel.getLatestPageObservable()
.firstOrError()
.subscribe(testObserver);
testObserver.awaitTerminalEvent();
testObserver.assertValue(Constants.NO_PAGE);
}
@Test
public void testNormalRecentPages() {
when(bookmarksAdapter.getRecentPages()).thenReturn(SAMPLE_RECENT_PAGES);
RecentPageModel recentPageModel = new RecentPageModel(bookmarksAdapter);
TestObserver<Integer> testObserver = new TestObserver<>();
recentPageModel.getLatestPageObservable()
.firstOrError()
.subscribe(testObserver);
testObserver.awaitTerminalEvent();
testObserver.assertValue(49);
}
@Test
public void testUpdateLatestPage() {
when(bookmarksAdapter.getRecentPages()).thenReturn(SAMPLE_RECENT_PAGES);
RecentPageModel recentPageModel = new RecentPageModel(bookmarksAdapter);
// make sure the mock data is received and onNext happens
TestObserver<Integer> testObserver = new TestObserver<>();
recentPageModel.getLatestPageObservable()
.take(1)
.subscribe(testObserver);
testObserver.awaitTerminalEvent();
// after that, let's resubscribe and update with 2 other pages
testObserver = new TestObserver<>();
recentPageModel.getLatestPageObservable()
.take(3)
.subscribe(testObserver);
recentPageModel.updateLatestPage(51);
recentPageModel.updateLatestPage(23);
testObserver.awaitTerminalEvent();
testObserver.assertValues(49, 51, 23);
}
@Test
public void testUpdateLatestPageWithSlowRecents() {
final TestScheduler testScheduler = new TestScheduler();
RecentPageModel recentPageModel = new RecentPageModel(bookmarksAdapter) {
@Override
Single<List<RecentPage>> getRecentPagesObservable() {
// use an implementation of getRecentPagesObservable that delays the results until
// testScheduler simulates the passing of 5 seconds (the timer time).
return Single.timer(5, TimeUnit.SECONDS, testScheduler)
.map(aLong -> SAMPLE_RECENT_PAGES)
.subscribeOn(Schedulers.trampoline());
}
};
TestObserver<Integer> testObserver = new TestObserver<>();
recentPageModel.getLatestPageObservable()
.take(2)
.subscribe(testObserver);
// write before the mock data from getRecentPagesObservable comes back
recentPageModel.updateLatestPage(51);
// now let's pretend the recent page came back - we expect that this page should be ignored.
testScheduler.advanceTimeBy(5, TimeUnit.SECONDS);
// and that another page afterwards was written
recentPageModel.updateLatestPage(23);
testObserver.awaitTerminalEvent();
testObserver.assertValues(51, 23);
}
@Test
public void testRecentPagesUpdated() {
RecentPageModel recentPageModel = new RecentPageModel(bookmarksAdapter);
TestObserver<Boolean> testObserver = new TestObserver<>();
recentPageModel.getRecentPagesUpdatedObservable()
.firstOrError()
.subscribe(testObserver);
recentPageModel.persistLatestPage(200, 200, 200);
testObserver.awaitTerminalEvent();
verify(bookmarksAdapter, times(1)).addRecentPage(200);
verify(bookmarksAdapter, times(0)).replaceRecentRangeWithPage(anyInt(), anyInt(), anyInt());
}
@Test
public void testRecentPagesUpdatedWithRange() {
RecentPageModel recentPageModel = new RecentPageModel(bookmarksAdapter);
TestObserver<Boolean> testObserver = new TestObserver<>();
recentPageModel.getRecentPagesUpdatedObservable()
.firstOrError()
.subscribe(testObserver);
recentPageModel.persistLatestPage(100, 300, 200);
testObserver.awaitTerminalEvent();
verify(bookmarksAdapter, times(1)).replaceRecentRangeWithPage(100, 300, 200);
}
}