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