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 
TEST(StreamTeeTest,DefaultConstructor)15 TEST(StreamTeeTest, DefaultConstructor) {
16   // Test the default constructor.
17   StreamTee tee;
18   ASSERT_EQ(0U, tee.GetNumStreams());
19 }
20 
TEST(StreamTeeTest,Constructor1Stream)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 
TEST(StreamTeeTest,Constructor2Streams)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 
TEST(StreamTeeTest,CopyConstructor)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 
TEST(StreamTeeTest,Assignment)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 
TEST(StreamTeeTest,Write)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;
Flush__anon2b926b2a0111::FlushTestStream89     void Flush() override {
90       ++m_flush_count;
91     }
WriteImpl__anon2b926b2a0111::FlushTestStream92     size_t WriteImpl(const void *src, size_t src_len) override {
93       return src_len;
94     }
95   };
96 }
97 
TEST(StreamTeeTest,Flush)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 
TEST(StreamTeeTest,AppendStream)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 
TEST(StreamTeeTest,GetStreamAtIndexOutOfBounds)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 
TEST(StreamTeeTest,GetStreamAtIndexOutOfBoundsEmpty)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 
TEST(StreamTeeTest,SetStreamAtIndexOverwrite)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 
TEST(StreamTeeTest,SetStreamAtIndexOutOfBounds)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