/* * 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/memory/fifo_buffer.h" #include #include "test/gtest.h" namespace rtc { 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