phoenix-firestorm/indra/llcommon/tests/llstreamqueue_test.cpp

195 lines
8.7 KiB
C++

/**
* @file llstreamqueue_test.cpp
* @author Nat Goodspeed
* @date 2012-01-05
* @brief Test for llstreamqueue.
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Copyright (c) 2012, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "llstreamqueue.h"
// STL headers
#include <vector>
// other Linden headers
#include "../test/lltut.h"
#include "stringize.h"
/*****************************************************************************
* TUT
*****************************************************************************/
namespace tut
{
struct llstreamqueue_data
{
llstreamqueue_data():
// we want a buffer with actual bytes in it, not an empty vector
buffer(10)
{}
// As LLStreamQueue is merely a typedef for
// LLGenericStreamQueue<char>, and no logic in LLGenericStreamQueue is
// specific to the <char> instantiation, we're comfortable for now
// testing only the narrow-char version.
LLStreamQueue strq;
// buffer for use in multiple tests
std::vector<char> buffer;
};
typedef test_group<llstreamqueue_data> llstreamqueue_group;
typedef llstreamqueue_group::object object;
llstreamqueue_group llstreamqueuegrp("llstreamqueue");
template<> template<>
void object::test<1>()
{
set_test_name("empty LLStreamQueue");
ensure_equals("brand-new LLStreamQueue isn't empty",
strq.size(), 0);
ensure_equals("brand-new LLStreamQueue returns data",
strq.asSource().read(&buffer[0], buffer.size()), 0);
strq.asSink().close();
ensure_equals("closed empty LLStreamQueue not at EOF",
strq.asSource().read(&buffer[0], buffer.size()), -1);
}
template<> template<>
void object::test<2>()
{
set_test_name("one internal block, one buffer");
LLStreamQueue::Sink sink(strq.asSink());
ensure_equals("write(\"\")", sink.write("", 0), 0);
ensure_equals("0 write should leave LLStreamQueue empty (size())",
strq.size(), 0);
ensure_equals("0 write should leave LLStreamQueue empty (peek())",
strq.peek(&buffer[0], buffer.size()), 0);
// The meaning of "atomic" is that it must be smaller than our buffer.
std::string atomic("atomic");
ensure("test data exceeds buffer", atomic.length() < buffer.size());
ensure_equals(STRINGIZE("write(\"" << atomic << "\")"),
sink.write(&atomic[0], atomic.length()), atomic.length());
ensure_equals("size() after write()", strq.size(), atomic.length());
size_t peeklen(strq.peek(&buffer[0], buffer.size()));
ensure_equals(STRINGIZE("peek(\"" << atomic << "\")"),
peeklen, atomic.length());
ensure_equals(STRINGIZE("peek(\"" << atomic << "\") result"),
std::string(buffer.begin(), buffer.begin() + peeklen), atomic);
ensure_equals("size() after peek()", strq.size(), atomic.length());
// peek() should not consume. Use a different buffer to prove it isn't
// just leftover data from the first peek().
std::vector<char> again(buffer.size());
peeklen = size_t(strq.peek(&again[0], again.size()));
ensure_equals(STRINGIZE("peek(\"" << atomic << "\") again"),
peeklen, atomic.length());
ensure_equals(STRINGIZE("peek(\"" << atomic << "\") again result"),
std::string(again.begin(), again.begin() + peeklen), atomic);
// now consume.
std::vector<char> third(buffer.size());
size_t readlen(strq.read(&third[0], third.size()));
ensure_equals(STRINGIZE("read(\"" << atomic << "\")"),
readlen, atomic.length());
ensure_equals(STRINGIZE("read(\"" << atomic << "\") result"),
std::string(third.begin(), third.begin() + readlen), atomic);
ensure_equals("peek() after read()", strq.peek(&buffer[0], buffer.size()), 0);
ensure_equals("size() after read()", strq.size(), 0);
}
template<> template<>
void object::test<3>()
{
set_test_name("basic skip()");
std::string lovecraft("lovecraft");
ensure("test data exceeds buffer", lovecraft.length() < buffer.size());
ensure_equals(STRINGIZE("write(\"" << lovecraft << "\")"),
strq.write(&lovecraft[0], lovecraft.length()), lovecraft.length());
size_t peeklen(strq.peek(&buffer[0], buffer.size()));
ensure_equals(STRINGIZE("peek(\"" << lovecraft << "\")"),
peeklen, lovecraft.length());
ensure_equals(STRINGIZE("peek(\"" << lovecraft << "\") result"),
std::string(buffer.begin(), buffer.begin() + peeklen), lovecraft);
std::streamsize skip1(4);
ensure_equals(STRINGIZE("skip(" << skip1 << ")"), strq.skip(skip1), skip1);
ensure_equals("size() after skip()", strq.size(), lovecraft.length() - skip1);
size_t readlen(strq.read(&buffer[0], buffer.size()));
ensure_equals(STRINGIZE("read(\"" << lovecraft.substr(skip1) << "\")"),
readlen, lovecraft.length() - skip1);
ensure_equals(STRINGIZE("read(\"" << lovecraft.substr(skip1) << "\") result"),
std::string(buffer.begin(), buffer.begin() + readlen),
lovecraft.substr(skip1));
ensure_equals("unconsumed", strq.read(&buffer[0], buffer.size()), 0);
}
template<> template<>
void object::test<4>()
{
set_test_name("skip() multiple blocks");
std::string blocks[] = { "books of ", "H.P. ", "Lovecraft" };
std::streamsize total(blocks[0].length() + blocks[1].length() + blocks[2].length());
std::streamsize leave(5); // len("craft") above
std::streamsize skip(total - leave);
std::streamsize written(0);
for (const std::string& block : blocks)
{
written += strq.write(&block[0], block.length());
ensure_equals("size() after write()", strq.size(), written);
}
std::streamsize skiplen(strq.skip(skip));
ensure_equals(STRINGIZE("skip(" << skip << ")"), skiplen, skip);
ensure_equals("size() after skip()", strq.size(), leave);
size_t readlen(strq.read(&buffer[0], buffer.size()));
ensure_equals("read(\"craft\")", readlen, leave);
ensure_equals("read(\"craft\") result",
std::string(buffer.begin(), buffer.begin() + readlen), "craft");
}
template<> template<>
void object::test<5>()
{
set_test_name("concatenate blocks");
std::string blocks[] = { "abcd", "efghij", "klmnopqrs" };
for (const std::string& block : blocks)
{
strq.write(&block[0], block.length());
}
std::vector<char> longbuffer(30);
std::streamsize readlen(strq.read(&longbuffer[0], longbuffer.size()));
ensure_equals("read() multiple blocks",
readlen, blocks[0].length() + blocks[1].length() + blocks[2].length());
ensure_equals("read() multiple blocks result",
std::string(longbuffer.begin(), longbuffer.begin() + readlen),
blocks[0] + blocks[1] + blocks[2]);
}
template<> template<>
void object::test<6>()
{
set_test_name("split blocks");
std::string blocks[] = { "abcdefghijklm", "nopqrstuvwxyz" };
for (const std::string& block : blocks)
{
strq.write(&block[0], block.length());
}
strq.close();
// We've already verified what strq.size() should be at this point;
// see above test named "skip() multiple blocks"
std::streamsize chksize(strq.size());
std::streamsize readlen(strq.read(&buffer[0], buffer.size()));
ensure_equals("read() 0", readlen, buffer.size());
ensure_equals("read() 0 result", std::string(buffer.begin(), buffer.end()), "abcdefghij");
chksize -= readlen;
ensure_equals("size() after read() 0", strq.size(), chksize);
readlen = strq.read(&buffer[0], buffer.size());
ensure_equals("read() 1", readlen, buffer.size());
ensure_equals("read() 1 result", std::string(buffer.begin(), buffer.end()), "klmnopqrst");
chksize -= readlen;
ensure_equals("size() after read() 1", strq.size(), chksize);
readlen = strq.read(&buffer[0], buffer.size());
ensure_equals("read() 2", readlen, chksize);
ensure_equals("read() 2 result",
std::string(buffer.begin(), buffer.begin() + readlen), "uvwxyz");
ensure_equals("read() 3", strq.read(&buffer[0], buffer.size()), -1);
}
} // namespace tut