summaryrefslogtreecommitdiffstats
path: root/netwerk/test/gtest/TestBufferedInputStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/gtest/TestBufferedInputStream.cpp')
-rw-r--r--netwerk/test/gtest/TestBufferedInputStream.cpp252
1 files changed, 252 insertions, 0 deletions
diff --git a/netwerk/test/gtest/TestBufferedInputStream.cpp b/netwerk/test/gtest/TestBufferedInputStream.cpp
new file mode 100644
index 0000000000..7230fe7e5b
--- /dev/null
+++ b/netwerk/test/gtest/TestBufferedInputStream.cpp
@@ -0,0 +1,252 @@
+#include "gtest/gtest.h"
+
+#include "mozilla/SpinEventLoopUntil.h"
+#include "nsBufferedStreams.h"
+#include "nsIThread.h"
+#include "nsNetUtil.h"
+#include "nsStreamUtils.h"
+#include "nsThreadUtils.h"
+#include "Helpers.h"
+
+// Helper function for creating a testing::AsyncStringStream
+already_AddRefed<nsBufferedInputStream> CreateStream(uint32_t aSize,
+ nsCString& aBuffer) {
+ aBuffer.SetLength(aSize);
+ for (uint32_t i = 0; i < aSize; ++i) {
+ aBuffer.BeginWriting()[i] = i % 10;
+ }
+
+ nsCOMPtr<nsIInputStream> stream = new testing::AsyncStringStream(aBuffer);
+
+ RefPtr<nsBufferedInputStream> bis = new nsBufferedInputStream();
+ bis->Init(stream, aSize);
+ return bis.forget();
+}
+
+// Simple reading.
+TEST(TestBufferedInputStream, SimpleRead)
+{
+ const size_t kBufSize = 10;
+
+ nsCString buf;
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ uint64_t length;
+ ASSERT_EQ(NS_OK, bis->Available(&length));
+ ASSERT_EQ((uint64_t)kBufSize, length);
+
+ char buf2[kBufSize];
+ uint32_t count;
+ ASSERT_EQ(NS_OK, bis->Read(buf2, sizeof(buf2), &count));
+ ASSERT_EQ(count, buf.Length());
+ ASSERT_TRUE(nsCString(buf.get(), kBufSize).Equals(nsCString(buf2, count)));
+}
+
+// Simple segment reading.
+TEST(TestBufferedInputStream, SimpleReadSegments)
+{
+ const size_t kBufSize = 10;
+
+ nsCString buf;
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ char buf2[kBufSize];
+ uint32_t count;
+ ASSERT_EQ(NS_OK, bis->ReadSegments(NS_CopySegmentToBuffer, buf2, sizeof(buf2),
+ &count));
+ ASSERT_EQ(count, buf.Length());
+ ASSERT_TRUE(nsCString(buf.get(), kBufSize).Equals(nsCString(buf2, count)));
+}
+
+// AsyncWait - sync
+TEST(TestBufferedInputStream, AsyncWait_sync)
+{
+ const size_t kBufSize = 10;
+
+ nsCString buf;
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback();
+
+ ASSERT_EQ(NS_OK, bis->AsyncWait(cb, 0, 0, nullptr));
+
+ // Immediatelly called
+ ASSERT_TRUE(cb->Called());
+}
+
+// AsyncWait - async
+TEST(TestBufferedInputStream, AsyncWait_async)
+{
+ const size_t kBufSize = 10;
+
+ nsCString buf;
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback();
+ nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
+
+ ASSERT_EQ(NS_OK, bis->AsyncWait(cb, 0, 0, thread));
+
+ ASSERT_FALSE(cb->Called());
+
+ // Eventually it is called.
+ MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
+ "TEST(TestBufferedInputStream, AsyncWait_async)"_ns,
+ [&]() { return cb->Called(); }));
+ ASSERT_TRUE(cb->Called());
+}
+
+// AsyncWait - sync - closureOnly
+TEST(TestBufferedInputStream, AsyncWait_sync_closureOnly)
+{
+ const size_t kBufSize = 10;
+
+ nsCString buf;
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback();
+
+ ASSERT_EQ(NS_OK, bis->AsyncWait(cb, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, 0,
+ nullptr));
+ ASSERT_FALSE(cb->Called());
+
+ bis->CloseWithStatus(NS_ERROR_FAILURE);
+
+ // Immediatelly called
+ ASSERT_TRUE(cb->Called());
+}
+
+// AsyncWait - async
+TEST(TestBufferedInputStream, AsyncWait_async_closureOnly)
+{
+ const size_t kBufSize = 10;
+
+ nsCString buf;
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ RefPtr<testing::InputStreamCallback> cb = new testing::InputStreamCallback();
+ nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
+
+ ASSERT_EQ(NS_OK, bis->AsyncWait(cb, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, 0,
+ thread));
+
+ ASSERT_FALSE(cb->Called());
+ bis->CloseWithStatus(NS_ERROR_FAILURE);
+ ASSERT_FALSE(cb->Called());
+
+ // Eventually it is called.
+ MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
+ "TEST(TestBufferedInputStream, AsyncWait_async_closureOnly)"_ns,
+ [&]() { return cb->Called(); }));
+ ASSERT_TRUE(cb->Called());
+}
+
+TEST(TestBufferedInputStream, AsyncWait_after_close)
+{
+ const size_t kBufSize = 10;
+
+ nsCString buf;
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ nsCOMPtr<nsIThread> eventTarget = do_GetCurrentThread();
+
+ auto cb = mozilla::MakeRefPtr<testing::InputStreamCallback>();
+ ASSERT_EQ(NS_OK, bis->AsyncWait(cb, 0, 0, eventTarget));
+ MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
+ "TEST(TestBufferedInputStream, AsyncWait_after_close) 1"_ns,
+ [&]() { return cb->Called(); }));
+ ASSERT_TRUE(cb->Called());
+
+ ASSERT_EQ(NS_OK, bis->Close());
+
+ cb = mozilla::MakeRefPtr<testing::InputStreamCallback>();
+ ASSERT_EQ(NS_OK, bis->AsyncWait(cb, 0, 0, eventTarget));
+ MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
+ "TEST(TestBufferedInputStream, AsyncWait_after_close) 2"_ns,
+ [&]() { return cb->Called(); }));
+ ASSERT_TRUE(cb->Called());
+}
+
+TEST(TestBufferedInputStream, AsyncLengthWait_after_close)
+{
+ nsCString buf{"The Quick Brown Fox Jumps over the Lazy Dog"};
+ const size_t kBufSize = 44;
+
+ RefPtr<nsBufferedInputStream> bis = CreateStream(kBufSize, buf);
+
+ nsCOMPtr<nsIThread> eventTarget = do_GetCurrentThread();
+
+ auto cb = mozilla::MakeRefPtr<testing::LengthCallback>();
+ ASSERT_EQ(NS_OK, bis->AsyncLengthWait(cb, eventTarget));
+ MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
+ "TEST(TestBufferedInputStream, AsyncLengthWait_after_close) 1"_ns,
+ [&]() { return cb->Called(); }));
+ ASSERT_TRUE(cb->Called());
+
+ uint64_t length;
+ ASSERT_EQ(NS_OK, bis->Available(&length));
+ ASSERT_EQ((uint64_t)kBufSize, length);
+
+ cb = mozilla::MakeRefPtr<testing::LengthCallback>();
+ ASSERT_EQ(NS_OK, bis->AsyncLengthWait(cb, eventTarget));
+ MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
+ "TEST(TestBufferedInputStream, AsyncLengthWait_after_close) 2"_ns,
+ [&]() { return cb->Called(); }));
+ ASSERT_TRUE(cb->Called());
+}
+
+// This stream returns a few bytes on the first read, and error on the second.
+class BrokenInputStream : public nsIInputStream {
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIINPUTSTREAM
+ private:
+ virtual ~BrokenInputStream() = default;
+ bool mFirst = true;
+};
+
+NS_IMPL_ISUPPORTS(BrokenInputStream, nsIInputStream)
+
+NS_IMETHODIMP BrokenInputStream::Close(void) { return NS_OK; }
+
+NS_IMETHODIMP BrokenInputStream::Available(uint64_t* _retval) {
+ *_retval = 100;
+ return NS_OK;
+}
+
+NS_IMETHODIMP BrokenInputStream::StreamStatus(void) { return NS_OK; }
+
+NS_IMETHODIMP BrokenInputStream::Read(char* aBuf, uint32_t aCount,
+ uint32_t* _retval) {
+ if (mFirst) {
+ aBuf[0] = 'h';
+ aBuf[1] = 'e';
+ aBuf[2] = 'l';
+ aBuf[3] = 0;
+ *_retval = 4;
+ mFirst = false;
+ return NS_OK;
+ }
+ return NS_ERROR_CORRUPTED_CONTENT;
+}
+
+NS_IMETHODIMP BrokenInputStream::ReadSegments(nsWriteSegmentFun aWriter,
+ void* aClosure, uint32_t aCount,
+ uint32_t* _retval) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP BrokenInputStream::IsNonBlocking(bool* _retval) {
+ *_retval = false;
+ return NS_OK;
+}
+
+// Check that the error from BrokenInputStream::Read is propagated
+// through NS_ReadInputStreamToString
+TEST(TestBufferedInputStream, BrokenInputStreamToBuffer)
+{
+ nsAutoCString out;
+ RefPtr<BrokenInputStream> stream = new BrokenInputStream();
+
+ nsresult rv = NS_ReadInputStreamToString(stream, out, -1);
+ ASSERT_EQ(rv, NS_ERROR_CORRUPTED_CONTENT);
+}