/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "chrome/common/ipc_message.h" #include "gtest/gtest.h" #include "mozilla/NotNull.h" #include "mozilla/Result.h" #include "mozilla/ResultVariant.h" #include "mozilla/ipc/RandomAccessStreamParams.h" #include "mozilla/ipc/RandomAccessStreamUtils.h" #include "mozilla/gtest/MozAssertions.h" #include "nsAppDirectoryServiceDefs.h" #include "nsCOMPtr.h" #include "nsDirectoryServiceUtils.h" #include "nsIFile.h" #include "nsIFileStreams.h" #include "nsIRandomAccessStream.h" #include "nsNetUtil.h" #include "nsStreamUtils.h" namespace mozilla::ipc { namespace { Result, nsresult> CreateFileStream() { nsCOMPtr dir; nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(dir)); if (NS_FAILED(rv)) { return Err(rv); } nsCOMPtr file; rv = dir->Clone(getter_AddRefs(file)); if (NS_FAILED(rv)) { return Err(rv); } rv = file->Append(u"testfile"_ns); if (NS_FAILED(rv)) { return Err(rv); } rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666); if (NS_FAILED(rv)) { return Err(rv); } nsCOMPtr stream; rv = NS_NewLocalFileRandomAccessStream(getter_AddRefs(stream), file); if (NS_FAILED(rv)) { return Err(rv); } return stream; } // Populate an array with the given number of bytes. Data is lorem ipsum // random text, but deterministic across multiple calls. void CreateData(uint32_t aNumBytes, nsCString& aDataOut) { static const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec egestas " "purus eu condimentum iaculis. In accumsan leo eget odio porttitor, non " "rhoncus nulla vestibulum. Etiam lacinia consectetur nisl nec " "sollicitudin. Sed fringilla accumsan diam, pulvinar varius massa. Duis " "mollis dignissim felis, eget tempus nisi tristique ut. Fusce euismod, " "lectus non lacinia tempor, tellus diam suscipit quam, eget hendrerit " "lacus nunc fringilla ante. Sed ultrices massa vitae risus molestie, ut " "finibus quam laoreet nullam."; static const uint32_t dataLength = sizeof(data) - 1; aDataOut.SetCapacity(aNumBytes); while (aNumBytes > 0) { uint32_t amount = std::min(dataLength, aNumBytes); aDataOut.Append(data, amount); aNumBytes -= amount; } } // Synchronously consume the given input stream and validate the resulting data // against the given string of expected values. void ConsumeAndValidateStream(nsIInputStream* aStream, const nsACString& aExpectedData) { uint64_t available = 0; nsresult rv = aStream->Available(&available); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(available, aExpectedData.Length()); nsAutoCString outputData; rv = NS_ConsumeStream(aStream, UINT32_MAX, outputData); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(aExpectedData.Length(), outputData.Length()); ASSERT_TRUE(aExpectedData.Equals(outputData)); } } // namespace TEST(RandomAccessStreamUtils, NullRandomAccessStream_MaybeSerialize) { nsCOMPtr stream; Maybe streamParams = SerializeRandomAccessStream(stream, nullptr); ASSERT_TRUE(streamParams.isNothing()); auto res = DeserializeRandomAccessStream(streamParams); ASSERT_TRUE(res.isOk()); nsCOMPtr stream2 = res.unwrap(); ASSERT_EQ(stream2, nullptr); } TEST(RandomAccessStreamUtils, FileRandomAccessStream_Serialize) { const uint32_t dataSize = 256; auto res = CreateFileStream(); ASSERT_TRUE(res.isOk()); auto stream = res.unwrap(); ASSERT_TRUE(stream); nsCOMPtr fileStream = do_QueryInterface(stream); ASSERT_TRUE(fileStream); nsCString inputData; CreateData(dataSize, inputData); uint32_t numWritten = 0; nsresult rv = stream->OutputStream()->Write(inputData.BeginReading(), inputData.Length(), &numWritten); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(numWritten, dataSize); RandomAccessStreamParams streamParams = SerializeRandomAccessStream( WrapMovingNotNullUnchecked(std::move(stream)), nullptr); ASSERT_EQ(streamParams.type(), RandomAccessStreamParams::TFileRandomAccessStreamParams); auto res2 = DeserializeRandomAccessStream(streamParams); ASSERT_TRUE(res2.isOk()); NotNull> stream2 = res2.unwrap(); nsCOMPtr fileStream2 = do_QueryInterface(stream2.get()); ASSERT_TRUE(fileStream2); int64_t offset; rv = stream2->Tell(&offset); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(offset, dataSize); rv = stream2->Seek(nsISeekableStream::NS_SEEK_SET, 0); ASSERT_NS_SUCCEEDED(rv); ConsumeAndValidateStream(stream2->InputStream(), inputData); } TEST(RandomAccessStreamUtils, FileRandomAccessStream_MaybeSerialize) { const uint32_t dataSize = 512; auto res = CreateFileStream(); ASSERT_TRUE(res.isOk()); auto stream = res.unwrap(); ASSERT_TRUE(stream); nsCOMPtr fileStream = do_QueryInterface(stream); ASSERT_TRUE(fileStream); nsCString inputData; CreateData(dataSize, inputData); uint32_t numWritten = 0; nsresult rv = stream->OutputStream()->Write(inputData.BeginReading(), inputData.Length(), &numWritten); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(numWritten, dataSize); Maybe streamParams = SerializeRandomAccessStream(stream, nullptr); ASSERT_TRUE(streamParams); ASSERT_EQ(streamParams->type(), RandomAccessStreamParams::TFileRandomAccessStreamParams); auto res2 = DeserializeRandomAccessStream(streamParams); ASSERT_TRUE(res2.isOk()); nsCOMPtr stream2 = res2.unwrap(); ASSERT_TRUE(stream2); nsCOMPtr fileStream2 = do_QueryInterface(stream2); ASSERT_TRUE(fileStream2); int64_t offset; rv = stream2->Tell(&offset); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(offset, dataSize); rv = stream2->Seek(nsISeekableStream::NS_SEEK_SET, 0); ASSERT_NS_SUCCEEDED(rv); ConsumeAndValidateStream(stream2->InputStream(), inputData); } } // namespace mozilla::ipc