TestBufferedInputStream.cpp (7508B)
1 #include "gtest/gtest.h" 2 3 #include "mozilla/SpinEventLoopUntil.h" 4 #include "nsBufferedStreams.h" 5 #include "nsIThread.h" 6 #include "nsNetUtil.h" 7 #include "nsStreamUtils.h" 8 #include "nsThreadUtils.h" 9 #include "Helpers.h" 10 11 // Helper function for creating a testing::AsyncStringStream 12 already_AddRefed<nsBufferedInputStream> CreateStream(uint32_t aSize, 13 nsCString& aBuffer) { 14 aBuffer.SetLength(aSize); 15 for (uint32_t i = 0; i < aSize; ++i) { 16 aBuffer.BeginWriting()[i] = i % 10; 17 } 18 19 nsCOMPtr<nsIInputStream> stream = new testing::AsyncStringStream(aBuffer); 20 21 RefPtr<nsBufferedInputStream> bis = new nsBufferedInputStream(); 22 bis->Init(stream, aSize); 23 return bis.forget(); 24 } 25 26 // Simple reading. 27 TEST(TestBufferedInputStream, SimpleRead) 28 { 29 const size_t kBufSize = 10; 30 31 nsCString buf; 32 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 33 34 uint64_t length; 35 ASSERT_EQ(NS_OK, bis->Available(&length)); 36 ASSERT_EQ((uint64_t)kBufSize, length); 37 38 char buf2[kBufSize]; 39 uint32_t count; 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))); 43 } 44 45 // Simple segment reading. 46 TEST(TestBufferedInputStream, SimpleReadSegments) 47 { 48 const size_t kBufSize = 10; 49 50 nsCString buf; 51 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 52 53 char buf2[kBufSize]; 54 uint32_t count; 55 ASSERT_EQ(NS_OK, bis->ReadSegments(NS_CopySegmentToBuffer, buf2, sizeof(buf2), 56 &count)); 57 ASSERT_EQ(count, buf.Length()); 58 ASSERT_TRUE(nsCString(buf.get(), kBufSize).Equals(nsCString(buf2, count))); 59 } 60 61 // AsyncWait - sync 62 TEST(TestBufferedInputStream, AsyncWait_sync) 63 { 64 const size_t kBufSize = 10; 65 66 nsCString buf; 67 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 68 69 RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback(); 70 71 ASSERT_EQ(NS_OK, bis->AsyncWait(cb, 0, 0, nullptr)); 72 73 // Immediatelly called 74 ASSERT_TRUE(cb->Called()); 75 } 76 77 // AsyncWait - async 78 TEST(TestBufferedInputStream, AsyncWait_async) 79 { 80 const size_t kBufSize = 10; 81 82 nsCString buf; 83 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 84 85 RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback(); 86 nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); 87 88 ASSERT_EQ(NS_OK, bis->AsyncWait(cb, 0, 0, thread)); 89 90 ASSERT_FALSE(cb->Called()); 91 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()); 97 } 98 99 // AsyncWait - sync - closureOnly 100 TEST(TestBufferedInputStream, AsyncWait_sync_closureOnly) 101 { 102 const size_t kBufSize = 10; 103 104 nsCString buf; 105 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 106 107 RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback(); 108 109 ASSERT_EQ(NS_OK, bis->AsyncWait(cb, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, 0, 110 nullptr)); 111 ASSERT_FALSE(cb->Called()); 112 113 bis->CloseWithStatus(NS_ERROR_FAILURE); 114 115 // Immediatelly called 116 ASSERT_TRUE(cb->Called()); 117 } 118 119 // AsyncWait - async 120 TEST(TestBufferedInputStream, AsyncWait_async_closureOnly) 121 { 122 const size_t kBufSize = 10; 123 124 nsCString buf; 125 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 126 127 RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback(); 128 nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); 129 130 ASSERT_EQ(NS_OK, bis->AsyncWait(cb, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, 0, 131 thread)); 132 133 ASSERT_FALSE(cb->Called()); 134 bis->CloseWithStatus(NS_ERROR_FAILURE); 135 ASSERT_FALSE(cb->Called()); 136 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()); 142 } 143 144 TEST(TestBufferedInputStream, AsyncWait_after_close) 145 { 146 const size_t kBufSize = 10; 147 148 nsCString buf; 149 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 150 151 nsCOMPtr<nsIThread> eventTarget = do_GetCurrentThread(); 152 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()); 159 160 ASSERT_EQ(NS_OK, bis->Close()); 161 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()); 168 } 169 170 TEST(TestBufferedInputStream, AsyncLengthWait_after_close) 171 { 172 nsCString buf{"The Quick Brown Fox Jumps over the Lazy Dog"}; 173 const size_t kBufSize = 44; 174 175 RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf); 176 177 nsCOMPtr<nsIThread> eventTarget = do_GetCurrentThread(); 178 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()); 185 186 uint64_t length; 187 ASSERT_EQ(NS_OK, bis->Available(&length)); 188 ASSERT_EQ((uint64_t)kBufSize, length); 189 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()); 196 } 197 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 202 private: 203 virtual ~BrokenInputStream() = default; 204 bool mFirst = true; 205 }; 206 207 NS_IMPL_ISUPPORTS(BrokenInputStream, nsIInputStream) 208 209 NS_IMETHODIMP BrokenInputStream::Close(void) { return NS_OK; } 210 211 NS_IMETHODIMP BrokenInputStream::Available(uint64_t* _retval) { 212 *_retval = 100; 213 return NS_OK; 214 } 215 216 NS_IMETHODIMP BrokenInputStream::StreamStatus(void) { return NS_OK; } 217 218 NS_IMETHODIMP BrokenInputStream::Read(char* aBuf, uint32_t aCount, 219 uint32_t* _retval) { 220 if (mFirst) { 221 aBuf[0] = 'h'; 222 aBuf[1] = 'e'; 223 aBuf[2] = 'l'; 224 aBuf[3] = 0; 225 *_retval = 4; 226 mFirst = false; 227 return NS_OK; 228 } 229 return NS_ERROR_CORRUPTED_CONTENT; 230 } 231 232 NS_IMETHODIMP BrokenInputStream::ReadSegments(nsWriteSegmentFun aWriter, 233 void* aClosure, uint32_t aCount, 234 uint32_t* _retval) { 235 return NS_ERROR_NOT_IMPLEMENTED; 236 } 237 238 NS_IMETHODIMP BrokenInputStream::IsNonBlocking(bool* _retval) { 239 *_retval = false; 240 return NS_OK; 241 } 242 243 // Check that the error from BrokenInputStream::Read is propagated 244 // through NS_ReadInputStreamToString 245 TEST(TestBufferedInputStream, BrokenInputStreamToBuffer) 246 { 247 nsAutoCString out; 248 RefPtr<BrokenInputStream> stream = new BrokenInputStream(); 249 250 nsresult rv = NS_ReadInputStreamToString(stream, out, -1); 251 ASSERT_EQ(rv, NS_ERROR_CORRUPTED_CONTENT); 252 }