Bug 1421176 - nsMultiplexInputStream::Available() sanitize - gtests. r=smaug, a=gchang
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 30 Nov 2017 20:00:23 +0100
changeset 445233 0509c78748016f4e861affa165e4f510e540c692
parent 445232 019a43b61a5b2f48824f8e795a4c39659b1ef43b
child 445234 52b742260c8458ebc7b0596e6e228cbb279332ab
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, gchang
bugs1421176
milestone58.0
Bug 1421176 - nsMultiplexInputStream::Available() sanitize - gtests. r=smaug, a=gchang
xpcom/tests/gtest/TestMultiplexInputStream.cpp
--- a/xpcom/tests/gtest/TestMultiplexInputStream.cpp
+++ b/xpcom/tests/gtest/TestMultiplexInputStream.cpp
@@ -208,8 +208,189 @@ TEST(TestMultiplexInputStream, AsyncWait
   ASSERT_FALSE(cb->Called());
   ais->CloseWithStatus(NS_ERROR_FAILURE);
   ASSERT_FALSE(cb->Called());
 
   // Eventually it is called.
   MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil([&]() { return cb->Called(); }));
   ASSERT_TRUE(cb->Called());
 }
+
+class ClosedStream final : public nsIInputStream
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+  ClosedStream() {}
+
+  NS_IMETHOD
+  Available(uint64_t* aLength) override
+  {
+    return NS_BASE_STREAM_CLOSED;
+  }
+
+  NS_IMETHOD
+  Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
+  {
+    MOZ_CRASH("This should not be called!");
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
+               uint32_t aCount, uint32_t *aResult) override
+  {
+    MOZ_CRASH("This should not be called!");
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  Close() override { return NS_OK; }
+
+  NS_IMETHOD
+  IsNonBlocking(bool* aNonBlocking) override
+  {
+    *aNonBlocking = true;
+    return NS_OK;
+  }
+
+private:
+  ~ClosedStream() = default;
+};
+
+NS_IMPL_ISUPPORTS(ClosedStream, nsIInputStream)
+
+class AsyncStream final : public nsIAsyncInputStream
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+  explicit AsyncStream(int64_t aSize) : mState(eBlocked), mSize(aSize) {}
+
+  void
+  Unblock()
+  {
+    mState = eUnblocked;
+  }
+
+  NS_IMETHOD
+  Available(uint64_t* aLength) override
+  {
+   *aLength = mState == eBlocked ? 0 : mSize;
+   return mState == eClosed ? NS_BASE_STREAM_CLOSED : NS_OK;
+  }
+
+  NS_IMETHOD
+  Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
+  {
+    MOZ_CRASH("This should not be called!");
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
+               uint32_t aCount, uint32_t *aResult) override
+  {
+    MOZ_CRASH("This should not be called!");
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  Close() override
+  {
+    mState = eClosed;
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  IsNonBlocking(bool* aNonBlocking) override
+  {
+    *aNonBlocking = true;
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  AsyncWait(nsIInputStreamCallback* aCallback,
+            uint32_t aFlags, uint32_t aRequestedCount,
+            nsIEventTarget* aEventTarget) override
+  {
+    MOZ_CRASH("This should not be called!");
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  CloseWithStatus(nsresult aStatus) override
+  {
+    return NS_OK;
+  }
+
+private:
+  ~AsyncStream() = default;
+
+  enum {
+    eBlocked,
+    eUnblocked,
+    eClosed
+  } mState;
+
+  uint64_t mSize;
+};
+
+NS_IMPL_ISUPPORTS(AsyncStream, nsIInputStream, nsIAsyncInputStream)
+
+TEST(TestMultiplexInputStream, Available) {
+  nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
+    do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
+
+  nsCOMPtr<nsIInputStream> s = do_QueryInterface(multiplexStream);
+  ASSERT_TRUE(!!s);
+
+  nsCOMPtr<nsIAsyncInputStream> as = do_QueryInterface(multiplexStream);
+  ASSERT_TRUE(!as);
+
+  uint64_t length;
+
+  // The stream returns NS_BASE_STREAM_CLOSED if there are no substreams.
+  nsresult rv = s->Available(&length);
+  ASSERT_EQ(NS_BASE_STREAM_CLOSED, rv);
+
+  rv = multiplexStream->AppendStream(new ClosedStream());
+  ASSERT_EQ(NS_OK, rv);
+
+  uint64_t asyncSize = 2;
+  RefPtr<AsyncStream> asyncStream = new AsyncStream(2);
+  rv = multiplexStream->AppendStream(asyncStream);
+  ASSERT_EQ(NS_OK, rv);
+
+  nsCString buffer;
+  buffer.Assign("World!!!");
+
+  nsCOMPtr<nsIInputStream> stringStream;
+  rv = NS_NewCStringInputStream(getter_AddRefs(stringStream), buffer);
+  ASSERT_EQ(NS_OK, rv);
+
+  rv = multiplexStream->AppendStream(stringStream);
+  ASSERT_EQ(NS_OK, rv);
+
+  // Now we are async.
+  as = do_QueryInterface(multiplexStream);
+  ASSERT_TRUE(!!as);
+
+  // Available should skip the closed stream and return 0 because the
+  // asyncStream returns 0 and it's async.
+  rv = s->Available(&length);
+  ASSERT_EQ(NS_OK, rv);
+  ASSERT_EQ((uint64_t)0, length);
+
+  asyncStream->Unblock();
+
+  // Now we should return only the size of the async stream because we don't
+  // know when this is completed.
+  rv = s->Available(&length);
+  ASSERT_EQ(NS_OK, rv);
+  ASSERT_EQ(asyncSize, length);
+
+  asyncStream->Close();
+
+  rv = s->Available(&length);
+  ASSERT_EQ(NS_OK, rv);
+  ASSERT_EQ(buffer.Length(), length);
+}