1111import org .json .JSONArray ;
1212import org .json .JSONException ;
1313import org .json .JSONObject ;
14+ import org .junit .After ;
1415import org .junit .Rule ;
1516import org .junit .Test ;
1617import org .junit .rules .ExpectedException ;
1718
19+ import java .util .ArrayList ;
1820import java .util .Arrays ;
21+ import java .util .Collections ;
1922import java .util .Date ;
2023import java .util .HashMap ;
2124import java .util .List ;
2225import java .util .Map ;
2326import java .util .Set ;
2427
28+ import bolts .Task ;
29+
2530import static org .junit .Assert .assertEquals ;
2631import static org .junit .Assert .assertFalse ;
2732import static org .junit .Assert .assertNull ;
2833import static org .junit .Assert .assertTrue ;
34+ import static org .mockito .Matchers .any ;
35+ import static org .mockito .Matchers .anyString ;
2936import static org .mockito .Mockito .mock ;
3037import static org .mockito .Mockito .when ;
3138
@@ -34,6 +41,11 @@ public class ParseObjectTest {
3441 @ Rule
3542 public ExpectedException thrown = ExpectedException .none ();
3643
44+ @ After
45+ public void tearDown () {
46+ ParseCorePlugins .getInstance ().reset ();
47+ }
48+
3749 @ Test
3850 public void testFromJSONPayload () throws JSONException {
3951 JSONObject json = new JSONObject (
@@ -72,6 +84,151 @@ public void testFromJSONPayloadWithoutClassname() throws JSONException {
7284 assertNull (parseObject );
7385 }
7486
87+ //region testRevert
88+
89+ @ Test
90+ public void testRevert () throws ParseException {
91+ List <Task <Void >> tasks = new ArrayList <>();
92+
93+ // Mocked to let save work
94+ ParseCurrentUserController userController = mock (ParseCurrentUserController .class );
95+ when (userController .getAsync ()).thenReturn (Task .<ParseUser >forResult (null ));
96+ ParseCorePlugins .getInstance ().registerCurrentUserController (userController );
97+
98+ // Mocked to simulate in-flight save
99+ Task <ParseObject .State >.TaskCompletionSource tcs = Task .create ();
100+ ParseObjectController objectController = mock (ParseObjectController .class );
101+ when (objectController .saveAsync (
102+ any (ParseObject .State .class ),
103+ any (ParseOperationSet .class ),
104+ anyString (),
105+ any (ParseDecoder .class )))
106+ .thenReturn (tcs .getTask ());
107+ ParseCorePlugins .getInstance ().registerObjectController (objectController );
108+
109+ // New clean object
110+ ParseObject object = new ParseObject ("TestObject" );
111+ object .revert ("foo" );
112+
113+ // Reverts changes on new object
114+ object .put ("foo" , "bar" );
115+ object .put ("name" , "grantland" );
116+ object .revert ();
117+ assertNull (object .get ("foo" ));
118+ assertNull (object .get ("name" ));
119+
120+ // Object from server
121+ ParseObject .State state = mock (ParseObject .State .class );
122+ when (state .className ()).thenReturn ("TestObject" );
123+ when (state .objectId ()).thenReturn ("test_id" );
124+ when (state .keySet ()).thenReturn (Collections .singleton ("foo" ));
125+ when (state .get ("foo" )).thenReturn ("bar" );
126+ object = ParseObject .from (state );
127+ object .revert ();
128+ assertFalse (object .isDirty ());
129+ assertEquals ("bar" , object .get ("foo" ));
130+
131+ // Reverts changes on existing object
132+ object .put ("foo" , "baz" );
133+ object .put ("name" , "grantland" );
134+ object .revert ();
135+ assertFalse (object .isDirty ());
136+ assertEquals ("bar" , object .get ("foo" ));
137+ assertFalse (object .isDataAvailable ("name" ));
138+
139+ // Shouldn't revert changes done before last call to `save`
140+ object .put ("foo" , "baz" );
141+ object .put ("name" , "nlutsenko" );
142+ tasks .add (object .saveInBackground ());
143+ object .revert ();
144+ assertFalse (object .isDirty ());
145+ assertEquals ("baz" , object .get ("foo" ));
146+ assertEquals ("nlutsenko" , object .get ("name" ));
147+
148+ // Should revert changes done after last call to `save`
149+ object .put ("foo" , "qux" );
150+ object .put ("name" , "grantland" );
151+ object .revert ();
152+ assertFalse (object .isDirty ());
153+ assertEquals ("baz" , object .get ("foo" ));
154+ assertEquals ("nlutsenko" , object .get ("name" ));
155+
156+ // Allow save to complete
157+ tcs .setResult (state );
158+ ParseTaskUtils .wait (Task .whenAll (tasks ));
159+ }
160+
161+ @ Test
162+ public void testRevertKey () throws ParseException {
163+ List <Task <Void >> tasks = new ArrayList <>();
164+
165+ // Mocked to let save work
166+ ParseCurrentUserController userController = mock (ParseCurrentUserController .class );
167+ when (userController .getAsync ()).thenReturn (Task .<ParseUser >forResult (null ));
168+ ParseCorePlugins .getInstance ().registerCurrentUserController (userController );
169+
170+ // Mocked to simulate in-flight save
171+ Task <ParseObject .State >.TaskCompletionSource tcs = Task .create ();
172+ ParseObjectController objectController = mock (ParseObjectController .class );
173+ when (objectController .saveAsync (
174+ any (ParseObject .State .class ),
175+ any (ParseOperationSet .class ),
176+ anyString (),
177+ any (ParseDecoder .class )))
178+ .thenReturn (tcs .getTask ());
179+ ParseCorePlugins .getInstance ().registerObjectController (objectController );
180+
181+ // New clean object
182+ ParseObject object = new ParseObject ("TestObject" );
183+ object .revert ("foo" );
184+
185+ // Reverts changes on new object
186+ object .put ("foo" , "bar" );
187+ object .put ("name" , "grantland" );
188+ object .revert ("foo" );
189+ assertNull (object .get ("foo" ));
190+ assertEquals ("grantland" , object .get ("name" ));
191+
192+ // Object from server
193+ ParseObject .State state = mock (ParseObject .State .class );
194+ when (state .className ()).thenReturn ("TestObject" );
195+ when (state .objectId ()).thenReturn ("test_id" );
196+ when (state .keySet ()).thenReturn (Collections .singleton ("foo" ));
197+ when (state .get ("foo" )).thenReturn ("bar" );
198+ object = ParseObject .from (state );
199+ object .revert ("foo" );
200+ assertFalse (object .isDirty ());
201+ assertEquals ("bar" , object .get ("foo" ));
202+
203+ // Reverts changes on existing object
204+ object .put ("foo" , "baz" );
205+ object .put ("name" , "grantland" );
206+ object .revert ("foo" );
207+ assertEquals ("bar" , object .get ("foo" ));
208+ assertEquals ("grantland" , object .get ("name" ));
209+
210+ // Shouldn't revert changes done before last call to `save`
211+ object .put ("foo" , "baz" );
212+ object .put ("name" , "nlutsenko" );
213+ tasks .add (object .saveInBackground ());
214+ object .revert ("foo" );
215+ assertEquals ("baz" , object .get ("foo" ));
216+ assertEquals ("nlutsenko" , object .get ("name" ));
217+
218+ // Should revert changes done after last call to `save`
219+ object .put ("foo" , "qux" );
220+ object .put ("name" , "grantland" );
221+ object .revert ("foo" );
222+ assertEquals ("baz" , object .get ("foo" ));
223+ assertEquals ("grantland" , object .get ("name" ));
224+
225+ // Allow save to complete
226+ tcs .setResult (state );
227+ ParseTaskUtils .wait (Task .whenAll (tasks ));
228+ }
229+
230+ //endregion
231+
75232 //region testGetter
76233
77234 @ Test ( expected = IllegalStateException .class )
0 commit comments