Commit 8da400ed authored by kenton@google.com's avatar kenton@google.com

Fix bugs in zero_copy_stream_impl.

Patch from Frank Chu.
parent 32d0c3b8
...@@ -218,7 +218,8 @@ int CopyingInputStream::Skip(int count) { ...@@ -218,7 +218,8 @@ int CopyingInputStream::Skip(int count) {
char junk[4096]; char junk[4096];
int skipped = 0; int skipped = 0;
while (skipped < count) { while (skipped < count) {
int bytes = Read(junk, min(count, implicit_cast<int>(sizeof(junk)))); int bytes = Read(junk, min(count - skipped,
implicit_cast<int>(sizeof(junk))));
if (bytes <= 0) { if (bytes <= 0) {
// EOF or read error. // EOF or read error.
return skipped; return skipped;
...@@ -757,7 +758,7 @@ LimitingInputStream::~LimitingInputStream() { ...@@ -757,7 +758,7 @@ LimitingInputStream::~LimitingInputStream() {
} }
bool LimitingInputStream::Next(const void** data, int* size) { bool LimitingInputStream::Next(const void** data, int* size) {
if (limit_ < 0) return false; if (limit_ <= 0) return false;
if (!input_->Next(data, size)) return false; if (!input_->Next(data, size)) return false;
limit_ -= *size; limit_ -= *size;
......
...@@ -90,10 +90,10 @@ class IoTest : public testing::Test { ...@@ -90,10 +90,10 @@ class IoTest : public testing::Test {
// Helper to read a fixed-length array of data from an input stream. // Helper to read a fixed-length array of data from an input stream.
int ReadFromInput(ZeroCopyInputStream* input, void* data, int size); int ReadFromInput(ZeroCopyInputStream* input, void* data, int size);
// Write a string to the output stream. // Write a string to the output stream.
void WriteString(ZeroCopyOutputStream* output, const char* str); void WriteString(ZeroCopyOutputStream* output, const string& str);
// Read a number of bytes equal to the size of the given string and checks // Read a number of bytes equal to the size of the given string and checks
// that it matches the string. // that it matches the string.
void ReadString(ZeroCopyInputStream* input, const char* str); void ReadString(ZeroCopyInputStream* input, const string& str);
// Writes some text to the output stream in a particular order. Returns // Writes some text to the output stream in a particular order. Returns
// the number of bytes written, incase the caller needs that to set up an // the number of bytes written, incase the caller needs that to set up an
// input stream. // input stream.
...@@ -102,6 +102,12 @@ class IoTest : public testing::Test { ...@@ -102,6 +102,12 @@ class IoTest : public testing::Test {
// WriteStuff() writes. // WriteStuff() writes.
void ReadStuff(ZeroCopyInputStream* input); void ReadStuff(ZeroCopyInputStream* input);
// Similar to WriteStuff, but performs more sophisticated testing.
int WriteStuffLarge(ZeroCopyOutputStream* output);
// Reads and tests a stream that should have been written to
// via WriteStuffLarge().
void ReadStuffLarge(ZeroCopyInputStream* input);
static const int kBlockSizes[]; static const int kBlockSizes[];
static const int kBlockSizeCount; static const int kBlockSizeCount;
}; };
...@@ -121,6 +127,7 @@ bool IoTest::WriteToOutput(ZeroCopyOutputStream* output, ...@@ -121,6 +127,7 @@ bool IoTest::WriteToOutput(ZeroCopyOutputStream* output,
if (!output->Next(&out, &out_size)) { if (!output->Next(&out, &out_size)) {
return false; return false;
} }
EXPECT_GT(out_size, 0);
if (in_size <= out_size) { if (in_size <= out_size) {
memcpy(out, in, in_size); memcpy(out, in, in_size);
...@@ -145,6 +152,7 @@ int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) { ...@@ -145,6 +152,7 @@ int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) {
if (!input->Next(&in, &in_size)) { if (!input->Next(&in, &in_size)) {
return size - out_size; return size - out_size;
} }
EXPECT_GT(in_size, 0);
if (out_size <= in_size) { if (out_size <= in_size) {
memcpy(out, in, out_size); memcpy(out, in, out_size);
...@@ -158,16 +166,15 @@ int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) { ...@@ -158,16 +166,15 @@ int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) {
} }
} }
void IoTest::WriteString(ZeroCopyOutputStream* output, const char* str) { void IoTest::WriteString(ZeroCopyOutputStream* output, const string& str) {
EXPECT_TRUE(WriteToOutput(output, str, strlen(str))); EXPECT_TRUE(WriteToOutput(output, str.c_str(), str.size()));
} }
void IoTest::ReadString(ZeroCopyInputStream* input, const char* str) { void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) {
int length = strlen(str); scoped_array<char> buffer(new char[str.size() + 1]);
scoped_array<char> buffer(new char[length + 1]); buffer[str.size()] = '\0';
buffer[length] = '\0'; EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size());
EXPECT_EQ(ReadFromInput(input, buffer.get(), length), length); EXPECT_STREQ(str.c_str(), buffer.get());
EXPECT_STREQ(str, buffer.get());
} }
int IoTest::WriteStuff(ZeroCopyOutputStream* output) { int IoTest::WriteStuff(ZeroCopyOutputStream* output) {
...@@ -202,6 +209,37 @@ void IoTest::ReadStuff(ZeroCopyInputStream* input) { ...@@ -202,6 +209,37 @@ void IoTest::ReadStuff(ZeroCopyInputStream* input) {
EXPECT_EQ(ReadFromInput(input, &byte, 1), 0); EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
} }
int IoTest::WriteStuffLarge(ZeroCopyOutputStream* output) {
WriteString(output, "Hello world!\n");
WriteString(output, "Some te");
WriteString(output, "xt. Blah blah.");
WriteString(output, string(100000, 'x')); // A very long string
WriteString(output, string(100000, 'y')); // A very long string
WriteString(output, "01234567890123456789");
EXPECT_EQ(output->ByteCount(), 200055);
int result = output->ByteCount();
return result;
}
// Reads text from an input stream and expects it to match what WriteStuff()
// writes.
void IoTest::ReadStuffLarge(ZeroCopyInputStream* input) {
ReadString(input, "Hello world!\nSome text. ");
EXPECT_TRUE(input->Skip(5));
ReadString(input, "blah.");
EXPECT_TRUE(input->Skip(100000 - 10));
ReadString(input, string(10, 'x') + string(100000 - 20000, 'y'));
EXPECT_TRUE(input->Skip(20000 - 10));
ReadString(input, "yyyyyyyyyy01234567890123456789");
EXPECT_EQ(input->ByteCount(), 200055);
uint8 byte;
EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
}
// =================================================================== // ===================================================================
TEST_F(IoTest, ArrayIo) { TEST_F(IoTest, ArrayIo) {
...@@ -369,18 +407,36 @@ TEST_F(IoTest, PipeIo) { ...@@ -369,18 +407,36 @@ TEST_F(IoTest, PipeIo) {
TEST_F(IoTest, IostreamIo) { TEST_F(IoTest, IostreamIo) {
for (int i = 0; i < kBlockSizeCount; i++) { for (int i = 0; i < kBlockSizeCount; i++) {
for (int j = 0; j < kBlockSizeCount; j++) { for (int j = 0; j < kBlockSizeCount; j++) {
stringstream stream;
{ {
OstreamOutputStream output(&stream, kBlockSizes[i]); stringstream stream;
WriteStuff(&output);
EXPECT_FALSE(stream.fail()); {
OstreamOutputStream output(&stream, kBlockSizes[i]);
WriteStuff(&output);
EXPECT_FALSE(stream.fail());
}
{
IstreamInputStream input(&stream, kBlockSizes[j]);
ReadStuff(&input);
EXPECT_TRUE(stream.eof());
}
} }
{ {
IstreamInputStream input(&stream, kBlockSizes[j]); stringstream stream;
ReadStuff(&input);
EXPECT_TRUE(stream.eof()); {
OstreamOutputStream output(&stream, kBlockSizes[i]);
WriteStuffLarge(&output);
EXPECT_FALSE(stream.fail());
}
{
IstreamInputStream input(&stream, kBlockSizes[j]);
ReadStuffLarge(&input);
EXPECT_TRUE(stream.eof());
}
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment