diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 3fdb1f2b9..5cfc96c3c 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -129,7 +129,7 @@ dependencies { testCompile "org.robolectric:robolectric:3.3.2" testCompile 'org.robolectric:shadows-multidex:3.3.2' testCompile "org.robolectric:shadows-support-v4:3.3.2" - testCompile "org.mockito:mockito-core:1.10.19" + testCompile "org.mockito:mockito-core:2.8.9" //Leak Detection debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java index fe8564b66..d2dd5a935 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java @@ -70,7 +70,7 @@ public class UserRepositoryImpl extends BaseRepositoryImpl Calendar calendar = new GregorianCalendar(); TimeZone timeZone = calendar.getTimeZone(); long offset = -TimeUnit.MINUTES.convert(timeZone.getOffset(calendar.getTimeInMillis()), TimeUnit.MILLISECONDS); - if (offset != user.getPreferences().getTimezoneOffset()) { + if (user != null && user.getPreferences() != null && offset != user.getPreferences().getTimezoneOffset()) { return updateUser(user, "preferences.timezoneOffset", String.valueOf(offset)); } else { return Observable.just(user); @@ -104,9 +104,7 @@ public class UserRepositoryImpl extends BaseRepositoryImpl public Observable sleep(User user) { return apiClient.sleep() .map(isSleeping -> { - localRepository.executeTransaction(realm -> { - user.getPreferences().setSleep(isSleeping); - }); + localRepository.executeTransaction(realm -> user.getPreferences().setSleep(isSleeping)); return user; }); } @@ -140,10 +138,10 @@ public class UserRepositoryImpl extends BaseRepositoryImpl return response; }) .doOnNext(skillResponse -> { - if (user != null) { - mergeUser(user, skillResponse.user); - } - }); + if (user != null) { + mergeUser(user, skillResponse.user); + } + }); } @Override @@ -158,7 +156,7 @@ public class UserRepositoryImpl extends BaseRepositoryImpl @Override public Observable changeClass(String selectedClass) { - return changeClass(selectedClass); + return apiClient.changeClass(selectedClass); } @Override @@ -196,7 +194,7 @@ public class UserRepositoryImpl extends BaseRepositoryImpl } private User mergeUser(User oldUser, User newUser) { - if (oldUser.isValid()) { + if (!oldUser.isValid()) { return oldUser; } User copiedUser = localRepository.getUnmanagedCopy(oldUser); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java index 0a9d96ddd..0a9f259d6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.java @@ -81,8 +81,12 @@ public class Stats extends RealmObject { this.str = stats.str != null ? stats.str : this.str; this.per = stats.per != null ? stats.per : this.per; this._int = stats._int != null ? stats._int : this._int; - this.training.merge(stats.training); - this.buffs.merge(stats.buffs); + if (training != null) { + this.training.merge(stats.training); + } + if (buffs != null) { + this.buffs.merge(stats.buffs); + } this.points = stats.points != null ? stats.points : this.points; this.lvl = stats.lvl != null ? stats.lvl : this.lvl; this.habitClass = stats.habitClass != null ? stats.habitClass : this.habitClass; diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/BaseTestCase.java b/Habitica/src/test/java/com/habitrpg/android/habitica/BaseTestCase.java new file mode 100644 index 000000000..d68b2ab8b --- /dev/null +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/BaseTestCase.java @@ -0,0 +1,12 @@ +package com.habitrpg.android.habitica; + +import org.junit.Before; +import org.mockito.MockitoAnnotations; + +public class BaseTestCase { + + @Before + public void initMocks() { + MockitoAnnotations.initMocks(this); + } +} diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImplTest.java b/Habitica/src/test/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImplTest.java new file mode 100644 index 000000000..bbba2ddbe --- /dev/null +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImplTest.java @@ -0,0 +1,113 @@ +package com.habitrpg.android.habitica.data.implementation; + +import com.habitrpg.android.habitica.BaseTestCase; +import com.habitrpg.android.habitica.data.ApiClient; +import com.habitrpg.android.habitica.data.TaskRepository; +import com.habitrpg.android.habitica.data.local.UserLocalRepository; +import com.habitrpg.android.habitica.models.tasks.TaskList; +import com.habitrpg.android.habitica.models.tasks.TasksOrder; +import com.habitrpg.android.habitica.models.user.Flags; +import com.habitrpg.android.habitica.models.user.Items; +import com.habitrpg.android.habitica.models.user.Preferences; +import com.habitrpg.android.habitica.models.user.Stats; +import com.habitrpg.android.habitica.models.user.User; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.HashMap; +import java.util.Map; + +import rx.Observable; +import rx.observers.TestSubscriber; + +import static junit.framework.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class UserRepositoryImplTest extends BaseTestCase { + + @Mock + private ApiClient mockedApiClient; + @Mock + private UserLocalRepository mockedLocalRepository; + @Mock + private TaskRepository mockedTaskRepository; + @InjectMocks + private UserRepositoryImpl userRepository; + private User testUser; + + + @Before + public void setUp() { + testUser = new User(); + testUser.setId("123"); + when(mockedLocalRepository.getUnmanagedCopy(testUser)).thenReturn(testUser); + } + + @Test + public void testUpdatingUserSavesChanges() { + testUser.setStats(new Stats()); + User newUser = new User(); + newUser.setItems(new Items()); + newUser.setPreferences(new Preferences()); + newUser.setFlags(new Flags()); + newUser.setStats(new Stats()); + TestSubscriber subscriber = new TestSubscriber<>(); + when(mockedApiClient.updateUser(anyMap())).thenReturn(Observable.just(newUser)); + userRepository.updateUser(testUser, "preferences.timezoneOffset", 2).toBlocking().subscribe(subscriber); + Map updateData = new HashMap<>(); + updateData.put("preferences.timezoneOffset", 2); + verify(mockedApiClient).updateUser(updateData); + verify(mockedLocalRepository).saveUser(testUser); + assertEquals(testUser.getItems(), newUser.getItems()); + assertEquals(testUser.getPreferences(), newUser.getPreferences()); + assertEquals(testUser.getFlags(), newUser.getFlags()); + } + + @Test + public void testRetrievingUserSaves() { + when(mockedApiClient.retrieveUser(false)).thenReturn(Observable.just(testUser)); + TestSubscriber subscriber = new TestSubscriber<>(); + userRepository.retrieveUser(false).toBlocking().subscribe(subscriber); + verify(mockedApiClient).retrieveUser(false); + verify(mockedLocalRepository).saveUser(testUser); + verify(mockedApiClient, never()).updateUser(anyMap()); + } + + @Test + public void testRetrievingUserUpdatesTimezone() { + testUser.setPreferences(new Preferences()); + testUser.getPreferences().setTimezoneOffset(99); + when(mockedApiClient.retrieveUser(false)).thenReturn(Observable.just(testUser)); + TestSubscriber subscriber = new TestSubscriber<>(); + userRepository.retrieveUser(false).toBlocking().subscribe(subscriber); + verify(mockedApiClient).retrieveUser(false); + verify(mockedLocalRepository).saveUser(testUser); + verify(mockedApiClient).updateUser(anyMap()); + } + + @Test + public void testRetrievingUserSavesTasks() { + testUser.setTasksOrder(new TasksOrder()); + testUser.tasks = new TaskList(); + when(mockedApiClient.retrieveUser(false)).thenReturn(Observable.just(testUser)); + TestSubscriber subscriber = new TestSubscriber<>(); + userRepository.retrieveUser(false).toBlocking().subscribe(subscriber); + verify(mockedApiClient).retrieveUser(false); + verify(mockedTaskRepository).saveTasks(testUser.getId(), testUser.getTasksOrder(), testUser.tasks); + } + + @Test + public void testRetrievingUserDoesntRetrieveTwice() { + when(mockedApiClient.retrieveUser(false)).thenReturn(Observable.just(testUser)); + TestSubscriber subscriber = new TestSubscriber<>(); + userRepository.retrieveUser(false).toBlocking().subscribe(subscriber); + userRepository.retrieveUser(false).toBlocking().subscribe(subscriber); + verify(mockedApiClient).retrieveUser(false); + } +} \ No newline at end of file