@SuppressWarnings("unchecked")
@Test
public void testSingleKeyReturnList2() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    MsgDao dao = mango.create(MsgDao.class, cacheHandler);
    int uid = 100;
    String key = getMsgKey(uid);
    List<Msg> actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(0));
    List<Msg> cacheActual = (List<Msg>) cacheHandler.get(key);
    assertThat(cacheActual, hasSize(0));
    Msg msg = createRandomMsg(uid);
    msgs.add(msg);
    msg.setId(dao.insert(msg));
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    cacheActual = (List<Msg>) cacheHandler.get(key);
    assertThat(cacheActual, hasSize(msgs.size()));
    assertThat(cacheActual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(0));
    cacheActual = (List<Msg>) cacheHandler.get(key);
    assertThat(cacheActual, hasSize(0));
}

@SuppressWarnings("unchecked")
@Test
public void testSingleKeyReturnList2() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    MsgDao dao = mango.create(MsgDao.class);
    int uid = 100;
    String key = getMsgKey(uid);
    List<Msg> actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(0));
    List<Msg> cacheActual = (List<Msg>) cacheHandler.get(key);
    assertThat(cacheActual, hasSize(0));
    Msg msg = createRandomMsg(uid);
    msgs.add(msg);
    msg.setId(dao.insert(msg));
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    cacheActual = (List<Msg>) cacheHandler.get(key);
    assertThat(cacheActual, hasSize(msgs.size()));
    assertThat(cacheActual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(0));
    cacheActual = (List<Msg>) cacheHandler.get(key);
    assertThat(cacheActual, hasSize(0));
}

@Test
public void testUpdateEmpty() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    Config oldConfig = mango.getConfig();
    Config newConfig = new Config();
    newConfig.setCompatibleWithEmptyList(true);
    mango.setConfig(newConfig);
    assertThat(dao.updateWithInStatement(new ArrayList<Integer>(), "ash"), equalTo(0));
    mango.setConfig(oldConfig);
}

@Test
public void testUpdateEmpty() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    Config oldConfig = mango.getConfig();
    Config newConfig = new Config();
    newConfig.setCompatibleWithEmptyList(true);
    mango.setConfig(newConfig);
    assertThat(dao.updateWithInStatement(new ArrayList<Integer>(), "ash"), equalTo(0));
    mango.setConfig(oldConfig);
}

@Test
public void testSingleKeyReturnList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    MsgDao dao = mango.create(MsgDao.class, cacheHandler);
    int uid = 100;
    String key = getMsgKey(uid);
    for (int i = 0; i < 3; i++) {
        Msg msg = createRandomMsg(uid);
        msgs.add(msg);
        msg.setId(dao.insert(msg));
        assertThat(cacheHandler.get(key), nullValue());
        List<Msg> actual = dao.getMsgs(uid);
        assertThat(actual, hasSize(msgs.size()));
        assertThat(actual, contains(msgs.toArray()));
        @SuppressWarnings("unchecked")
        List<Msg> cacheActual = (List<Msg>) cacheHandler.get(key);
        assertThat(cacheActual, hasSize(msgs.size()));
        assertThat(cacheActual, contains(msgs.toArray()));
    }
    List<Msg> actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    Msg msg = msgs.get(0);
    msg.setContent("ash");
    dao.update(msg);
    assertThat(cacheHandler.get(key), nullValue());
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
}

@Test
public void testSingleKeyReturnList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    MsgDao dao = mango.create(MsgDao.class);
    int uid = 100;
    String key = getMsgKey(uid);
    for (int i = 0; i < 3; i++) {
        Msg msg = createRandomMsg(uid);
        msgs.add(msg);
        msg.setId(dao.insert(msg));
        assertThat(cacheHandler.get(key), nullValue());
        List<Msg> actual = dao.getMsgs(uid);
        assertThat(actual, hasSize(msgs.size()));
        assertThat(actual, contains(msgs.toArray()));
        @SuppressWarnings("unchecked")
        List<Msg> cacheActual = (List<Msg>) cacheHandler.get(key);
        assertThat(cacheActual, hasSize(msgs.size()));
        assertThat(cacheActual, contains(msgs.toArray()));
    }
    List<Msg> actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    Msg msg = msgs.get(0);
    msg.setContent("ash");
    dao.update(msg);
    assertThat(cacheHandler.get(key), nullValue());
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
}

@Test
public void testQueryEmpty() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    Config oldConfig = mango.getConfig();
    Config newConfig = new Config();
    newConfig.setCompatibleWithEmptyList(true);
    mango.setConfig(newConfig);
    assertThat(dao.getUserArray(new ArrayList<Integer>()).length, equalTo(0));
    mango.setConfig(oldConfig);
}

@Test
public void testQueryEmpty() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    Config oldConfig = mango.getConfig();
    Config newConfig = new Config();
    newConfig.setCompatibleWithEmptyList(true);
    mango.setConfig(newConfig);
    assertThat(dao.getUserArray(new ArrayList<Integer>()).length, equalTo(0));
    mango.setConfig(oldConfig);
}

@Test
public void testMultiKeysReturnArray() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    List<User> actual = Arrays.asList(dao.getUserArray(ids));
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    for (int i = 0; i < ids.size(); i++) {
        Integer id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    actual = Arrays.asList(dao.getUserArray(ids));
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    cacheHandler.delete(getUserKey(users.get(0).getId()));
    actual = Arrays.asList(dao.getUserArray(ids));
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testMultiKeysReturnArray() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    List<User> actual = Arrays.asList(dao.getUserArray(ids));
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    for (int i = 0; i < ids.size(); i++) {
        Integer id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    actual = Arrays.asList(dao.getUserArray(ids));
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    cacheHandler.delete(getUserKey(users.get(0).getId()));
    actual = Arrays.asList(dao.getUserArray(ids));
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testBatchUpdateEmpetyList() {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    List<User> users = Lists.newArrayList();
    assertThat(dao.batchUpdate(users).length, equalTo(0));
}

@Test
public void testBatchUpdateEmpetyList() {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    List<User> users = Lists.newArrayList();
    assertThat(dao.batchUpdate(users).length, equalTo(0));
}

@Test
public void testMultiKeysReturnList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    List<User> actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    for (int i = 0; i < ids.size(); i++) {
        Integer id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    cacheHandler.delete(getUserKey(users.get(0).getId()));
    actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testMultiKeysReturnList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    List<User> actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    for (int i = 0; i < ids.size(); i++) {
        Integer id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    cacheHandler.delete(getUserKey(users.get(0).getId()));
    actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testReturnLinkedList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    MsgDao dao = mango.create(MsgDao.class, cacheHandler);
    int uid = 100;
    String key = getMsgKey(uid);
    for (int i = 0; i < 3; i++) {
        Msg msg = createRandomMsg(uid);
        msgs.add(msg);
        msg.setId(dao.insert(msg));
        assertThat(cacheHandler.get(key), nullValue());
        LinkedList<Msg> actual = dao.getLinkedMsgs(uid);
        assertThat(actual, hasSize(msgs.size()));
        assertThat(actual, contains(msgs.toArray()));
        @SuppressWarnings("unchecked")
        LinkedList<Msg> cacheActual = (LinkedList<Msg>) cacheHandler.get(key);
        assertThat(cacheActual, hasSize(msgs.size()));
        assertThat(cacheActual, contains(msgs.toArray()));
    }
    LinkedList<Msg> actual = dao.getLinkedMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    Msg msg = msgs.get(0);
    msg.setContent("ash");
    dao.update(msg);
    assertThat(cacheHandler.get(key), nullValue());
    actual = dao.getLinkedMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getLinkedMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
}

@Test
public void testReturnLinkedList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    MsgDao dao = mango.create(MsgDao.class);
    int uid = 100;
    String key = getMsgKey(uid);
    for (int i = 0; i < 3; i++) {
        Msg msg = createRandomMsg(uid);
        msgs.add(msg);
        msg.setId(dao.insert(msg));
        assertThat(cacheHandler.get(key), nullValue());
        LinkedList<Msg> actual = dao.getLinkedMsgs(uid);
        assertThat(actual, hasSize(msgs.size()));
        assertThat(actual, contains(msgs.toArray()));
        @SuppressWarnings("unchecked")
        LinkedList<Msg> cacheActual = (LinkedList<Msg>) cacheHandler.get(key);
        assertThat(cacheActual, hasSize(msgs.size()));
        assertThat(cacheActual, contains(msgs.toArray()));
    }
    LinkedList<Msg> actual = dao.getLinkedMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    Msg msg = msgs.get(0);
    msg.setContent("ash");
    dao.update(msg);
    assertThat(cacheHandler.get(key), nullValue());
    actual = dao.getLinkedMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getLinkedMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
}

@Test
public void testReturnArrayList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    MsgDao dao = mango.create(MsgDao.class, cacheHandler);
    int uid = 100;
    String key = getMsgKey(uid);
    for (int i = 0; i < 3; i++) {
        Msg msg = createRandomMsg(uid);
        msgs.add(msg);
        msg.setId(dao.insert(msg));
        assertThat(cacheHandler.get(key), nullValue());
        ArrayList<Msg> actual = dao.getArrayMsgs(uid);
        assertThat(actual, hasSize(msgs.size()));
        assertThat(actual, contains(msgs.toArray()));
        @SuppressWarnings("unchecked")
        ArrayList<Msg> cacheActual = (ArrayList<Msg>) cacheHandler.get(key);
        assertThat(cacheActual, hasSize(msgs.size()));
        assertThat(cacheActual, contains(msgs.toArray()));
    }
    ArrayList<Msg> actual = dao.getArrayMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    Msg msg = msgs.get(0);
    msg.setContent("ash");
    dao.update(msg);
    assertThat(cacheHandler.get(key), nullValue());
    actual = dao.getArrayMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getArrayMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
}

@Test
public void testReturnArrayList() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    List<Msg> msgs = new ArrayList<Msg>();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    MsgDao dao = mango.create(MsgDao.class);
    int uid = 100;
    String key = getMsgKey(uid);
    for (int i = 0; i < 3; i++) {
        Msg msg = createRandomMsg(uid);
        msgs.add(msg);
        msg.setId(dao.insert(msg));
        assertThat(cacheHandler.get(key), nullValue());
        ArrayList<Msg> actual = dao.getArrayMsgs(uid);
        assertThat(actual, hasSize(msgs.size()));
        assertThat(actual, contains(msgs.toArray()));
        @SuppressWarnings("unchecked")
        ArrayList<Msg> cacheActual = (ArrayList<Msg>) cacheHandler.get(key);
        assertThat(cacheActual, hasSize(msgs.size()));
        assertThat(cacheActual, contains(msgs.toArray()));
    }
    ArrayList<Msg> actual = dao.getArrayMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    Msg msg = msgs.get(0);
    msg.setContent("ash");
    dao.update(msg);
    assertThat(cacheHandler.get(key), nullValue());
    actual = dao.getArrayMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
    msg = msgs.remove(0);
    dao.delete(msg.getUid(), msg.getId());
    actual = dao.getArrayMsgs(uid);
    assertThat(actual, hasSize(msgs.size()));
    assertThat(actual, contains(msgs.toArray()));
}

@Test
public void testBatchUpdate() {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    for (Integer id : ids) {
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
    }
    dao.getUserList(ids);
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    List<User> newUsers = new ArrayList<User>();
    String name = "ash";
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        User newUser = new User();
        newUser.setId(id);
        newUser.setName(name);
        newUsers.add(newUser);
        users.get(i).setName(name);
    }
    int[] r = dao.batchUpdate(newUsers);
    assertThat(r.length, greaterThan(0));
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
    }
    List<User> actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testBatchUpdate() {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    for (Integer id : ids) {
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
    }
    dao.getUserList(ids);
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    List<User> newUsers = new ArrayList<User>();
    String name = "ash";
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        User newUser = new User();
        newUser.setId(id);
        newUser.setName(name);
        newUsers.add(newUser);
        users.get(i).setName(name);
    }
    int[] r = dao.batchUpdate(newUsers);
    assertThat(r.length, greaterThan(0));
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
    }
    List<User> actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testMultiKeysReturnSet() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    Set<User> actual = dao.getUserSet(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    for (int i = 0; i < ids.size(); i++) {
        Integer id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    actual = dao.getUserSet(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    cacheHandler.delete(getUserKey(users.get(0).getId()));
    actual = dao.getUserSet(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testMultiKeysReturnSet() throws Exception {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    Set<User> actual = dao.getUserSet(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    for (int i = 0; i < ids.size(); i++) {
        Integer id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    actual = dao.getUserSet(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
    cacheHandler.delete(getUserKey(users.get(0).getId()));
    actual = dao.getUserSet(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testUpdateWithInStatement() {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    UserDao dao = mango.create(UserDao.class, cacheHandler);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    for (Integer id : ids) {
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
    }
    dao.getUserList(ids);
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    String name = "ash";
    int r = dao.updateWithInStatement(ids, name);
    assertThat(r, greaterThan(0));
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
        users.get(i).setName(name);
    }
    List<User> actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}

@Test
public void testUpdateWithInStatement() {
    LocalCacheHandler cacheHandler = new LocalCacheHandler();
    Mango mango = Mango.newInstance(ds);
    mango.setCacheHandler(cacheHandler);
    UserDao dao = mango.create(UserDao.class);
    List<User> users = createRandomUsers(5);
    List<Integer> ids = new ArrayList<Integer>();
    for (User user : users) {
        int id = dao.insert(user);
        user.setId(id);
        ids.add(id);
    }
    for (Integer id : ids) {
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
    }
    dao.getUserList(ids);
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        User user = users.get(i);
        assertThat((User) cacheHandler.get(getUserKey(id)), equalTo(user));
    }
    String name = "ash";
    int r = dao.updateWithInStatement(ids, name);
    assertThat(r, greaterThan(0));
    for (int i = 0; i < ids.size(); i++) {
        int id = ids.get(i);
        assertThat(cacheHandler.get(getUserKey(id)), nullValue());
        users.get(i).setName(name);
    }
    List<User> actual = dao.getUserList(ids);
    assertThat(actual, hasSize(users.size()));
    assertThat(actual, containsInAnyOrder(users.toArray()));
}


@Test
public void test() {
    thrown.expect(IllegalStateException.class);
    thrown.expectMessage("dao interface expected one @DB annotation but not found");
    mango.create(Dao.class);
}

@Test
public void test() {
    thrown.expect(IllegalStateException.class);
    thrown.expectMessage("dao interface expected one @DB annotation but not found");
    Mango mango = Mango.newInstance(DataSourceConfig.getDataSource());
    mango.setLazyInit(true);
    mango.create(Dao.class);
}

public Mango setLazyInit(boolean isLazyInit) {
    this.isLazyInit = isLazyInit;
    return this;
}

@Test
public void test3() {
    thrown.expect(IllegalStateException.class);
    thrown.expectMessage("if use cache, each method expected one or more " + "@CacheBy annotation on parameter but found 0");
    Dao3 dao = mango.create(Dao3.class, new LocalCacheHandler());
    dao.add();
}

@Test
public void test3() {
    thrown.expect(IllegalStateException.class);
    thrown.expectMessage("if use cache, each method expected one or more " + "@CacheBy annotation on parameter but found 0");
    Mango mango = Mango.newInstance(DataSourceConfig.getDataSource());
    mango.setLazyInit(true);
    mango.setCacheHandler(new LocalCacheHandler());
    Dao3 dao = mango.create(Dao3.class);
    dao.add();
}

@Test
public void test2() {
    thrown.expect(DescriptionException.class);
    thrown.expectMessage("each method expected one @SQL annotation but not found");
    Dao2 dao = mango.create(Dao2.class, new LocalCacheHandler());
    dao.add();
}

@Test
public void test2() {
    thrown.expect(DescriptionException.class);
    thrown.expectMessage("each method expected one @SQL annotation but not found");
    Mango mango = Mango.newInstance(DataSourceConfig.getDataSource());
    mango.setLazyInit(true);
    mango.setCacheHandler(new LocalCacheHandler());
    Dao2 dao = mango.create(Dao2.class);
    dao.add();
}


@Test
public void test2() {
    thrown.expect(IncorrectCacheByException.class);
    thrown.expectMessage("CacheBy :1 can't match any db parameter");
    Dao dao = mango.create(Dao.class, new LocalCacheHandler());
    dao.batchAdd(new ArrayList<Integer>());
}

@Test
public void test2() {
    thrown.expect(IncorrectCacheByException.class);
    thrown.expectMessage("CacheBy :1 can't match any db parameter");
    Dao dao = mango.create(Dao.class);
    dao.batchAdd(new ArrayList<Integer>());
}

public <T> T create(Class<T> daoClass) {
    return create(daoClass, defaultCacheHandler, isDefaultLazyInit);
}

public <T> T create(Class<T> daoClass) {
    if (daoClass == null) {
        throw new NullPointerException("dao interface can't be null");
    }
    if (!daoClass.isInterface()) {
        throw new IllegalArgumentException("expected an interface to proxy, but " + daoClass);
    }
    DB dbAnno = daoClass.getAnnotation(DB.class);
    if (dbAnno == null) {
        throw new IllegalStateException("dao interface expected one @DB " + "annotation but not found");
    }
    Cache cacheAnno = daoClass.getAnnotation(Cache.class);
    if (cacheAnno != null && cacheHandler == null) {
        throw new IllegalStateException("if @Cache annotation on dao interface, " + "cacheHandler can't be null");
    }
    if (dataSourceFactory == null) {
        throw new IllegalArgumentException("dataSourceFactory can't be null");
    }
    MangoInvocationHandler handler = new MangoInvocationHandler(this, cacheHandler);
    if (!isLazyInit) {
        Method[] methods = daoClass.getMethods();
        for (Method method : methods) {
            try {
                handler.getOperator(method);
            } catch (Throwable e) {
                throw new InitializationException("initialize " + ToStringHelper.toString(method) + " error", e);
            }
        }
    }
    return Reflection.newProxy(daoClass, handler);
}

@Test
public void test() {
    thrown.expect(IncorrectCacheByException.class);
    thrown.expectMessage("CacheBy :2 can't match any db parameter");
    Dao dao = mango.create(Dao.class, new LocalCacheHandler());
    dao.add(1, 2);
}

@Test
public void test() {
    thrown.expect(IncorrectCacheByException.class);
    thrown.expectMessage("CacheBy :2 can't match any db parameter");
    Dao dao = mango.create(Dao.class);
    dao.add(1, 2);
}


@Test
public void testIterableParameterNullWithCache() {
    thrown.expect(BindingException.class);
    thrown.expectMessage("Parameter ':1' need a non-null value");
    MsgCacheDao dao = mango.create(MsgCacheDao.class, new LocalCacheHandler());
    dao.getMsgs(null);
}

@Test
public void testIterableParameterNullWithCache() {
    thrown.expect(BindingException.class);
    thrown.expectMessage("Parameter ':1' need a non-null value");
    Mango mango = Mango.newInstance(ds);
    mango.setLazyInit(true);
    mango.setCacheHandler(new LocalCacheHandler());
    MsgCacheDao dao = mango.create(MsgCacheDao.class);
    dao.getMsgs(null);
}

public <T> T create(Class<T> daoClass, @Nullable CacheHandler cacheHandler) {
    return create(daoClass, cacheHandler, isDefaultLazyInit);
}


@Test
public void testGenericException2() throws Exception {
    thrown.expect(ClassCastException.class);
    thrown.expectMessage("TableShardingStrategy[class org.jfaster.mango.sharding.ShardingExceptionTest$UserTableShardingStrategy]'s generic type[class java.lang.String] must be assignable from the type of parameter Modified @TableShardingBy [long], please note that @ShardingBy = @TableShardingBy + @DatabaseShardingBy");
    UserDao2 dao = mango.create(UserDao2.class, true);
    dao.getUser(1);
}

@Test
public void testGenericException2() throws Exception {
    thrown.expect(ClassCastException.class);
    thrown.expectMessage("TableShardingStrategy[class org.jfaster.mango.sharding.ShardingExceptionTest$UserTableShardingStrategy]'s generic type[class java.lang.String] must be assignable from the type of parameter Modified @TableShardingBy [long], please note that @ShardingBy = @TableShardingBy + @DatabaseShardingBy");
    UserDao2 dao = mango.create(UserDao2.class);
    dao.getUser(1);
}

public <T> T create(Class<T> daoClass, boolean isLazyInit) {
    return create(daoClass, defaultCacheHandler, isLazyInit);
}

@Test
public void testGenericException() throws Exception {
    thrown.expect(ClassCastException.class);
    thrown.expectMessage("DatabaseShardingStrategy[class org.jfaster.mango.sharding.ShardingExceptionTest$UserDatabaseShardingStrategy]'s generic type[class java.lang.String] must be assignable from the type of parameter Modified @DatabaseShardingBy [long], please note that @ShardingBy = @TableShardingBy + @DatabaseShardingBy");
    UserDao dao = mango.create(UserDao.class, true);
    dao.getUser(1);
}

@Test
public void testGenericException() throws Exception {
    thrown.expect(ClassCastException.class);
    thrown.expectMessage("DatabaseShardingStrategy[class org.jfaster.mango.sharding.ShardingExceptionTest$UserDatabaseShardingStrategy]'s generic type[class java.lang.String] must be assignable from the type of parameter Modified @DatabaseShardingBy [long], please note that @ShardingBy = @TableShardingBy + @DatabaseShardingBy");
    UserDao dao = mango.create(UserDao.class);
    dao.getUser(1);
}


@Test
void knownTags() {
    TagSet tags = TagSet.Html();
    Tag custom = new Tag("custom");
    assertEquals("custom", custom.name());
    assertEquals(NamespaceHtml, custom.namespace());
    assertFalse(custom.isKnownTag());
    Tag br = tags.get("br", NamespaceHtml);
    assertNotNull(br);
    assertTrue(br.isKnownTag());
    assertSame(br, tags.valueOf("br", NamespaceHtml));
    Tag foo = tags.valueOf("foo", NamespaceHtml);
    assertFalse(foo.isKnownTag());
    tags.add(custom);
    assertTrue(custom.isKnownTag());
    assertSame(custom, tags.get("custom", NamespaceHtml));
    assertSame(custom, tags.valueOf("custom", NamespaceHtml));
    Tag capCustom = tags.valueOf("Custom", NamespaceHtml);
    assertTrue(capCustom.isKnownTag());
    Tag c1 = new Tag("bar");
    assertFalse(c1.isKnownTag());
    c1.set(Tag.Block);
    assertTrue(c1.isKnownTag());
    c1.clear(Tag.Block);
    assertTrue(c1.isKnownTag());
    c1.clear(Tag.Defined);
    assertFalse(c1.isKnownTag());
}

@Test
void knownTags() {
    TagSet tags = TagSet.Html();
    Tag custom = new Tag("custom");
    assertEquals("custom", custom.name());
    assertEquals(NamespaceHtml, custom.namespace());
    assertFalse(custom.isKnownTag());
    Tag br = tags.get("br", NamespaceHtml);
    assertNotNull(br);
    assertTrue(br.isKnownTag());
    assertSame(br, tags.valueOf("br", NamespaceHtml));
    Tag foo = tags.valueOf("foo", NamespaceHtml);
    assertFalse(foo.isKnownTag());
    tags.add(custom);
    assertTrue(custom.isKnownTag());
    assertSame(custom, tags.get("custom", NamespaceHtml));
    assertSame(custom, tags.valueOf("custom", NamespaceHtml));
    Tag capCustom = tags.valueOf("Custom", NamespaceHtml);
    assertTrue(capCustom.isKnownTag());
    Tag c1 = new Tag("bar");
    assertFalse(c1.isKnownTag());
    c1.set(Tag.Block);
    assertTrue(c1.isKnownTag());
    c1.clear(Tag.Block);
    assertTrue(c1.isKnownTag());
    c1.clear(Tag.Known);
    assertFalse(c1.isKnownTag());
}

public TagSet add(Tag tag) {
    tag.set(Tag.Defined);
    doAdd(tag);
    return this;
}

public TagSet add(Tag tag) {
    tag.set(Tag.Known);
    doAdd(tag);
    return this;
}


@Test
public void orphanDivToString() {
    Element orphan = new Element("div").id("foo").text("Hello");
    assertEquals("
\n Hello\n
", orphan.toString());
}

@Test
public void orphanDivToString() {
    Element orphan = new Element("div").id("foo").text("Hello");
    assertEquals("
Hello
", orphan.toString());
}

public Element text(String text) {
    Validate.notNull(text);
    empty();
    Document owner = ownerDocument();
    if (owner != null && owner.parser().isContentForTagData(normalName()))
        appendChild(new DataNode(text));
    else
        appendChild(new TextNode(text));
    return this;
}

public Element text(String text) {
    Validate.notNull(text);
    empty();
    if (tag().is(Tag.Data))
        appendChild(new DataNode(text));
    else
        appendChild(new TextNode(text));
    return this;
}

@Test
public void insertChildrenAsCopy() {
    Document doc = Jsoup.parse("
Text
One
 Text
Two

");
    Element div1 = doc.select("div").get(0);
    Element div2 = doc.select("div").get(1);
    Elements ps = doc.select("p").clone();
    ps.first().text("One cloned");
    div2.insertChildren(-1, ps);
    assertEquals(4, div1.childNodeSize());
    assertEquals(2, div2.childNodeSize());
    assertEquals("
Text
One
 Text
Two

One cloned

Two

", TextUtil.stripNewlines(doc.body().html()));
}

@Test
public void insertChildrenAsCopy() {
    Document doc = Jsoup.parse("
Text
One
 Text
Two

");
    Element div1 = doc.select("div").get(0);
    Element div2 = doc.select("div").get(1);
    Elements ps = doc.select("p").clone();
    ps.first().text("One cloned");
    div2.insertChildren(-1, ps);
    assertEquals(4, div1.childNodeSize());
    assertEquals(2, div2.childNodeSize());
    assertEquals("
\n Text\n
One
\n Text\n
Two
\n
\n
\n
One cloned
\n
Two
\n
", doc.body().html());
}

@Test
void outerHtmlAppendable() {
    Document doc = Jsoup.parse("
One
");
    StringBuffer buffer = new StringBuffer();
    doc.body().outerHtml(buffer);
    assertEquals("\n\n
\n  One\n
\n", buffer.toString());
    StringBuilder builder = new StringBuilder();
    doc.body().outerHtml(builder);
    assertEquals("\n
\n  One\n
\n", builder.toString());
}

@Test
void outerHtmlAppendable() {
    Document doc = Jsoup.parse("
One
");
    StringBuffer buffer = new StringBuffer();
    doc.body().outerHtml(buffer);
    assertEquals("\n
One
\n", buffer.toString());
    StringBuilder builder = new StringBuilder();
    doc.body().outerHtml(builder);
    assertEquals("\n
One
\n", builder.toString());
}

protected void outerHtml(Appendable accum) {
    NodeTraversor.traverse(new OuterHtmlVisitor(accum, NodeUtils.outputSettings(this)), this);
}

protected void outerHtml(Appendable accum) {
    Printer printer = Printer.printerFor(this, accum);
    NodeTraversor.traverse(printer, this);
}

@Test
public void testShadowElementsAreUpdated() {
    String html = "

One

Two
Three
Four<foo></foo>";
    Document doc = Jsoup.parse(html);
    Element div = doc.select("div").first();
    Elements els = div.children();
    List<Node> nodes = div.childNodes();
    assertEquals(2, els.size());
    assertEquals(3, nodes.size());
    Element p3 = new Element("p").text("P3");
    Element p4 = new Element("p").text("P4");
    div.insertChildren(1, p3);
    div.insertChildren(3, p4);
    Elements els2 = div.children();
    assertEquals(2, els.size());
    assertEquals(4, els2.size());
    assertEquals("
One
\n" + "
P3
\n" + "
Two
\n" + "
P4
Three", div.html());
    assertEquals("P3", els2.get(1).text());
    assertEquals("P4", els2.get(3).text());
    p3.after("Another</span");
    Elements els3 = div.children();
    assertEquals(5, els3.size());
    assertEquals("span", els3.get(2).tagName());
    assertEquals("Another", els3.get(2).text());
    assertEquals("
One
\n" + "
P3
Another\n" + "
Two
\n" + "
P4
Three", div.html());
}

@Test
public void testShadowElementsAreUpdated() {
    String html = "

One

Two
Three
Four<foo></foo>";
    Document doc = Jsoup.parse(html);
    Element div = doc.select("div").first();
    Elements els = div.children();
    List<Node> nodes = div.childNodes();
    assertEquals(2, els.size());
    assertEquals(3, nodes.size());
    Element p3 = new Element("p").text("P3");
    Element p4 = new Element("p").text("P4");
    div.insertChildren(1, p3);
    div.insertChildren(3, p4);
    Elements els2 = div.children();
    assertEquals(2, els.size());
    assertEquals(4, els2.size());
    assertEquals("
One
\n" + "
P3
\n" + "
Two
\n" + "
P4
\nThree", div.html());
    assertEquals("P3", els2.get(1).text());
    assertEquals("P4", els2.get(3).text());
    p3.after("Another</span");
    Elements els3 = div.children();
    assertEquals(5, els3.size());
    assertEquals("span", els3.get(2).tagName());
    assertEquals("Another", els3.get(2).text());
    assertEquals("
One
\n" + "
P3
\n" + "Another\n" + "
Two
\n" + "
P4
\n" + "Three", div.html());
}


@Test
public void pSemantics() {
    Tag p = Tag.valueOf("p");
    assertTrue(p.isBlock());
    assertFalse(p.formatAsBlock());
}

@Test
public void pSemantics() {
    Tag p = Tag.valueOf("p");
    assertTrue(p.isKnownTag());
    assertTrue(p.isBlock());
    assertFalse(p.isInline());
}

public boolean isInline() {
    return !isBlock;
}

public boolean isInline() {
    return (options & Block) == 0;
}

@Test
public void defaultSemantics() {
    Tag foo = Tag.valueOf("FOO");
    Tag foo2 = Tag.valueOf("FOO");
    assertEquals(foo, foo2);
    assertTrue(foo.isInline());
    assertTrue(foo.formatAsBlock());
}

@Test
public void defaultSemantics() {
    Tag foo = Tag.valueOf("FOO");
    Tag foo2 = Tag.valueOf("FOO");
    assertEquals(foo, foo2);
    assertFalse(foo.isKnownTag());
    assertTrue(foo.isInline());
    assertFalse(foo.isBlock());
    assertFalse(foo.is(Tag.InlineContainer));
    assertFalse(foo.preserveWhitespace());
}

public boolean is(int option) {
    return (options & option) != 0;
}

@Test
public void equality() {
    Tag p1 = Tag.valueOf("p");
    Tag p2 = Tag.valueOf("p");
    assertEquals(p1, p2);
    assertSame(p1, p2);
}

@Test
public void equality() {
    Tag p1 = Tag.valueOf("p");
    Tag p2 = Tag.valueOf("p");
    assertEquals(p1, p2);
    assertNotSame(p1, p2);
    TagSet html1 = TagSet.Html();
    TagSet html2 = TagSet.Html();
    assertEquals(html1, html2);
    assertNotSame(html1, html2);
    Tag p3 = html1.valueOf("p", NamespaceHtml);
    Tag p4 = html1.valueOf("p", NamespaceHtml);
    Tag p5 = html2.valueOf("p", NamespaceHtml);
    Tag p6 = html2.valueOf("p", NamespaceHtml);
    assertEquals(p1, p3);
    assertEquals(p3, p4);
    assertEquals(p4, p5);
    assertSame(p3, p4);
    assertSame(p5, p6);
    assertNotSame(p3, p5);
}

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (!(o instanceof Tag))
        return false;
    Tag tag = (Tag) o;
    if (!tagName.equals(tag.tagName))
        return false;
    if (empty != tag.empty)
        return false;
    if (formatAsBlock != tag.formatAsBlock)
        return false;
    if (isBlock != tag.isBlock)
        return false;
    if (preserveWhitespace != tag.preserveWhitespace)
        return false;
    if (selfClosing != tag.selfClosing)
        return false;
    if (formList != tag.formList)
        return false;
    return formSubmit == tag.formSubmit;
}

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (!(o instanceof Tag))
        return false;
    Tag tag = (Tag) o;
    return Objects.equals(tagName, tag.tagName) && Objects.equals(namespace, tag.namespace) && Objects.equals(normalName, tag.normalName) && options == tag.options;
}

@Test
public void divSemantics() {
    Tag div = Tag.valueOf("div");
    assertTrue(div.isBlock());
    assertTrue(div.formatAsBlock());
}

@Test
public void divSemantics() {
    Tag div = Tag.valueOf("div");
    assertTrue(div.isBlock());
    assertFalse(div.isInline());
    assertTrue(div.isKnownTag());
}


@Test
public void preservesRelativeLinksIfConfigured() {
    String html = "Link ";
    String clean = Jsoup.clean(html, "http://example.com/", Safelist.basicWithImages().preserveRelativeLinks(true));
    assertEquals("Link ", clean);
}

public static String clean(String bodyHtml, String baseUri, Safelist safelist) {
    Document dirty = parseBodyFragment(bodyHtml, baseUri);
    Cleaner cleaner = new Cleaner(safelist);
    Document clean = cleaner.clean(dirty);
    return clean.body().html();
}

public static String clean(String bodyHtml, String baseUri, Safelist safelist) {
    if (baseUri.isEmpty() && safelist.preserveRelativeLinks()) {
        baseUri = DummyUri;
    }
    Document dirty = parseBodyFragment(bodyHtml, baseUri);
    Cleaner cleaner = new Cleaner(safelist);
    Document clean = cleaner.clean(dirty);
    return clean.body().html();
}

@Test
public void resolvesRelativeLinks() {
    String html = "Link";
    String clean = Jsoup.clean(html, "http://example.com/", Safelist.basicWithImages());
    assertEquals("Link", clean);
}


@Test
public void testSizeWhenHasInternal() {
    Attributes a = new Attributes();
    a.put("One", "One");
    a.put("Two", "Two");
    assertEquals(2, a.size());
    a.put(Attributes.internalKey("baseUri"), "example.com");
    a.put(Attributes.internalKey("another"), "example.com");
    a.put(Attributes.internalKey("last"), "example.com");
    a.remove(Attributes.internalKey("last"));
    assertEquals(4, a.size());
    assertEquals(2, a.asList().size());
}

@Test
public void testSizeWhenHasInternal() {
    Attributes a = new Attributes();
    a.put("One", "One");
    a.put("Two", "Two");
    assertEquals(2, a.size());
    a.put(Attributes.internalKey("baseUri"), "example.com");
    a.put(Attributes.internalKey("another"), "example.com");
    a.put(Attributes.internalKey("last"), "example.com");
    a.remove(Attributes.internalKey("last"));
    assertEquals(2, a.size());
    assertEquals(2, a.asList().size());
}

public int size() {
    if (size == 0)
        return 0;
    int count = 0;
    for (int i = 0; i < size; i++) {
        if (!isInternalKey(keys[i]))
            count++;
    }
    return count;
}


@Test
public void testInterfaceFiltering() {
    Collection<Class<?>> interfaces = new AnnotatedInterfaceStrategy(true).withFilters(inter -> inter != One.class).getInterfaces(GenericTypeReflector.annotate(Three.class)).stream().map(inter -> ClassUtils.getRawType(inter.getType())).collect(Collectors.toList());
    assertTrue(interfaces.containsAll(Arrays.asList(Zero.class, Two.class, Three.class)));
}

@Test
public void testInterfaceFiltering() {
    Collection<Class<?>> interfaces = new AnnotatedInterfaceStrategy().withFilters(inter -> inter != One.class).getInterfaces(GenericTypeReflector.annotate(Three.class)).stream().map(inter -> ClassUtils.getRawType(inter.getType())).collect(Collectors.toList());
    assertEquals(3, interfaces.size());
    assertTrue(interfaces.containsAll(Arrays.asList(Zero.class, Two.class, Three.class)));
}

@SafeVarargs
public final AbstractInterfaceMappingStrategy withFilters(Predicate<Class>... filters) {
    Collections.addAll(this.filters, filters);
    return this;
}

@SafeVarargs
public final AbstractInterfaceMappingStrategy withFilters(Predicate<Class>... filters) {
    this.filter = this.filter.and(Arrays.stream(filters).reduce(Predicate::and).orElseGet(Utils::acceptAll));
    return this;
}


@Test
public void badBasePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder("bad.package");
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(new ResolverBuilderParams(new UserHandleService(), GenericTypeReflector.annotate(UserHandleService.class), INCLUSION_STRATEGY, TYPE_TRANSFORMER, BASE_PACKAGES, ENVIRONMENT)));
    assertEquals(1, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
}

@Test
public void badBasePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder("bad.package");
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(ResolverBuilderParams.builder().withQuerySourceBean(new UserHandleService()).withBeanType(GenericTypeReflector.annotate(UserHandleService.class)).withInclusionStrategy(INCLUSION_STRATEGY).withTypeTransformer(TYPE_TRANSFORMER).withBasePackages(BASE_PACKAGES).withEnvironment(ENVIRONMENT).build()));
    assertEquals(1, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
}

public Builder withBasePackages(String[] basePackages) {
    this.basePackages = basePackages;
    return this;
}

@Test
public void basePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder(BASE_PACKAGES);
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(new ResolverBuilderParams(new UserHandleService(), GenericTypeReflector.annotate(UserHandleService.class), INCLUSION_STRATEGY, TYPE_TRANSFORMER, BASE_PACKAGES, ENVIRONMENT)));
    assertEquals(2, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getNickname")));
}

@Test
public void basePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder(BASE_PACKAGES);
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(ResolverBuilderParams.builder().withQuerySourceBean(new UserHandleService()).withBeanType(GenericTypeReflector.annotate(UserHandleService.class)).withInclusionStrategy(INCLUSION_STRATEGY).withTypeTransformer(TYPE_TRANSFORMER).withBasePackages(BASE_PACKAGES).withEnvironment(ENVIRONMENT).build()));
    assertEquals(2, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getNickname")));
}


@Test
public void bridgeMethodTest() {
    Collection<Resolver> resolvers = new PublicResolverBuilder(BASE_PACKAGES).buildQueryResolvers(new ResolverBuilderParams(new BaseServiceImpl<Number, String>(), new TypeToken<BaseServiceImpl<Number, String>>() {
    }.getAnnotatedType(), INCLUSION_STRATEGY, TYPE_TRANSFORMER, BASE_PACKAGES, ENVIRONMENT));
    assertEquals(1, resolvers.size());
    assertEquals(resolvers.iterator().next().getReturnType().getType(), Number.class);
}

@Test
public void bridgeMethodTest() {
    Collection<Resolver> resolvers = new PublicResolverBuilder(BASE_PACKAGES).buildQueryResolvers(ResolverBuilderParams.builder().withQuerySourceBean(new BaseServiceImpl<Number, String>()).withBeanType(new TypeToken<BaseServiceImpl<Number, String>>() {
    }.getAnnotatedType()).withInclusionStrategy(INCLUSION_STRATEGY).withTypeTransformer(TYPE_TRANSFORMER).withBasePackages(BASE_PACKAGES).withEnvironment(ENVIRONMENT).build());
    assertEquals(1, resolvers.size());
    assertEquals(resolvers.iterator().next().getReturnType().getType(), Number.class);
}

public ResolverBuilderParams build() {
    return new ResolverBuilderParams(querySourceBean, beanType, inclusionStrategy, typeTransformer, basePackages, environment);
}


@Test
public void badBasePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder("bad.package");
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(ResolverBuilderParams.builder().withQuerySourceBean(new UserHandleService()).withBeanType(GenericTypeReflector.annotate(UserHandleService.class)).withInclusionStrategy(INCLUSION_STRATEGY).withTypeTransformer(TYPE_TRANSFORMER).withBasePackages(BASE_PACKAGES).withEnvironment(ENVIRONMENT).build()));
    assertEquals(1, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
}

@Test
public void badBasePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder("bad.package");
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(new ResolverBuilderParams(new UserHandleService(), GenericTypeReflector.annotate(UserHandleService.class), INCLUSION_STRATEGY, TYPE_TRANSFORMER, BASE_PACKAGES, ENVIRONMENT)));
    assertEquals(1, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
}

public Builder withBasePackages(String[] basePackages) {
    this.basePackages = basePackages;
    return this;
}

@Test
public void basePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder(BASE_PACKAGES);
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(ResolverBuilderParams.builder().withQuerySourceBean(new UserHandleService()).withBeanType(GenericTypeReflector.annotate(UserHandleService.class)).withInclusionStrategy(INCLUSION_STRATEGY).withTypeTransformer(TYPE_TRANSFORMER).withBasePackages(BASE_PACKAGES).withEnvironment(ENVIRONMENT).build()));
    assertEquals(2, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getNickname")));
}

@Test
public void basePackageTest() {
    PublicResolverBuilder resolverBuilder = new PublicResolverBuilder(BASE_PACKAGES);
    List<Resolver> resolvers = new ArrayList<>(resolverBuilder.buildQueryResolvers(new ResolverBuilderParams(new UserHandleService(), GenericTypeReflector.annotate(UserHandleService.class), INCLUSION_STRATEGY, TYPE_TRANSFORMER, BASE_PACKAGES, ENVIRONMENT)));
    assertEquals(2, resolvers.size());
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getUserHandle")));
    assertTrue(resolvers.stream().anyMatch(resolver -> resolver.getOperationName().equals("getNickname")));
}


@Test
public void bridgeMethodTest() {
    Collection<Resolver> resolvers = new PublicResolverBuilder(BASE_PACKAGES).buildQueryResolvers(ResolverBuilderParams.builder().withQuerySourceBean(new BaseServiceImpl<Number, String>()).withBeanType(new TypeToken<BaseServiceImpl<Number, String>>() {
    }.getAnnotatedType()).withInclusionStrategy(INCLUSION_STRATEGY).withTypeTransformer(TYPE_TRANSFORMER).withBasePackages(BASE_PACKAGES).withEnvironment(ENVIRONMENT).build());
    assertEquals(1, resolvers.size());
    assertEquals(resolvers.iterator().next().getReturnType().getType(), Number.class);
}

@Test
public void bridgeMethodTest() {
    Collection<Resolver> resolvers = new PublicResolverBuilder(BASE_PACKAGES).buildQueryResolvers(new ResolverBuilderParams(new BaseServiceImpl<Number, String>(), new TypeToken<BaseServiceImpl<Number, String>>() {
    }.getAnnotatedType(), INCLUSION_STRATEGY, TYPE_TRANSFORMER, BASE_PACKAGES, ENVIRONMENT));
    assertEquals(1, resolvers.size());
    assertEquals(resolvers.iterator().next().getReturnType().getType(), Number.class);
}

public ResolverBuilderParams build() {
    return new ResolverBuilderParams(querySourceBean, beanType, inclusionStrategy, typeTransformer, basePackages, environment);
}


@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer.getWords(), bitmap2.buffer.getWords());
}

@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer, bitmap2.buffer);
}

public boolean setSizeInBits(final int size, final boolean defaultValue) {
    if (size <= this.sizeInBits) {
        return false;
    }
    if ((this.sizeInBits % WORD_IN_BITS) != 0) {
        if (!defaultValue) {
            if (this.rlw.getNumberOfLiteralWords() > 0) {
                final int bitsToAdd = size - this.sizeInBits;
                final int usedBitsInLast = this.sizeInBits % WORD_IN_BITS;
                final int freeBitsInLast = WORD_IN_BITS - usedBitsInLast;
                if (this.buffer.getLastWord() == 0l) {
                    this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                    this.buffer.removeLastWord();
                    this.sizeInBits -= usedBitsInLast;
                } else if (usedBitsInLast > 0) {
                    this.sizeInBits += Math.min(bitsToAdd, freeBitsInLast);
                }
            }
        } else {
            if (this.rlw.getNumberOfLiteralWords() == 0) {
                this.rlw.setRunningLength(this.rlw.getRunningLength() - 1);
                insertLiteralWord(0);
            }
            final int maskWidth = Math.min(WORD_IN_BITS - this.sizeInBits % WORD_IN_BITS, size - this.sizeInBits);
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            final long mask = ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            this.buffer.orLastWord(mask);
            if (this.buffer.getLastWord() == ~0l) {
                this.buffer.removeLastWord();
                this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                insertEmptyWord(true);
            }
            this.sizeInBits += maskWidth;
        }
    }
    this.addStreamOfEmptyWords(defaultValue, (size / WORD_IN_BITS) - (this.sizeInBits / WORD_IN_BITS));
    if (this.sizeInBits < size) {
        final int dist = distanceInWords(size - 1);
        if (dist > 0) {
            insertLiteralWord(0);
        }
        if (defaultValue) {
            final int maskWidth = size - this.sizeInBits;
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            final long mask = ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            this.buffer.orLastWord(mask);
        }
        this.sizeInBits = size;
    }
    return true;
}

public boolean setSizeInBits(final int size, final boolean defaultValue) {
    if (size <= this.sizeInBits) {
        return false;
    }
    if ((this.sizeInBits % WORD_IN_BITS) != 0) {
        if (!defaultValue) {
            if (this.rlw.getNumberOfLiteralWords() > 0) {
                final int bitsToAdd = size - this.sizeInBits;
                final int usedBitsInLast = this.sizeInBits % WORD_IN_BITS;
                final int freeBitsInLast = WORD_IN_BITS - usedBitsInLast;
                if (this.buffer[this.actualSizeInWords - 1] == 0l) {
                    this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                    this.actualSizeInWords--;
                    this.sizeInBits -= usedBitsInLast;
                } else if (usedBitsInLast > 0) {
                    this.sizeInBits += Math.min(bitsToAdd, freeBitsInLast);
                }
            }
        } else {
            if (this.rlw.getNumberOfLiteralWords() == 0) {
                this.rlw.setRunningLength(this.rlw.getRunningLength() - 1);
                insertLiteralWord(0);
            }
            final int maskWidth = Math.min(WORD_IN_BITS - this.sizeInBits % WORD_IN_BITS, size - this.sizeInBits);
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            this.buffer[this.actualSizeInWords - 1] |= ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            if (this.buffer[this.actualSizeInWords - 1] == ~0l) {
                this.buffer[this.actualSizeInWords - 1] = 0;
                --this.actualSizeInWords;
                this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                insertEmptyWord(true);
            }
            this.sizeInBits += maskWidth;
        }
    }
    this.addStreamOfEmptyWords(defaultValue, (size / WORD_IN_BITS) - (this.sizeInBits / WORD_IN_BITS));
    if (this.sizeInBits < size) {
        final int dist = distanceInWords(size - 1);
        if (dist > 0) {
            insertLiteralWord(0);
        }
        if (defaultValue) {
            final int maskWidth = size - this.sizeInBits;
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            this.buffer[this.actualSizeInWords - 1] |= ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
        }
        this.sizeInBits = size;
    }
    return true;
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer.getWords(), bitmap2.buffer.getWords());
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer, bitmap2.buffer);
}


@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap32 bitmap1 = EWAHCompressedBitmap32.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap32 bitmap2 = EWAHCompressedBitmap32.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer.getWords(), bitmap2.buffer.getWords());
}

@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap32 bitmap1 = EWAHCompressedBitmap32.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap32 bitmap2 = EWAHCompressedBitmap32.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer, bitmap2.buffer);
}

public boolean setSizeInBits(final int size, final boolean defaultValue) {
    if (size <= this.sizeInBits) {
        return false;
    }
    if ((this.sizeInBits % WORD_IN_BITS) != 0) {
        if (!defaultValue) {
            if (this.rlw.getNumberOfLiteralWords() > 0) {
                final int bitsToAdd = size - this.sizeInBits;
                final int usedBitsInLast = this.sizeInBits % WORD_IN_BITS;
                final int freeBitsInLast = WORD_IN_BITS - usedBitsInLast;
                if (this.buffer.getLastWord() == 0) {
                    this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                    this.buffer.removeLastWord();
                    this.sizeInBits -= usedBitsInLast;
                } else if (usedBitsInLast > 0) {
                    this.sizeInBits += Math.min(bitsToAdd, freeBitsInLast);
                }
            }
        } else {
            if (this.rlw.getNumberOfLiteralWords() == 0) {
                this.rlw.setRunningLength(this.rlw.getRunningLength() - 1);
                insertLiteralWord(0);
            }
            final int maskWidth = Math.min(WORD_IN_BITS - this.sizeInBits % WORD_IN_BITS, size - this.sizeInBits);
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            final int mask = ((~0) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            this.buffer.orLastWord(mask);
            if (this.buffer.getLastWord() == ~0) {
                this.buffer.removeLastWord();
                this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                insertEmptyWord(true);
            }
            this.sizeInBits += maskWidth;
        }
    }
    this.addStreamOfEmptyWords(defaultValue, (size / WORD_IN_BITS) - (this.sizeInBits / WORD_IN_BITS));
    if (this.sizeInBits < size) {
        final int dist = distanceInWords(size - 1);
        if (dist > 0) {
            insertLiteralWord(0);
        }
        if (defaultValue) {
            final int maskWidth = size - this.sizeInBits;
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            final int mask = ((~0) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            this.buffer.orLastWord(mask);
        }
        this.sizeInBits = size;
    }
    return true;
}

public boolean setSizeInBits(final int size, final boolean defaultValue) {
    if (size <= this.sizeInBits) {
        return false;
    }
    if ((this.sizeInBits % WORD_IN_BITS) != 0) {
        if (!defaultValue) {
            if (this.rlw.getNumberOfLiteralWords() > 0) {
                final int bitsToAdd = size - this.sizeInBits;
                final int usedBitsInLast = this.sizeInBits % WORD_IN_BITS;
                final int freeBitsInLast = WORD_IN_BITS - usedBitsInLast;
                if (this.buffer[this.actualSizeInWords - 1] == 0) {
                    this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                    this.actualSizeInWords--;
                    this.sizeInBits -= usedBitsInLast;
                } else if (usedBitsInLast > 0) {
                    this.sizeInBits += Math.min(bitsToAdd, freeBitsInLast);
                }
            }
        } else {
            if (this.rlw.getNumberOfLiteralWords() == 0) {
                this.rlw.setRunningLength(this.rlw.getRunningLength() - 1);
                insertLiteralWord(0);
            }
            final int maskWidth = Math.min(WORD_IN_BITS - this.sizeInBits % WORD_IN_BITS, size - this.sizeInBits);
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            this.buffer[this.actualSizeInWords - 1] |= ((~0) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            if (this.buffer[this.actualSizeInWords - 1] == (~0)) {
                this.buffer[this.actualSizeInWords - 1] = 0;
                --this.actualSizeInWords;
                this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                insertEmptyWord(true);
            }
            this.sizeInBits += maskWidth;
        }
    }
    this.addStreamOfEmptyWords(defaultValue, (size / WORD_IN_BITS) - (this.sizeInBits / WORD_IN_BITS));
    if (this.sizeInBits < size) {
        final int dist = distanceInWords(size - 1);
        if (dist > 0) {
            insertLiteralWord(0);
        }
        if (defaultValue) {
            final int maskWidth = size - this.sizeInBits;
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            this.buffer[this.actualSizeInWords - 1] |= ((~0) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
        }
        this.sizeInBits = size;
    }
    return true;
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap32 bitmap1 = EWAHCompressedBitmap32.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap32 bitmap2 = EWAHCompressedBitmap32.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer.getWords(), bitmap2.buffer.getWords());
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap32 bitmap1 = EWAHCompressedBitmap32.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap32 bitmap2 = EWAHCompressedBitmap32.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer, bitmap2.buffer);
}


@SuppressWarnings({ "deprecation", "boxing" })
@Test
public void OKaserBugReportJuly2013() {
    System.out.println("testing OKaserBugReportJuly2013");
    int[][] data = { {}, { 5, 6, 7, 8, 9 }, { 1 }, { 2 }, { 2, 5, 7 }, { 1 }, { 2 }, { 1, 6, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 6, 8, 9 }, { 2, 5, 7 }, { 2, 5, 7 }, { 1, 3, 9 }, { 3, 8, 9 } };
    EWAHCompressedBitmap[] toBeOred = new EWAHCompressedBitmap[data.length];
    Set<Integer> bruteForceAnswer = new HashSet<Integer>();
    for (int i = 0; i < toBeOred.length; ++i) {
        toBeOred[i] = new EWAHCompressedBitmap();
        for (int j : data[i]) {
            toBeOred[i].set(j);
            bruteForceAnswer.add(j);
        }
        toBeOred[i].setSizeInBits(1000, false);
    }
    long rightcard = bruteForceAnswer.size();
    EWAHCompressedBitmap e1 = FastAggregation.or(toBeOred);
    Assert.assertEquals(rightcard, e1.cardinality());
    EWAHCompressedBitmap e2 = FastAggregation.bufferedor(65536, toBeOred);
    Assert.assertEquals(rightcard, e2.cardinality());
    EWAHCompressedBitmap foo = new EWAHCompressedBitmap();
    FastAggregation.legacy_orWithContainer(foo, toBeOred);
    Assert.assertEquals(rightcard, foo.cardinality());
}

@SuppressWarnings({ "deprecation", "boxing" })
@Test
public void OKaserBugReportJuly2013() {
    System.out.println("testing OKaserBugReportJuly2013");
    int[][] data = { {}, { 5, 6, 7, 8, 9 }, { 1 }, { 2 }, { 2, 5, 7 }, { 1 }, { 2 }, { 1, 6, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 6, 8, 9 }, { 2, 5, 7 }, { 2, 5, 7 }, { 1, 3, 9 }, { 3, 8, 9 } };
    EWAHCompressedBitmap[] toBeOred = new EWAHCompressedBitmap[data.length];
    Set<Integer> bruteForceAnswer = new HashSet<Integer>();
    for (int i = 0; i < toBeOred.length; ++i) {
        toBeOred[i] = new EWAHCompressedBitmap();
        for (int j : data[i]) {
            toBeOred[i].set(j);
            bruteForceAnswer.add(j);
        }
        toBeOred[i].setSizeInBits(1000, false);
    }
    long rightcard = bruteForceAnswer.size();
    EWAHCompressedBitmap e1 = FastAggregation.or(toBeOred);
    Assert.assertEquals(rightcard, e1.cardinality());
    EWAHCompressedBitmap e2 = FastAggregation.bufferedor(65536, toBeOred);
    Assert.assertEquals(rightcard, e2.cardinality());
    EWAHCompressedBitmap foo = new EWAHCompressedBitmap();
    FastAggregation.orToContainer(foo, toBeOred);
    Assert.assertEquals(rightcard, foo.cardinality());
}

@Deprecated
public static void legacy_orWithContainer(final BitmapStorage container, final EWAHCompressedBitmap... bitmaps) {
    if (bitmaps.length == 2) {
        bitmaps[0].orToContainer(bitmaps[1], container);
        return;
    }
    final EWAHCompressedBitmap[] sortedBitmaps = bitmaps.clone();
    Arrays.sort(sortedBitmaps, new Comparator<EWAHCompressedBitmap>() {

        @Override
        public int compare(EWAHCompressedBitmap a, EWAHCompressedBitmap b) {
            return a.sizeInBits() < b.sizeInBits() ? 1 : a.sizeInBits() == b.sizeInBits() ? 0 : -1;
        }
    });
    final IteratingBufferedRunningLengthWord[] rlws = new IteratingBufferedRunningLengthWord[bitmaps.length];
    int maxAvailablePos = 0;
    for (EWAHCompressedBitmap bitmap : sortedBitmaps) {
        EWAHIterator iterator = bitmap.getEWAHIterator();
        if (iterator.hasNext()) {
            rlws[maxAvailablePos++] = new IteratingBufferedRunningLengthWord(iterator);
        }
    }
    if (maxAvailablePos == 0) {
        container.setSizeInBitsWithinLastWord(0);
        return;
    }
    int maxSize = sortedBitmaps[0].sizeInBits();
    while (true) {
        long maxOneRl = 0;
        long minZeroRl = Long.MAX_VALUE;
        long minSize = Long.MAX_VALUE;
        int numEmptyRl = 0;
        for (int i = 0; i < maxAvailablePos; i++) {
            IteratingBufferedRunningLengthWord rlw = rlws[i];
            long size = rlw.size();
            if (size == 0) {
                maxAvailablePos = i;
                break;
            }
            minSize = Math.min(minSize, size);
            if (rlw.getRunningBit()) {
                long rl = rlw.getRunningLength();
                maxOneRl = Math.max(maxOneRl, rl);
                minZeroRl = 0;
                if (rl == 0 && size > 0) {
                    numEmptyRl++;
                }
            } else {
                long rl = rlw.getRunningLength();
                minZeroRl = Math.min(minZeroRl, rl);
                if (rl == 0 && size > 0) {
                    numEmptyRl++;
                }
            }
        }
        if (maxAvailablePos == 0) {
            break;
        } else if (maxAvailablePos == 1) {
            rlws[0].discharge(container);
            break;
        }
        if (maxOneRl > 0) {
            container.addStreamOfEmptyWords(true, maxOneRl);
            for (int i = 0; i < maxAvailablePos; i++) {
                IteratingBufferedRunningLengthWord rlw = rlws[i];
                rlw.discardFirstWords(maxOneRl);
            }
        } else if (minZeroRl > 0) {
            container.addStreamOfEmptyWords(false, minZeroRl);
            for (int i = 0; i < maxAvailablePos; i++) {
                IteratingBufferedRunningLengthWord rlw = rlws[i];
                rlw.discardFirstWords(minZeroRl);
            }
        } else {
            int index = 0;
            if (numEmptyRl == 1) {
                IteratingBufferedRunningLengthWord emptyRl = null;
                long minNonEmptyRl = Long.MAX_VALUE;
                for (int i = 0; i < maxAvailablePos; i++) {
                    IteratingBufferedRunningLengthWord rlw = rlws[i];
                    long rl = rlw.getRunningLength();
                    if (rl == 0) {
                        assert emptyRl == null;
                        emptyRl = rlw;
                    } else {
                        minNonEmptyRl = Math.min(minNonEmptyRl, rl);
                    }
                }
                long wordsToWrite = minNonEmptyRl > minSize ? minSize : minNonEmptyRl;
                if (emptyRl != null)
                    emptyRl.writeLiteralWords((int) wordsToWrite, container);
                index += wordsToWrite;
            }
            while (index < minSize) {
                long word = 0;
                for (int i = 0; i < maxAvailablePos; i++) {
                    IteratingBufferedRunningLengthWord rlw = rlws[i];
                    if (rlw.getRunningLength() <= index) {
                        word |= rlw.getLiteralWordAt(index - (int) rlw.getRunningLength());
                    }
                }
                container.addWord(word);
                index++;
            }
            for (int i = 0; i < maxAvailablePos; i++) {
                IteratingBufferedRunningLengthWord rlw = rlws[i];
                rlw.discardFirstWords(minSize);
            }
        }
    }
    container.setSizeInBitsWithinLastWord(maxSize);
}


@SuppressWarnings("deprecation")
@Test
public void testWideOr() {
    for (int nbr = 3; nbr <= 24; nbr += 3) {
        for (int N = 100; N < 1000; N += 100) {
            System.out.println("testWideOr N = " + N);
            Iterator<EWAHCompressedBitmap[]> i = getCollections(N, 3);
            while (i.hasNext()) {
                EWAHCompressedBitmap[] x = i.next();
                EWAHCompressedBitmap tanswer = EWAHCompressedBitmap.or(x);
                EWAHCompressedBitmap container = new EWAHCompressedBitmap();
                FastAggregation.legacy_orWithContainer(container, x);
                assertTrue(container.equals(tanswer));
                EWAHCompressedBitmap x1 = IteratorUtil.materialize(IteratorAggregation.bufferedor(IteratorUtil.toIterators(x)));
                assertTrue(x1.equals(tanswer));
            }
            System.gc();
        }
    }
}

@SuppressWarnings("deprecation")
@Test
public void testWideOr() {
    for (int nbr = 3; nbr <= 24; nbr += 3) {
        for (int N = 100; N < 1000; N += 100) {
            System.out.println("testWideOr N = " + N);
            Iterator<EWAHCompressedBitmap[]> i = getCollections(N, 3);
            while (i.hasNext()) {
                EWAHCompressedBitmap[] x = i.next();
                EWAHCompressedBitmap tanswer = EWAHCompressedBitmap.or(x);
                EWAHCompressedBitmap container = new EWAHCompressedBitmap();
                FastAggregation.orToContainer(container, x);
                assertTrue(container.equals(tanswer));
                EWAHCompressedBitmap x1 = IteratorUtil.materialize(IteratorAggregation.bufferedor(IteratorUtil.toIterators(x)));
                assertTrue(x1.equals(tanswer));
            }
            System.gc();
        }
    }
}


@SuppressWarnings({ "deprecation", "boxing" })
@Test
public void OKaserBugReportJuly2013() {
    System.out.println("testing OKaserBugReportJuly2013");
    int[][] data = { {}, { 5, 6, 7, 8, 9 }, { 1 }, { 2 }, { 2, 5, 7 }, { 1 }, { 2 }, { 1, 6, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 6, 8, 9 }, { 2, 5, 7 }, { 2, 5, 7 }, { 1, 3, 9 }, { 3, 8, 9 } };
    EWAHCompressedBitmap32[] toBeOred = new EWAHCompressedBitmap32[data.length];
    Set<Integer> bruteForceAnswer = new HashSet<Integer>();
    for (int i = 0; i < toBeOred.length; ++i) {
        toBeOred[i] = new EWAHCompressedBitmap32();
        for (int j : data[i]) {
            toBeOred[i].set(j);
            bruteForceAnswer.add(j);
        }
        toBeOred[i].setSizeInBits(1000, false);
    }
    long rightcard = bruteForceAnswer.size();
    EWAHCompressedBitmap32 foo = new EWAHCompressedBitmap32();
    FastAggregation32.legacy_orWithContainer(foo, toBeOred);
    Assert.assertEquals(rightcard, foo.cardinality());
    EWAHCompressedBitmap32 e1 = FastAggregation.or(toBeOred);
    Assert.assertEquals(rightcard, e1.cardinality());
    EWAHCompressedBitmap32 e2 = FastAggregation32.bufferedor(65536, toBeOred);
    Assert.assertEquals(rightcard, e2.cardinality());
}

@SuppressWarnings({ "deprecation", "boxing" })
@Test
public void OKaserBugReportJuly2013() {
    System.out.println("testing OKaserBugReportJuly2013");
    int[][] data = { {}, { 5, 6, 7, 8, 9 }, { 1 }, { 2 }, { 2, 5, 7 }, { 1 }, { 2 }, { 1, 6, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 4, 6, 8, 9 }, { 1, 3, 6, 8, 9 }, { 2, 5, 7 }, { 2, 5, 7 }, { 1, 3, 9 }, { 3, 8, 9 } };
    EWAHCompressedBitmap32[] toBeOred = new EWAHCompressedBitmap32[data.length];
    Set<Integer> bruteForceAnswer = new HashSet<Integer>();
    for (int i = 0; i < toBeOred.length; ++i) {
        toBeOred[i] = new EWAHCompressedBitmap32();
        for (int j : data[i]) {
            toBeOred[i].set(j);
            bruteForceAnswer.add(j);
        }
        toBeOred[i].setSizeInBits(1000, false);
    }
    long rightcard = bruteForceAnswer.size();
    EWAHCompressedBitmap32 foo = new EWAHCompressedBitmap32();
    FastAggregation32.orToContainer(foo, toBeOred);
    Assert.assertEquals(rightcard, foo.cardinality());
    EWAHCompressedBitmap32 e1 = FastAggregation.or(toBeOred);
    Assert.assertEquals(rightcard, e1.cardinality());
    EWAHCompressedBitmap32 e2 = FastAggregation32.bufferedor(65536, toBeOred);
    Assert.assertEquals(rightcard, e2.cardinality());
}

@Deprecated
public static void legacy_orWithContainer(final BitmapStorage32 container, final EWAHCompressedBitmap32... bitmaps) {
    if (bitmaps.length == 2) {
        bitmaps[0].orToContainer(bitmaps[1], container);
        return;
    }
    final EWAHCompressedBitmap32[] sortedBitmaps = bitmaps.clone();
    Arrays.sort(sortedBitmaps, new Comparator<EWAHCompressedBitmap32>() {

        @Override
        public int compare(EWAHCompressedBitmap32 a, EWAHCompressedBitmap32 b) {
            return a.sizeInBits() < b.sizeInBits() ? 1 : a.sizeInBits() == b.sizeInBits() ? 0 : -1;
        }
    });
    final IteratingBufferedRunningLengthWord32[] rlws = new IteratingBufferedRunningLengthWord32[bitmaps.length];
    int maxAvailablePos = 0;
    for (EWAHCompressedBitmap32 bitmap : sortedBitmaps) {
        EWAHIterator32 iterator = bitmap.getEWAHIterator();
        if (iterator.hasNext()) {
            rlws[maxAvailablePos++] = new IteratingBufferedRunningLengthWord32(iterator);
        }
    }
    if (maxAvailablePos == 0) {
        container.setSizeInBitsWithinLastWord(0);
        return;
    }
    int maxSize = sortedBitmaps[0].sizeInBits();
    while (true) {
        int maxOneRl = 0;
        int minZeroRl = Integer.MAX_VALUE;
        int minSize = Integer.MAX_VALUE;
        int numEmptyRl = 0;
        for (int i = 0; i < maxAvailablePos; i++) {
            IteratingBufferedRunningLengthWord32 rlw = rlws[i];
            int size = rlw.size();
            if (size == 0) {
                maxAvailablePos = i;
                break;
            }
            minSize = Math.min(minSize, size);
            if (rlw.getRunningBit()) {
                int rl = rlw.getRunningLength();
                maxOneRl = Math.max(maxOneRl, rl);
                minZeroRl = 0;
                if (rl == 0 && size > 0) {
                    numEmptyRl++;
                }
            } else {
                int rl = rlw.getRunningLength();
                minZeroRl = Math.min(minZeroRl, rl);
                if (rl == 0 && size > 0) {
                    numEmptyRl++;
                }
            }
        }
        if (maxAvailablePos == 0) {
            break;
        } else if (maxAvailablePos == 1) {
            rlws[0].discharge(container);
            break;
        }
        if (maxOneRl > 0) {
            container.addStreamOfEmptyWords(true, maxOneRl);
            for (int i = 0; i < maxAvailablePos; i++) {
                IteratingBufferedRunningLengthWord32 rlw = rlws[i];
                rlw.discardFirstWords(maxOneRl);
            }
        } else if (minZeroRl > 0) {
            container.addStreamOfEmptyWords(false, minZeroRl);
            for (int i = 0; i < maxAvailablePos; i++) {
                IteratingBufferedRunningLengthWord32 rlw = rlws[i];
                rlw.discardFirstWords(minZeroRl);
            }
        } else {
            int index = 0;
            if (numEmptyRl == 1) {
                IteratingBufferedRunningLengthWord32 emptyRl = null;
                int minNonEmptyRl = Integer.MAX_VALUE;
                for (int i = 0; i < maxAvailablePos; i++) {
                    IteratingBufferedRunningLengthWord32 rlw = rlws[i];
                    int rl = rlw.getRunningLength();
                    if (rl == 0) {
                        assert emptyRl == null;
                        emptyRl = rlw;
                    } else {
                        minNonEmptyRl = Math.min(minNonEmptyRl, rl);
                    }
                }
                int wordsToWrite = minNonEmptyRl > minSize ? minSize : minNonEmptyRl;
                if (emptyRl != null)
                    emptyRl.writeLiteralWords(wordsToWrite, container);
                index += wordsToWrite;
            }
            while (index < minSize) {
                int word = 0;
                for (int i = 0; i < maxAvailablePos; i++) {
                    IteratingBufferedRunningLengthWord32 rlw = rlws[i];
                    if (rlw.getRunningLength() <= index) {
                        word |= rlw.getLiteralWordAt(index - rlw.getRunningLength());
                    }
                }
                container.addWord(word);
                index++;
            }
            for (int i = 0; i < maxAvailablePos; i++) {
                IteratingBufferedRunningLengthWord32 rlw = rlws[i];
                rlw.discardFirstWords(minSize);
            }
        }
    }
    container.setSizeInBitsWithinLastWord(maxSize);
}


@SuppressWarnings("deprecation")
@Test
public void testWideOr() {
    for (int nbr = 3; nbr <= 24; nbr += 3) {
        for (int N = 100; N < 1000; N += 100) {
            System.out.println("testWideOr N = " + N);
            Iterator<EWAHCompressedBitmap32[]> i = getCollections(N, 3);
            while (i.hasNext()) {
                EWAHCompressedBitmap32[] x = i.next();
                EWAHCompressedBitmap32 tanswer = EWAHCompressedBitmap32.or(x);
                EWAHCompressedBitmap32 container = new EWAHCompressedBitmap32();
                FastAggregation32.legacy_orWithContainer(container, x);
                assertTrue(container.equals(tanswer));
                EWAHCompressedBitmap32 x1 = IteratorUtil32.materialize(IteratorAggregation32.bufferedor(IteratorUtil32.toIterators(x)));
                assertTrue(x1.equals(tanswer));
            }
            System.gc();
        }
    }
}

@SuppressWarnings("deprecation")
@Test
public void testWideOr() {
    for (int nbr = 3; nbr <= 24; nbr += 3) {
        for (int N = 100; N < 1000; N += 100) {
            System.out.println("testWideOr N = " + N);
            Iterator<EWAHCompressedBitmap32[]> i = getCollections(N, 3);
            while (i.hasNext()) {
                EWAHCompressedBitmap32[] x = i.next();
                EWAHCompressedBitmap32 tanswer = EWAHCompressedBitmap32.or(x);
                EWAHCompressedBitmap32 container = new EWAHCompressedBitmap32();
                FastAggregation32.orToContainer(container, x);
                assertTrue(container.equals(tanswer));
                EWAHCompressedBitmap32 x1 = IteratorUtil32.materialize(IteratorAggregation32.bufferedor(IteratorUtil32.toIterators(x)));
                assertTrue(x1.equals(tanswer));
            }
            System.gc();
        }
    }
}


@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertEquals(bitmap1.buffer.sizeInWords(), bitmap2.buffer.sizeInWords());
    for (int i = 0; i < bitmap1.buffer.sizeInWords(); i++) {
        Assert.assertEquals(bitmap1.buffer.getWord(i), bitmap2.buffer.getWord(i));
    }
}

@Override
public long[] getWords() {
    return this.buffer;
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertEquals(bitmap1.buffer.sizeInWords(), bitmap2.buffer.sizeInWords());
    for (int i = 0; i < bitmap1.buffer.sizeInWords(); i++) {
        Assert.assertEquals(bitmap1.buffer.getWord(i), bitmap2.buffer.getWord(i));
    }
}


@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap32 bitmap1 = EWAHCompressedBitmap32.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap32 bitmap2 = EWAHCompressedBitmap32.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertEquals(bitmap1.buffer.sizeInWords(), bitmap2.buffer.sizeInWords());
    for (int i = 0; i < bitmap1.buffer.sizeInWords(); i++) {
        Assert.assertEquals(bitmap1.buffer.getWord(i), bitmap2.buffer.getWord(i));
    }
}

@Override
public int[] getWords() {
    return this.buffer;
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap32 bitmap1 = EWAHCompressedBitmap32.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap32 bitmap2 = EWAHCompressedBitmap32.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertEquals(bitmap1.buffer.sizeInWords(), bitmap2.buffer.sizeInWords());
    for (int i = 0; i < bitmap1.buffer.sizeInWords(); i++) {
        Assert.assertEquals(bitmap1.buffer.getWord(i), bitmap2.buffer.getWord(i));
    }
}


@Test
public void testsetSizeInBits() {
    System.out.println("testing setSizeInBits");
    for (int k = 0; k < 4096; ++k) {
        EWAHCompressedBitmap ewah = new EWAHCompressedBitmap();
        ewah.setSizeInBits(k, false);
        Assert.assertEquals(ewah.sizeInBits, k);
        Assert.assertEquals(ewah.cardinality(), 0);
        EWAHCompressedBitmap ewah2 = new EWAHCompressedBitmap();
        ewah2.setSizeInBits(k, false);
        Assert.assertEquals(ewah2.sizeInBits, k);
        Assert.assertEquals(ewah2.cardinality(), 0);
        EWAHCompressedBitmap ewah3 = new EWAHCompressedBitmap();
        for (int i = 0; i < k; ++i) {
            ewah3.set(i);
        }
        Assert.assertEquals(ewah3.sizeInBits, k);
        Assert.assertEquals(ewah3.cardinality(), k);
        EWAHCompressedBitmap ewah4 = new EWAHCompressedBitmap();
        ewah4.setSizeInBits(k, true);
        Assert.assertEquals(ewah4.sizeInBits, k);
        Assert.assertEquals(ewah4.cardinality(), k);
    }
}

@Test
public void testsetSizeInBits() {
    System.out.println("testing setSizeInBits");
    for (int k = 0; k < 4096; ++k) {
        EWAHCompressedBitmap ewah = new EWAHCompressedBitmap();
        ewah.setSizeInBits(k, false);
        Assert.assertEquals(ewah.sizeInBits(), k);
        Assert.assertEquals(ewah.cardinality(), 0);
        EWAHCompressedBitmap ewah2 = new EWAHCompressedBitmap();
        ewah2.setSizeInBits(k, false);
        Assert.assertEquals(ewah2.sizeInBits(), k);
        Assert.assertEquals(ewah2.cardinality(), 0);
        EWAHCompressedBitmap ewah3 = new EWAHCompressedBitmap();
        for (int i = 0; i < k; ++i) {
            ewah3.set(i);
        }
        Assert.assertEquals(ewah3.sizeInBits(), k);
        Assert.assertEquals(ewah3.cardinality(), k);
        EWAHCompressedBitmap ewah4 = new EWAHCompressedBitmap();
        ewah4.setSizeInBits(k, true);
        Assert.assertEquals(ewah4.sizeInBits(), k);
        Assert.assertEquals(ewah4.cardinality(), k);
    }
}

public boolean setSizeInBits(final int size, final boolean defaultValue) {
    if (size <= this.sizeInBits) {
        return false;
    }
    if ((this.sizeInBits % WORD_IN_BITS) != 0) {
        if (!defaultValue) {
            if (this.rlw.getNumberOfLiteralWords() > 0) {
                final int bitsToAdd = size - this.sizeInBits;
                final int usedBitsInLast = this.sizeInBits % WORD_IN_BITS;
                final int freeBitsInLast = WORD_IN_BITS - usedBitsInLast;
                if (this.buffer[this.actualSizeInWords - 1] == 0l) {
                    this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                    this.actualSizeInWords--;
                    this.sizeInBits -= usedBitsInLast;
                } else if (usedBitsInLast > 0) {
                    this.sizeInBits += Math.min(bitsToAdd, freeBitsInLast);
                }
            }
        } else {
            if (this.rlw.getNumberOfLiteralWords() == 0) {
                this.rlw.setRunningLength(this.rlw.getRunningLength() - 1);
                insertLiteralWord(0);
            }
            final int maskWidth = Math.min(WORD_IN_BITS - this.sizeInBits % WORD_IN_BITS, size - this.sizeInBits);
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            this.buffer[this.actualSizeInWords - 1] |= ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            if (this.buffer[this.actualSizeInWords - 1] == ~0l) {
                this.buffer[this.actualSizeInWords - 1] = 0;
                --this.actualSizeInWords;
                this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                insertEmptyWord(true);
            }
            this.sizeInBits += maskWidth;
        }
    }
    this.addStreamOfEmptyWords(defaultValue, (size / WORD_IN_BITS) - (this.sizeInBits / WORD_IN_BITS));
    if (this.sizeInBits < size) {
        final int dist = distanceInWords(size - 1);
        if (dist > 0) {
            insertLiteralWord(0);
        }
        if (defaultValue) {
            final int maskWidth = size - this.sizeInBits;
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            this.buffer[this.actualSizeInWords - 1] |= ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
        }
        this.sizeInBits = size;
    }
    return true;
}

public boolean setSizeInBits(final int size, final boolean defaultValue) {
    if (size <= this.sizeInBits) {
        return false;
    }
    if ((this.sizeInBits % WORD_IN_BITS) != 0) {
        if (!defaultValue) {
            if (this.rlw.getNumberOfLiteralWords() > 0) {
                final int bitsToAdd = size - this.sizeInBits;
                final int usedBitsInLast = this.sizeInBits % WORD_IN_BITS;
                final int freeBitsInLast = WORD_IN_BITS - usedBitsInLast;
                if (this.buffer.getLastWord() == 0l) {
                    this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                    this.buffer.removeLastWord();
                    this.sizeInBits -= usedBitsInLast;
                } else if (usedBitsInLast > 0) {
                    this.sizeInBits += Math.min(bitsToAdd, freeBitsInLast);
                }
            }
        } else {
            if (this.rlw.getNumberOfLiteralWords() == 0) {
                this.rlw.setRunningLength(this.rlw.getRunningLength() - 1);
                insertLiteralWord(0);
            }
            final int maskWidth = Math.min(WORD_IN_BITS - this.sizeInBits % WORD_IN_BITS, size - this.sizeInBits);
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            final long mask = ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            this.buffer.orLastWord(mask);
            if (this.buffer.getLastWord() == ~0l) {
                this.buffer.removeLastWord();
                this.rlw.setNumberOfLiteralWords(this.rlw.getNumberOfLiteralWords() - 1);
                insertEmptyWord(true);
            }
            this.sizeInBits += maskWidth;
        }
    }
    this.addStreamOfEmptyWords(defaultValue, (size / WORD_IN_BITS) - (this.sizeInBits / WORD_IN_BITS));
    if (this.sizeInBits < size) {
        final int dist = distanceInWords(size - 1);
        if (dist > 0) {
            insertLiteralWord(0);
        }
        if (defaultValue) {
            final int maskWidth = size - this.sizeInBits;
            final int maskShift = this.sizeInBits % WORD_IN_BITS;
            final long mask = ((~0l) >>> (WORD_IN_BITS - maskWidth)) << maskShift;
            this.buffer.orLastWord(mask);
        }
        this.sizeInBits = size;
    }
    return true;
}

@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer, bitmap2.buffer);
}

@Test
public void compareSetAndSetSizeInBits2() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = 0; i < WORD_IN_BITS / 2; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS; i < WORD_IN_BITS * 3 / 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, true);
    bitmap2.setSizeInBits(WORD_IN_BITS, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer.getWords(), bitmap2.buffer.getWords());
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer, bitmap2.buffer);
}

@Test
public void compareSetAndSetSizeInBits() {
    EWAHCompressedBitmap bitmap1 = EWAHCompressedBitmap.bitmapOf();
    for (int i = WORD_IN_BITS / 2; i < WORD_IN_BITS; ++i) {
        bitmap1.set(i);
    }
    for (int i = WORD_IN_BITS * 3 / 2; i < WORD_IN_BITS * 2; ++i) {
        bitmap1.set(i);
    }
    EWAHCompressedBitmap bitmap2 = EWAHCompressedBitmap.bitmapOf();
    bitmap2.setSizeInBits(WORD_IN_BITS / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS, true);
    bitmap2.setSizeInBits(WORD_IN_BITS * 3 / 2, false);
    bitmap2.setSizeInBits(WORD_IN_BITS * 2, true);
    Assert.assertEquals(bitmap1, bitmap2);
    Assert.assertArrayEquals(bitmap1.buffer.getWords(), bitmap2.buffer.getWords());
}