Message ID | 1361129932-7466-1-git-send-email-loic@dachary.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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@dachary.org> > --- > 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@cloudwatt.com> > + * > + * Author: Loic Dachary <loic@dachary.org> > + * > + * 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@cloudwatt.com> > +# > +# Author: Loic Dachary <loic@dachary.org> > +# > +# 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@vger.kernel.org > 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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Sage, On 02/18/2013 06:48 AM, Sage Weil wrote: > Hi Loic, > > I merged this in, which two small changes: Thanks ! > - the malloc ULLONG_MAX tests were succeeding and eating RAM on my box; > commented them out. You have a lot of RAM ( kidding ). I'll investigate and find a safe way to fail memory allocation. > - the BIG_SZ buffer on teh stack was segfaulting; put it on the heap. That was not a test I wrote and I worked around the problem with ulimit -s unlimited ; make unittest_bufferlist but the heap is a better choice. I was not sure if allocating in the stack was deliberate or not. > > Otherwise, looks great! I'm very pleased to have test coverage on this > code. :) It was an interesting experience :-) I'll write a small blog post about the buffers before I forget the details. Cheers > 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@dachary.org> >> --- >> 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@cloudwatt.com> >> + * >> + * Author: Loic Dachary <loic@dachary.org> >> + * >> + * 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@cloudwatt.com> >> +# >> +# Author: Loic Dachary <loic@dachary.org> >> +# >> +# 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@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >>
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@cloudwatt.com> + * + * Author: Loic Dachary <loic@dachary.org> + * + * 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@cloudwatt.com> +# +# Author: Loic Dachary <loic@dachary.org> +# +# 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
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@dachary.org> --- 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