webrtc/rtc_base/stream_unittest.cc
Niels Möller a8fa2d061f Move some methods from StreamInterface to FifoBuffer
Moved methods: GetReadData, ConsumeReadData, GetWriteBuffer,
ConsumeWriteBuffer, GetWriteRemaining.

These methods represented an optional interface for reading and
writing streams, intended to optimize certain use cases. However,
it was implemented only in the FifoBuffer subclass, and the few
users of that class all have a concrete FifoBuffer, and hence
don't need the methods on the abstract StreamInterface.

Bug: webrtc:6424
Change-Id: I6de74d1a9205fcb7037ad84e24679d4a27c1d219
Reviewed-on: https://webrtc-review.googlesource.com/c/108621
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25446}
2018-10-31 10:11:39 +00:00

373 lines
12 KiB
C++

/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/stream.h"
#include "rtc_base/gunit.h"
namespace rtc {
///////////////////////////////////////////////////////////////////////////////
// TestStream
///////////////////////////////////////////////////////////////////////////////
class TestStream : public StreamInterface {
public:
TestStream() : pos_(0) {}
StreamState GetState() const override { return SS_OPEN; }
StreamResult Read(void* buffer,
size_t buffer_len,
size_t* read,
int* error) override {
unsigned char* uc_buffer = static_cast<unsigned char*>(buffer);
for (size_t i = 0; i < buffer_len; ++i) {
uc_buffer[i] = static_cast<unsigned char>(pos_++);
}
if (read)
*read = buffer_len;
return SR_SUCCESS;
}
StreamResult Write(const void* data,
size_t data_len,
size_t* written,
int* error) override {
if (error)
*error = -1;
return SR_ERROR;
}
void Close() override {}
bool SetPosition(size_t position) override {
pos_ = position;
return true;
}
bool GetPosition(size_t* position) const override {
if (position)
*position = pos_;
return true;
}
bool GetSize(size_t* size) const override { return false; }
private:
size_t pos_;
};
bool VerifyTestBuffer(unsigned char* buffer, size_t len, unsigned char value) {
bool passed = true;
for (size_t i = 0; i < len; ++i) {
if (buffer[i] != value++) {
passed = false;
break;
}
}
// Ensure that we don't pass again without re-writing
memset(buffer, 0, len);
return passed;
}
void SeekTest(StreamInterface* stream, const unsigned char value) {
size_t bytes;
unsigned char buffer[13] = {0};
const size_t kBufSize = sizeof(buffer);
EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, nullptr), SR_SUCCESS);
EXPECT_EQ(bytes, kBufSize);
EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, value));
EXPECT_TRUE(stream->GetPosition(&bytes));
EXPECT_EQ(13U, bytes);
EXPECT_TRUE(stream->SetPosition(7));
EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, nullptr), SR_SUCCESS);
EXPECT_EQ(bytes, kBufSize);
EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, value + 7));
EXPECT_TRUE(stream->GetPosition(&bytes));
EXPECT_EQ(20U, bytes);
}
TEST(FifoBufferTest, TestAll) {
const size_t kSize = 16;
const char in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
char out[kSize * 2];
void* p;
const void* q;
size_t bytes;
FifoBuffer buf(kSize);
// Test assumptions about base state
EXPECT_EQ(SS_OPEN, buf.GetState());
EXPECT_EQ(SR_BLOCK, buf.Read(out, kSize, &bytes, nullptr));
EXPECT_TRUE(nullptr != buf.GetWriteBuffer(&bytes));
EXPECT_EQ(kSize, bytes);
buf.ConsumeWriteBuffer(0);
// Try a full write
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
// Try a write that should block
EXPECT_EQ(SR_BLOCK, buf.Write(in, kSize, &bytes, nullptr));
// Try a full read
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize));
// Try a read that should block
EXPECT_EQ(SR_BLOCK, buf.Read(out, kSize, &bytes, nullptr));
// Try a too-big write
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize * 2, &bytes, nullptr));
EXPECT_EQ(bytes, kSize);
// Try a too-big read
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize * 2, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize));
// Try some small writes and reads
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize / 2));
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize / 2));
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize / 2));
// Try wraparound reads and writes in the following pattern
// WWWWWWWWWWWW.... 0123456789AB....
// RRRRRRRRXXXX.... ........89AB....
// WWWW....XXXXWWWW 4567....89AB0123
// XXXX....RRRRXXXX 4567........0123
// XXXXWWWWWWWWXXXX 4567012345670123
// RRRRXXXXXXXXRRRR ....01234567....
// ....RRRRRRRR.... ................
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize * 3 / 4, &bytes, nullptr));
EXPECT_EQ(kSize * 3 / 4, bytes);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize / 2));
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 4, &bytes, nullptr));
EXPECT_EQ(kSize / 4, bytes);
EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4));
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize / 2));
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize / 2));
// Use GetWriteBuffer to reset the read_position for the next tests
buf.GetWriteBuffer(&bytes);
buf.ConsumeWriteBuffer(0);
// Try using GetReadData to do a full read
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize, &bytes, nullptr));
q = buf.GetReadData(&bytes);
EXPECT_TRUE(nullptr != q);
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(0, memcmp(q, in, kSize));
buf.ConsumeReadData(kSize);
EXPECT_EQ(SR_BLOCK, buf.Read(out, kSize, &bytes, nullptr));
// Try using GetReadData to do some small reads
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize, &bytes, nullptr));
q = buf.GetReadData(&bytes);
EXPECT_TRUE(nullptr != q);
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(0, memcmp(q, in, kSize / 2));
buf.ConsumeReadData(kSize / 2);
q = buf.GetReadData(&bytes);
EXPECT_TRUE(nullptr != q);
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(q, in + kSize / 2, kSize / 2));
buf.ConsumeReadData(kSize / 2);
EXPECT_EQ(SR_BLOCK, buf.Read(out, kSize, &bytes, nullptr));
// Try using GetReadData in a wraparound case
// WWWWWWWWWWWWWWWW 0123456789ABCDEF
// RRRRRRRRRRRRXXXX ............CDEF
// WWWWWWWW....XXXX 01234567....CDEF
// ............RRRR 01234567........
// RRRRRRRR........ ................
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize, &bytes, nullptr));
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize * 3 / 4, &bytes, nullptr));
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize / 2, &bytes, nullptr));
q = buf.GetReadData(&bytes);
EXPECT_TRUE(nullptr != q);
EXPECT_EQ(kSize / 4, bytes);
EXPECT_EQ(0, memcmp(q, in + kSize * 3 / 4, kSize / 4));
buf.ConsumeReadData(kSize / 4);
q = buf.GetReadData(&bytes);
EXPECT_TRUE(nullptr != q);
EXPECT_EQ(kSize / 2, bytes);
EXPECT_EQ(0, memcmp(q, in, kSize / 2));
buf.ConsumeReadData(kSize / 2);
// Use GetWriteBuffer to reset the read_position for the next tests
buf.GetWriteBuffer(&bytes);
buf.ConsumeWriteBuffer(0);
// Try using GetWriteBuffer to do a full write
p = buf.GetWriteBuffer(&bytes);
EXPECT_TRUE(nullptr != p);
EXPECT_EQ(kSize, bytes);
memcpy(p, in, kSize);
buf.ConsumeWriteBuffer(kSize);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize));
// Try using GetWriteBuffer to do some small writes
p = buf.GetWriteBuffer(&bytes);
EXPECT_TRUE(nullptr != p);
EXPECT_EQ(kSize, bytes);
memcpy(p, in, kSize / 2);
buf.ConsumeWriteBuffer(kSize / 2);
p = buf.GetWriteBuffer(&bytes);
EXPECT_TRUE(nullptr != p);
EXPECT_EQ(kSize / 2, bytes);
memcpy(p, in + kSize / 2, kSize / 2);
buf.ConsumeWriteBuffer(kSize / 2);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize));
// Try using GetWriteBuffer in a wraparound case
// WWWWWWWWWWWW.... 0123456789AB....
// RRRRRRRRXXXX.... ........89AB....
// ........XXXXWWWW ........89AB0123
// WWWW....XXXXXXXX 4567....89AB0123
// RRRR....RRRRRRRR ................
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize * 3 / 4, &bytes, nullptr));
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
p = buf.GetWriteBuffer(&bytes);
EXPECT_TRUE(nullptr != p);
EXPECT_EQ(kSize / 4, bytes);
memcpy(p, in, kSize / 4);
buf.ConsumeWriteBuffer(kSize / 4);
p = buf.GetWriteBuffer(&bytes);
EXPECT_TRUE(nullptr != p);
EXPECT_EQ(kSize / 2, bytes);
memcpy(p, in + kSize / 4, kSize / 4);
buf.ConsumeWriteBuffer(kSize / 4);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize * 3 / 4, &bytes, nullptr));
EXPECT_EQ(kSize * 3 / 4, bytes);
EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4));
EXPECT_EQ(0, memcmp(in, out + kSize / 4, kSize / 4));
// Check that the stream is now empty
EXPECT_EQ(SR_BLOCK, buf.Read(out, kSize, &bytes, nullptr));
// Try growing the buffer
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_TRUE(buf.SetCapacity(kSize * 2));
EXPECT_EQ(SR_SUCCESS, buf.Write(in + kSize, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize * 2, &bytes, nullptr));
EXPECT_EQ(kSize * 2, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize * 2));
// Try shrinking the buffer
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_TRUE(buf.SetCapacity(kSize));
EXPECT_EQ(SR_BLOCK, buf.Write(in, kSize, &bytes, nullptr));
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize, &bytes, nullptr));
EXPECT_EQ(kSize, bytes);
EXPECT_EQ(0, memcmp(in, out, kSize));
// Write to the stream, close it, read the remaining bytes
EXPECT_EQ(SR_SUCCESS, buf.Write(in, kSize / 2, &bytes, nullptr));
buf.Close();
EXPECT_EQ(SS_CLOSED, buf.GetState());
EXPECT_EQ(SR_EOS, buf.Write(in, kSize / 2, &bytes, nullptr));
EXPECT_EQ(SR_SUCCESS, buf.Read(out, kSize / 2, &bytes, nullptr));
EXPECT_EQ(0, memcmp(in, out, kSize / 2));
EXPECT_EQ(SR_EOS, buf.Read(out, kSize / 2, &bytes, nullptr));
}
TEST(FifoBufferTest, FullBufferCheck) {
FifoBuffer buff(10);
buff.ConsumeWriteBuffer(10);
size_t free;
EXPECT_TRUE(buff.GetWriteBuffer(&free) != nullptr);
EXPECT_EQ(0U, free);
}
TEST(FifoBufferTest, WriteOffsetAndReadOffset) {
const size_t kSize = 16;
const char in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
char out[kSize * 2];
FifoBuffer buf(kSize);
// Write 14 bytes.
EXPECT_EQ(SR_SUCCESS, buf.Write(in, 14, nullptr, nullptr));
// Make sure data is in |buf|.
size_t buffered;
EXPECT_TRUE(buf.GetBuffered(&buffered));
EXPECT_EQ(14u, buffered);
// Read 10 bytes.
buf.ConsumeReadData(10);
// There should be now 12 bytes of available space.
size_t remaining;
EXPECT_TRUE(buf.GetWriteRemaining(&remaining));
EXPECT_EQ(12u, remaining);
// Write at offset 12, this should fail.
EXPECT_EQ(SR_BLOCK, buf.WriteOffset(in, 10, 12, nullptr));
// Write 8 bytes at offset 4, this wraps around the buffer.
EXPECT_EQ(SR_SUCCESS, buf.WriteOffset(in, 8, 4, nullptr));
// Number of available space remains the same until we call
// ConsumeWriteBuffer().
EXPECT_TRUE(buf.GetWriteRemaining(&remaining));
EXPECT_EQ(12u, remaining);
buf.ConsumeWriteBuffer(12);
// There's 4 bytes bypassed and 4 bytes no read so skip them and verify the
// 8 bytes written.
size_t read;
EXPECT_EQ(SR_SUCCESS, buf.ReadOffset(out, 8, 8, &read));
EXPECT_EQ(8u, read);
EXPECT_EQ(0, memcmp(out, in, 8));
// There should still be 16 bytes available for reading.
EXPECT_TRUE(buf.GetBuffered(&buffered));
EXPECT_EQ(16u, buffered);
// Read at offset 16, this should fail since we don't have that much data.
EXPECT_EQ(SR_BLOCK, buf.ReadOffset(out, 10, 16, nullptr));
}
} // namespace rtc