1 //===-- StreamTeeTest.cpp -------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Utility/StreamTee.h" 10 #include "lldb/Utility/StreamString.h" 11 #include "gtest/gtest.h" 12 13 using namespace lldb_private; 14 15 TEST(StreamTeeTest, DefaultConstructor) { 16 // Test the default constructor. 17 StreamTee tee; 18 ASSERT_EQ(0U, tee.GetNumStreams()); 19 } 20 21 TEST(StreamTeeTest, Constructor1Stream) { 22 // Test the constructor for a single stream. 23 lldb::StreamSP s1(std::make_shared<StreamString>()); 24 StreamTee tee(s1); 25 26 ASSERT_EQ(1U, tee.GetNumStreams()); 27 EXPECT_EQ(s1, tee.GetStreamAtIndex(0U)); 28 } 29 30 TEST(StreamTeeTest, Constructor2Streams) { 31 // Test the constructor for two streams. 32 lldb::StreamSP s1(std::make_shared<StreamString>()); 33 lldb::StreamSP s2(std::make_shared<StreamString>()); 34 StreamTee tee(s1, s2); 35 36 ASSERT_EQ(2U, tee.GetNumStreams()); 37 EXPECT_EQ(s1, tee.GetStreamAtIndex(0U)); 38 EXPECT_EQ(s2, tee.GetStreamAtIndex(1U)); 39 } 40 41 TEST(StreamTeeTest, CopyConstructor) { 42 // Test the copy constructor. 43 lldb::StreamSP s1(std::make_shared<StreamString>()); 44 lldb::StreamSP s2(std::make_shared<StreamString>()); 45 StreamTee tee1(s1, s2); 46 StreamTee tee2(tee1); 47 48 ASSERT_EQ(2U, tee2.GetNumStreams()); 49 EXPECT_EQ(s1, tee2.GetStreamAtIndex(0U)); 50 EXPECT_EQ(s2, tee2.GetStreamAtIndex(1U)); 51 } 52 53 TEST(StreamTeeTest, Assignment) { 54 // Test the assignment of StreamTee. 55 lldb::StreamSP s1(std::make_shared<StreamString>()); 56 lldb::StreamSP s2(std::make_shared<StreamString>()); 57 StreamTee tee1(s1, s2); 58 StreamTee tee2 = tee1; 59 60 ASSERT_EQ(2U, tee2.GetNumStreams()); 61 EXPECT_EQ(s1, tee2.GetStreamAtIndex(0U)); 62 EXPECT_EQ(s2, tee2.GetStreamAtIndex(1U)); 63 } 64 65 TEST(StreamTeeTest, Write) { 66 // Test that write is sent out to all children. 67 auto ss1 = new StreamString(); 68 auto ss2 = new StreamString(); 69 lldb::StreamSP s1(ss1); 70 lldb::StreamSP s2(ss2); 71 StreamTee tee(s1, s2); 72 73 tee << "foo"; 74 tee.Flush(); 75 76 ASSERT_EQ(2U, tee.GetNumStreams()); 77 EXPECT_EQ("foo", ss1->GetString().str()); 78 EXPECT_EQ("foo", ss2->GetString().str()); 79 80 tee << "bar"; 81 tee.Flush(); 82 EXPECT_EQ("foobar", ss1->GetString().str()); 83 EXPECT_EQ("foobar", ss2->GetString().str()); 84 } 85 86 namespace { 87 struct FlushTestStream : public Stream { 88 unsigned m_flush_count = false; 89 void Flush() override { 90 ++m_flush_count; 91 } 92 size_t WriteImpl(const void *src, size_t src_len) override { 93 return src_len; 94 } 95 }; 96 } 97 98 TEST(StreamTeeTest, Flush) { 99 // Check that Flush is distributed to all streams. 100 auto fs1 = new FlushTestStream(); 101 auto fs2 = new FlushTestStream(); 102 lldb::StreamSP s1(fs1); 103 lldb::StreamSP s2(fs2); 104 StreamTee tee(s1, s2); 105 106 tee << "foo"; 107 tee.Flush(); 108 109 ASSERT_EQ(2U, tee.GetNumStreams()); 110 EXPECT_EQ(1U, fs1->m_flush_count); 111 EXPECT_EQ(1U, fs2->m_flush_count); 112 113 tee << "bar"; 114 tee.Flush(); 115 EXPECT_EQ(2U, fs1->m_flush_count); 116 EXPECT_EQ(2U, fs2->m_flush_count); 117 } 118 119 TEST(StreamTeeTest, AppendStream) { 120 // Append new streams to our StreamTee. 121 auto ss1 = new StreamString(); 122 auto ss2 = new StreamString(); 123 lldb::StreamSP s1(ss1); 124 lldb::StreamSP s2(ss2); 125 126 StreamTee tee; 127 128 ASSERT_EQ(0U, tee.GetNumStreams()); 129 130 tee.AppendStream(s1); 131 ASSERT_EQ(1U, tee.GetNumStreams()); 132 EXPECT_EQ(s1, tee.GetStreamAtIndex(0U)); 133 134 tee.AppendStream(s2); 135 ASSERT_EQ(2U, tee.GetNumStreams()); 136 EXPECT_EQ(s1, tee.GetStreamAtIndex(0U)); 137 EXPECT_EQ(s2, tee.GetStreamAtIndex(1U)); 138 } 139 140 TEST(StreamTeeTest, GetStreamAtIndexOutOfBounds) { 141 // The index we check for is not in the bounds of the StreamTee. 142 lldb::StreamSP s1(std::make_shared<StreamString>()); 143 StreamTee tee(s1); 144 145 ASSERT_EQ(1U, tee.GetNumStreams()); 146 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1)); 147 } 148 149 TEST(StreamTeeTest, GetStreamAtIndexOutOfBoundsEmpty) { 150 // Same as above, but with an empty StreamTee. 151 StreamTee tee; 152 ASSERT_EQ(0U, tee.GetNumStreams()); 153 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(0U)); 154 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U)); 155 } 156 157 TEST(StreamTeeTest, SetStreamAtIndexOverwrite) { 158 // We overwrite an existing stream at a given index. 159 lldb::StreamSP s1(std::make_shared<StreamString>()); 160 StreamTee tee(s1); 161 162 ASSERT_EQ(1U, tee.GetNumStreams()); 163 EXPECT_EQ(s1, tee.GetStreamAtIndex(0U)); 164 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U)); 165 166 lldb::StreamSP s2(std::make_shared<StreamString>()); 167 tee.SetStreamAtIndex(0U, s2); 168 EXPECT_EQ(1U, tee.GetNumStreams()); 169 EXPECT_EQ(s2, tee.GetStreamAtIndex(0U)); 170 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1)); 171 } 172 173 TEST(StreamTeeTest, SetStreamAtIndexOutOfBounds) { 174 // We place a new stream out of the bounds of the current StreamTee. 175 lldb::StreamSP s1(std::make_shared<StreamString>()); 176 StreamTee tee(s1); 177 178 ASSERT_EQ(1U, tee.GetNumStreams()); 179 EXPECT_EQ(s1, tee.GetStreamAtIndex(0U)); 180 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U)); 181 182 // Place a new stream out of bounds of the current array. The StreamTee should 183 // resize itself until it can contain this index. 184 lldb::StreamSP s2(std::make_shared<StreamString>()); 185 tee.SetStreamAtIndex(4U, s2); 186 // Check that the vector has been resized. 187 EXPECT_EQ(5U, tee.GetNumStreams()); 188 // Is our stream at the right place? 189 EXPECT_EQ(s2, tee.GetStreamAtIndex(4U)); 190 191 // Existing stream should still be there. 192 EXPECT_EQ(s1, tee.GetStreamAtIndex(0U)); 193 // Other elements are all invalid StreamSPs. 194 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U)); 195 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(2U)); 196 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(3U)); 197 EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(5U)); 198 } 199