| // 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 { | |
| namespace { | |
| // Implements a simple sink | |
| class Writer : public 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 |