1 #include "gtest/gtest.h"
3 #include "mozilla/SpinEventLoopUntil.h"
4 #include "nsBufferedStreams.h"
7 #include "nsStreamUtils.h"
8 #include "nsThreadUtils.h"
11 // Helper function for creating a testing::AsyncStringStream
12 already_AddRefed
<nsBufferedInputStream
> CreateStream(uint32_t aSize
,
14 aBuffer
.SetLength(aSize
);
15 for (uint32_t i
= 0; i
< aSize
; ++i
) {
16 aBuffer
.BeginWriting()[i
] = i
% 10;
19 nsCOMPtr
<nsIInputStream
> stream
= new testing::AsyncStringStream(aBuffer
);
21 RefPtr
<nsBufferedInputStream
> bis
= new nsBufferedInputStream();
22 bis
->Init(stream
, aSize
);
27 TEST(TestBufferedInputStream
, SimpleRead
)
29 const size_t kBufSize
= 10;
32 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
35 ASSERT_EQ(NS_OK
, bis
->Available(&length
));
36 ASSERT_EQ((uint64_t)kBufSize
, length
);
40 ASSERT_EQ(NS_OK
, bis
->Read(buf2
, sizeof(buf2
), &count
));
41 ASSERT_EQ(count
, buf
.Length());
42 ASSERT_TRUE(nsCString(buf
.get(), kBufSize
).Equals(nsCString(buf2
, count
)));
45 // Simple segment reading.
46 TEST(TestBufferedInputStream
, SimpleReadSegments
)
48 const size_t kBufSize
= 10;
51 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
55 ASSERT_EQ(NS_OK
, bis
->ReadSegments(NS_CopySegmentToBuffer
, buf2
, sizeof(buf2
),
57 ASSERT_EQ(count
, buf
.Length());
58 ASSERT_TRUE(nsCString(buf
.get(), kBufSize
).Equals(nsCString(buf2
, count
)));
62 TEST(TestBufferedInputStream
, AsyncWait_sync
)
64 const size_t kBufSize
= 10;
67 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
69 RefPtr
<testing::InputStreamCallback
> cb
= new testing::InputStreamCallback();
71 ASSERT_EQ(NS_OK
, bis
->AsyncWait(cb
, 0, 0, nullptr));
73 // Immediatelly called
74 ASSERT_TRUE(cb
->Called());
78 TEST(TestBufferedInputStream
, AsyncWait_async
)
80 const size_t kBufSize
= 10;
83 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
85 RefPtr
<testing::InputStreamCallback
> cb
= new testing::InputStreamCallback();
86 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
88 ASSERT_EQ(NS_OK
, bis
->AsyncWait(cb
, 0, 0, thread
));
90 ASSERT_FALSE(cb
->Called());
92 // Eventually it is called.
93 MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
94 "TEST(TestBufferedInputStream, AsyncWait_async)"_ns
,
95 [&]() { return cb
->Called(); }));
96 ASSERT_TRUE(cb
->Called());
99 // AsyncWait - sync - closureOnly
100 TEST(TestBufferedInputStream
, AsyncWait_sync_closureOnly
)
102 const size_t kBufSize
= 10;
105 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
107 RefPtr
<testing::InputStreamCallback
> cb
= new testing::InputStreamCallback();
109 ASSERT_EQ(NS_OK
, bis
->AsyncWait(cb
, nsIAsyncInputStream::WAIT_CLOSURE_ONLY
, 0,
111 ASSERT_FALSE(cb
->Called());
113 bis
->CloseWithStatus(NS_ERROR_FAILURE
);
115 // Immediatelly called
116 ASSERT_TRUE(cb
->Called());
120 TEST(TestBufferedInputStream
, AsyncWait_async_closureOnly
)
122 const size_t kBufSize
= 10;
125 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
127 RefPtr
<testing::InputStreamCallback
> cb
= new testing::InputStreamCallback();
128 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
130 ASSERT_EQ(NS_OK
, bis
->AsyncWait(cb
, nsIAsyncInputStream::WAIT_CLOSURE_ONLY
, 0,
133 ASSERT_FALSE(cb
->Called());
134 bis
->CloseWithStatus(NS_ERROR_FAILURE
);
135 ASSERT_FALSE(cb
->Called());
137 // Eventually it is called.
138 MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
139 "TEST(TestBufferedInputStream, AsyncWait_async_closureOnly)"_ns
,
140 [&]() { return cb
->Called(); }));
141 ASSERT_TRUE(cb
->Called());
144 TEST(TestBufferedInputStream
, AsyncWait_after_close
)
146 const size_t kBufSize
= 10;
149 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
151 nsCOMPtr
<nsIThread
> eventTarget
= do_GetCurrentThread();
153 auto cb
= mozilla::MakeRefPtr
<testing::InputStreamCallback
>();
154 ASSERT_EQ(NS_OK
, bis
->AsyncWait(cb
, 0, 0, eventTarget
));
155 MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
156 "TEST(TestBufferedInputStream, AsyncWait_after_close) 1"_ns
,
157 [&]() { return cb
->Called(); }));
158 ASSERT_TRUE(cb
->Called());
160 ASSERT_EQ(NS_OK
, bis
->Close());
162 cb
= mozilla::MakeRefPtr
<testing::InputStreamCallback
>();
163 ASSERT_EQ(NS_OK
, bis
->AsyncWait(cb
, 0, 0, eventTarget
));
164 MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
165 "TEST(TestBufferedInputStream, AsyncWait_after_close) 2"_ns
,
166 [&]() { return cb
->Called(); }));
167 ASSERT_TRUE(cb
->Called());
170 TEST(TestBufferedInputStream
, AsyncLengthWait_after_close
)
172 nsCString buf
{"The Quick Brown Fox Jumps over the Lazy Dog"};
173 const size_t kBufSize
= 44;
175 RefPtr
<nsBufferedInputStream
> bis
= CreateStream(kBufSize
, buf
);
177 nsCOMPtr
<nsIThread
> eventTarget
= do_GetCurrentThread();
179 auto cb
= mozilla::MakeRefPtr
<testing::LengthCallback
>();
180 ASSERT_EQ(NS_OK
, bis
->AsyncLengthWait(cb
, eventTarget
));
181 MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
182 "TEST(TestBufferedInputStream, AsyncLengthWait_after_close) 1"_ns
,
183 [&]() { return cb
->Called(); }));
184 ASSERT_TRUE(cb
->Called());
187 ASSERT_EQ(NS_OK
, bis
->Available(&length
));
188 ASSERT_EQ((uint64_t)kBufSize
, length
);
190 cb
= mozilla::MakeRefPtr
<testing::LengthCallback
>();
191 ASSERT_EQ(NS_OK
, bis
->AsyncLengthWait(cb
, eventTarget
));
192 MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
193 "TEST(TestBufferedInputStream, AsyncLengthWait_after_close) 2"_ns
,
194 [&]() { return cb
->Called(); }));
195 ASSERT_TRUE(cb
->Called());
198 // This stream returns a few bytes on the first read, and error on the second.
199 class BrokenInputStream
: public nsIInputStream
{
200 NS_DECL_THREADSAFE_ISUPPORTS
201 NS_DECL_NSIINPUTSTREAM
203 virtual ~BrokenInputStream() = default;
207 NS_IMPL_ISUPPORTS(BrokenInputStream
, nsIInputStream
)
209 NS_IMETHODIMP
BrokenInputStream::Close(void) { return NS_OK
; }
211 NS_IMETHODIMP
BrokenInputStream::Available(uint64_t* _retval
) {
216 NS_IMETHODIMP
BrokenInputStream::StreamStatus(void) { return NS_OK
; }
218 NS_IMETHODIMP
BrokenInputStream::Read(char* aBuf
, uint32_t aCount
,
229 return NS_ERROR_CORRUPTED_CONTENT
;
232 NS_IMETHODIMP
BrokenInputStream::ReadSegments(nsWriteSegmentFun aWriter
,
233 void* aClosure
, uint32_t aCount
,
235 return NS_ERROR_NOT_IMPLEMENTED
;
238 NS_IMETHODIMP
BrokenInputStream::IsNonBlocking(bool* _retval
) {
243 // Check that the error from BrokenInputStream::Read is propagated
244 // through NS_ReadInputStreamToString
245 TEST(TestBufferedInputStream
, BrokenInputStreamToBuffer
)
248 RefPtr
<BrokenInputStream
> stream
= new BrokenInputStream();
250 nsresult rv
= NS_ReadInputStreamToString(stream
, out
, -1);
251 ASSERT_EQ(rv
, NS_ERROR_CORRUPTED_CONTENT
);