diff --git a/Parse/src/main/java/com/parse/ParseUserCurrentCoder.java b/Parse/src/main/java/com/parse/ParseUserCurrentCoder.java index d2ab4a85b..ad6cb793e 100644 --- a/Parse/src/main/java/com/parse/ParseUserCurrentCoder.java +++ b/Parse/src/main/java/com/parse/ParseUserCurrentCoder.java @@ -11,6 +11,7 @@ import org.json.JSONException; import org.json.JSONObject; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; import static com.parse.ParseUser.State; @@ -54,7 +55,11 @@ public static ParseUserCurrentCoder get() { @Override public JSONObject encode( T state, ParseOperationSet operations, ParseEncoder encoder) { + // FYI we'll be double writing sessionToken and authData for now... + // This is important. super.encode() has no notion of sessionToken and authData, so it treats them + // like objects (simply passed to the encoder). This means that a null sessionToken will become + // JSONObject.NULL. This must be accounted in #decode(). JSONObject objectJSON = super.encode(state, operations, encoder); String sessionToken = ((State) state).sessionToken(); @@ -90,17 +95,20 @@ public JSONObject encode( @Override public > T decode( T builder, JSONObject json, ParseDecoder decoder) { - ParseUser.State.Builder userBuilder = (State.Builder) builder; + ParseUser.State.Builder userBuilder = (State.Builder) super.decode(builder, json, decoder); + + // super.decode will read its own values and add them to the builder using put(). + // This means the state for session token and auth data might be illegal, returning + // unexpected types. For instance if sessionToken was null, now it's JSONObject.NULL. + // We must overwrite these possibly wrong values. String newSessionToken = json.optString(KEY_SESSION_TOKEN, null); - if (newSessionToken != null) { - userBuilder.sessionToken(newSessionToken); - json.remove(KEY_SESSION_TOKEN); - } + userBuilder.sessionToken(newSessionToken); JSONObject newAuthData = json.optJSONObject(KEY_AUTH_DATA); - if (newAuthData != null) { + if (newAuthData == null) { + userBuilder.authData(null); + } else { try { - // Merge in auth data. @SuppressWarnings("rawtypes") Iterator i = newAuthData.keys(); while (i.hasNext()) { @@ -113,10 +121,8 @@ public > T decode( } catch (JSONException e) { throw new RuntimeException(e); } - json.remove(KEY_AUTH_DATA); } - // FYI we'll be double writing sessionToken and authData for now... - return super.decode(builder, json, decoder); + return (T) userBuilder; } } diff --git a/Parse/src/test/java/com/parse/ParseConfigTest.java b/Parse/src/test/java/com/parse/ParseConfigTest.java index 48e29790b..c10e4f120 100644 --- a/Parse/src/test/java/com/parse/ParseConfigTest.java +++ b/Parse/src/test/java/com/parse/ParseConfigTest.java @@ -48,18 +48,14 @@ // For android.os.Looper @RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) -public class ParseConfigTest { +public class ParseConfigTest extends ResetPluginsParseTest { @Before - public void setUp() { + public void setUp() throws Exception { + super.setUp(); ParseTestUtils.setTestParseUser(); } - @After - public void tearDown() { - ParseCorePlugins.getInstance().reset(); - } - //region testConstructor @Test diff --git a/Parse/src/test/java/com/parse/ParseInstallationTest.java b/Parse/src/test/java/com/parse/ParseInstallationTest.java index 202066eb1..aa51f978e 100644 --- a/Parse/src/test/java/com/parse/ParseInstallationTest.java +++ b/Parse/src/test/java/com/parse/ParseInstallationTest.java @@ -27,6 +27,7 @@ import bolts.Task; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -253,8 +254,16 @@ public void testUpdateBeforeSave() throws Exception { installation.updateBeforeSave(); // Make sure we update timezone - String zone = TimeZone.getDefault().getID(); - assertEquals(zone, installation.getString(KEY_TIME_ZONE)); + String zone = installation.getString(KEY_TIME_ZONE); + String deviceZone = TimeZone.getDefault().getID(); + if (zone != null) { + assertEquals(zone, deviceZone); + } else { + // If it's not updated it's because it was not acceptable. + assertFalse(deviceZone.equals("GMT")); + assertFalse(deviceZone.indexOf("/") > 0); + } + // Make sure we update version info Context context = Parse.getApplicationContext(); String packageName = context.getPackageName(); @@ -265,9 +274,11 @@ public void testUpdateBeforeSave() throws Exception { assertEquals(packageName, installation.getString(KEY_APP_IDENTIFIER)); assertEquals(appName, installation.getString(KEY_APP_NAME)); assertEquals(appVersion, installation.getString(KEY_APP_VERSION)); + // Make sure we update device info assertEquals("android", installation.getString(KEY_DEVICE_TYPE)); assertEquals("installationId", installation.getString(KEY_INSTALLATION_ID)); + // Make sure we update the locale identifier assertEquals("en-US", installation.getString(KEY_LOCALE_IDENTIFIER)); } diff --git a/Parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java b/Parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java index 1f53cc333..aef1feccf 100644 --- a/Parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java +++ b/Parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java @@ -92,9 +92,6 @@ public void testDecodeSuccessWithSessionTokenAndAuthData() throws Exception { Map twitterAuthData = authData.get("twitter"); assertEquals("twitterId", twitterAuthData.get("id")); assertEquals("twitterAccessToken", twitterAuthData.get("access_token")); - // Make sure objectJson does not have sessionToken and authData anymore - assertFalse(objectJson.has(KEY_SESSION_TOKEN)); - assertFalse(objectJson.has(KEY_AUTH_DATA)); } @Test @@ -111,4 +108,19 @@ public void testDecodeSuccessWithoutSessionTokenAndAuthData() throws Exception { // We always return non-null for authData() assertEquals(0, state.authData().size()); } + + @Test + public void testEncodeDecodeWithNullValues() throws Exception { + ParseUser.State state = new ParseUser.State.Builder() + .sessionToken(null) + .authData(null) + .build(); + ParseUserCurrentCoder coder = ParseUserCurrentCoder.get(); + JSONObject object = coder.encode(state, null, PointerEncoder.get()); + ParseUser.State.Builder builder = + coder.decode(new ParseUser.State.Builder(), object, ParseDecoder.get()); + state = builder.build(); + assertNull(state.sessionToken()); + assertEquals(0, state.authData().size()); + } }