#include "gtest/gtest.h" #include "mozilla/InputStreamLengthHelper.h" #include "mozilla/SpinEventLoopUntil.h" #include "nsCOMPtr.h" #include "nsIInputStream.h" #include "nsStreamUtils.h" #include "nsString.h" #include "nsStringStream.h" #include "nsThreadUtils.h" #include "nsXPCOM.h" #include "Helpers.h" using namespace mozilla; TEST(TestInputStreamLengthHelper, NonLengthStream) { nsCString buf; buf.AssignLiteral("Hello world"); nsCOMPtr stream; NS_NewCStringInputStream(getter_AddRefs(stream), buf); bool called = false; InputStreamLengthHelper::GetAsyncLength(stream, [&](int64_t aLength) { ASSERT_EQ(int64_t(buf.Length()), aLength); called = true; }); MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST(TestInputStreamLengthHelper, NonLengthStream)"_ns, [&]() { return called; })); } class LengthStream final : public nsIInputStreamLength, public nsIAsyncInputStreamLength, public nsIInputStream { public: NS_DECL_ISUPPORTS LengthStream(int64_t aLength, nsresult aLengthRv, uint64_t aAvailable, bool aIsAsyncLength) : mLength(aLength), mLengthRv(aLengthRv), mAvailable(aAvailable), mIsAsyncLength(aIsAsyncLength) {} NS_IMETHOD Close(void) override { MOZ_CRASH("Invalid call!"); } NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval) override { MOZ_CRASH("Invalid call!"); } NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, uint32_t* _retval) override { MOZ_CRASH("Invalid call!"); } NS_IMETHOD IsNonBlocking(bool* _retval) override { MOZ_CRASH("Invalid call!"); } NS_IMETHOD Length(int64_t* aLength) override { *aLength = mLength; return mLengthRv; } NS_IMETHOD AsyncLengthWait(nsIInputStreamLengthCallback* aCallback, nsIEventTarget* aEventTarget) override { if (aCallback) { aCallback->OnInputStreamLengthReady(this, mLength); } return NS_OK; } NS_IMETHOD Available(uint64_t* aAvailable) override { *aAvailable = mAvailable; return NS_OK; } NS_IMETHOD StreamStatus() override { return NS_OK; } private: ~LengthStream() = default; int64_t mLength; nsresult mLengthRv; uint64_t mAvailable; bool mIsAsyncLength; }; NS_IMPL_ADDREF(LengthStream); NS_IMPL_RELEASE(LengthStream); NS_INTERFACE_MAP_BEGIN(LengthStream) NS_INTERFACE_MAP_ENTRY(nsIInputStream) NS_INTERFACE_MAP_ENTRY(nsIInputStreamLength) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStreamLength, mIsAsyncLength) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) NS_INTERFACE_MAP_END TEST(TestInputStreamLengthHelper, LengthStream) { nsCOMPtr stream = new LengthStream(42, NS_OK, 0, false); bool called = false; InputStreamLengthHelper::GetAsyncLength(stream, [&](int64_t aLength) { ASSERT_EQ(42, aLength); called = true; }); MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST(TestInputStreamLengthHelper, LengthStream)"_ns, [&]() { return called; })); } TEST(TestInputStreamLengthHelper, InvalidLengthStream) { nsCOMPtr stream = new LengthStream(42, NS_ERROR_NOT_AVAILABLE, 0, false); bool called = false; InputStreamLengthHelper::GetAsyncLength(stream, [&](int64_t aLength) { ASSERT_EQ(-1, aLength); called = true; }); MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST(TestInputStreamLengthHelper, InvalidLengthStream)"_ns, [&]() { return called; })); } TEST(TestInputStreamLengthHelper, AsyncLengthStream) { nsCOMPtr stream = new LengthStream(22, NS_BASE_STREAM_WOULD_BLOCK, 123, true); bool called = false; InputStreamLengthHelper::GetAsyncLength(stream, [&](int64_t aLength) { ASSERT_EQ(22, aLength); called = true; }); MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST(TestInputStreamLengthHelper, AsyncLengthStream)"_ns, [&]() { return called; })); } TEST(TestInputStreamLengthHelper, FallbackLengthStream) { nsCOMPtr stream = new LengthStream(-1, NS_BASE_STREAM_WOULD_BLOCK, 123, false); bool called = false; InputStreamLengthHelper::GetAsyncLength(stream, [&](int64_t aLength) { ASSERT_EQ(123, aLength); called = true; }); MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST(TestInputStreamLengthHelper, FallbackLengthStream)"_ns, [&]() { return called; })); }