Java tutorial
/* * Copyright (c) 2015-present, Parse, LLC. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.parse; import org.json.JSONObject; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.annotation.Config; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import bolts.Task; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyMapOf; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; // For ParseExecutors.main() @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class ParseUserTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Before public void setUp() { ParseObject.registerSubclass(ParseUser.class); ParseObject.registerSubclass(ParseSession.class); } @After public void tearDown() { ParseObject.unregisterSubclass(ParseUser.class); ParseObject.unregisterSubclass(ParseSession.class); ParseCorePlugins.getInstance().reset(); ParsePlugins.reset(); Parse.disableLocalDatastore(); } @Test public void testImmutableKeys() { ParseUser user = new ParseUser(); user.put("foo", "bar"); try { user.put("sessionToken", "blah"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Cannot modify")); } try { user.remove("sessionToken"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Cannot modify")); } try { user.removeAll("sessionToken", Collections.emptyList()); } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Cannot modify")); } } //region SignUpAsync @Test public void testSignUpAsyncWithNoUserName() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Username cannot be missing or blank"); ParseTaskUtils.wait(user.signUpAsync(Task.<Void>forResult(null))); } @Test public void testSignUpAsyncWithNoPassword() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); user.setUsername("userName"); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Password cannot be missing or blank"); ParseTaskUtils.wait(user.signUpAsync(Task.<Void>forResult(null))); } @Test public void testSignUpAsyncWithObjectIdSetAndAuthDataNotSet() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser.State userState = new ParseUser.State.Builder().objectId("test").build(); ParseUser user = ParseObject.from(userState); user.setUsername("userName"); user.setPassword("password"); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Cannot sign up a user that has already signed up."); ParseTaskUtils.wait(user.signUpAsync(Task.<Void>forResult(null))); } @Test public void testSignUpAsyncWithObjectIdSetAndAuthDataSet() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = mock(ParseUser.class); when(currentUser.getSessionToken()).thenReturn("sessionToken"); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(currentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser.State userState = new ParseUser.State.Builder().objectId("test") .putAuthData(ParseAnonymousUtils.AUTH_TYPE, null).build(); ParseUser user = ParseObject.from(userState); user.setUsername("userName"); user.setPassword("password"); //TODO (mengyan): Avoid using partial mock after we have ParseObjectInstanceController ParseUser partialMockUser = spy(user); doReturn(Task.<Void>forResult(null)).when(partialMockUser).saveAsync(anyString(), Matchers.<Task<Void>>any()); ParseTaskUtils.wait(partialMockUser.signUpAsync(Task.<Void>forResult(null))); // Verify user is saved verify(partialMockUser, times(1)).saveAsync(eq("sessionToken"), Matchers.<Task<Void>>any()); } @Test public void testSignUpAsyncWithAnotherSignUpAlreadyRunning() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); user.setUsername("userName"); user.setPassword("password"); user.startSave(); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Cannot sign up a user that is already signing up."); ParseTaskUtils.wait(user.signUpAsync(Task.<Void>forResult(null))); } @Test public void testSignUpAsyncWithSignUpSameAnonymousUser() throws Exception { ParseUser user = new ParseUser(); user.setUsername("userName"); user.setPassword("password"); Map<String, String> anonymousAuthData = new HashMap<>(); anonymousAuthData.put("key", "token"); user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, anonymousAuthData); // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(user)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Attempt to merge currentUser with itself."); ParseTaskUtils.wait(user.signUpAsync(Task.<Void>forResult(null))); } @Test public void testSignUpAsyncWithMergeInDiskAnonymousUser() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = mock(ParseUser.class); when(currentUser.getUsername()).thenReturn("oldUserName"); when(currentUser.getPassword()).thenReturn("oldPassword"); when(currentUser.isLazy()).thenReturn(false); when(currentUser.isLinked(ParseAnonymousUtils.AUTH_TYPE)).thenReturn(true); when(currentUser.getSessionToken()).thenReturn("oldSessionToken"); when(currentUser.getAuthData()).thenReturn(new HashMap<String, Map<String, String>>()); when(currentUser.saveAsync(anyString(), eq(false), Matchers.<Task<Void>>any())) .thenReturn(Task.<Void>forResult(null)); ParseUser.State state = new ParseUser.State.Builder().put("oldKey", "oldValue").build(); when(currentUser.getState()).thenReturn(state); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(currentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); user.setUsername("userName"); user.setPassword("password"); Map<String, String> anonymousAuthData = new HashMap<>(); anonymousAuthData.put("key", "token"); user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, anonymousAuthData); Task<Void> signUpTask = user.signUpAsync(Task.<Void>forResult(null)); signUpTask.waitForCompletion(); // Make sure currentUser copy changes from user verify(currentUser, times(1)).copyChangesFrom(user); // Make sure we update currentUser username and password verify(currentUser, times(1)).setUsername("userName"); verify(currentUser, times(1)).setPassword("password"); // Make sure we save currentUser verify(currentUser, times(1)).saveAsync(eq("oldSessionToken"), eq(false), Matchers.<Task<Void>>any()); // Make sure we merge currentUser with user after save assertEquals("oldValue", user.get("oldKey")); // Make sure set currentUser verify(currentUserController, times(1)).setAsync(eq(user)); } @Test public void testSignUpAsyncWithMergeInDiskAnonymousUserSaveFailure() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); Map<String, String> oldAnonymousAuthData = new HashMap<>(); oldAnonymousAuthData.put("oldKey", "oldToken"); currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, oldAnonymousAuthData); ParseUser partialMockCurrentUser = spy(currentUser); // Spy since we need mutex when(partialMockCurrentUser.getUsername()).thenReturn("oldUserName"); when(partialMockCurrentUser.getPassword()).thenReturn("oldPassword"); when(partialMockCurrentUser.getSessionToken()).thenReturn("oldSessionToken"); when(partialMockCurrentUser.isLazy()).thenReturn(false); ParseException saveException = new ParseException(ParseException.OTHER_CAUSE, ""); doReturn(Task.<Void>forError(saveException)).when(partialMockCurrentUser).saveAsync(anyString(), eq(false), Matchers.<Task<Void>>any()); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(partialMockCurrentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); user.setUsername("userName"); user.setPassword("password"); Map<String, String> anonymousAuthData = new HashMap<>(); anonymousAuthData.put("key", "token"); user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, anonymousAuthData); Task<Void> signUpTask = user.signUpAsync(Task.<Void>forResult(null)); signUpTask.waitForCompletion(); // Make sure we update currentUser username and password verify(partialMockCurrentUser, times(1)).setUsername("userName"); verify(partialMockCurrentUser, times(1)).setPassword("password"); // Make sure we sync user with currentUser verify(partialMockCurrentUser, times(1)).copyChangesFrom(eq(user)); // Make sure we save currentUser verify(partialMockCurrentUser, times(1)).saveAsync(eq("oldSessionToken"), eq(false), Matchers.<Task<Void>>any()); // Make sure we restore old username and password after save fails verify(partialMockCurrentUser, times(1)).setUsername("oldUserName"); verify(partialMockCurrentUser, times(1)).setPassword("oldPassword"); // Make sure we restore anonymity verify(partialMockCurrentUser, times(1)).putAuthData(ParseAnonymousUtils.AUTH_TYPE, oldAnonymousAuthData); // Make sure task is failed assertTrue(signUpTask.isFaulted()); assertSame(saveException, signUpTask.getError()); } @Test public void testSignUpAsyncWithNoCurrentUserAndSignUpSuccess() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("newKey", "newValue") .sessionToken("newSessionToken").build(); when(userController.signUpAsync(any(ParseUser.State.class), any(ParseOperationSet.class), anyString())) .thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); ParseUser user = new ParseUser(); user.setUsername("userName"); user.setPassword("password"); ParseTaskUtils.wait(user.signUpAsync(Task.<Void>forResult(null))); // Make sure we sign up the user verify(userController, times(1)).signUpAsync(any(ParseUser.State.class), any(ParseOperationSet.class), anyString()); // Make sure user's data is correct assertEquals("newSessionToken", user.getSessionToken()); assertEquals("newValue", user.getString("newKey")); assertFalse(user.isLazy()); // Make sure we set the current user verify(currentUserController, times(1)).setAsync(user); } @Test public void testSignUpAsyncWithNoCurrentUserAndSignUpFailure() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseException signUpException = new ParseException(ParseException.OTHER_CAUSE, "test"); when(userController.signUpAsync(any(ParseUser.State.class), any(ParseOperationSet.class), anyString())) .thenReturn(Task.<ParseUser.State>forError(signUpException)); ParseCorePlugins.getInstance().registerUserController(userController); ParseUser user = new ParseUser(); user.put("key", "value"); user.setUsername("userName"); user.setPassword("password"); Task<Void> signUpTask = user.signUpAsync(Task.<Void>forResult(null)); // Make sure we sign up the user verify(userController, times(1)).signUpAsync(any(ParseUser.State.class), any(ParseOperationSet.class), anyString()); // Make sure user's data is correct assertEquals("value", user.getString("key")); // Make sure we never set the current user verify(currentUserController, never()).setAsync(user); // Make sure task is failed assertTrue(signUpTask.isFaulted()); assertSame(signUpException, signUpTask.getError()); } //endregion //region testLogInWithAsync @Test public void testLoginWithAsyncWithoutExistingLazyUser() throws ParseException { ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(false)).thenReturn(Task.<ParseUser>forResult(null)); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseUser.State userState = mock(ParseUser.State.class); when(userState.className()).thenReturn("_User"); when(userState.objectId()).thenReturn("1234"); when(userState.isComplete()).thenReturn(true); ParseUserController userController = mock(ParseUserController.class); when(userController.logInAsync(anyString(), anyMapOf(String.class, String.class))) .thenReturn(Task.forResult(userState)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseCorePlugins.getInstance().registerUserController(userController); String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("token", "123"); ParseUser user = ParseTaskUtils.wait(ParseUser.logInWithInBackground(authType, authData)); verify(currentUserController).getAsync(false); verify(userController).logInAsync(authType, authData); verify(currentUserController).setAsync(user); assertSame(userState, user.getState()); verifyNoMoreInteractions(currentUserController); verifyNoMoreInteractions(userController); } @Test public void testLoginWithAsyncWithLinkedLazyUser() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<String, String>()); setLazy(currentUser); ParseUser partialMockCurrentUser = spy(currentUser); when(partialMockCurrentUser.getSessionToken()).thenReturn("oldSessionToken"); doReturn(Task.<ParseUser>forResult(null)).when(partialMockCurrentUser) .resolveLazinessAsync(Matchers.<Task<Void>>any()); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(false)).thenReturn(Task.forResult(partialMockCurrentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("token", "123"); ParseUser userAfterLogin = ParseTaskUtils.wait(ParseUser.logInWithInBackground(authType, authData)); // Make sure we stripAnonymity assertNull(userAfterLogin.getAuthData().get(ParseAnonymousUtils.AUTH_TYPE)); // Make sure we update authData assertEquals(authData, userAfterLogin.getAuthData().get("facebook")); // Make sure we resolveLaziness verify(partialMockCurrentUser, times(1)).resolveLazinessAsync(Matchers.<Task<Void>>any()); } @Test public void testLoginWithAsyncWithLinkedLazyUseAndResolveLazinessFailure() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); Map<String, String> oldAnonymousAuthData = new HashMap<>(); oldAnonymousAuthData.put("oldKey", "oldToken"); currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, oldAnonymousAuthData); ParseUser partialMockCurrentUser = spy(currentUser); when(partialMockCurrentUser.getSessionToken()).thenReturn("oldSessionToken"); doReturn(Task.<ParseUser>forError(new Exception())).when(partialMockCurrentUser) .resolveLazinessAsync(Matchers.<Task<Void>>any()); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(false)).thenReturn(Task.forResult(partialMockCurrentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("token", "123"); Task<ParseUser> loginTask = ParseUser.logInWithInBackground(authType, authData); loginTask.waitForCompletion(); // Make sure we try to resolveLaziness verify(partialMockCurrentUser, times(1)).resolveLazinessAsync(Matchers.<Task<Void>>any()); // Make sure we do not save new authData assertNull(partialMockCurrentUser.getAuthData().get("facebook")); // Make sure we restore anonymity after resolve laziness failure assertEquals(oldAnonymousAuthData, partialMockCurrentUser.getAuthData().get(ParseAnonymousUtils.AUTH_TYPE)); // Make sure task fails assertTrue(loginTask.isFaulted()); } @Test public void testLoginWithAsyncWithLinkedNotLazyUser() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser.State state = new ParseUser.State.Builder().objectId("objectId") // Make it not lazy .putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<String, String>()).build(); ParseUser currentUser = ParseUser.from(state); ParseUser partialMockCurrentUser = spy(currentUser); // ParseUser.mutex doReturn(Task.<Void>forResult(null)).when(partialMockCurrentUser).linkWithInBackground(anyString(), Matchers.<Map<String, String>>any()); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync()).thenReturn(Task.forResult(partialMockCurrentUser)); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(partialMockCurrentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("token", "123"); ParseUser userAfterLogin = ParseTaskUtils.wait(ParseUser.logInWithInBackground(authType, authData)); // Make sure we link authData verify(partialMockCurrentUser, times(1)).linkWithInBackground(authType, authData); assertSame(partialMockCurrentUser, userAfterLogin); } @Test public void testLoginWithAsyncWithLinkedNotLazyUserLinkFailure() throws Exception { // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("newKey", "newValue") .sessionToken("newSessionToken").build(); when(userController.logInAsync(anyString(), Matchers.<Map<String, String>>any())) .thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<String, String>()); currentUser.setObjectId("objectId"); // Make it not lazy. ParseUser partialMockCurrentUser = spy(currentUser); when(partialMockCurrentUser.getSessionToken()).thenReturn("sessionToken"); ParseException linkException = new ParseException(ParseException.ACCOUNT_ALREADY_LINKED, "Account already linked"); doReturn(Task.<Void>forError(linkException)).when(partialMockCurrentUser).linkWithInBackground(anyString(), Matchers.<Map<String, String>>any()); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(false)).thenReturn(Task.forResult(partialMockCurrentUser)); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("token", "123"); ParseUser userAfterLogin = ParseTaskUtils.wait(ParseUser.logInWithInBackground(authType, authData)); // Make sure we link authData verify(partialMockCurrentUser, times(1)).linkWithInBackground(authType, authData); // Make sure we login authData verify(userController, times(1)).logInAsync("facebook", authData); // Make sure we save the new created user as currentUser verify(currentUserController, times(1)).setAsync(any(ParseUser.class)); // Make sure the new created user has correct data assertEquals("newValue", userAfterLogin.get("newKey")); assertEquals("newSessionToken", userAfterLogin.getSessionToken()); } @Test public void testLoginWithAsyncWithNoCurrentUser() throws Exception { // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("newKey", "newValue") .sessionToken("newSessionToken").build(); when(userController.logInAsync(anyString(), Matchers.<Map<String, String>>any())) .thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(false)).thenReturn(Task.<ParseUser>forResult(null)); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("token", "123"); ParseUser userAfterLogin = ParseTaskUtils.wait(ParseUser.logInWithInBackground(authType, authData)); // Make sure we login authData verify(userController, times(1)).logInAsync("facebook", authData); // Make sure we save the new created user as currentUser verify(currentUserController, times(1)).setAsync(any(ParseUser.class)); // Make sure the new created user has correct data assertEquals("newValue", userAfterLogin.get("newKey")); assertEquals("newSessionToken", userAfterLogin.getSessionToken()); } //endregion //region testlinkWithInBackground @Test public void testlinkWithInBackgroundWithSaveAsyncSuccess() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getCurrentSessionTokenAsync()).thenReturn(Task.<String>forResult(null)); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register mock callbacks AuthenticationCallback callbacks = mock(AuthenticationCallback.class); when(callbacks.onRestore(Matchers.<Map<String, String>>any())).thenReturn(true); ParseUser.registerAuthenticationCallback("facebook", callbacks); ParseUser user = new ParseUser(); // To make synchronizeAuthData work user.setIsCurrentUser(true); // To verify stripAnonymity user.setObjectId("objectId"); user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<String, String>()); ParseUser partialMockUser = spy(user); doReturn(Task.<Void>forResult(null)).when(partialMockUser).saveAsync(anyString(), eq(false), Matchers.<Task<Void>>any()); doReturn("sessionTokenAgain").when(partialMockUser).getSessionToken(); Map<String, String> authData = new HashMap<>(); authData.put("token", "test"); ParseTaskUtils.wait(partialMockUser.linkWithInBackground("facebook", authData)); // Make sure we stripAnonymity assertNull(partialMockUser.getAuthData().get(ParseAnonymousUtils.AUTH_TYPE)); // Make sure new authData is added assertSame(authData, partialMockUser.getAuthData().get("facebook")); // Make sure we save the user verify(partialMockUser, times(1)).saveAsync(eq("sessionTokenAgain"), eq(false), Matchers.<Task<Void>>any()); // Make sure synchronizeAuthData() is called verify(callbacks, times(1)).onRestore(authData); } @Test public void testlinkWithInBackgroundWithSaveAsyncFailure() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getCurrentSessionTokenAsync()).thenReturn(Task.forResult("sessionToken")); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); Map<String, String> anonymousAuthData = new HashMap<>(); anonymousAuthData.put("anonymousToken", "anonymousTest"); // To verify stripAnonymity user.setObjectId("objectId"); user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, anonymousAuthData); ParseUser partialMockUser = spy(user); Exception saveException = new Exception(); doReturn(Task.<Void>forError(saveException)).when(partialMockUser).saveAsync(anyString(), eq(false), Matchers.<Task<Void>>any()); doReturn("sessionTokenAgain").when(partialMockUser).getSessionToken(); String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("facebookToken", "facebookTest"); Task<Void> linkTask = partialMockUser.linkWithInBackground(authType, authData); linkTask.waitForCompletion(); // Make sure new authData is added assertSame(authData, partialMockUser.getAuthData().get(authType)); // Make sure we save the user verify(partialMockUser, times(1)).saveAsync(eq("sessionTokenAgain"), eq(false), Matchers.<Task<Void>>any()); // Make sure old authData is restored assertSame(anonymousAuthData, partialMockUser.getAuthData().get(ParseAnonymousUtils.AUTH_TYPE)); // Verify exception assertSame(saveException, linkTask.getError()); } //endregion //region testResolveLazinessAsync @Test public void testResolveLazinessAsyncWithAuthDataAndNotNewUser() throws Exception { ParseUser user = new ParseUser(); setLazy(user); user.putAuthData("facebook", new HashMap<String, String>()); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("newKey", "newValue") .sessionToken("newSessionToken").isNew(false).build(); when(userController.logInAsync(any(ParseUser.State.class), any(ParseOperationSet.class))) .thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseTaskUtils.wait(user.resolveLazinessAsync(Task.<Void>forResult(null))); ArgumentCaptor<ParseUser> userAfterResolveLazinessCaptor = ArgumentCaptor.forClass(ParseUser.class); // Make sure we logIn the lazy user verify(userController, times(1)).logInAsync(any(ParseUser.State.class), any(ParseOperationSet.class)); // Make sure we save currentUser verify(currentUserController, times(1)).setAsync(userAfterResolveLazinessCaptor.capture()); ParseUser userAfterResolveLaziness = userAfterResolveLazinessCaptor.getValue(); // Make sure user's data is correct assertEquals("newSessionToken", userAfterResolveLaziness.getSessionToken()); assertEquals("newValue", userAfterResolveLaziness.get("newKey")); // Make sure userAfterResolveLaziness is not lazy assertFalse(userAfterResolveLaziness.isLazy()); // Make sure we create new user assertNotSame(user, userAfterResolveLaziness); } @Test public void testResolveLazinessAsyncWithAuthDataAndNewUser() throws Exception { ParseUser user = new ParseUser(); setLazy(user); user.putAuthData("facebook", new HashMap<String, String>()); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().objectId("objectId").put("newKey", "newValue") .sessionToken("newSessionToken").isNew(true).build(); when(userController.logInAsync(any(ParseUser.State.class), any(ParseOperationSet.class))) .thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); // Register a mock currentUserController to verify setAsync ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseTaskUtils.wait(user.resolveLazinessAsync(Task.<Void>forResult(null))); // Make sure we logIn the lazy user verify(userController, times(1)).logInAsync(any(ParseUser.State.class), any(ParseOperationSet.class)); // Make sure we do not save currentUser verify(currentUserController, never()).setAsync(any(ParseUser.class)); // Make sure userAfterResolveLaziness's data is correct assertEquals("newSessionToken", user.getSessionToken()); assertEquals("newValue", user.get("newKey")); // Make sure userAfterResolveLaziness is not lazy assertFalse(user.isLazy()); } @Test public void testResolveLazinessAsyncWithAuthDataAndNotNewUserAndLDSEnabled() throws Exception { ParseUser user = new ParseUser(); setLazy(user); user.putAuthData("facebook", new HashMap<String, String>()); // To verify handleSaveResultAsync is not called user.setPassword("password"); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("newKey", "newValue") .sessionToken("newSessionToken").isNew(false).build(); when(userController.logInAsync(any(ParseUser.State.class), any(ParseOperationSet.class))) .thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); // Register a mock currentUserController to make getCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Enable LDS Parse.enableLocalDatastore(null); ParseTaskUtils.wait(user.resolveLazinessAsync(Task.<Void>forResult(null))); ArgumentCaptor<ParseUser> userAfterResolveLazinessCaptor = ArgumentCaptor.forClass(ParseUser.class); // Make sure we logIn the lazy user verify(userController, times(1)).logInAsync(any(ParseUser.State.class), any(ParseOperationSet.class)); // Make sure handleSaveResultAsync() is not called, if handleSaveResultAsync is called, password // field should be cleaned assertEquals("password", user.getPassword()); // Make sure we do not save currentUser verify(currentUserController, times(1)).setAsync(userAfterResolveLazinessCaptor.capture()); ParseUser userAfterResolveLaziness = userAfterResolveLazinessCaptor.getValue(); // Make sure userAfterResolveLaziness's data is correct assertEquals("newSessionToken", userAfterResolveLaziness.getSessionToken()); assertEquals("newValue", userAfterResolveLaziness.get("newKey")); // Make sure userAfterResolveLaziness is not lazy assertFalse(userAfterResolveLaziness.isLazy()); // Make sure we create new user assertNotSame(user, userAfterResolveLaziness); } //endregion //region testValidateSave @Test public void testValidateSaveWithNoObjectId() throws Exception { ParseUser user = new ParseUser(); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Cannot save a ParseUser until it has been signed up. Call signUp first."); user.validateSave(); } // TODO(mengyan): Add testValidateSaveWithIsAuthenticatedWithNotDirty // TODO(mengyan): Add testValidateSaveWithIsAuthenticatedWithIsCurrentUser @Test public void testValidateSaveWithLDSNotEnabled() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); currentUser.setObjectId("test"); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(currentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); user.setObjectId("test"); // Make isDirty return true user.put("key", "value"); // Make isCurrent return false user.setIsCurrentUser(false); user.validateSave(); } @Test public void testValidateSaveWithLDSNotEnabledAndCurrentUserNotMatch() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); currentUser.setObjectId("testAgain"); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(currentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); user.setObjectId("test"); // Make isDirty return true user.put("key", "value"); // Make isCurrent return false user.setIsCurrentUser(false); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Cannot save a ParseUser that is not authenticated."); user.validateSave(); } //endregion //region testSaveAsync @Test public void testSaveAsyncWithLazyAndCurrentUser() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Set facebook authData to null to verify cleanAuthData() ParseUser.State userState = new ParseUser.State.Builder().putAuthData("facebook", null).build(); ParseUser user = ParseObject.from(userState); setLazy(user); user.setIsCurrentUser(true); ParseUser partialMockUser = spy(user); doReturn(Task.<Void>forResult(null)).when(partialMockUser).resolveLazinessAsync(Matchers.<Task<Void>>any()); ParseTaskUtils.wait(partialMockUser.saveAsync("sessionToken", Task.<Void>forResult(null))); // Make sure we clean authData assertFalse(partialMockUser.getAuthData().containsKey("facebook")); // Make sure we save new currentUser verify(currentUserController, times(1)).setAsync(partialMockUser); } @Test public void testSaveAsyncWithLazyAndNotCurrentUser() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Set facebook authData to null to verify cleanAuthData() ParseUser.State userState = new ParseUser.State.Builder().putAuthData("facebook", null).build(); ParseUser user = ParseObject.from(userState); setLazy(user); user.setIsCurrentUser(false); ParseUser partialMockUser = spy(user); doReturn(Task.<Void>forResult(null)).when(partialMockUser).resolveLazinessAsync(Matchers.<Task<Void>>any()); ParseTaskUtils.wait(partialMockUser.saveAsync("sessionToken", Task.<Void>forResult(null))); // Make sure we do not clean authData assertTrue(partialMockUser.getAuthData().containsKey("facebook")); // Make sure we do not save new currentUser verify(currentUserController, never()).setAsync(partialMockUser); } // TODO(mengyan): Add testSaveAsyncWithNotLazyAndNotCurrentUser, right now we can not mock // super.save() //endregion //region testLogOutAsync @Test public void testLogOutAsync() throws Exception { // Register a mock sessionController to verify revokeAsync() NetworkSessionController sessionController = mock(NetworkSessionController.class); when(sessionController.revokeAsync(anyString())).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerSessionController(sessionController); ParseAuthenticationManager manager = mock(ParseAuthenticationManager.class); when(manager.deauthenticateAsync(anyString())).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerAuthenticationManager(manager); // Set user initial state String facebookAuthType = "facebook"; Map<String, String> facebookAuthData = new HashMap<>(); facebookAuthData.put("facebookToken", "facebookTest"); ParseUser.State userState = new ParseUser.State.Builder().objectId("test") .putAuthData(facebookAuthType, facebookAuthData).sessionToken("r:oldSessionToken").build(); ParseUser user = ParseObject.from(userState); ParseTaskUtils.wait(user.logOutAsync()); verify(manager).deauthenticateAsync("facebook"); // Verify we revoke session verify(sessionController, times(1)).revokeAsync("r:oldSessionToken"); } //endregion //region testEnable/UpgradeSessionToken @Test public void testEnableRevocableSessionInBackgroundWithCurrentUser() throws Exception { // Register a mock ParsePlugins to make restClient() work ParsePlugins mockPlugins = mock(ParsePlugins.class); when(mockPlugins.restClient()).thenReturn(null); ParsePlugins.set(mockPlugins); // Register a mock currentUserController to verify setAsync ParseUser mockUser = mock(ParseUser.class); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(mockUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseTaskUtils.wait(ParseUser.enableRevocableSessionInBackground()); verify(currentUserController, times(1)).getAsync(false); verify(mockUser, times(1)).upgradeToRevocableSessionAsync(); } @Test public void testEnableRevocableSessionInBackgroundWithNoCurrentUser() throws Exception { // Register a mock ParsePlugins to make restClient() work ParsePlugins mockPlugins = mock(ParsePlugins.class); when(mockPlugins.restClient()).thenReturn(null); ParsePlugins.set(mockPlugins); // Register a mock currentUserController to verify setAsync ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.<ParseUser>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseTaskUtils.wait(ParseUser.enableRevocableSessionInBackground()); verify(currentUserController, times(1)).getAsync(false); } @Test public void testUpgradeToRevocableSessionAsync() throws Exception { // Register a mock currentUserController to verify setAsync ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register a mock sessionController to verify revokeAsync() NetworkSessionController sessionController = mock(NetworkSessionController.class); ParseSession.State state = new ParseSession.State.Builder("_Session") .put("sessionToken", "r:newSessionToken").build(); when(sessionController.upgradeToRevocable(anyString())).thenReturn(Task.forResult(state)); ParseCorePlugins.getInstance().registerSessionController(sessionController); // Set user initial state ParseUser.State userState = new ParseUser.State.Builder().objectId("test").sessionToken("oldSessionToken") .build(); ParseUser user = ParseObject.from(userState); ParseTaskUtils.wait(user.upgradeToRevocableSessionAsync()); // Make sure we update to new sessionToken assertEquals("r:newSessionToken", user.getSessionToken()); // Make sure we update currentUser verify(currentUserController, times(1)).setAsync(user); } @Test public void testDontOverwriteSessionTokenForCurrentUser() throws Exception { ParseUser.State sessionTokenState = new ParseUser.State.Builder().sessionToken("sessionToken") .put("key0", "value0").put("key1", "value1").isComplete(true).build(); ParseUser.State newState = new ParseUser.State.Builder().put("key0", "newValue0").put("key2", "value2") .isComplete(true).build(); ParseUser.State emptyState = new ParseUser.State.Builder().isComplete(true).build(); ParseUser user = ParseObject.from(sessionTokenState); user.setIsCurrentUser(true); assertEquals(user.getSessionToken(), "sessionToken"); assertEquals(user.getString("key0"), "value0"); assertEquals(user.getString("key1"), "value1"); user.setState(newState); assertEquals(user.getSessionToken(), "sessionToken"); assertEquals(user.getString("key0"), "newValue0"); assertNull(user.getString("key1")); assertEquals(user.getString("key2"), "value2"); user.setIsCurrentUser(false); user.setState(emptyState); assertNull(user.getSessionToken()); assertNull(user.getString("key0")); assertNull(user.getString("key1")); assertNull(user.getString("key2")); } //endregion //region testUnlinkFromAsync @Test public void testUnlinkFromAsyncWithAuthType() throws Exception { // Register a mock currentUserController to make getAsync work ParseUser mockUser = mock(ParseUser.class); when(mockUser.getSessionToken()).thenReturn("sessionToken"); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync()).thenReturn(Task.forResult(mockUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Set user initial state String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("facebookToken", "facebookTest"); ParseUser.State userState = new ParseUser.State.Builder().objectId("test").putAuthData(authType, authData) .build(); ParseUser user = ParseObject.from(userState); ParseUser partialMockUser = spy(user); doReturn(Task.<Void>forResult(null)).when(partialMockUser).saveAsync(anyString(), Matchers.<Task<Void>>any()); ParseTaskUtils.wait(partialMockUser.unlinkFromInBackground(authType)); // Verify we delete authData assertNull(user.getAuthData().get("facebook")); // Verify we save the user verify(partialMockUser, times(1)).saveAsync(eq("sessionToken"), Matchers.<Task<Void>>any()); } //endregion //region testLogin @Test public void testLogInInWithNoUserName() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Must specify a username for the user to log in with"); ParseTaskUtils.wait(ParseUser.logInInBackground(null, "password")); } @Test public void testLogInWithNoPassword() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Must specify a password for the user to log in with"); ParseTaskUtils.wait(ParseUser.logInInBackground("userName", null)); } @Test public void testLogIn() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("newKey", "newValue") .sessionToken("newSessionToken").build(); when(userController.logInAsync(anyString(), anyString())).thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); ParseUser user = ParseUser.logIn("userName", "password"); // Make sure user is login verify(userController, times(1)).logInAsync("userName", "password"); // Make sure we set currentUser verify(currentUserController, times(1)).setAsync(user); // Make sure user's data is correct assertEquals("newSessionToken", user.getSessionToken()); assertEquals("newValue", user.get("newKey")); } @Test public void testLogInWithCallback() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("newKey", "newValue") .sessionToken("newSessionToken").build(); when(userController.logInAsync(anyString(), anyString())).thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); final Semaphore done = new Semaphore(0); ParseUser.logInInBackground("userName", "password", new LogInCallback() { @Override public void done(ParseUser user, ParseException e) { done.release(); assertNull(e); // Make sure user's data is correct assertEquals("newSessionToken", user.getSessionToken()); assertEquals("newValue", user.get("newKey")); } }); assertTrue(done.tryAcquire(5, TimeUnit.SECONDS)); // Make sure user is login verify(userController, times(1)).logInAsync("userName", "password"); // Make sure we set currentUser verify(currentUserController, times(1)).setAsync(any(ParseUser.class)); } //endregion //region testBecome @Test public void testBecomeWithNoSessionToken() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Must specify a sessionToken for the user to log in with"); ParseUser.become(null); } @Test public void testBecome() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register a mock userController to make getUsreAsync work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("key", "value") .sessionToken("sessionToken").build(); when(userController.getUserAsync(anyString())).thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); ParseUser user = ParseUser.become("sessionToken"); // Make sure we call getUserAsync verify(userController, times(1)).getUserAsync("sessionToken"); // Make sure we set currentUser verify(currentUserController, times(1)).setAsync(user); // Make sure user's data is correct assertEquals("sessionToken", user.getSessionToken()); assertEquals("value", user.get("key")); } @Test public void testBecomeWithCallback() throws Exception { // Register a mock currentUserController to make setCurrentUser work ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.setAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register a mock userController to make getUsreAsync work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder().put("key", "value") .sessionToken("sessionToken").build(); when(userController.getUserAsync(anyString())).thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); final Semaphore done = new Semaphore(0); ParseUser.becomeInBackground("sessionToken", new LogInCallback() { @Override public void done(ParseUser user, ParseException e) { done.release(); assertNull(e); // Make sure user's data is correct assertEquals("sessionToken", user.getSessionToken()); assertEquals("value", user.get("key")); } }); // Make sure we call getUserAsync verify(userController, times(1)).getUserAsync("sessionToken"); // Make sure we set currentUser verify(currentUserController, times(1)).setAsync(any(ParseUser.class)); } //endregion //region testToRest @Test public void testToRest() throws Exception { ParseUser user = new ParseUser(); user.setUsername("userName"); user.setPassword("password"); JSONObject json = user.toRest(user.getState(), user.operationSetQueue, PointerEncoder.get()); // Make sure we delete password operations assertFalse(json.getJSONArray("__operations").getJSONObject(0).has("password")); // Make sure we have username operations assertEquals("userName", json.getJSONArray("__operations").getJSONObject(0).getString("username")); } //endregion //region testValidateDelete @Test public void testValidDelete() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); currentUser.setObjectId("test"); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(currentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); user.setObjectId("test"); // Make isDirty return true user.put("key", "value"); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Cannot delete a ParseUser that is not authenticated."); user.validateDelete(); } //endregion //region testValidateDelete @Test public void testValidateSaveEventually() throws Exception { ParseUser user = new ParseUser(); user.setPassword("password"); thrown.expect(ParseException.class); thrown.expectMessage("Unable to saveEventually on a ParseUser with dirty password"); user.validateSaveEventually(); } //endregion //region testSynchronizeAuthData @Test public void testSynchronizeAuthData() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(currentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register mock callbacks AuthenticationCallback callbacks = mock(AuthenticationCallback.class); when(callbacks.onRestore(Matchers.<Map<String, String>>any())).thenReturn(true); ParseUser.registerAuthenticationCallback("facebook", callbacks); // Set user initial state String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("facebookToken", "facebookTest"); ParseUser.State userState = new ParseUser.State.Builder().putAuthData(authType, authData).build(); ParseUser user = ParseObject.from(userState); user.setIsCurrentUser(true); ParseTaskUtils.wait(user.synchronizeAuthDataAsync(authType)); // Make sure we restore authentication verify(callbacks, times(1)).onRestore(authData); } @Test public void testSynchronizeAllAuthData() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); ParseCurrentUserController currentUserController = mock(ParseCurrentUserController.class); when(currentUserController.getAsync(anyBoolean())).thenReturn(Task.forResult(currentUser)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); // Register mock callbacks AuthenticationCallback callbacks = mock(AuthenticationCallback.class); when(callbacks.onRestore(Matchers.<Map<String, String>>any())).thenReturn(true); ParseUser.registerAuthenticationCallback("facebook", callbacks); // Set user initial state String facebookAuthType = "facebook"; Map<String, String> facebookAuthData = new HashMap<>(); facebookAuthData.put("facebookToken", "facebookTest"); ParseUser.State userState = new ParseUser.State.Builder().putAuthData(facebookAuthType, facebookAuthData) .build(); ParseUser user = ParseObject.from(userState); user.setIsCurrentUser(true); ParseTaskUtils.wait(user.synchronizeAllAuthDataAsync()); // Make sure we restore authentication verify(callbacks, times(1)).onRestore(facebookAuthData); } //endregion //region testAutomaticUser @Test public void testAutomaticUser() throws Exception { new ParseUser(); ParseUser.disableAutomaticUser(); assertFalse(ParseUser.isAutomaticUserEnabled()); ParseUser.enableAutomaticUser(); assertTrue(ParseUser.isAutomaticUserEnabled()); } //endregion //region testAutomaticUser @Test public void testPinCurrentUserIfNeededAsyncWithNoLDSEnabled() throws Exception { thrown.expect(IllegalStateException.class); thrown.expectMessage("Method requires Local Datastore."); ParseUser.pinCurrentUserIfNeededAsync(new ParseUser()); } //endregion //region testPinCurrentUserIfNeededAsync @Test public void testPinCurrentUserIfNeededAsync() throws Exception { // Enable LDS Parse.enableLocalDatastore(null); // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); currentUser.setObjectId("test"); CachedCurrentUserController currentUserController = mock(CachedCurrentUserController.class); when(currentUserController.setIfNeededAsync(any(ParseUser.class))).thenReturn(Task.<Void>forResult(null)); ParseCorePlugins.getInstance().registerCurrentUserController(currentUserController); ParseUser user = new ParseUser(); ParseUser.pinCurrentUserIfNeededAsync(user); // Make sure we pin the user verify(currentUserController, times(1)).setIfNeededAsync(user); } //endregion //region testRemove @Test public void testRemoveWithUserName() throws Exception { ParseUser user = new ParseUser(); thrown.expect(IllegalArgumentException.class); thrown.expectMessage("Can't remove the username key."); user.remove("username"); } //endregion //region testSetState @Test public void testSetCurrentUserStateWithoutAuthData() throws Exception { // Set user initial state String authType = "facebook"; Map<String, String> authData = new HashMap<>(); authData.put("facebookToken", "facebookTest"); ParseUser.State userState = new ParseUser.State.Builder().objectId("test").put("oldKey", "oldValue") .put("key", "value").putAuthData(authType, authData).build(); ParseUser user = ParseObject.from(userState); user.setIsCurrentUser(true); // Build new state ParseUser.State newUserState = new ParseUser.State.Builder().objectId("testAgain").put("key", "valueAgain") .build(); user.setState(newUserState); // Make sure we keep the authData assertEquals(1, user.getAuthData().size()); assertEquals(authData, user.getAuthData().get(authType)); // Make sure old state is replaced assertFalse(user.has("oldKey")); // Make sure new state is set assertEquals("testAgain", user.getObjectId()); assertEquals("valueAgain", user.get("key")); } @Test public void testSetStateDoesNotAddNonExistentAuthData() throws Exception { // Set user initial state ParseUser.State userState = new ParseUser.State.Builder().objectId("test").put("oldKey", "oldValue") .put("key", "value").build(); ParseUser user = ParseObject.from(userState); user.setIsCurrentUser(true); // Build new state ParseUser.State newUserState = new ParseUser.State.Builder().objectId("testAgain").put("key", "valueAgain") .build(); user.setState(newUserState); // Make sure we do not add authData when it did not exist before assertFalse(user.keySet().contains("authData")); assertEquals(1, user.keySet().size()); assertEquals(0, user.getAuthData().size()); // Make sure old state is replaced assertFalse(user.has("oldKey")); // Make sure new state is set assertEquals("testAgain", user.getObjectId()); assertEquals("valueAgain", user.get("key")); } //endregion private static void setLazy(ParseUser user) { Map<String, String> anonymousAuthData = new HashMap<>(); anonymousAuthData.put("anonymousToken", "anonymousTest"); user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, anonymousAuthData); } }