|  | /* | 
|  | *  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 <string.h> | 
|  |  | 
|  | #include "test/gtest.h" | 
|  |  | 
|  | namespace rtc { | 
|  |  | 
|  | TEST(FifoBufferTest, TestAll) { | 
|  | rtc::AutoThread main_thread; | 
|  | const size_t kSize = 16; | 
|  | const uint8_t in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; | 
|  | uint8_t 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()); | 
|  | int error; | 
|  | EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  | EXPECT_TRUE(nullptr != buf.GetWriteBuffer(&bytes)); | 
|  | EXPECT_EQ(kSize, bytes); | 
|  | buf.ConsumeWriteBuffer(0); | 
|  |  | 
|  | // Try a full write | 
|  | EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); | 
|  | EXPECT_EQ(kSize, bytes); | 
|  |  | 
|  | // Try a write that should block | 
|  | EXPECT_EQ(SR_BLOCK, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); | 
|  |  | 
|  | // Try a full read | 
|  | EXPECT_EQ(SR_SUCCESS, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  | EXPECT_EQ(kSize, bytes); | 
|  | EXPECT_EQ(0, memcmp(in, out, kSize)); | 
|  |  | 
|  | // Try a read that should block | 
|  | EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  |  | 
|  | // Try a too-big write | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize * 2), bytes, error)); | 
|  | EXPECT_EQ(bytes, kSize); | 
|  |  | 
|  | // Try a too-big read | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize * 2), bytes, error)); | 
|  | EXPECT_EQ(kSize, bytes); | 
|  | EXPECT_EQ(0, memcmp(in, out, kSize)); | 
|  |  | 
|  | // Try some small writes and reads | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(0, memcmp(in, out, kSize / 2)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(0, memcmp(in, out, kSize / 2)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | 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(rtc::MakeArrayView(in, kSize * 3 / 4), bytes, error)); | 
|  | EXPECT_EQ(kSize * 3 / 4, bytes); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(0, memcmp(in, out, kSize / 2)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 4), bytes, error)); | 
|  | EXPECT_EQ(kSize / 4, bytes); | 
|  | EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(kSize / 2, bytes); | 
|  | EXPECT_EQ(0, memcmp(in, out, kSize / 2)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | 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(rtc::MakeArrayView(in, kSize), bytes, error)); | 
|  | 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(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  |  | 
|  | // Try using GetReadData to do some small reads | 
|  | EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); | 
|  | 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(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  |  | 
|  | // Try using GetReadData in a wraparound case | 
|  | // WWWWWWWWWWWWWWWW 0123456789ABCDEF | 
|  | // RRRRRRRRRRRRXXXX ............CDEF | 
|  | // WWWWWWWW....XXXX 01234567....CDEF | 
|  | // ............RRRR 01234567........ | 
|  | // RRRRRRRR........ ................ | 
|  | EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize * 3 / 4), bytes, error)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | 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(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  | 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(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  | 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(rtc::MakeArrayView(in, kSize * 3 / 4), bytes, error)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | 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(rtc::MakeArrayView(out, kSize * 3 / 4), bytes, error)); | 
|  | 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(rtc::MakeArrayView(out, kSize), bytes, error)); | 
|  |  | 
|  | // Write to the stream, close it, read the remaining bytes | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | buf.Close(); | 
|  | EXPECT_EQ(SS_CLOSED, buf.GetState()); | 
|  | EXPECT_EQ(SR_EOS, buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(SR_SUCCESS, | 
|  | buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | EXPECT_EQ(0, memcmp(in, out, kSize / 2)); | 
|  | EXPECT_EQ(SR_EOS, buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error)); | 
|  | } | 
|  |  | 
|  | TEST(FifoBufferTest, FullBufferCheck) { | 
|  | rtc::AutoThread main_thread; | 
|  | FifoBuffer buff(10); | 
|  | buff.ConsumeWriteBuffer(10); | 
|  |  | 
|  | size_t free; | 
|  | EXPECT_TRUE(buff.GetWriteBuffer(&free) != nullptr); | 
|  | EXPECT_EQ(0U, free); | 
|  | } | 
|  |  | 
|  | }  // namespace rtc |