@Test
  public void testHasReadAccessWithPublicReadAccess() {
    ParseACL acl = mock(ParseACL.class);
    when(acl.getPublicReadAccess()).thenReturn(true);

    ParseObject object = mock(ParseObject.class);
    when(object.getACL()).thenReturn(acl);

    assertTrue(OfflineQueryLogic.hasReadAccess(null, object));
  }
  @Test
  public void testHasReadAccessWithNoReadAccess() {
    ParseACL acl = mock(ParseACL.class);
    when(acl.getPublicReadAccess()).thenReturn(false);
    when(acl.getReadAccess(any(ParseUser.class))).thenReturn(false);

    ParseObject object = mock(ParseObject.class);
    when(object.getACL()).thenReturn(acl);

    assertFalse(OfflineQueryLogic.hasReadAccess(null, object));
  }
  @Test
  public void testHasWriteAccessWithWriteAccess() {
    ParseUser user = mock(ParseUser.class);

    ParseACL acl = mock(ParseACL.class);
    when(acl.getWriteAccess(user)).thenReturn(true);

    ParseObject object = mock(ParseObject.class);
    when(object.getACL()).thenReturn(acl);

    assertTrue(OfflineQueryLogic.hasWriteAccess(user, object));
  }
  @Test
  public void testMatcherWithNoReadAccess() throws ParseException {
    OfflineQueryLogic logic = new OfflineQueryLogic(null);

    ParseQuery.State<ParseObject> query = new ParseQuery.State.Builder<>("TestObject").build();

    ParseACL acl = new ParseACL();
    acl.setPublicReadAccess(false);
    ParseObject object = new ParseObject("TestObject");
    object.setACL(acl);

    ParseUser user = mock(ParseUser.class);
    when(user.getObjectId()).thenReturn("test");

    assertFalse(matches(logic, query, object, user));
  }
  /** The inverse of toRest. Creates a new OperationSet from the given JSON. */
  public static ParseOperationSet fromRest(JSONObject json, ParseDecoder decoder)
      throws JSONException {
    // Copy the json object to avoid making changes to the old object
    Iterator<String> keysIter = json.keys();
    String[] keys = new String[json.length()];
    int index = 0;
    while (keysIter.hasNext()) {
      String key = keysIter.next();
      keys[index++] = key;
    }

    JSONObject jsonCopy = new JSONObject(json, keys);
    String uuid = (String) jsonCopy.remove(REST_KEY_UUID);
    ParseOperationSet operationSet =
        (uuid == null ? new ParseOperationSet() : new ParseOperationSet(uuid));

    boolean isSaveEventually = jsonCopy.optBoolean(REST_KEY_IS_SAVE_EVENTUALLY);
    jsonCopy.remove(REST_KEY_IS_SAVE_EVENTUALLY);
    operationSet.setIsSaveEventually(isSaveEventually);

    Iterator<?> opKeys = jsonCopy.keys();
    while (opKeys.hasNext()) {
      String opKey = (String) opKeys.next();
      Object value = decoder.decode(jsonCopy.get(opKey));
      ParseFieldOperation fieldOp;
      if (opKey.equals("ACL")) {
        value = ParseACL.createACLFromJSONObject(jsonCopy.getJSONObject(opKey), decoder);
      }
      if (value instanceof ParseFieldOperation) {
        fieldOp = (ParseFieldOperation) value;
      } else {
        fieldOp = new ParseSetOperation(value);
      }
      operationSet.put(opKey, fieldOp);
    }

    return operationSet;
  }