| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/shared/stream_buffer.h" |
| |
| #include <gtest/gtest.h> |
| |
| namespace debug_ipc { |
| |
| namespace { |
| |
| // Implements a simple sink |
| class Writer : public debug_ipc::StreamBuffer::Writer { |
| public: |
| // This class reads only up to a given amount of data. It starts as 0 (it |
| // can't read anything) and can be increased with this function. |
| void set_read_amount(size_t amount) { read_amount_ = amount; } |
| |
| // StreamBuffer::Writer implementation. |
| size_t ConsumeStreamBufferData(const char* data, size_t len) override { |
| size_t to_read = std::min(read_amount_, len); |
| data_.insert(data_.end(), data, &data[to_read]); |
| read_amount_ -= to_read; |
| return to_read; |
| } |
| |
| const std::vector<char>& data() { return data_; } |
| |
| private: |
| std::vector<char> data_; |
| size_t read_amount_ = 0; |
| }; |
| |
| } // namespace |
| |
| TEST(StreamBuffer, Read) { |
| StreamBuffer buf; |
| char output[16]; |
| |
| // Test the empty case. |
| EXPECT_TRUE(buf.IsAvailable(0)); |
| EXPECT_FALSE(buf.IsAvailable(1)); |
| EXPECT_EQ(0u, buf.Read(output, sizeof(output))); |
| EXPECT_EQ(0u, buf.Peek(output, sizeof(output))); |
| |
| size_t first_block_size = 3; |
| std::vector<char> first_block(first_block_size); |
| first_block[0] = 'a'; |
| first_block[1] = 'b'; |
| first_block[2] = 'c'; |
| buf.AddReadData(std::move(first_block)); |
| |
| EXPECT_TRUE(buf.IsAvailable(0)); |
| EXPECT_TRUE(buf.IsAvailable(1)); |
| EXPECT_TRUE(buf.IsAvailable(3)); |
| EXPECT_FALSE(buf.IsAvailable(4)); |
| |
| size_t second_block_size = 3; |
| std::vector<char> second_block(second_block_size); |
| second_block[0] = 'd'; |
| second_block[1] = 'e'; |
| second_block[2] = 'f'; |
| buf.AddReadData(std::move(second_block)); |
| |
| size_t third_block_size = 5; |
| std::vector<char> third_block(third_block_size); |
| third_block[0] = 'g'; |
| third_block[1] = 'h'; |
| third_block[2] = 'i'; |
| third_block[3] = 'j'; |
| third_block[4] = 'k'; |
| buf.AddReadData(std::move(third_block)); |
| |
| // Try a peek, the next read should give the same data. |
| EXPECT_EQ(2u, buf.Peek(output, 2u)); |
| EXPECT_EQ('a', output[0]); |
| EXPECT_EQ('b', output[1]); |
| |
| // This read goes to a block boundary exactly. |
| EXPECT_EQ(first_block_size, buf.Read(output, first_block_size)); |
| EXPECT_EQ('a', output[0]); |
| EXPECT_EQ('b', output[1]); |
| EXPECT_EQ('c', output[2]); |
| |
| // Now do a read across blocks. |
| EXPECT_EQ(5u, buf.Read(output, 5u)); |
| EXPECT_EQ('d', output[0]); |
| EXPECT_EQ('e', output[1]); |
| EXPECT_EQ('f', output[2]); |
| EXPECT_EQ('g', output[3]); |
| EXPECT_EQ('h', output[4]); |
| |
| // Now do a read off the end which should be partial. |
| EXPECT_EQ(3u, buf.Read(output, 5u)); |
| EXPECT_EQ('i', output[0]); |
| EXPECT_EQ('j', output[1]); |
| EXPECT_EQ('k', output[2]); |
| |
| EXPECT_FALSE(buf.IsAvailable(1)); |
| } |
| |
| TEST(StreamBuffer, Write) { |
| Writer sink; |
| StreamBuffer buf; |
| buf.set_writer(&sink); |
| |
| // Write when the writer isn't ready. |
| std::vector<char> block_one; |
| block_one.push_back(0); |
| block_one.push_back(1); |
| block_one.push_back(2); |
| buf.Write(std::move(block_one)); |
| |
| EXPECT_TRUE(sink.data().empty()); |
| |
| // Read two of the bytes available. |
| sink.set_read_amount(2); |
| buf.SetWritable(); |
| EXPECT_EQ(2u, sink.data().size()); |
| |
| // Add two more blocks of pending writes. |
| std::vector<char> block_two; |
| block_two.push_back(3); |
| block_two.push_back(4); |
| block_two.push_back(5); |
| buf.Write(std::move(block_two)); |
| |
| std::vector<char> block_three; |
| block_three.push_back(6); |
| block_three.push_back(7); |
| block_three.push_back(8); |
| block_three.push_back(9); |
| block_three.push_back(10); |
| buf.Write(std::move(block_three)); |
| |
| // Read to the middle of the last block (this will consume two), then |
| // consume the rest. |
| sink.set_read_amount(6); |
| buf.SetWritable(); |
| sink.set_read_amount(1000); |
| buf.SetWritable(); |
| |
| ASSERT_EQ(11u, sink.data().size()); |
| for (size_t i = 0; i < sink.data().size(); i++) |
| EXPECT_EQ(i, static_cast<size_t>(sink.data()[i])); |
| } |
| |
| } // namespace debug_ipc |