TEST(TestLocatedBlocks, TestFindBlock) {
// repro GPSQL-3051
LocatedBlocksImpl *lbs = new LocatedBlocksImpl();

// one element in blocks
lbs->setFileLength(10*1024+500);
LocatedBlock *blk = new LocatedBlock(10240);
blk->setNumBytes(500);
lbs->getBlocks().push_back(*blk);
const LocatedBlock *lb = lbs->findBlock(10239);
EXPECT_TRUE(lb == NULL);
lb = lbs->findBlock(10240);
EXPECT_TRUE(lb->getOffset() == blk->getOffset());
EXPECT_TRUE(lb->getNumBytes() == blk->getNumBytes());

lbs->getBlocks().clear();
// 3 elements in blocks
lbs->setFileLength(1024*2+100);
LocatedBlock *blk1 = new LocatedBlock(0);
blk1->setNumBytes(1024);
LocatedBlock *blk2 = new LocatedBlock(1024);
blk2->setNumBytes(1024);
LocatedBlock *blk3 = new LocatedBlock(2048);
blk3->setNumBytes(100);
lbs->getBlocks().push_back(*blk1);
lbs->getBlocks().push_back(*blk2);
lbs->getBlocks().push_back(*blk3);

lb = lbs->findBlock(-100);
EXPECT_TRUE(lb == NULL);
lb = lbs->findBlock(0);
EXPECT_TRUE(lb->getOffset() == 0);
lb = lbs->findBlock(100);
EXPECT_TRUE(lb->getOffset() == 0);
lb = lbs->findBlock(1023);
EXPECT_TRUE(lb->getOffset() == 0);
lb = lbs->findBlock(1024);
EXPECT_TRUE(lb->getOffset() == 1024);
lb = lbs->findBlock(1024+100);
EXPECT_TRUE(lb->getOffset() == 1024);
lb = lbs->findBlock(2047);
EXPECT_TRUE(lb->getOffset() == 1024);
lb = lbs->findBlock(2047);
EXPECT_TRUE(lb->getOffset() == 1024);
lb = lbs->findBlock(2048);
EXPECT_TRUE(lb->getOffset() == 2048);
lb = lbs->findBlock(2048+100-1);
EXPECT_TRUE(lb->getOffset() == 2048);

lb = lbs->findBlock(2048+100);
EXPECT_TRUE(lb == NULL);
lb = lbs->findBlock(2048+1000);
EXPECT_TRUE(lb == NULL);

delete blk;
delete blk1;
delete blk2;
delete blk3;
delete lbs;
}
const LocatedBlock * LocatedBlocksImpl::findBlock(int64_t position) {
    if (position < fileLength) {
        LocatedBlock target(position);
        std::vector<LocatedBlock>::iterator bound;

        if (blocks.empty() || position < blocks.begin()->getOffset()) {
            return NULL;
        }

        /*
         * bound is first block which start offset is larger than
         * or equal to position
         */
        bound = std::lower_bound(blocks.begin(), blocks.end(), target,
                                 std::less<LocatedBlock>());
        assert(bound == blocks.end() || bound->getOffset() >= position);
        LocatedBlock * retval = NULL;

        if (bound == blocks.end()) {
            retval = &blocks.back();
        } else if (bound->getOffset() > position) {
            assert(bound != blocks.begin());
            --bound;
            retval = &(*bound);
        } else {
            retval = &(*bound);
        }

        if (position < retval->getOffset()
                || position >= retval->getOffset() + retval->getNumBytes()) {
            return NULL;
        }

        return retval;
    } else {
        return lastBlock.get();
    }
}