Hi Loic, I merged this in, which two small changes: - the malloc ULLONG_MAX tests were succeeding and eating RAM on my box; commented them out. - the BIG_SZ buffer on teh stack was segfaulting; put it on the heap. Otherwise, looks great! I'm very pleased to have test coverage on this code. :) sage On Sun, 17 Feb 2013, Loic Dachary wrote: > Implement unit tests covering most lines of code ( > 92% ) and all > methods as show by the output of make check-coverage : > http://dachary.org/wp-uploads/2013/03/ceph-lcov/ . > > The following static constructors are implemented by opaque classes > defined in buffer.cc ( buffer::raw_char, buffer::raw_posix_aligned > etc. ). Testing the implementation of these classes is done by > variations of the calls to the static constructors. > > copy(const char *c, unsigned len); > create(unsigned len); > claim_char(unsigned len, char *buf); > create_malloc(unsigned len); > claim_malloc(unsigned len, char *buf); > create_static(unsigned len, char *buf); > create_page_aligned(unsigned len); > > The raw_mmap_pages class cannot be tested because it is commented out in > raw_posix_aligned. The raw_hack_aligned class is only tested under Cygwin. > The raw_posix_aligned class is not tested under Cygwin. > > The unittest_bufferlist.sh script calls unittest_bufferlist with the > CEPH_BUFFER_TRACK=true environment variable to enable the code > tracking the memory usage. It cannot be done within the bufferlist.cc > file itself because it relies on the initialization of a global > variable ( buffer_track_alloc ). > > When raw_posix_aligned is called on DARWIN, the data is not aligned > on CEPH_PAGE_SIZE because it calls valloc(size) which is the equivalent of > memalign(sysconf(_SC_PAGESIZE),size) and not memalign(CEPH_PAGE_SIZE,size). > For this reason the alignment test is de-activated on DARWIN. > > The tests are grouped in > > TEST(BufferPtr, ... ) for buffer::ptr > TEST(BufferListIterator, ...) for buffer::list::iterator > TEST(BufferList, ...) for buffer::list > TEST(BufferHash, ...) for buffer::hash > > and each method ( and all variations of the prototype ) are > included into a single TEST() function. > > Although most aspects of the methods are tested, including exceptions > and border cases, inconsistencies are not highlighted . For > instance > > buffer::list::iterator i; > i.advance(1); > > would dereference a buffer::raw NULL pointer although > > buffer::ptr p; > p.wasted() > > asserts instead of dereferencing the buffer::raw NULL pointer. It > would be better to always assert in case a NULL pointer is about to be > used. But this is a minor inconsistency that is probably not worth a > test. > > The following buffer::list methods > > ssize_t read_fd(int fd, size_t len); > int write_fd(int fd) const; > > are not fully tested because the border cases cannot be reliably > reproduced. Going thru a pointer indirection when calling the ::writev > or safe_read functions would allow the test to create mockups to synthetize > the conditions for border cases. > > tracker.ceph.com/issues/4066 refs #4066 > > Signed-off-by: Loic Dachary <loic@xxxxxxxxxxx> > --- > src/Makefile.am | 5 +- > src/test/bufferlist.cc | 1801 +++++++++++++++++++++++++++++++++++++++++--- > src/unittest_bufferlist.sh | 19 + > 3 files changed, 1731 insertions(+), 94 deletions(-) > create mode 100755 src/unittest_bufferlist.sh > > diff --git a/src/Makefile.am b/src/Makefile.am > index 556de51..1725588 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -19,7 +19,8 @@ EXTRA_DIST = \ > libs3/libs3.spec \ > libs3/mswin \ > libs3/src \ > - libs3/test > + libs3/test \ > + unittest_bufferlist.sh > > CLEANFILES = > bin_PROGRAMS = > @@ -38,7 +39,7 @@ check_PROGRAMS = > # tests to actually run on "make check"; if you need extra, non-test, > # executables built, you need to replace this with manual assignments > # target by target > -TESTS = $(check_PROGRAMS) > +TESTS = $(check_PROGRAMS) unittest_bufferlist.sh > > check-local: > $(srcdir)/test/encoding/check-generated.sh > diff --git a/src/test/bufferlist.cc b/src/test/bufferlist.cc > index 7abced1..6f8ba19 100644 > --- a/src/test/bufferlist.cc > +++ b/src/test/bufferlist.cc > @@ -1,77 +1,1650 @@ > +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- > +// vim: ts=8 sw=2 smarttab > +/* > + * Ceph - scalable distributed file system > + * > + * Copyright (C) 2013 Cloudwatt <libre.licensing@xxxxxxxxxxxxx> > + * > + * Author: Loic Dachary <loic@xxxxxxxxxxx> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU Library Public License as published by > + * the Free Software Foundation; either version 2, or (at your option) > + * any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU Library Public License for more details. > + * > + */ > + > #include <tr1/memory> > +#include <limits.h> > +#include <errno.h> > +#include <sys/uio.h> > > #include "include/buffer.h" > #include "include/encoding.h" > +#include "common/environment.h" > > #include "gtest/gtest.h" > #include "stdlib.h" > - > +#include "fcntl.h" > +#include "sys/stat.h" > > #define MAX_TEST 1000000 > > -TEST(BufferPtr, cmp) { > - bufferptr empty; > - bufferptr a("A", 1); > - bufferptr ab("AB", 2); > - bufferptr af("AF", 2); > - bufferptr acc("ACC", 3); > - EXPECT_GE(-1, empty.cmp(a)); > - EXPECT_LE(1, a.cmp(empty)); > - EXPECT_GE(-1, a.cmp(ab)); > - EXPECT_LE(1, ab.cmp(a)); > - EXPECT_EQ(0, ab.cmp(ab)); > - EXPECT_GE(-1, ab.cmp(af)); > - EXPECT_LE(1, af.cmp(ab)); > - EXPECT_GE(-1, acc.cmp(af)); > - EXPECT_LE(1, af.cmp(acc)); > +TEST(Buffer, constructors) { > + bool ceph_buffer_track = get_env_bool("CEPH_BUFFER_TRACK"); > + unsigned len = 17; > + // > + // buffer::create > + // > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + { > + bufferptr ptr(buffer::create(len)); > + EXPECT_EQ(len, ptr.length()); > + if (ceph_buffer_track) > + EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); > + } > + // > + // buffer::claim_char > + // > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + { > + char* str = new char[len]; > + ::memset(str, 'X', len); > + bufferptr ptr(buffer::claim_char(len, str)); > + if (ceph_buffer_track) > + EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); > + EXPECT_EQ(len, ptr.length()); > + EXPECT_EQ(str, ptr.c_str()); > + bufferptr clone = ptr.clone(); > + EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); > + } > + // > + // buffer::create_static > + // > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + { > + char* str = new char[len]; > + bufferptr ptr(buffer::create_static(len, str)); > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + EXPECT_EQ(len, ptr.length()); > + EXPECT_EQ(str, ptr.c_str()); > + delete [] str; > + } > + // > + // buffer::create_malloc > + // > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + { > + bufferptr ptr(buffer::create_malloc(len)); > + if (ceph_buffer_track) > + EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); > + EXPECT_EQ(len, ptr.length()); > + EXPECT_THROW(buffer::create_malloc((unsigned)ULLONG_MAX), buffer::bad_alloc); > + } > + // > + // buffer::claim_malloc > + // > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + { > + char* str = (char*)malloc(len); > + ::memset(str, 'X', len); > + bufferptr ptr(buffer::claim_malloc(len, str)); > + if (ceph_buffer_track) > + EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); > + EXPECT_EQ(len, ptr.length()); > + EXPECT_EQ(str, ptr.c_str()); > + bufferptr clone = ptr.clone(); > + EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); > + } > + // > + // buffer::copy > + // > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + { > + const std::string expected(len, 'X'); > + bufferptr ptr(buffer::copy(expected.c_str(), expected.size())); > + if (ceph_buffer_track) > + EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); > + EXPECT_NE(expected.c_str(), ptr.c_str()); > + EXPECT_EQ(0, ::memcmp(expected.c_str(), ptr.c_str(), len)); > + } > + // > + // buffer::create_page_aligned > + // > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > + { > + bufferptr ptr(buffer::create_page_aligned(len)); > + ::memset(ptr.c_str(), 'X', len); > + if (ceph_buffer_track) > + EXPECT_EQ(len, (unsigned)buffer::get_total_alloc()); > + EXPECT_THROW(buffer::create_page_aligned((unsigned)ULLONG_MAX), buffer::bad_alloc); > +#ifndef DARWIN > + ASSERT_TRUE(ptr.is_page_aligned()); > +#endif // DARWIN > + bufferptr clone = ptr.clone(); > + EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); > + } > + if (ceph_buffer_track) > + EXPECT_EQ(0, buffer::get_total_alloc()); > +} > + > +TEST(BufferRaw, ostream) { > + bufferptr ptr(1); > + std::ostringstream stream; > + stream << *ptr.get_raw(); > + EXPECT_GT(stream.str().size(), stream.str().find("buffer::raw(")); > + EXPECT_GT(stream.str().size(), stream.str().find("len 1 nref 1)")); > +} > + > +// > +// +-----------+ +-----+ > +// | | | | > +// | offset +----------------+ | > +// | | | | > +// | length +---- | | > +// | | \------- | | > +// +-----------+ \---+ | > +// | ptr | +-----+ > +// +-----------+ | raw | > +// +-----+ > +// > +TEST(BufferPtr, constructors) { > + unsigned len = 17; > + // > + // ptr::ptr() > + // > + { > + buffer::ptr ptr; > + EXPECT_FALSE(ptr.have_raw()); > + EXPECT_EQ((unsigned)0, ptr.offset()); > + EXPECT_EQ((unsigned)0, ptr.length()); > + } > + // > + // ptr::ptr(raw *r) > + // > + { > + bufferptr ptr(buffer::create(len)); > + EXPECT_TRUE(ptr.have_raw()); > + EXPECT_EQ((unsigned)0, ptr.offset()); > + EXPECT_EQ(len, ptr.length()); > + EXPECT_EQ(ptr.raw_length(), ptr.length()); > + EXPECT_EQ(1, ptr.raw_nref()); > + } > + // > + // ptr::ptr(unsigned l) > + // > + { > + bufferptr ptr(len); > + EXPECT_TRUE(ptr.have_raw()); > + EXPECT_EQ((unsigned)0, ptr.offset()); > + EXPECT_EQ(len, ptr.length()); > + EXPECT_EQ(1, ptr.raw_nref()); > + } > + // > + // ptr(const char *d, unsigned l) > + // > + { > + const std::string str(len, 'X'); > + bufferptr ptr(str.c_str(), len); > + EXPECT_TRUE(ptr.have_raw()); > + EXPECT_EQ((unsigned)0, ptr.offset()); > + EXPECT_EQ(len, ptr.length()); > + EXPECT_EQ(1, ptr.raw_nref()); > + EXPECT_EQ(0, ::memcmp(str.c_str(), ptr.c_str(), len)); > + } > + // > + // ptr(const ptr& p) > + // > + { > + const std::string str(len, 'X'); > + bufferptr original(str.c_str(), len); > + bufferptr ptr(original); > + EXPECT_TRUE(ptr.have_raw()); > + EXPECT_EQ(original.get_raw(), ptr.get_raw()); > + EXPECT_EQ(2, ptr.raw_nref()); > + EXPECT_EQ(0, ::memcmp(original.c_str(), ptr.c_str(), len)); > + } > + // > + // ptr(const ptr& p, unsigned o, unsigned l) > + // > + { > + const std::string str(len, 'X'); > + bufferptr original(str.c_str(), len); > + bufferptr ptr(original, 0, 0); > + EXPECT_TRUE(ptr.have_raw()); > + EXPECT_EQ(original.get_raw(), ptr.get_raw()); > + EXPECT_EQ(2, ptr.raw_nref()); > + EXPECT_EQ(0, ::memcmp(original.c_str(), ptr.c_str(), len)); > + EXPECT_THROW(bufferptr(original, 0, original.length() + 1), FailedAssertion); > + EXPECT_THROW(bufferptr(bufferptr(), 0, 0), FailedAssertion); > + } > +} > + > +TEST(BufferPtr, assignment) { > + unsigned len = 17; > + // > + // override a bufferptr set with the same raw > + // > + { > + bufferptr original(len); > + bufferptr same_raw(original.get_raw()); > + unsigned offset = 5; > + unsigned length = len - offset; > + original.set_offset(offset); > + original.set_length(length); > + same_raw = original; > + ASSERT_EQ(2, original.raw_nref()); > + ASSERT_EQ(same_raw.get_raw(), original.get_raw()); > + ASSERT_EQ(same_raw.offset(), original.offset()); > + ASSERT_EQ(same_raw.length(), original.length()); > + } > + > + // > + // self assignment is a noop > + // > + { > + bufferptr original(len); > + original = original; > + ASSERT_EQ(1, original.raw_nref()); > + ASSERT_EQ((unsigned)0, original.offset()); > + ASSERT_EQ(len, original.length()); > + } > + > + // > + // a copy points to the same raw > + // > + { > + bufferptr original(len); > + unsigned offset = 5; > + unsigned length = len - offset; > + original.set_offset(offset); > + original.set_length(length); > + bufferptr ptr; > + ptr = original; > + ASSERT_EQ(2, original.raw_nref()); > + ASSERT_EQ(ptr.get_raw(), original.get_raw()); > + ASSERT_EQ(original.offset(), ptr.offset()); > + ASSERT_EQ(original.length(), ptr.length()); > + } > +} > + > +TEST(BufferPtr, clone) { > + unsigned len = 17; > + bufferptr ptr(len); > + ::memset(ptr.c_str(), 'X', len); > + bufferptr clone = ptr.clone(); > + EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); > +} > + > +TEST(BufferPtr, swap) { > + unsigned len = 17; > + > + bufferptr ptr1(len); > + ::memset(ptr1.c_str(), 'X', len); > + unsigned ptr1_offset = 4; > + ptr1.set_offset(ptr1_offset); > + unsigned ptr1_length = 3; > + ptr1.set_length(ptr1_length); > + > + bufferptr ptr2(len); > + ::memset(ptr2.c_str(), 'Y', len); > + unsigned ptr2_offset = 5; > + ptr2.set_offset(ptr2_offset); > + unsigned ptr2_length = 7; > + ptr2.set_length(ptr2_length); > + > + ptr1.swap(ptr2); > + > + EXPECT_EQ(ptr2_length, ptr1.length()); > + EXPECT_EQ(ptr2_offset, ptr1.offset()); > + EXPECT_EQ('Y', ptr1[0]); > + > + EXPECT_EQ(ptr1_length, ptr2.length()); > + EXPECT_EQ(ptr1_offset, ptr2.offset()); > + EXPECT_EQ('X', ptr2[0]); > +} > + > +TEST(BufferPtr, release) { > + unsigned len = 17; > + > + bufferptr ptr1(len); > + { > + bufferptr ptr2(ptr1); > + EXPECT_EQ(2, ptr1.raw_nref()); > + } > + EXPECT_EQ(1, ptr1.raw_nref()); > +} > + > +TEST(BufferPtr, have_raw) { > + { > + bufferptr ptr; > + EXPECT_FALSE(ptr.have_raw()); > + } > + { > + bufferptr ptr(1); > + EXPECT_TRUE(ptr.have_raw()); > + } > +} > + > +TEST(BufferPtr, at_buffer_head) { > + bufferptr ptr(2); > + EXPECT_TRUE(ptr.at_buffer_head()); > + ptr.set_offset(1); > + EXPECT_FALSE(ptr.at_buffer_head()); > +} > + > +TEST(BufferPtr, at_buffer_tail) { > + bufferptr ptr(2); > + EXPECT_TRUE(ptr.at_buffer_tail()); > + ptr.set_length(1); > + EXPECT_FALSE(ptr.at_buffer_tail()); > +} > + > +TEST(BufferPtr, is_n_page_sized) { > + { > + bufferptr ptr(CEPH_PAGE_SIZE); > + EXPECT_TRUE(ptr.is_n_page_sized()); > + } > + { > + bufferptr ptr(1); > + EXPECT_FALSE(ptr.is_n_page_sized()); > + } > +} > + > +TEST(BufferPtr, accessors) { > + unsigned len = 17; > + bufferptr ptr(len); > + ptr.c_str()[0] = 'X'; > + ptr[1] = 'Y'; > + const bufferptr const_ptr(ptr); > + > + EXPECT_NE((void*)NULL, (void*)ptr.get_raw()); > + EXPECT_EQ('X', ptr.c_str()[0]); > + { > + bufferptr ptr; > + EXPECT_THROW(ptr.c_str(), FailedAssertion); > + EXPECT_THROW(ptr[0], FailedAssertion); > + } > + EXPECT_EQ('X', const_ptr.c_str()[0]); > + { > + const bufferptr const_ptr; > + EXPECT_THROW(const_ptr.c_str(), FailedAssertion); > + EXPECT_THROW(const_ptr[0], FailedAssertion); > + } > + EXPECT_EQ(len, const_ptr.length()); > + EXPECT_EQ((unsigned)0, const_ptr.offset()); > + EXPECT_EQ((unsigned)0, const_ptr.start()); > + EXPECT_EQ(len, const_ptr.end()); > + EXPECT_EQ(len, const_ptr.end()); > + { > + bufferptr ptr(len); > + unsigned unused = 1; > + ptr.set_length(ptr.length() - unused); > + EXPECT_EQ(unused, ptr.unused_tail_length()); > + } > + { > + bufferptr ptr; > + EXPECT_EQ((unsigned)0, ptr.unused_tail_length()); > + } > + EXPECT_THROW(ptr[len], FailedAssertion); > + EXPECT_THROW(const_ptr[len], FailedAssertion); > + { > + const bufferptr const_ptr; > + EXPECT_THROW(const_ptr.raw_c_str(), FailedAssertion); > + EXPECT_THROW(const_ptr.raw_length(), FailedAssertion); > + EXPECT_THROW(const_ptr.raw_nref(), FailedAssertion); > + } > + EXPECT_NE((const char *)NULL, const_ptr.raw_c_str()); > + EXPECT_EQ(len, const_ptr.raw_length()); > + EXPECT_EQ(2, const_ptr.raw_nref()); > + { > + bufferptr ptr(len); > + unsigned wasted = 1; > + ptr.set_length(ptr.length() - wasted * 2); > + ptr.set_offset(wasted); > + EXPECT_EQ(wasted * 2, ptr.wasted()); > + } > +} > + > +TEST(BufferPtr, cmp) { > + bufferptr empty; > + bufferptr a("A", 1); > + bufferptr ab("AB", 2); > + bufferptr af("AF", 2); > + bufferptr acc("ACC", 3); > + EXPECT_GE(-1, empty.cmp(a)); > + EXPECT_LE(1, a.cmp(empty)); > + EXPECT_GE(-1, a.cmp(ab)); > + EXPECT_LE(1, ab.cmp(a)); > + EXPECT_EQ(0, ab.cmp(ab)); > + EXPECT_GE(-1, ab.cmp(af)); > + EXPECT_LE(1, af.cmp(ab)); > + EXPECT_GE(-1, acc.cmp(af)); > + EXPECT_LE(1, af.cmp(acc)); > +} > + > +TEST(BufferPtr, is_zero) { > + char str[2] = { '\0', 'X' }; > + { > + const bufferptr ptr(buffer::create_static(2, str)); > + EXPECT_FALSE(ptr.is_zero()); > + } > + { > + const bufferptr ptr(buffer::create_static(1, str)); > + EXPECT_TRUE(ptr.is_zero()); > + } > +} > + > +TEST(BufferPtr, copy_out) { > + { > + const bufferptr ptr; > + EXPECT_THROW(ptr.copy_out((unsigned)0, (unsigned)0, NULL), FailedAssertion); > + } > + { > + char in[] = "ABC"; > + const bufferptr ptr(buffer::create_static(strlen(in), in)); > + EXPECT_THROW(ptr.copy_out((unsigned)0, strlen(in) + 1, NULL), buffer::end_of_buffer); > + EXPECT_THROW(ptr.copy_out(strlen(in) + 1, (unsigned)0, NULL), buffer::end_of_buffer); > + char out[1] = { 'X' }; > + ptr.copy_out((unsigned)1, (unsigned)1, out); > + EXPECT_EQ('B', out[0]); > + } > +} > + > +TEST(BufferPtr, copy_in) { > + { > + bufferptr ptr; > + EXPECT_THROW(ptr.copy_in((unsigned)0, (unsigned)0, NULL), FailedAssertion); > + } > + { > + char in[] = "ABCD"; > + bufferptr ptr(2); > + EXPECT_THROW(ptr.copy_in((unsigned)0, strlen(in) + 1, NULL), FailedAssertion); > + EXPECT_THROW(ptr.copy_in(strlen(in) + 1, (unsigned)0, NULL), FailedAssertion); > + ptr.copy_in((unsigned)0, (unsigned)2, in); > + EXPECT_EQ(in[0], ptr[0]); > + EXPECT_EQ(in[1], ptr[1]); > + } > +} > + > +TEST(BufferPtr, append) { > + { > + bufferptr ptr; > + EXPECT_THROW(ptr.append('A'), FailedAssertion); > + EXPECT_THROW(ptr.append("B", (unsigned)1), FailedAssertion); > + } > + { > + bufferptr ptr(2); > + EXPECT_THROW(ptr.append('A'), FailedAssertion); > + EXPECT_THROW(ptr.append("B", (unsigned)1), FailedAssertion); > + ptr.set_length(0); > + ptr.append('A'); > + EXPECT_EQ((unsigned)1, ptr.length()); > + EXPECT_EQ('A', ptr[0]); > + ptr.append("B", (unsigned)1); > + EXPECT_EQ((unsigned)2, ptr.length()); > + EXPECT_EQ('B', ptr[1]); > + } > +} > + > +TEST(BufferPtr, zero) { > + char str[] = "XXXX"; > + bufferptr ptr(buffer::create_static(strlen(str), str)); > + EXPECT_THROW(ptr.zero(ptr.length() + 1, 0), FailedAssertion); > + ptr.zero(1, 1); > + EXPECT_EQ('X', ptr[0]); > + EXPECT_EQ('\0', ptr[1]); > + EXPECT_EQ('X', ptr[2]); > + ptr.zero(); > + EXPECT_EQ('\0', ptr[0]); > +} > + > +TEST(BufferPtr, ostream) { > + { > + bufferptr ptr; > + std::ostringstream stream; > + stream << ptr; > + EXPECT_GT(stream.str().size(), stream.str().find("buffer:ptr(0~0 no raw")); > + } > + { > + char str[] = "XXXX"; > + bufferptr ptr(buffer::create_static(strlen(str), str)); > + std::ostringstream stream; > + stream << ptr; > + EXPECT_GT(stream.str().size(), stream.str().find("len 4 nref 1)")); > + } > +} > + > +// > +// +---------+ > +// | +-----+ | > +// list ptr | | | | > +// +----------+ +-----+ | | | | > +// | append_ >-------> >--------------------> | | > +// | buffer | +-----+ | | | | > +// +----------+ ptr | | | | > +// | _len | list +-----+ | | | | > +// +----------+ +------+ ,--->+ >-----> | | > +// | _buffers >----> >----- +-----+ | +-----+ | > +// +----------+ +----^-+ \ ptr | raw | > +// | last_p | / `-->+-----+ | +-----+ | > +// +--------+-+ / + >-----> | | > +// | ,- ,--->+-----+ | | | | > +// | / ,--- | | | | > +// | / ,--- | | | | > +// +-v--+-^--+--^+-------+ | | | | > +// | bl | ls | p | p_off >--------------->| | | > +// +----+----+-----+-----+ | +-----+ | > +// | | off >------------->| raw | > +// +---------------+-----+ | | > +// iterator +---------+ > +// > +TEST(BufferListIterator, constructors) { > + // > + // iterator() > + // > + { > + buffer::list::iterator i; > + EXPECT_EQ((unsigned)0, i.get_off()); > + } > + > + // > + // iterator(list *l, unsigned o=0) > + // > + { > + bufferlist bl; > + bl.append("ABC", 3); > + > + { > + bufferlist::iterator i(&bl); > + EXPECT_EQ((unsigned)0, i.get_off()); > + EXPECT_EQ('A', *i); > + } > + { > + bufferlist::iterator i(&bl, 1); > + EXPECT_EQ('B', *i); > + EXPECT_EQ((unsigned)2, i.get_remaining()); > + } > + } > + > + // > + // iterator(list *l, unsigned o, std::list<ptr>::iterator ip, unsigned po) > + // not tested because of http://tracker.ceph.com/issues/4101 > + > + // > + // iterator(const iterator& other) > + // > + { > + bufferlist bl; > + bl.append("ABC", 3); > + bufferlist::iterator i(&bl, 1); > + bufferlist::iterator j(i); > + EXPECT_EQ(*i, *j); > + ++j; > + EXPECT_NE(*i, *j); > + EXPECT_EQ('B', *i); > + EXPECT_EQ('C', *j); > + bl.c_str()[1] = 'X'; > + j.advance(-1); > + EXPECT_EQ('X', *j); > + } > +} > + > +TEST(BufferListIterator, operator_equal) { > + bufferlist bl; > + bl.append("ABC", 3); > + bufferlist::iterator i(&bl, 1); > + > + i = i; > + EXPECT_EQ('B', *i); > + bufferlist::iterator j; > + j = i; > + EXPECT_EQ('B', *j); > +} > + > +TEST(BufferListIterator, get_off) { > + bufferlist bl; > + bl.append("ABC", 3); > + bufferlist::iterator i(&bl, 1); > + EXPECT_EQ((unsigned)1, i.get_off()); > +} > + > +TEST(BufferListIterator, get_remaining) { > + bufferlist bl; > + bl.append("ABC", 3); > + bufferlist::iterator i(&bl, 1); > + EXPECT_EQ((unsigned)2, i.get_remaining()); > +} > + > +TEST(BufferListIterator, end) { > + bufferlist bl; > + { > + bufferlist::iterator i(&bl); > + EXPECT_TRUE(i.end()); > + } > + bl.append("ABC", 3); > + { > + bufferlist::iterator i(&bl); > + EXPECT_FALSE(i.end()); > + } > +} > + > +TEST(BufferListIterator, advance) { > + bufferlist bl; > + const std::string one("ABC"); > + bl.append(bufferptr(one.c_str(), one.size())); > + const std::string two("DEF"); > + bl.append(bufferptr(two.c_str(), two.size())); > + > + { > + bufferlist::iterator i(&bl); > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + } > + { > + bufferlist::iterator i(&bl); > + EXPECT_THROW(i.advance(-1), buffer::end_of_buffer); > + } > + { > + bufferlist::iterator i(&bl); > + EXPECT_EQ('A', *i); > + i.advance(1); > + EXPECT_EQ('B', *i); > + i.advance(3); > + EXPECT_EQ('E', *i); > + i.advance(-3); > + EXPECT_EQ('B', *i); > + i.advance(-1); > + EXPECT_EQ('A', *i); > + } > +} > + > +TEST(BufferListIterator, seek) { > + bufferlist bl; > + bl.append("ABC", 3); > + bufferlist::iterator i(&bl, 1); > + EXPECT_EQ('B', *i); > + i.seek(2); > + EXPECT_EQ('C', *i); > +} > + > +TEST(BufferListIterator, operator_star) { > + bufferlist bl; > + { > + bufferlist::iterator i(&bl); > + EXPECT_THROW(*i, buffer::end_of_buffer); > + } > + bl.append("ABC", 3); > + { > + bufferlist::iterator i(&bl); > + EXPECT_EQ('A', *i); > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + EXPECT_THROW(*i, buffer::end_of_buffer); > + } > +} > + > +TEST(BufferListIterator, operator_plus_plus) { > + bufferlist bl; > + { > + bufferlist::iterator i(&bl); > + EXPECT_THROW(++i, buffer::end_of_buffer); > + } > + bl.append("ABC", 3); > + { > + bufferlist::iterator i(&bl); > + ++i; > + EXPECT_EQ('B', *i); > + } > +} > + > +TEST(BufferListIterator, get_current_ptr) { > + bufferlist bl; > + { > + bufferlist::iterator i(&bl); > + EXPECT_THROW(++i, buffer::end_of_buffer); > + } > + bl.append("ABC", 3); > + { > + bufferlist::iterator i(&bl, 1); > + const buffer::ptr ptr = i.get_current_ptr(); > + EXPECT_EQ('B', ptr[0]); > + EXPECT_EQ((unsigned)1, ptr.offset()); > + EXPECT_EQ((unsigned)2, ptr.length()); > + } > +} > + > +TEST(BufferListIterator, copy) { > + bufferlist bl; > + const char *expected = "ABC"; > + bl.append(expected, 3); > + // > + // void copy(unsigned len, char *dest); > + // > + { > + char* copy = (char*)malloc(3); > + ::memset(copy, 'X', 3); > + bufferlist::iterator i(&bl); > + // > + // demonstrates that it seeks back to offset if p == ls->end() > + // > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + i.copy(2, copy); > + EXPECT_EQ(0, ::memcmp(copy, expected, 2)); > + EXPECT_EQ('X', copy[2]); > + i.seek(0); > + i.copy(3, copy); > + EXPECT_EQ(0, ::memcmp(copy, expected, 3)); > + } > + // > + // void buffer::list::iterator::copy(unsigned len, ptr &dest) > + // > + { > + bufferptr ptr; > + bufferlist::iterator i(&bl); > + i.copy(2, ptr); > + EXPECT_EQ((unsigned)2, ptr.length()); > + EXPECT_EQ('A', ptr[0]); > + EXPECT_EQ('B', ptr[1]); > + } > + // > + // void buffer::list::iterator::copy(unsigned len, list &dest) > + // > + { > + bufferlist copy; > + bufferlist::iterator i(&bl); > + // > + // demonstrates that it seeks back to offset if p == ls->end() > + // > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + i.copy(2, copy); > + EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2)); > + i.seek(0); > + i.copy(3, copy); > + EXPECT_EQ('A', copy[0]); > + EXPECT_EQ('B', copy[1]); > + EXPECT_EQ('A', copy[2]); > + EXPECT_EQ('B', copy[3]); > + EXPECT_EQ('C', copy[4]); > + EXPECT_EQ((unsigned)(2 + 3), copy.length()); > + } > + // > + // void buffer::list::iterator::copy_all(list &dest) > + // > + { > + bufferlist copy; > + bufferlist::iterator i(&bl); > + // > + // demonstrates that it seeks back to offset if p == ls->end() > + // > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + i.copy_all(copy); > + EXPECT_EQ('A', copy[0]); > + EXPECT_EQ('B', copy[1]); > + EXPECT_EQ('C', copy[2]); > + EXPECT_EQ((unsigned)3, copy.length()); > + } > + // > + // void copy(unsigned len, std::string &dest) > + // > + { > + std::string copy; > + bufferlist::iterator i(&bl); > + // > + // demonstrates that it seeks back to offset if p == ls->end() > + // > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + i.copy(2, copy); > + EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2)); > + i.seek(0); > + i.copy(3, copy); > + EXPECT_EQ('A', copy[0]); > + EXPECT_EQ('B', copy[1]); > + EXPECT_EQ('A', copy[2]); > + EXPECT_EQ('B', copy[3]); > + EXPECT_EQ('C', copy[4]); > + EXPECT_EQ((unsigned)(2 + 3), copy.length()); > + } > +} > + > +TEST(BufferListIterator, copy_in) { > + bufferlist bl; > + const char *existing = "XXX"; > + bl.append(existing, 3); > + // > + // void buffer::list::iterator::copy_in(unsigned len, const char *src) > + // > + { > + bufferlist::iterator i(&bl); > + // > + // demonstrates that it seeks back to offset if p == ls->end() > + // > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + const char *expected = "ABC"; > + i.copy_in(3, expected); > + EXPECT_EQ(0, ::memcmp(bl.c_str(), expected, 3)); > + EXPECT_EQ('A', bl[0]); > + EXPECT_EQ('B', bl[1]); > + EXPECT_EQ('C', bl[2]); > + EXPECT_EQ((unsigned)3, bl.length()); > + } > + // > + // void buffer::list::iterator::copy_in(unsigned len, const list& otherl) > + // > + { > + bufferlist::iterator i(&bl); > + // > + // demonstrates that it seeks back to offset if p == ls->end() > + // > + EXPECT_THROW(i.advance(200), buffer::end_of_buffer); > + bufferlist expected; > + expected.append("ABC", 3); > + i.copy_in(3, expected); > + EXPECT_EQ(0, ::memcmp(bl.c_str(), expected.c_str(), 3)); > + EXPECT_EQ('A', bl[0]); > + EXPECT_EQ('B', bl[1]); > + EXPECT_EQ('C', bl[2]); > + EXPECT_EQ((unsigned)3, bl.length()); > + } > +} > + > +TEST(BufferList, constructors) { > + // > + // list() > + // > + { > + bufferlist bl; > + ASSERT_EQ((unsigned)0, bl.length()); > + } > + // > + // list(unsigned prealloc) > + // > + { > + bufferlist bl(1); > + ASSERT_EQ((unsigned)0, bl.length()); > + bl.append('A'); > + ASSERT_EQ('A', bl[0]); > + } > + // > + // list(const list& other) > + // > + { > + bufferlist bl(1); > + bl.append('A'); > + ASSERT_EQ('A', bl[0]); > + bufferlist copy(bl); > + ASSERT_EQ('A', copy[0]); > + } > +} > + > +TEST(BufferList, operator_equal) { > + bufferlist bl; > + bl.append("ABC", 3); > + { > + std::string dest; > + bl.copy(1, 1, dest); > + ASSERT_EQ('B', dest[0]); > + } > + bufferlist copy; > + copy = bl; > + { > + std::string dest; > + copy.copy(1, 1, dest); > + ASSERT_EQ('B', dest[0]); > + } > +} > + > +TEST(BufferList, buffers) { > + bufferlist bl; > + ASSERT_EQ((unsigned)0, bl.buffers().size()); > + bl.append('A'); > + ASSERT_EQ((unsigned)1, bl.buffers().size()); > +} > + > +TEST(BufferList, swap) { > + bufferlist b1; > + b1.append('A'); > + > + bufferlist b2; > + b2.append('B'); > + > + b1.swap(b2); > + > + std::string s1; > + b1.copy(0, 1, s1); > + ASSERT_EQ('B', s1[0]); > + > + std::string s2; > + b2.copy(0, 1, s2); > + ASSERT_EQ('A', s2[0]); > +} > + > +TEST(BufferList, length) { > + bufferlist bl; > + ASSERT_EQ((unsigned)0, bl.length()); > + bl.append('A'); > + ASSERT_EQ((unsigned)1, bl.length()); > +} > + > +TEST(BufferList, contents_equal) { > + // > + // A BB > + // AB B > + // > + bufferlist bl1; > + bl1.append("A"); > + bl1.append("BB"); > + bufferlist bl2; > + ASSERT_FALSE(bl1.contents_equal(bl2)); // different length > + bl2.append("AB"); > + bl2.append("B"); > + ASSERT_TRUE(bl1.contents_equal(bl2)); // same length same content > + // > + // ABC > + // > + bufferlist bl3; > + bl3.append("ABC"); > + ASSERT_FALSE(bl1.contents_equal(bl3)); // same length different content > +} > + > +TEST(BufferList, is_page_aligned) { > + { > + bufferlist bl; > + EXPECT_TRUE(bl.is_page_aligned()); > + } > + { > + bufferlist bl; > + bufferptr ptr(2); > + ptr.set_offset(1); > + ptr.set_length(1); > + bl.append(ptr); > + EXPECT_FALSE(bl.is_page_aligned()); > + bl.rebuild_page_aligned(); > + EXPECT_FALSE(bl.is_page_aligned()); > + } > + { > + bufferlist bl; > + bufferptr ptr(CEPH_PAGE_SIZE + 1); > + ptr.set_offset(1); > + ptr.set_length(CEPH_PAGE_SIZE); > + bl.append(ptr); > + EXPECT_FALSE(bl.is_page_aligned()); > + bl.rebuild_page_aligned(); > + EXPECT_TRUE(bl.is_page_aligned()); > + } > +} > + > +TEST(BufferList, is_n_page_sized) { > + { > + bufferlist bl; > + EXPECT_TRUE(bl.is_n_page_sized()); > + } > + { > + bufferlist bl; > + bl.append_zero(1); > + EXPECT_FALSE(bl.is_n_page_sized()); > + } > + { > + bufferlist bl; > + bl.append_zero(CEPH_PAGE_SIZE); > + EXPECT_TRUE(bl.is_n_page_sized()); > + } > +} > + > +TEST(BufferList, is_zero) { > + { > + bufferlist bl; > + EXPECT_TRUE(bl.is_zero()); > + } > + { > + bufferlist bl; > + bl.append('A'); > + EXPECT_FALSE(bl.is_zero()); > + } > + { > + bufferlist bl; > + bl.append_zero(1); > + EXPECT_TRUE(bl.is_zero()); > + } > +} > + > +TEST(BufferList, clear) { > + bufferlist bl; > + unsigned len = 17; > + bl.append_zero(len); > + bl.clear(); > + EXPECT_EQ((unsigned)0, bl.length()); > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > +} > + > +TEST(BufferList, push_front) { > + // > + // void push_front(ptr& bp) > + // > + { > + bufferlist bl; > + bufferptr ptr; > + bl.push_front(ptr); > + EXPECT_EQ((unsigned)0, bl.length()); > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > + } > + unsigned len = 17; > + { > + bufferlist bl; > + bl.append('A'); > + bufferptr ptr(len); > + ptr.c_str()[0] = 'B'; > + bl.push_front(ptr); > + EXPECT_EQ((unsigned)(1 + len), bl.length()); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ('B', bl.buffers().front()[0]); > + EXPECT_EQ(ptr.get_raw(), bl.buffers().front().get_raw()); > + } > + // > + // void push_front(raw *r) > + // > + { > + bufferlist bl; > + bl.append('A'); > + bufferptr ptr(len); > + ptr.c_str()[0] = 'B'; > + bl.push_front(ptr.get_raw()); > + EXPECT_EQ((unsigned)(1 + len), bl.length()); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ('B', bl.buffers().front()[0]); > + EXPECT_EQ(ptr.get_raw(), bl.buffers().front().get_raw()); > + } > +} > + > +TEST(BufferList, push_back) { > + // > + // void push_back(ptr& bp) > + // > + { > + bufferlist bl; > + bufferptr ptr; > + bl.push_back(ptr); > + EXPECT_EQ((unsigned)0, bl.length()); > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > + } > + unsigned len = 17; > + { > + bufferlist bl; > + bl.append('A'); > + bufferptr ptr(len); > + ptr.c_str()[0] = 'B'; > + bl.push_back(ptr); > + EXPECT_EQ((unsigned)(1 + len), bl.length()); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ('B', bl.buffers().back()[0]); > + EXPECT_EQ(ptr.get_raw(), bl.buffers().back().get_raw()); > + } > + // > + // void push_back(raw *r) > + // > + { > + bufferlist bl; > + bl.append('A'); > + bufferptr ptr(len); > + ptr.c_str()[0] = 'B'; > + bl.push_back(ptr.get_raw()); > + EXPECT_EQ((unsigned)(1 + len), bl.length()); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ('B', bl.buffers().back()[0]); > + EXPECT_EQ(ptr.get_raw(), bl.buffers().back().get_raw()); > + } > +} > + > +TEST(BufferList, is_contiguous) { > + bufferlist bl; > + EXPECT_TRUE(bl.is_contiguous()); > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > + bl.append('A'); > + EXPECT_TRUE(bl.is_contiguous()); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + bufferptr ptr(1); > + bl.push_back(ptr); > + EXPECT_FALSE(bl.is_contiguous()); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > +} > + > +TEST(BufferList, rebuild) { > + { > + bufferlist bl; > + bufferptr ptr(2); > + ptr.set_offset(1); > + ptr.set_length(1); > + bl.append(ptr); > + EXPECT_FALSE(bl.is_page_aligned()); > + bl.rebuild(); > + EXPECT_FALSE(bl.is_page_aligned()); > + } > + { > + bufferlist bl; > + const std::string str(CEPH_PAGE_SIZE, 'X'); > + bl.append(str.c_str(), str.size()); > + bl.append(str.c_str(), str.size()); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_TRUE(bl.is_page_aligned()); > + bl.rebuild(); > + EXPECT_TRUE(bl.is_page_aligned()); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + } > +} > + > +TEST(BufferList, rebuild_page_aligned) { > + { > + bufferlist bl; > + { > + bufferptr ptr(CEPH_PAGE_SIZE + 1); > + ptr.set_offset(1); > + ptr.set_length(CEPH_PAGE_SIZE); > + bl.append(ptr); > + } > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + EXPECT_FALSE(bl.is_page_aligned()); > + bl.rebuild_page_aligned(); > + EXPECT_TRUE(bl.is_page_aligned()); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + } > + { > + bufferlist bl; > + { > + bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE)); > + bl.append(ptr); > + } > + { > + bufferptr ptr(CEPH_PAGE_SIZE + 1); > + bl.append(ptr); > + } > + { > + bufferptr ptr(2); > + ptr.set_offset(1); > + ptr.set_length(1); > + bl.append(ptr); > + } > + { > + bufferptr ptr(CEPH_PAGE_SIZE - 2); > + bl.append(ptr); > + } > + { > + bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE)); > + bl.append(ptr); > + } > + { > + bufferptr ptr(CEPH_PAGE_SIZE + 1); > + ptr.set_offset(1); > + ptr.set_length(CEPH_PAGE_SIZE); > + bl.append(ptr); > + } > + EXPECT_EQ((unsigned)6, bl.buffers().size()); > + EXPECT_TRUE((bl.length() & ~CEPH_PAGE_MASK) == 0); > + EXPECT_FALSE(bl.is_page_aligned()); > + bl.rebuild_page_aligned(); > + EXPECT_TRUE(bl.is_page_aligned()); > + EXPECT_EQ((unsigned)4, bl.buffers().size()); > + } > +} > + > +TEST(BufferList, claim) { > + bufferlist from; > + { > + bufferptr ptr(2); > + from.append(ptr); > + } > + bufferlist to; > + { > + bufferptr ptr(4); > + to.append(ptr); > + } > + EXPECT_EQ((unsigned)4, to.length()); > + EXPECT_EQ((unsigned)1, to.buffers().size()); > + to.claim(from); > + EXPECT_EQ((unsigned)2, to.length()); > + EXPECT_EQ((unsigned)1, to.buffers().size()); > + EXPECT_EQ((unsigned)0, from.buffers().size()); > + EXPECT_EQ((unsigned)0, from.length()); > +} > + > +TEST(BufferList, claim_append) { > + bufferlist from; > + { > + bufferptr ptr(2); > + from.append(ptr); > + } > + bufferlist to; > + { > + bufferptr ptr(4); > + to.append(ptr); > + } > + EXPECT_EQ((unsigned)4, to.length()); > + EXPECT_EQ((unsigned)1, to.buffers().size()); > + to.claim_append(from); > + EXPECT_EQ((unsigned)(4 + 2), to.length()); > + EXPECT_EQ((unsigned)4, to.buffers().front().length()); > + EXPECT_EQ((unsigned)2, to.buffers().back().length()); > + EXPECT_EQ((unsigned)2, to.buffers().size()); > + EXPECT_EQ((unsigned)0, from.buffers().size()); > + EXPECT_EQ((unsigned)0, from.length()); > +} > + > +TEST(BufferList, claim_prepend) { > + bufferlist from; > + { > + bufferptr ptr(2); > + from.append(ptr); > + } > + bufferlist to; > + { > + bufferptr ptr(4); > + to.append(ptr); > + } > + EXPECT_EQ((unsigned)4, to.length()); > + EXPECT_EQ((unsigned)1, to.buffers().size()); > + to.claim_prepend(from); > + EXPECT_EQ((unsigned)(2 + 4), to.length()); > + EXPECT_EQ((unsigned)2, to.buffers().front().length()); > + EXPECT_EQ((unsigned)4, to.buffers().back().length()); > + EXPECT_EQ((unsigned)2, to.buffers().size()); > + EXPECT_EQ((unsigned)0, from.buffers().size()); > + EXPECT_EQ((unsigned)0, from.length()); > +} > + > +TEST(BufferList, begin) { > + bufferlist bl; > + bl.append("ABC"); > + bufferlist::iterator i = bl.begin(); > + EXPECT_EQ('A', *i); > +} > + > +TEST(BufferList, end) { > + bufferlist bl; > + bl.append("ABC"); > + bufferlist::iterator i = bl.end(); > + i.advance(-1); > + EXPECT_EQ('C', *i); > +} > + > +TEST(BufferList, copy) { > + // > + // void copy(unsigned off, unsigned len, char *dest) const; > + // > + { > + bufferlist bl; > + EXPECT_THROW(bl.copy((unsigned)100, (unsigned)100, (char*)0), buffer::end_of_buffer); > + const char *expected = "ABC"; > + bl.append(expected); > + char *dest = new char[2]; > + bl.copy(1, 2, dest); > + EXPECT_EQ(0, ::memcmp(expected + 1, dest, 2)); > + delete [] dest; > + } > + // > + // void copy(unsigned off, unsigned len, list &dest) const; > + // > + { > + bufferlist bl; > + bufferlist dest; > + EXPECT_THROW(bl.copy((unsigned)100, (unsigned)100, dest), buffer::end_of_buffer); > + const char *expected = "ABC"; > + bl.append(expected); > + bl.copy(1, 2, dest); > + EXPECT_EQ(0, ::memcmp(expected + 1, dest.c_str(), 2)); > + } > + // > + // void copy(unsigned off, unsigned len, std::string &dest) const; > + // > + { > + bufferlist bl; > + std::string dest; > + EXPECT_THROW(bl.copy((unsigned)100, (unsigned)100, dest), buffer::end_of_buffer); > + const char *expected = "ABC"; > + bl.append(expected); > + bl.copy(1, 2, dest); > + EXPECT_EQ(0, ::memcmp(expected + 1, dest.c_str(), 2)); > + } > +} > + > +TEST(BufferList, copy_in) { > + // > + // void copy_in(unsigned off, unsigned len, const char *src); > + // > + { > + bufferlist bl; > + bl.append("XXX"); > + EXPECT_THROW(bl.copy_in((unsigned)100, (unsigned)100, (char*)0), buffer::end_of_buffer); > + bl.copy_in(1, 2, "AB"); > + EXPECT_EQ(0, ::memcmp("XAB", bl.c_str(), 3)); > + } > + // > + // void copy_in(unsigned off, unsigned len, const list& src); > + // > + { > + bufferlist bl; > + bl.append("XXX"); > + bufferlist src; > + src.append("ABC"); > + EXPECT_THROW(bl.copy_in((unsigned)100, (unsigned)100, src), buffer::end_of_buffer); > + bl.copy_in(1, 2, src); > + EXPECT_EQ(0, ::memcmp("XAB", bl.c_str(), 3)); > + } > } > > -TEST(BufferList, zero) { > +TEST(BufferList, append) { > // > - // void zero() > + // void append(char c); > // > { > bufferlist bl; > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > bl.append('A'); > - EXPECT_EQ('A', bl[0]); > - bl.zero(); > - EXPECT_EQ('\0', bl[0]); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + EXPECT_TRUE(bl.is_page_aligned()); > } > // > - // void zero(unsigned o, unsigned l) > + // void append(const char *data, unsigned len); > + // > + { > + bufferlist bl(CEPH_PAGE_SIZE); > + std::string str(CEPH_PAGE_SIZE * 2, 'X'); > + bl.append(str.c_str(), str.size()); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().front().length()); > + EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().back().length()); > + } > + // > + // void append(const std::string& s); > + // > + { > + bufferlist bl(CEPH_PAGE_SIZE); > + std::string str(CEPH_PAGE_SIZE * 2, 'X'); > + bl.append(str); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().front().length()); > + EXPECT_EQ(CEPH_PAGE_SIZE, bl.buffers().back().length()); > + } > + // > + // void append(const ptr& bp); > + // > + { > + bufferlist bl; > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > + EXPECT_EQ((unsigned)0, bl.length()); > + { > + bufferptr ptr; > + bl.append(ptr); > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > + EXPECT_EQ((unsigned)0, bl.length()); > + } > + { > + bufferptr ptr(3); > + bl.append(ptr); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + EXPECT_EQ((unsigned)3, bl.length()); > + } > + } > + // > + // void append(const ptr& bp, unsigned off, unsigned len); > + // > + { > + bufferlist bl; > + bl.append('A'); > + bufferptr back(bl.buffers().back()); > + bufferptr in(back); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + EXPECT_EQ((unsigned)1, bl.length()); > + EXPECT_THROW(bl.append(in, (unsigned)100, (unsigned)100), FailedAssertion); > + EXPECT_LT((unsigned)0, in.unused_tail_length()); > + in.append('B'); > + bl.append(in, back.end(), 1); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + EXPECT_EQ((unsigned)2, bl.length()); > + EXPECT_EQ('B', bl[1]); > + } > + { > + bufferlist bl; > + EXPECT_EQ((unsigned)0, bl.buffers().size()); > + EXPECT_EQ((unsigned)0, bl.length()); > + bufferptr ptr(2); > + ptr.set_length(0); > + ptr.append("AB", 2); > + bl.append(ptr, 1, 1); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + EXPECT_EQ((unsigned)1, bl.length()); > + } > + // > + // void append(const list& bl); > + // > + { > + bufferlist bl; > + bl.append('A'); > + bufferlist other; > + other.append('B'); > + bl.append(other); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ('B', bl[1]); > + } > + // > + // void append(std::istream& in); > // > + { > + bufferlist bl; > + std::string expected("ABC\n\nDEF\n"); > + std::istringstream is("ABC\n\nDEF"); > + bl.append(is); > + EXPECT_EQ(0, ::memcmp(expected.c_str(), bl.c_str(), expected.size())); > + EXPECT_EQ(expected.size(), bl.length()); > + } > +} > + > +TEST(BufferList, append_zero) { > + bufferlist bl; > + bl.append('A'); > + EXPECT_EQ((unsigned)1, bl.buffers().size()); > + EXPECT_EQ((unsigned)1, bl.length()); > + bl.append_zero(1); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ((unsigned)2, bl.length()); > + EXPECT_EQ('\0', bl[1]); > +} > + > +TEST(BufferList, operator_brackets) { > + bufferlist bl; > + EXPECT_THROW(bl[1], buffer::end_of_buffer); > + bl.append('A'); > + bufferlist other; > + other.append('B'); > + bl.append(other); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ('B', bl[1]); > +} > + > +TEST(BufferList, c_str) { > + bufferlist bl; > + EXPECT_EQ((const char*)NULL, bl.c_str()); > + bl.append('A'); > + bufferlist other; > + other.append('B'); > + bl.append(other); > + EXPECT_EQ((unsigned)2, bl.buffers().size()); > + EXPECT_EQ(0, ::memcmp("AB", bl.c_str(), 2)); > +} > + > +TEST(BufferList, substr_of) { > + bufferlist bl; > + EXPECT_THROW(bl.substr_of(bl, 1, 1), buffer::end_of_buffer); > const char *s[] = { > "ABC", > "DEF", > "GHI", > - "KLM" > + "JKL" > }; > - { > - bufferlist bl; > - bufferptr ptr(s[0], strlen(s[0])); > + for (unsigned i = 0; i < 4; i++) { > + bufferptr ptr(s[i], strlen(s[i])); > bl.push_back(ptr); > - bl.zero((unsigned)0, (unsigned)1); > - EXPECT_EQ(0, ::memcmp("\0BC", bl.c_str(), 3)); > } > - { > - bufferlist bl; > - for (unsigned i = 0; i < 4; i++) { > - bufferptr ptr(s[i], strlen(s[i])); > - bl.push_back(ptr); > - } > - EXPECT_THROW(bl.zero((unsigned)0, (unsigned)2000), FailedAssertion); > - bl.zero((unsigned)2, (unsigned)5); > - EXPECT_EQ(0, ::memcmp("AB\0\0\0\0\0HIKLM", bl.c_str(), 9)); > + EXPECT_EQ((unsigned)4, bl.buffers().size()); > + > + bufferlist other; > + other.append("TO BE CLEARED"); > + other.substr_of(bl, 4, 4); > + EXPECT_EQ((unsigned)2, other.buffers().size()); > + EXPECT_EQ((unsigned)4, other.length()); > + EXPECT_EQ(0, ::memcmp("EFGH", other.c_str(), 4)); > +} > + > +TEST(BufferList, splice) { > + bufferlist bl; > + EXPECT_THROW(bl.splice(1, 1), buffer::end_of_buffer); > + const char *s[] = { > + "ABC", > + "DEF", > + "GHI", > + "JKL" > + }; > + for (unsigned i = 0; i < 4; i++) { > + bufferptr ptr(s[i], strlen(s[i])); > + bl.push_back(ptr); > } > + EXPECT_EQ((unsigned)4, bl.buffers().size()); > + EXPECT_THROW(bl.splice(0, 0), FailedAssertion); > + > + bufferlist other; > + other.append('X'); > + bl.splice(4, 4, &other); > + EXPECT_EQ((unsigned)3, other.buffers().size()); > + EXPECT_EQ((unsigned)5, other.length()); > + EXPECT_EQ(0, ::memcmp("XEFGH", other.c_str(), other.length())); > + EXPECT_EQ((unsigned)8, bl.length()); > { > - bufferlist bl; > - for (unsigned i = 0; i < 4; i++) { > - bufferptr ptr(s[i], strlen(s[i])); > - bl.push_back(ptr); > - } > - bl.zero((unsigned)3, (unsigned)3); > - EXPECT_EQ(0, ::memcmp("ABC\0\0\0GHIKLM", bl.c_str(), 9)); > + bufferlist tmp(bl); > + EXPECT_EQ(0, ::memcmp("ABCDIJKL", tmp.c_str(), tmp.length())); > + } > + > + bl.splice(4, 4); > + EXPECT_EQ((unsigned)4, bl.length()); > + EXPECT_EQ(0, ::memcmp("ABCD", bl.c_str(), bl.length())); > +} > + > +TEST(BufferList, write) { > + std::ostringstream stream; > + bufferlist bl; > + bl.append("ABC"); > + bl.write(1, 2, stream); > + EXPECT_EQ("BC", stream.str()); > +} > + > +TEST(BufferList, encode_base64) { > + bufferlist bl; > + bl.append("ABCD"); > + bufferlist other; > + bl.encode_base64(other); > + const char *expected = "QUJDRA=="; > + EXPECT_EQ(0, ::memcmp(expected, other.c_str(), strlen(expected))); > +} > + > +TEST(BufferList, decode_base64) { > + bufferlist bl; > + bl.append("QUJDRA=="); > + bufferlist other; > + other.decode_base64(bl); > + const char *expected = "ABCD"; > + EXPECT_EQ(0, ::memcmp(expected, other.c_str(), strlen(expected))); > + bufferlist malformed; > + malformed.append("QUJDRA"); > + EXPECT_THROW(other.decode_base64(malformed), buffer::malformed_input); > +} > + > +TEST(BufferList, hexdump) { > + bufferlist bl; > + std::ostringstream stream; > + bl.append("013245678901234\0006789012345678901234", 32); > + bl.hexdump(stream); > + EXPECT_EQ("0000 : 30 31 33 32 34 35 36 37 38 39 30 31 32 33 34 00 : 013245678901234.\n" > + "0010 : 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 : 6789012345678901\n", > + stream.str()); > +} > + > +TEST(BufferList, read_file) { > + std::string error; > + bufferlist bl; > + ::unlink("testfile"); > + EXPECT_EQ(-ENOENT, bl.read_file("UNLIKELY", &error)); > + ::system("echo ABC > testfile ; chmod 0 testfile"); > + EXPECT_EQ(-EACCES, bl.read_file("testfile", &error)); > + ::system("chmod +r testfile"); > + EXPECT_EQ(0, bl.read_file("testfile", &error)); > + ::unlink("testfile"); > + EXPECT_EQ((unsigned)4, bl.length()); > + std::string actual(bl.c_str(), bl.length()); > + EXPECT_EQ("ABC\n", actual); > +} > + > +TEST(BufferList, read_fd) { > + unsigned len = 4; > + ::unlink("testfile"); > + ::system("echo ABC > testfile"); > + int fd = -1; > + bufferlist bl; > + EXPECT_EQ(-EBADF, bl.read_fd(fd, len)); > + fd = ::open("testfile", O_RDONLY); > + EXPECT_EQ(len, bl.read_fd(fd, len)); > + EXPECT_EQ(len, bl.length()); > + EXPECT_EQ(CEPH_PAGE_SIZE - len, bl.buffers().front().unused_tail_length()); > + ::close(fd); > + ::unlink("testfile"); > +} > + > +TEST(BufferList, write_file) { > + ::unlink("testfile"); > + int mode = 0600; > + bufferlist bl; > + EXPECT_EQ(-ENOENT, bl.write_file("un/like/ly", mode)); > + bl.append("ABC"); > + EXPECT_EQ(0, bl.write_file("testfile", mode)); > + struct stat st; > + memset(&st, 0, sizeof(st)); > + ::stat("testfile", &st); > + EXPECT_EQ((unsigned)(mode | S_IFREG), st.st_mode); > + ::unlink("testfile"); > +} > + > +TEST(BufferList, write_fd) { > + ::unlink("testfile"); > + int fd = ::open("testfile", O_WRONLY|O_CREAT|O_TRUNC, 0600); > + bufferlist bl; > + for (unsigned i = 0; i < IOV_MAX * 2; i++) { > + bufferptr ptr("A", 1); > + bl.push_back(ptr); > } > + EXPECT_EQ(0, bl.write_fd(fd)); > + ::close(fd); > + struct stat st; > + memset(&st, 0, sizeof(st)); > + ::stat("testfile", &st); > + EXPECT_EQ(IOV_MAX * 2, st.st_size); > + ::unlink("testfile"); > +} > + > +TEST(BufferList, crc32c) { > + bufferlist bl; > + __u32 crc = 0; > + bl.append("A"); > + crc = bl.crc32c(crc); > + EXPECT_EQ((unsigned)0xB3109EBF, crc); > + crc = bl.crc32c(crc); > + EXPECT_EQ((unsigned)0x5FA5C0CC, crc); > } > > TEST(BufferList, compare) { > @@ -121,6 +1694,72 @@ TEST(BufferList, compare) { > ASSERT_TRUE(ab == ab); > } > > +TEST(BufferList, ostream) { > + std::ostringstream stream; > + bufferlist bl; > + const char *s[] = { > + "ABC", > + "DEF" > + }; > + for (unsigned i = 0; i < 2; i++) { > + bufferptr ptr(s[i], strlen(s[i])); > + bl.push_back(ptr); > + } > + stream << bl; > + std::cerr << stream.str() << std::endl; > + EXPECT_GT(stream.str().size(), stream.str().find("list(len=6,")); > + EXPECT_GT(stream.str().size(), stream.str().find("len 3 nref 1),\n")); > + EXPECT_GT(stream.str().size(), stream.str().find("len 3 nref 1)\n")); > +} > + > +TEST(BufferList, zero) { > + // > + // void zero() > + // > + { > + bufferlist bl; > + bl.append('A'); > + EXPECT_EQ('A', bl[0]); > + bl.zero(); > + EXPECT_EQ('\0', bl[0]); > + } > + // > + // void zero(unsigned o, unsigned l) > + // > + const char *s[] = { > + "ABC", > + "DEF", > + "GHI", > + "KLM" > + }; > + { > + bufferlist bl; > + bufferptr ptr(s[0], strlen(s[0])); > + bl.push_back(ptr); > + bl.zero((unsigned)0, (unsigned)1); > + EXPECT_EQ(0, ::memcmp("\0BC", bl.c_str(), 3)); > + } > + { > + bufferlist bl; > + for (unsigned i = 0; i < 4; i++) { > + bufferptr ptr(s[i], strlen(s[i])); > + bl.push_back(ptr); > + } > + EXPECT_THROW(bl.zero((unsigned)0, (unsigned)2000), FailedAssertion); > + bl.zero((unsigned)2, (unsigned)5); > + EXPECT_EQ(0, ::memcmp("AB\0\0\0\0\0HIKLM", bl.c_str(), 9)); > + } > + { > + bufferlist bl; > + for (unsigned i = 0; i < 4; i++) { > + bufferptr ptr(s[i], strlen(s[i])); > + bl.push_back(ptr); > + } > + bl.zero((unsigned)3, (unsigned)3); > + EXPECT_EQ(0, ::memcmp("ABC\0\0\0GHIKLM", bl.c_str(), 9)); > + } > +} > + > TEST(BufferList, EmptyAppend) { > bufferlist bl; > bufferptr ptr; > @@ -151,54 +1790,6 @@ TEST(BufferList, TestPtrAppend) { > ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0); > } > > -TEST(BufferList, ptr_assignment) { > - unsigned len = 17; > - // > - // override a bufferptr set with the same raw > - // > - { > - bufferptr original(len); > - bufferptr same_raw(original.get_raw()); > - unsigned offset = 5; > - unsigned length = len - offset; > - original.set_offset(offset); > - original.set_length(length); > - same_raw = original; > - ASSERT_EQ(2, original.raw_nref()); > - ASSERT_EQ(same_raw.get_raw(), original.get_raw()); > - ASSERT_EQ(same_raw.offset(), original.offset()); > - ASSERT_EQ(same_raw.length(), original.length()); > - } > - > - // > - // self assignment is a noop > - // > - { > - bufferptr original(len); > - original = original; > - ASSERT_EQ(1, original.raw_nref()); > - ASSERT_EQ((unsigned)0, original.offset()); > - ASSERT_EQ(len, original.length()); > - } > - > - // > - // a copy points to the same raw > - // > - { > - bufferptr original(len); > - unsigned offset = 5; > - unsigned length = len - offset; > - original.set_offset(offset); > - original.set_length(length); > - bufferptr ptr; > - ptr = original; > - ASSERT_EQ(2, original.raw_nref()); > - ASSERT_EQ(ptr.get_raw(), original.get_raw()); > - ASSERT_EQ(original.offset(), ptr.offset()); > - ASSERT_EQ(original.length(), ptr.length()); > - } > -} > - > TEST(BufferList, TestDirectAppend) { > bufferlist bl; > char correct[MAX_TEST]; > @@ -234,3 +1825,29 @@ TEST(BufferList, TestCopyAll) { > bl2.copy(0, BIG_SZ, (char*)big2); > ASSERT_EQ(memcmp(big.get(), big2, BIG_SZ), 0); > } > + > +TEST(BufferHash, all) { > + { > + bufferlist bl; > + bl.append("A"); > + bufferhash hash; > + EXPECT_EQ((unsigned)0, hash.digest()); > + hash.update(bl); > + EXPECT_EQ((unsigned)0xB3109EBF, hash.digest()); > + hash.update(bl); > + EXPECT_EQ((unsigned)0x5FA5C0CC, hash.digest()); > + } > + { > + bufferlist bl; > + bl.append("A"); > + bufferhash hash; > + EXPECT_EQ((unsigned)0, hash.digest()); > + bufferhash& returned_hash = hash << bl; > + EXPECT_EQ(&returned_hash, &hash); > + EXPECT_EQ((unsigned)0xB3109EBF, hash.digest()); > + } > +} > + > +// Local Variables: > +// compile-command: "cd .. ; make unittest_bufferlist ; ulimit -s unlimited ; CEPH_BUFFER_TRACK=true valgrind --max-stackframe=20000000 --tool=memcheck ./unittest_bufferlist # --gtest_filter=BufferList.constructors" > +// End: > diff --git a/src/unittest_bufferlist.sh b/src/unittest_bufferlist.sh > new file mode 100755 > index 0000000..0f05afe > --- /dev/null > +++ b/src/unittest_bufferlist.sh > @@ -0,0 +1,19 @@ > +#!/bin/bash > +# > +# Ceph - scalable distributed file system > +# > +# Copyright (C) 2013 Cloudwatt <libre.licensing@xxxxxxxxxxxxx> > +# > +# Author: Loic Dachary <loic@xxxxxxxxxxx> > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU Library Public License as published by > +# the Free Software Foundation; either version 2, or (at your option) > +# any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU Library Public License for more details. > +# > +CEPH_BUFFER_TRACK=true ./unittest_bufferlist > -- > 1.7.10.4 > > -- > To unsubscribe from this list: send the line "unsubscribe ceph-devel" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > > -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html