* [PATCH] unit tests for src/common/buffer.{cc,h}
@ 2013-02-17 19:38 Loic Dachary
2013-02-18 5:48 ` Sage Weil
0 siblings, 1 reply; 3+ messages in thread
From: Loic Dachary @ 2013-02-17 19:38 UTC (permalink / raw)
To: ceph-devel
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
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] unit tests for src/common/buffer.{cc,h}
2013-02-17 19:38 [PATCH] unit tests for src/common/buffer.{cc,h} Loic Dachary
@ 2013-02-18 5:48 ` Sage Weil
2013-02-18 7:17 ` Loic Dachary
0 siblings, 1 reply; 3+ messages in thread
From: Sage Weil @ 2013-02-18 5:48 UTC (permalink / raw)
To: Loic Dachary; +Cc: ceph-devel
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
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] unit tests for src/common/buffer.{cc,h}
2013-02-18 5:48 ` Sage Weil
@ 2013-02-18 7:17 ` Loic Dachary
0 siblings, 0 replies; 3+ messages in thread
From: Loic Dachary @ 2013-02-18 7:17 UTC (permalink / raw)
To: Sage Weil; +Cc: ceph-devel
[-- Attachment #1: Type: text/plain, Size: 62182 bytes --]
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
>>
>>
--
Loïc Dachary, Artisan Logiciel Libre
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-02-18 7:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-17 19:38 [PATCH] unit tests for src/common/buffer.{cc,h} Loic Dachary
2013-02-18 5:48 ` Sage Weil
2013-02-18 7:17 ` Loic Dachary
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.