package com.quran.labs.androidquran.presenter.bookmark;
import android.support.v4.util.Pair;
import com.quran.labs.androidquran.dao.Tag;
import com.quran.labs.androidquran.model.bookmark.BookmarkModel;
import com.quran.labs.androidquran.ui.fragment.TagBookmarkDialog;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.plugins.RxAndroidPlugins;
import io.reactivex.schedulers.Schedulers;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class TagBookmarkPresenterTest {
@Mock private BookmarkModel bookmarkModel;
@BeforeClass
public static void setup() {
RxAndroidPlugins.setInitMainThreadSchedulerHandler(schedulerCallable -> Schedulers.io());
}
@Before
public void setupTest() {
MockitoAnnotations.initMocks(TagBookmarkPresenterTest.this);
List<Tag> tags = new ArrayList<>();
tags.add(new Tag(1, "Test"));
when(bookmarkModel.tagsObservable()).thenReturn(Observable.empty());
when(bookmarkModel.getTagsObservable()).thenReturn(Single.just(tags));
when(bookmarkModel.getBookmarkTagIds(Matchers.any()))
.thenReturn(Maybe.empty());
}
@Test
public void testTagRefresh() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch secondLatch = new CountDownLatch(2);
TagBookmarkPresenter presenter = spy(new TagBookmarkPresenter(bookmarkModel) {
@Override
void onRefreshedData(Pair<List<Tag>, List<Long>> data) {
super.onRefreshedData(data);
latch.countDown();
secondLatch.countDown();
}
});
presenter.setBookmarksMode(new long[] { 1 });
latch.await();
presenter.setAyahBookmarkMode(6, 76, 137);
secondLatch.await();
// make sure we called refresh twice
verify(presenter, times(2)).refresh();
// but make sure we only queried tags from the database once
verify(bookmarkModel, times(1)).getTagsObservable();
}
@Test
public void testChangeShouldOnlySaveExplicitlyForBookmarkIds() throws InterruptedException {
when(bookmarkModel.updateBookmarkTags(
any(long[].class), Matchers.any(), anyBoolean()))
.thenReturn(Observable.just(true));
CountDownLatch saveLatch = new CountDownLatch(1);
CountDownLatch refreshLatch = new CountDownLatch(1);
TagBookmarkPresenter presenter = spy(new TagBookmarkPresenter(bookmarkModel) {
@Override
void onRefreshedData(Pair<List<Tag>, List<Long>> data) {
super.onRefreshedData(data);
refreshLatch.countDown();
}
@Override
public void saveChanges() {
// override because we aren't testing the save process here, just that save is called
saveLatch.countDown();
}
});
presenter.setBookmarksMode(new long[] { 1 });
refreshLatch.await();
// try to modify a tag - save shouldn't be called
assertThat(presenter.toggleTag(1)).isTrue();
verify(presenter, times(0)).saveChanges();
// explicitly call save
presenter.saveChanges();
saveLatch.countDown();
verify(presenter, times(1)).saveChanges();
}
@Test
public void testChangeShouldSaveImmediatelyForAyahBookmarks() throws InterruptedException {
when(bookmarkModel.updateBookmarkTags(
any(long[].class), Matchers.any(), anyBoolean()))
.thenReturn(Observable.just(true));
when(bookmarkModel.safeAddBookmark(anyInt(), anyInt(), anyInt()))
.thenReturn(Observable.just(2L));
// when refresh is done
CountDownLatch refreshLatch = new CountDownLatch(1);
// save latches
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch secondLatch = new CountDownLatch(2);
TagBookmarkPresenter presenter = spy(new TagBookmarkPresenter(bookmarkModel) {
@Override
void onRefreshedData(Pair<List<Tag>, List<Long>> data) {
super.onRefreshedData(data);
refreshLatch.countDown();
}
@Override
void onSaveChangesDone() {
super.onSaveChangesDone();
latch.countDown();
secondLatch.countDown();
}
});
presenter.setAyahBookmarkMode(6, 76, 137);
// make sure refresh is done first
refreshLatch.await();
// switch tag and wait for the save
assertThat(presenter.toggleTag(1)).isTrue();
latch.await();
verify(presenter, times(1)).saveChanges();
// try to save again (should do nothing)
presenter.saveChanges();
secondLatch.await();
verify(bookmarkModel, times(1))
.updateBookmarkTags(any(long[].class), Matchers.any(), anyBoolean());
}
@Test
public void testAddDialogCall() {
TagBookmarkDialog bookmarkDialog = mock(TagBookmarkDialog.class);
TagBookmarkPresenter presenter = spy(new TagBookmarkPresenter(bookmarkModel));
presenter.bind(bookmarkDialog);
assertThat(presenter.toggleTag(-1)).isFalse();
verify(bookmarkDialog, times(1)).showAddTagDialog();
presenter.unbind(bookmarkDialog);
}
@Test
public void testAddDialogCallUnbound() {
TagBookmarkPresenter presenter = spy(new TagBookmarkPresenter(bookmarkModel));
assertThat(presenter.toggleTag(-1)).isFalse();
verify(presenter, times(0)).setMadeChanges();
}
}