1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /* Helper routines for xpcom gtests. */
8
9 #include "Helpers.h"
10
11 #include <algorithm>
12 #include "gtest/gtest.h"
13 #include "nsIOutputStream.h"
14 #include "nsStreamUtils.h"
15 #include "nsTArray.h"
16 #include "nsThreadUtils.h"
17
18 namespace testing {
19
20 // Populate an array with the given number of bytes. Data is lorem ipsum
21 // random text, but deterministic across multiple calls.
22 void
CreateData(uint32_t aNumBytes,nsTArray<char> & aDataOut)23 CreateData(uint32_t aNumBytes, nsTArray<char>& aDataOut)
24 {
25 static const char data[] =
26 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec egestas "
27 "purus eu condimentum iaculis. In accumsan leo eget odio porttitor, non "
28 "rhoncus nulla vestibulum. Etiam lacinia consectetur nisl nec "
29 "sollicitudin. Sed fringilla accumsan diam, pulvinar varius massa. Duis "
30 "mollis dignissim felis, eget tempus nisi tristique ut. Fusce euismod, "
31 "lectus non lacinia tempor, tellus diam suscipit quam, eget hendrerit "
32 "lacus nunc fringilla ante. Sed ultrices massa vitae risus molestie, ut "
33 "finibus quam laoreet nullam.";
34 static const uint32_t dataLength = sizeof(data) - 1;
35
36 aDataOut.SetCapacity(aNumBytes);
37
38 while (aNumBytes > 0) {
39 uint32_t amount = std::min(dataLength, aNumBytes);
40 aDataOut.AppendElements(data, amount);
41 aNumBytes -= amount;
42 }
43 }
44
45 // Write the given number of bytes out to the stream. Loop until expected
46 // bytes count is reached or an error occurs.
47 void
Write(nsIOutputStream * aStream,const nsTArray<char> & aData,uint32_t aOffset,uint32_t aNumBytes)48 Write(nsIOutputStream* aStream, const nsTArray<char>& aData, uint32_t aOffset,
49 uint32_t aNumBytes)
50 {
51 uint32_t remaining =
52 std::min(aNumBytes, static_cast<uint32_t>(aData.Length() - aOffset));
53
54 while (remaining > 0) {
55 uint32_t numWritten;
56 nsresult rv = aStream->Write(aData.Elements() + aOffset, remaining,
57 &numWritten);
58 ASSERT_TRUE(NS_SUCCEEDED(rv));
59 if (numWritten < 1) {
60 break;
61 }
62 aOffset += numWritten;
63 remaining -= numWritten;
64 }
65 }
66
67 // Write the given number of bytes and then close the stream.
68 void
WriteAllAndClose(nsIOutputStream * aStream,const nsTArray<char> & aData)69 WriteAllAndClose(nsIOutputStream* aStream, const nsTArray<char>& aData)
70 {
71 Write(aStream, aData, 0, aData.Length());
72 aStream->Close();
73 }
74
75 // Synchronously consume the given input stream and validate the resulting data
76 // against the given array of expected values.
77 void
ConsumeAndValidateStream(nsIInputStream * aStream,const nsTArray<char> & aExpectedData)78 ConsumeAndValidateStream(nsIInputStream* aStream,
79 const nsTArray<char>& aExpectedData)
80 {
81 nsDependentCSubstring data(aExpectedData.Elements(), aExpectedData.Length());
82 ConsumeAndValidateStream(aStream, data);
83 }
84
85 // Synchronously consume the given input stream and validate the resulting data
86 // against the given string of expected values.
87 void
ConsumeAndValidateStream(nsIInputStream * aStream,const nsACString & aExpectedData)88 ConsumeAndValidateStream(nsIInputStream* aStream,
89 const nsACString& aExpectedData)
90 {
91 nsAutoCString outputData;
92 nsresult rv = NS_ConsumeStream(aStream, UINT32_MAX, outputData);
93 ASSERT_TRUE(NS_SUCCEEDED(rv));
94 ASSERT_EQ(aExpectedData.Length(), outputData.Length());
95 ASSERT_TRUE(aExpectedData.Equals(outputData));
96 }
97
98 NS_IMPL_ISUPPORTS(OutputStreamCallback, nsIOutputStreamCallback);
99
OutputStreamCallback()100 OutputStreamCallback::OutputStreamCallback()
101 : mCalled(false)
102 {
103 }
104
~OutputStreamCallback()105 OutputStreamCallback::~OutputStreamCallback()
106 {
107 }
108
109 NS_IMETHODIMP
OnOutputStreamReady(nsIAsyncOutputStream * aStream)110 OutputStreamCallback::OnOutputStreamReady(nsIAsyncOutputStream* aStream)
111 {
112 mCalled = true;
113 return NS_OK;
114 }
115
116 NS_IMPL_ISUPPORTS(InputStreamCallback, nsIInputStreamCallback);
117
InputStreamCallback()118 InputStreamCallback::InputStreamCallback()
119 : mCalled(false)
120 {
121 }
122
~InputStreamCallback()123 InputStreamCallback::~InputStreamCallback()
124 {
125 }
126
127 NS_IMETHODIMP
OnInputStreamReady(nsIAsyncInputStream * aStream)128 InputStreamCallback::OnInputStreamReady(nsIAsyncInputStream* aStream)
129 {
130 mCalled = true;
131 return NS_OK;
132 }
133
AsyncStringStream(const nsACString & aBuffer)134 AsyncStringStream::AsyncStringStream(const nsACString& aBuffer)
135 {
136 NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer);
137 }
138
139 NS_IMETHODIMP
Available(uint64_t * aLength)140 AsyncStringStream::Available(uint64_t* aLength)
141 {
142 return mStream->Available(aLength);
143 }
144
145 NS_IMETHODIMP
Read(char * aBuffer,uint32_t aCount,uint32_t * aReadCount)146 AsyncStringStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount)
147 {
148 return mStream->Read(aBuffer, aCount, aReadCount);
149 }
150
151 NS_IMETHODIMP
ReadSegments(nsWriteSegmentFun aWriter,void * aClosure,uint32_t aCount,uint32_t * aResult)152 AsyncStringStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
153 uint32_t aCount, uint32_t *aResult)
154 {
155 return NS_ERROR_NOT_IMPLEMENTED;
156 }
157
158 NS_IMETHODIMP
Close()159 AsyncStringStream::Close()
160 {
161 nsresult rv = mStream->Close();
162 if (NS_SUCCEEDED(rv)) {
163 MaybeExecCallback(mCallback, mCallbackEventTarget);
164 }
165 return rv;
166 }
167
168 NS_IMETHODIMP
IsNonBlocking(bool * aNonBlocking)169 AsyncStringStream::IsNonBlocking(bool* aNonBlocking)
170 {
171 return mStream->IsNonBlocking(aNonBlocking);
172 }
173
174 NS_IMETHODIMP
CloseWithStatus(nsresult aStatus)175 AsyncStringStream::CloseWithStatus(nsresult aStatus)
176 {
177 return Close();
178 }
179
180 NS_IMETHODIMP
AsyncWait(nsIInputStreamCallback * aCallback,uint32_t aFlags,uint32_t aRequestedCount,nsIEventTarget * aEventTarget)181 AsyncStringStream::AsyncWait(nsIInputStreamCallback* aCallback,
182 uint32_t aFlags, uint32_t aRequestedCount,
183 nsIEventTarget* aEventTarget)
184 {
185 if (aFlags & nsIAsyncInputStream::WAIT_CLOSURE_ONLY) {
186 mCallback = aCallback;
187 mCallbackEventTarget = aEventTarget;
188 return NS_OK;
189 }
190
191 MaybeExecCallback(aCallback, aEventTarget);
192 return NS_OK;
193 }
194
195 void
MaybeExecCallback(nsIInputStreamCallback * aCallback,nsIEventTarget * aEventTarget)196 AsyncStringStream::MaybeExecCallback(nsIInputStreamCallback* aCallback,
197 nsIEventTarget* aEventTarget)
198 {
199 if (!aCallback) {
200 return;
201 }
202
203 nsCOMPtr<nsIInputStreamCallback> callback = aCallback;
204 nsCOMPtr<nsIAsyncInputStream> self = this;
205
206 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
207 "AsyncWait", [callback, self]() { callback->OnInputStreamReady(self); });
208
209 if (aEventTarget) {
210 aEventTarget->Dispatch(r.forget());
211 } else {
212 r->Run();
213 }
214 }
215
216 NS_IMPL_ISUPPORTS(AsyncStringStream, nsIAsyncInputStream, nsIInputStream)
217
218 } // namespace testing
219