/src/mozilla-central/xpcom/tests/gtest/TestSlicedInputStream.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "gtest/gtest.h" |
2 | | |
3 | | #include "mozilla/SlicedInputStream.h" |
4 | | #include "nsCOMPtr.h" |
5 | | #include "nsIInputStream.h" |
6 | | #include "nsIPipe.h" |
7 | | #include "nsStreamUtils.h" |
8 | | #include "nsString.h" |
9 | | #include "nsStringStream.h" |
10 | | #include "Helpers.h" |
11 | | |
12 | | using namespace mozilla; |
13 | | |
14 | | // This helper class is used to call OnInputStreamReady with the right stream |
15 | | // as argument. |
16 | | class InputStreamCallback final : public nsIInputStreamCallback |
17 | | { |
18 | | nsCOMPtr<nsIAsyncInputStream> mStream; |
19 | | nsCOMPtr<nsIInputStreamCallback> mCallback; |
20 | | |
21 | | public: |
22 | | NS_DECL_THREADSAFE_ISUPPORTS |
23 | | |
24 | | InputStreamCallback(nsIAsyncInputStream* aStream, |
25 | | nsIInputStreamCallback* aCallback) |
26 | | : mStream(aStream) |
27 | | , mCallback(aCallback) |
28 | 0 | {} |
29 | | |
30 | | NS_IMETHOD |
31 | | OnInputStreamReady(nsIAsyncInputStream* aStream) override |
32 | 0 | { |
33 | 0 | return mCallback->OnInputStreamReady(mStream); |
34 | 0 | } |
35 | | |
36 | | private: |
37 | 0 | ~InputStreamCallback() {} |
38 | | }; |
39 | | |
40 | | NS_IMPL_ISUPPORTS(InputStreamCallback, nsIInputStreamCallback) |
41 | | |
42 | | /* We want to ensure that sliced streams work with both seekable and |
43 | | * non-seekable input streams. As our string streams are seekable, we need to |
44 | | * provide a string stream that doesn't permit seeking, so we can test the |
45 | | * logic that emulates seeking in sliced input streams. |
46 | | */ |
47 | | class NonSeekableStringStream final : public nsIAsyncInputStream |
48 | | { |
49 | | nsCOMPtr<nsIInputStream> mStream; |
50 | | |
51 | | public: |
52 | | NS_DECL_THREADSAFE_ISUPPORTS |
53 | | |
54 | | explicit NonSeekableStringStream(const nsACString& aBuffer) |
55 | 0 | { |
56 | 0 | NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer); |
57 | 0 | } |
58 | | |
59 | | explicit NonSeekableStringStream(nsIInputStream* aStream) |
60 | | : mStream(aStream) |
61 | 0 | { |
62 | 0 | } |
63 | | |
64 | | NS_IMETHOD |
65 | | Available(uint64_t* aLength) override |
66 | 0 | { |
67 | 0 | return mStream->Available(aLength); |
68 | 0 | } |
69 | | |
70 | | NS_IMETHOD |
71 | | Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override |
72 | 0 | { |
73 | 0 | return mStream->Read(aBuffer, aCount, aReadCount); |
74 | 0 | } |
75 | | |
76 | | NS_IMETHOD |
77 | | ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, |
78 | | uint32_t aCount, uint32_t *aResult) override |
79 | 0 | { |
80 | 0 | return mStream->ReadSegments(aWriter, aClosure, aCount, aResult); |
81 | 0 | } |
82 | | |
83 | | NS_IMETHOD |
84 | | Close() override |
85 | 0 | { |
86 | 0 | return mStream->Close(); |
87 | 0 | } |
88 | | |
89 | | NS_IMETHOD |
90 | | IsNonBlocking(bool* aNonBlocking) override |
91 | 0 | { |
92 | 0 | return mStream->IsNonBlocking(aNonBlocking); |
93 | 0 | } |
94 | | |
95 | | NS_IMETHOD |
96 | | CloseWithStatus(nsresult aStatus) override |
97 | 0 | { |
98 | 0 | nsCOMPtr<nsIAsyncInputStream> async = do_QueryInterface(mStream); |
99 | 0 | if (!async) { |
100 | 0 | MOZ_CRASH("This should not happen."); |
101 | 0 | return NS_ERROR_FAILURE; |
102 | 0 | } |
103 | 0 | |
104 | 0 | return async->CloseWithStatus(aStatus); |
105 | 0 | } |
106 | | |
107 | | NS_IMETHOD |
108 | | AsyncWait(nsIInputStreamCallback* aCallback, |
109 | | uint32_t aFlags, uint32_t aRequestedCount, |
110 | | nsIEventTarget* aEventTarget) override |
111 | 0 | { |
112 | 0 | nsCOMPtr<nsIAsyncInputStream> async = do_QueryInterface(mStream); |
113 | 0 | if (!async) { |
114 | 0 | MOZ_CRASH("This should not happen."); |
115 | 0 | return NS_ERROR_FAILURE; |
116 | 0 | } |
117 | 0 | |
118 | 0 | RefPtr<InputStreamCallback> callback = |
119 | 0 | new InputStreamCallback(this, aCallback); |
120 | 0 |
|
121 | 0 | return async->AsyncWait(callback, aFlags, aRequestedCount, aEventTarget); |
122 | 0 | } |
123 | | |
124 | | private: |
125 | 0 | ~NonSeekableStringStream() {} |
126 | | }; |
127 | | |
128 | | NS_IMPL_ISUPPORTS(NonSeekableStringStream, nsIInputStream, nsIAsyncInputStream) |
129 | | |
130 | | // Helper function for creating a seekable nsIInputStream + a SlicedInputStream. |
131 | | SlicedInputStream* |
132 | | CreateSeekableStreams(uint32_t aSize, uint64_t aStart, uint64_t aLength, |
133 | | nsCString& aBuffer) |
134 | 0 | { |
135 | 0 | aBuffer.SetLength(aSize); |
136 | 0 | for (uint32_t i = 0; i < aSize; ++i) { |
137 | 0 | aBuffer.BeginWriting()[i] = i % 10; |
138 | 0 | } |
139 | 0 |
|
140 | 0 | nsCOMPtr<nsIInputStream> stream; |
141 | 0 | NS_NewCStringInputStream(getter_AddRefs(stream), aBuffer); |
142 | 0 | return new SlicedInputStream(stream.forget(), aStart, aLength); |
143 | 0 | } |
144 | | |
145 | | // Helper function for creating a non-seekable nsIInputStream + a |
146 | | // SlicedInputStream. |
147 | | SlicedInputStream* |
148 | | CreateNonSeekableStreams(uint32_t aSize, uint64_t aStart, uint64_t aLength, |
149 | | nsCString& aBuffer) |
150 | 0 | { |
151 | 0 | aBuffer.SetLength(aSize); |
152 | 0 | for (uint32_t i = 0; i < aSize; ++i) { |
153 | 0 | aBuffer.BeginWriting()[i] = i % 10; |
154 | 0 | } |
155 | 0 |
|
156 | 0 | RefPtr<NonSeekableStringStream> stream = new NonSeekableStringStream(aBuffer); |
157 | 0 | return new SlicedInputStream(stream.forget(), aStart, aLength); |
158 | 0 | } |
159 | | |
160 | | // Same start, same length. |
161 | 0 | TEST(TestSlicedInputStream, Simple) { |
162 | 0 | const size_t kBufSize = 4096; |
163 | 0 |
|
164 | 0 | nsCString buf; |
165 | 0 | RefPtr<SlicedInputStream> sis = |
166 | 0 | CreateSeekableStreams(kBufSize, 0, kBufSize, buf); |
167 | 0 |
|
168 | 0 | uint64_t length; |
169 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
170 | 0 | ASSERT_EQ((uint64_t)kBufSize, length); |
171 | 0 |
|
172 | 0 | char buf2[kBufSize]; |
173 | 0 | uint32_t count; |
174 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
175 | 0 | ASSERT_EQ(count, buf.Length()); |
176 | 0 | ASSERT_TRUE(nsCString(buf.get()).Equals(nsCString(buf2))); |
177 | 0 | } |
178 | | |
179 | | // Simple sliced stream - seekable |
180 | 0 | TEST(TestSlicedInputStream, Sliced) { |
181 | 0 | const size_t kBufSize = 4096; |
182 | 0 |
|
183 | 0 | nsCString buf; |
184 | 0 | RefPtr<SlicedInputStream> sis = |
185 | 0 | CreateSeekableStreams(kBufSize, 10, 100, buf); |
186 | 0 |
|
187 | 0 | uint64_t length; |
188 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
189 | 0 | ASSERT_EQ((uint64_t)100, length); |
190 | 0 |
|
191 | 0 | char buf2[kBufSize / 2]; |
192 | 0 | uint32_t count; |
193 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
194 | 0 | ASSERT_EQ((uint64_t)100, count); |
195 | 0 | ASSERT_TRUE(nsCString(buf.get() + 10, count).Equals(nsCString(buf2, count))); |
196 | 0 | } |
197 | | |
198 | | // Simple sliced stream - non seekable |
199 | 0 | TEST(TestSlicedInputStream, SlicedNoSeek) { |
200 | 0 | const size_t kBufSize = 4096; |
201 | 0 |
|
202 | 0 | nsCString buf; |
203 | 0 | RefPtr<SlicedInputStream> sis = |
204 | 0 | CreateNonSeekableStreams(kBufSize, 10, 100, buf); |
205 | 0 |
|
206 | 0 | uint64_t length; |
207 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
208 | 0 | ASSERT_EQ((uint64_t)100, length); |
209 | 0 |
|
210 | 0 | char buf2[kBufSize / 2]; |
211 | 0 | uint32_t count; |
212 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
213 | 0 | ASSERT_EQ((uint64_t)100, count); |
214 | 0 | ASSERT_TRUE(nsCString(buf.get() + 10, count).Equals(nsCString(buf2, count))); |
215 | 0 | } |
216 | | |
217 | | // Big inputStream - seekable |
218 | 0 | TEST(TestSlicedInputStream, BigSliced) { |
219 | 0 | const size_t kBufSize = 4096 * 40; |
220 | 0 |
|
221 | 0 | nsCString buf; |
222 | 0 | RefPtr<SlicedInputStream> sis = |
223 | 0 | CreateSeekableStreams(kBufSize, 4096 * 5, 4096 * 10, buf); |
224 | 0 |
|
225 | 0 | uint64_t length; |
226 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
227 | 0 | ASSERT_EQ((uint64_t)4096 * 10, length); |
228 | 0 |
|
229 | 0 | char buf2[kBufSize / 2]; |
230 | 0 | uint32_t count; |
231 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
232 | 0 | ASSERT_EQ((uint64_t)4096 * 10, count); |
233 | 0 | ASSERT_TRUE(nsCString(buf.get() + 4096 * 5, count).Equals(nsCString(buf2, count))); |
234 | 0 | } |
235 | | |
236 | | // Big inputStream - non seekable |
237 | 0 | TEST(TestSlicedInputStream, BigSlicedNoSeek) { |
238 | 0 | const size_t kBufSize = 4096 * 40; |
239 | 0 |
|
240 | 0 | nsCString buf; |
241 | 0 | RefPtr<SlicedInputStream> sis = |
242 | 0 | CreateNonSeekableStreams(kBufSize, 4096 * 5, 4096 * 10, buf); |
243 | 0 |
|
244 | 0 | uint64_t length; |
245 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
246 | 0 | ASSERT_EQ((uint64_t)4096 * 10, length); |
247 | 0 |
|
248 | 0 | char buf2[kBufSize / 2]; |
249 | 0 | uint32_t count; |
250 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
251 | 0 | ASSERT_EQ((uint64_t)4096 * 10, count); |
252 | 0 | ASSERT_TRUE(nsCString(buf.get() + 4096 * 5, count).Equals(nsCString(buf2, count))); |
253 | 0 | } |
254 | | |
255 | | // Available size. |
256 | 0 | TEST(TestSlicedInputStream, Available) { |
257 | 0 | nsCString buf; |
258 | 0 | RefPtr<SlicedInputStream> sis = |
259 | 0 | CreateNonSeekableStreams(500000, 4, 400000, buf); |
260 | 0 |
|
261 | 0 | uint64_t toRead = 400000; |
262 | 0 | for (uint32_t i = 0; i < 400; ++i) { |
263 | 0 | uint64_t length; |
264 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
265 | 0 | ASSERT_EQ(toRead, length); |
266 | 0 |
|
267 | 0 | char buf2[1000]; |
268 | 0 | uint32_t count; |
269 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
270 | 0 | ASSERT_EQ((uint64_t)1000, count); |
271 | 0 | ASSERT_TRUE(nsCString(buf.get() + 4 + (1000 * i), count).Equals(nsCString(buf2, count))); |
272 | 0 |
|
273 | 0 | toRead -= count; |
274 | 0 | } |
275 | 0 |
|
276 | 0 | uint64_t length; |
277 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
278 | 0 | ASSERT_EQ((uint64_t)0, length); |
279 | 0 |
|
280 | 0 | char buf2[4096]; |
281 | 0 | uint32_t count; |
282 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
283 | 0 | ASSERT_EQ((uint64_t)0, count); |
284 | 0 | } |
285 | | |
286 | | // What if start is > then the size of the buffer? |
287 | 0 | TEST(TestSlicedInputStream, StartBiggerThan) { |
288 | 0 | nsCString buf; |
289 | 0 | RefPtr<SlicedInputStream> sis = |
290 | 0 | CreateNonSeekableStreams(500, 4000, 1, buf); |
291 | 0 |
|
292 | 0 | uint64_t length; |
293 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
294 | 0 | ASSERT_EQ((uint64_t)0, length); |
295 | 0 |
|
296 | 0 | char buf2[4096]; |
297 | 0 | uint32_t count; |
298 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
299 | 0 | ASSERT_EQ((uint64_t)0, count); |
300 | 0 | } |
301 | | |
302 | | // What if the length is > than the size of the buffer? |
303 | 0 | TEST(TestSlicedInputStream, LengthBiggerThan) { |
304 | 0 | nsCString buf; |
305 | 0 | RefPtr<SlicedInputStream> sis = |
306 | 0 | CreateNonSeekableStreams(500, 0, 500000, buf); |
307 | 0 |
|
308 | 0 | uint64_t length; |
309 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
310 | 0 | ASSERT_EQ((uint64_t)500, length); |
311 | 0 |
|
312 | 0 | char buf2[4096]; |
313 | 0 | uint32_t count; |
314 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
315 | 0 | ASSERT_EQ((uint64_t)500, count); |
316 | 0 | } |
317 | | |
318 | | // What if the length is 0? |
319 | 0 | TEST(TestSlicedInputStream, Length0) { |
320 | 0 | nsCString buf; |
321 | 0 | RefPtr<SlicedInputStream> sis = |
322 | 0 | CreateNonSeekableStreams(500, 0, 0, buf); |
323 | 0 |
|
324 | 0 | uint64_t length; |
325 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
326 | 0 | ASSERT_EQ((uint64_t)0, length); |
327 | 0 |
|
328 | 0 | char buf2[4096]; |
329 | 0 | uint32_t count; |
330 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
331 | 0 | ASSERT_EQ((uint64_t)0, count); |
332 | 0 | } |
333 | | |
334 | | // Seek test NS_SEEK_SET |
335 | 0 | TEST(TestSlicedInputStream, Seek_SET) { |
336 | 0 | nsCString buf; |
337 | 0 | buf.AssignLiteral("Hello world"); |
338 | 0 |
|
339 | 0 | RefPtr<SlicedInputStream> sis; |
340 | 0 | { |
341 | 0 | nsCOMPtr<nsIInputStream> stream; |
342 | 0 | NS_NewCStringInputStream(getter_AddRefs(stream), buf); |
343 | 0 | sis = new SlicedInputStream(stream.forget(), 1, buf.Length()); |
344 | 0 | } |
345 | 0 |
|
346 | 0 | ASSERT_EQ(NS_OK, sis->Seek(nsISeekableStream::NS_SEEK_SET, 1)); |
347 | 0 |
|
348 | 0 | uint64_t length; |
349 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
350 | 0 | ASSERT_EQ((uint64_t)buf.Length() - 2, length); |
351 | 0 |
|
352 | 0 | char buf2[4096]; |
353 | 0 | uint32_t count; |
354 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
355 | 0 | ASSERT_EQ((uint64_t)buf.Length() - 2, count); |
356 | 0 | ASSERT_EQ(0, strncmp(buf2, "llo world", count)); |
357 | 0 | } |
358 | | |
359 | | // Seek test NS_SEEK_CUR |
360 | 0 | TEST(TestSlicedInputStream, Seek_CUR) { |
361 | 0 | nsCString buf; |
362 | 0 | buf.AssignLiteral("Hello world"); |
363 | 0 |
|
364 | 0 | RefPtr<SlicedInputStream> sis; |
365 | 0 | { |
366 | 0 | nsCOMPtr<nsIInputStream> stream; |
367 | 0 | NS_NewCStringInputStream(getter_AddRefs(stream), buf); |
368 | 0 |
|
369 | 0 | sis = new SlicedInputStream(stream.forget(), 1, buf.Length()); |
370 | 0 | } |
371 | 0 |
|
372 | 0 | ASSERT_EQ(NS_OK, sis->Seek(nsISeekableStream::NS_SEEK_CUR, 1)); |
373 | 0 |
|
374 | 0 | uint64_t length; |
375 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
376 | 0 | ASSERT_EQ((uint64_t)buf.Length() - 2, length); |
377 | 0 |
|
378 | 0 | char buf2[3]; |
379 | 0 | uint32_t count; |
380 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
381 | 0 | ASSERT_EQ((uint64_t)3, count); |
382 | 0 | ASSERT_EQ(0, strncmp(buf2, "llo", count)); |
383 | 0 |
|
384 | 0 | ASSERT_EQ(NS_OK, sis->Seek(nsISeekableStream::NS_SEEK_CUR, 1)); |
385 | 0 |
|
386 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
387 | 0 | ASSERT_EQ((uint64_t)3, count); |
388 | 0 | ASSERT_EQ(0, strncmp(buf2, "wor", count)); |
389 | 0 | } |
390 | | |
391 | | // Seek test NS_SEEK_END - length > real one |
392 | 0 | TEST(TestSlicedInputStream, Seek_END_Bigger) { |
393 | 0 | nsCString buf; |
394 | 0 | buf.AssignLiteral("Hello world"); |
395 | 0 |
|
396 | 0 | RefPtr<SlicedInputStream> sis; |
397 | 0 | { |
398 | 0 | nsCOMPtr<nsIInputStream> stream; |
399 | 0 | NS_NewCStringInputStream(getter_AddRefs(stream), buf); |
400 | 0 |
|
401 | 0 | sis = new SlicedInputStream(stream.forget(), 2, buf.Length()); |
402 | 0 | } |
403 | 0 |
|
404 | 0 | ASSERT_EQ(NS_OK, sis->Seek(nsISeekableStream::NS_SEEK_END, -5)); |
405 | 0 |
|
406 | 0 | nsCOMPtr<nsIInputStream> stream; |
407 | 0 | NS_NewCStringInputStream(getter_AddRefs(stream), buf); |
408 | 0 | nsCOMPtr<nsISeekableStream> seekStream = do_QueryInterface(stream); |
409 | 0 | ASSERT_EQ(NS_OK, seekStream->Seek(nsISeekableStream::NS_SEEK_END, -5)); |
410 | 0 |
|
411 | 0 | uint64_t length; |
412 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
413 | 0 | ASSERT_EQ((uint64_t)5, length); |
414 | 0 |
|
415 | 0 | ASSERT_EQ(NS_OK, stream->Available(&length)); |
416 | 0 | ASSERT_EQ((uint64_t)5, length); |
417 | 0 |
|
418 | 0 | char buf2[5]; |
419 | 0 | uint32_t count; |
420 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
421 | 0 | ASSERT_EQ((uint64_t)5, count); |
422 | 0 | ASSERT_EQ(0, strncmp(buf2, "world", count)); |
423 | 0 |
|
424 | 0 | ASSERT_EQ(NS_OK, stream->Read(buf2, sizeof(buf2), &count)); |
425 | 0 | ASSERT_EQ((uint64_t)5, count); |
426 | 0 | ASSERT_EQ(0, strncmp(buf2, "world", count)); |
427 | 0 | } |
428 | | |
429 | | // Seek test NS_SEEK_END - length < real one |
430 | 0 | TEST(TestSlicedInputStream, Seek_END_Lower) { |
431 | 0 | nsCString buf; |
432 | 0 | buf.AssignLiteral("Hello world"); |
433 | 0 |
|
434 | 0 | RefPtr<SlicedInputStream> sis; |
435 | 0 | { |
436 | 0 | nsCOMPtr<nsIInputStream> stream; |
437 | 0 | NS_NewCStringInputStream(getter_AddRefs(stream), buf); |
438 | 0 |
|
439 | 0 | sis = new SlicedInputStream(stream.forget(), 2, 6); |
440 | 0 | } |
441 | 0 |
|
442 | 0 | ASSERT_EQ(NS_OK, sis->Seek(nsISeekableStream::NS_SEEK_END, -3)); |
443 | 0 |
|
444 | 0 | uint64_t length; |
445 | 0 | ASSERT_EQ(NS_OK, sis->Available(&length)); |
446 | 0 | ASSERT_EQ((uint64_t)3, length); |
447 | 0 |
|
448 | 0 | char buf2[5]; |
449 | 0 | uint32_t count; |
450 | 0 | ASSERT_EQ(NS_OK, sis->Read(buf2, sizeof(buf2), &count)); |
451 | 0 | ASSERT_EQ((uint64_t)3, count); |
452 | 0 | ASSERT_EQ(0, strncmp(buf2, " wo", count)); |
453 | 0 | } |
454 | | |
455 | | // Check the nsIAsyncInputStream interface |
456 | 0 | TEST(TestSlicedInputStream, NoAsyncInputStream) { |
457 | 0 | const size_t kBufSize = 4096; |
458 | 0 |
|
459 | 0 | nsCString buf; |
460 | 0 | nsCOMPtr<nsIInputStream> sis = |
461 | 0 | CreateSeekableStreams(kBufSize, 0, kBufSize, buf); |
462 | 0 |
|
463 | 0 | // If the stream is not asyncInputStream, also SIS is not. |
464 | 0 | nsCOMPtr<nsIAsyncInputStream> async = do_QueryInterface(sis); |
465 | 0 | ASSERT_TRUE(!async); |
466 | 0 | } |
467 | | |
468 | 0 | TEST(TestSlicedInputStream, AsyncInputStream) { |
469 | 0 | nsCOMPtr<nsIAsyncInputStream> reader; |
470 | 0 | nsCOMPtr<nsIAsyncOutputStream> writer; |
471 | 0 |
|
472 | 0 | const uint32_t segmentSize = 1024; |
473 | 0 | const uint32_t numSegments = 1; |
474 | 0 |
|
475 | 0 | nsresult rv = NS_NewPipe2(getter_AddRefs(reader), getter_AddRefs(writer), |
476 | 0 | true, true, // non-blocking - reader, writer |
477 | 0 | segmentSize, numSegments); |
478 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
479 | 0 |
|
480 | 0 | nsTArray<char> inputData; |
481 | 0 | testing::CreateData(segmentSize, inputData); |
482 | 0 |
|
483 | 0 | // We have to wrap the reader because it implements only a partial |
484 | 0 | // nsISeekableStream interface. When ::Seek() is called, it does a MOZ_CRASH. |
485 | 0 | nsCOMPtr<nsIInputStream> sis; |
486 | 0 | { |
487 | 0 | RefPtr<NonSeekableStringStream> wrapper = |
488 | 0 | new NonSeekableStringStream(reader); |
489 | 0 |
|
490 | 0 | sis = new SlicedInputStream(wrapper.forget(), 500, 500); |
491 | 0 | } |
492 | 0 |
|
493 | 0 | nsCOMPtr<nsIAsyncInputStream> async = do_QueryInterface(sis); |
494 | 0 | ASSERT_TRUE(!!async); |
495 | 0 |
|
496 | 0 | RefPtr<testing::InputStreamCallback> cb = |
497 | 0 | new testing::InputStreamCallback(); |
498 | 0 |
|
499 | 0 | rv = async->AsyncWait(cb, 0, 0, nullptr); |
500 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
501 | 0 |
|
502 | 0 | ASSERT_FALSE(cb->Called()); |
503 | 0 |
|
504 | 0 | uint32_t numWritten = 0; |
505 | 0 | rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten); |
506 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
507 | 0 |
|
508 | 0 | ASSERT_TRUE(cb->Called()); |
509 | 0 |
|
510 | 0 | inputData.RemoveElementsAt(0, 500); |
511 | 0 | inputData.RemoveElementsAt(500, 24); |
512 | 0 |
|
513 | 0 | testing::ConsumeAndValidateStream(async, inputData); |
514 | 0 | } |
515 | | |
516 | 0 | TEST(TestSlicedInputStream, QIInputStreamLength) { |
517 | 0 | nsCString buf; |
518 | 0 | buf.AssignLiteral("Hello world"); |
519 | 0 |
|
520 | 0 | for (int i = 0; i < 4; i++) { |
521 | 0 | nsCOMPtr<nsIInputStream> sis; |
522 | 0 | { |
523 | 0 | RefPtr<testing::LengthInputStream> stream = |
524 | 0 | new testing::LengthInputStream(buf, i % 2, i > 1); |
525 | 0 |
|
526 | 0 | sis = new SlicedInputStream(stream.forget(), 0, 5); |
527 | 0 | } |
528 | 0 |
|
529 | 0 | { |
530 | 0 | nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(sis); |
531 | 0 | ASSERT_EQ(!!(i % 2), !!qi); |
532 | 0 | } |
533 | 0 |
|
534 | 0 | { |
535 | 0 | nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(sis); |
536 | 0 | ASSERT_EQ(i > 1, !!qi); |
537 | 0 | } |
538 | 0 | } |
539 | 0 | } |
540 | | |
541 | 0 | TEST(TestSlicedInputStream, InputStreamLength) { |
542 | 0 | nsCString buf; |
543 | 0 | buf.AssignLiteral("Hello world"); |
544 | 0 |
|
545 | 0 | nsCOMPtr<nsIInputStream> sis; |
546 | 0 | { |
547 | 0 | RefPtr<testing::LengthInputStream> stream = |
548 | 0 | new testing::LengthInputStream(buf, true, false); |
549 | 0 |
|
550 | 0 | sis = new SlicedInputStream(stream.forget(), 0, 5); |
551 | 0 | } |
552 | 0 |
|
553 | 0 | nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(sis); |
554 | 0 | ASSERT_TRUE(!!qi); |
555 | 0 |
|
556 | 0 | int64_t size; |
557 | 0 | nsresult rv = qi->Length(&size); |
558 | 0 | ASSERT_EQ(NS_OK, rv); |
559 | 0 | ASSERT_EQ(5, size); |
560 | 0 | } |
561 | | |
562 | 0 | TEST(TestSlicedInputStream, NegativeInputStreamLength) { |
563 | 0 | nsCString buf; |
564 | 0 | buf.AssignLiteral("Hello world"); |
565 | 0 |
|
566 | 0 | nsCOMPtr<nsIInputStream> sis; |
567 | 0 | { |
568 | 0 | RefPtr<testing::LengthInputStream> stream = |
569 | 0 | new testing::LengthInputStream(buf, true, false, NS_OK, true); |
570 | 0 |
|
571 | 0 | sis = new SlicedInputStream(stream.forget(), 0, 5); |
572 | 0 | } |
573 | 0 |
|
574 | 0 | nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(sis); |
575 | 0 | ASSERT_TRUE(!!qi); |
576 | 0 |
|
577 | 0 | int64_t size; |
578 | 0 | nsresult rv = qi->Length(&size); |
579 | 0 | ASSERT_EQ(NS_OK, rv); |
580 | 0 | ASSERT_EQ(-1, size); |
581 | 0 | } |
582 | | |
583 | 0 | TEST(TestSlicedInputStream, AsyncInputStreamLength) { |
584 | 0 | nsCString buf; |
585 | 0 | buf.AssignLiteral("Hello world"); |
586 | 0 |
|
587 | 0 | nsCOMPtr<nsIInputStream> sis; |
588 | 0 | { |
589 | 0 | RefPtr<testing::LengthInputStream> stream = |
590 | 0 | new testing::LengthInputStream(buf, false, true); |
591 | 0 |
|
592 | 0 | sis = new SlicedInputStream(stream.forget(), 0, 5); |
593 | 0 | } |
594 | 0 |
|
595 | 0 | nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(sis); |
596 | 0 | ASSERT_TRUE(!!qi); |
597 | 0 |
|
598 | 0 | RefPtr<testing::LengthCallback> callback = new testing::LengthCallback(); |
599 | 0 |
|
600 | 0 | nsresult rv = |
601 | 0 | qi->AsyncLengthWait(callback, GetCurrentThreadSerialEventTarget()); |
602 | 0 | ASSERT_EQ(NS_OK, rv); |
603 | 0 |
|
604 | 0 | MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback->Called(); })); |
605 | 0 | ASSERT_EQ(5, callback->Size()); |
606 | 0 | } |
607 | | |
608 | 0 | TEST(TestSlicedInputStream, NegativeAsyncInputStreamLength) { |
609 | 0 | nsCString buf; |
610 | 0 | buf.AssignLiteral("Hello world"); |
611 | 0 |
|
612 | 0 | nsCOMPtr<nsIInputStream> sis; |
613 | 0 | { |
614 | 0 | RefPtr<testing::LengthInputStream> stream = |
615 | 0 | new testing::LengthInputStream(buf, false, true, NS_OK, true); |
616 | 0 |
|
617 | 0 | sis = new SlicedInputStream(stream.forget(), 0, 5); |
618 | 0 | } |
619 | 0 |
|
620 | 0 | nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(sis); |
621 | 0 | ASSERT_TRUE(!!qi); |
622 | 0 |
|
623 | 0 | RefPtr<testing::LengthCallback> callback = new testing::LengthCallback(); |
624 | 0 |
|
625 | 0 | nsresult rv = |
626 | 0 | qi->AsyncLengthWait(callback, GetCurrentThreadSerialEventTarget()); |
627 | 0 | ASSERT_EQ(NS_OK, rv); |
628 | 0 |
|
629 | 0 | MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback->Called(); })); |
630 | 0 | ASSERT_EQ(-1, callback->Size()); |
631 | 0 | } |
632 | | |
633 | 0 | TEST(TestSlicedInputStream, AbortLengthCallback) { |
634 | 0 | nsCString buf; |
635 | 0 | buf.AssignLiteral("Hello world"); |
636 | 0 |
|
637 | 0 | nsCOMPtr<nsIInputStream> sis; |
638 | 0 | { |
639 | 0 | RefPtr<testing::LengthInputStream> stream = |
640 | 0 | new testing::LengthInputStream(buf, false, true, NS_OK, true); |
641 | 0 |
|
642 | 0 | sis = new SlicedInputStream(stream.forget(), 0, 5); |
643 | 0 | } |
644 | 0 |
|
645 | 0 | nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(sis); |
646 | 0 | ASSERT_TRUE(!!qi); |
647 | 0 |
|
648 | 0 | RefPtr<testing::LengthCallback> callback1 = new testing::LengthCallback(); |
649 | 0 | nsresult rv = |
650 | 0 | qi->AsyncLengthWait(callback1, GetCurrentThreadSerialEventTarget()); |
651 | 0 | ASSERT_EQ(NS_OK, rv); |
652 | 0 |
|
653 | 0 | RefPtr<testing::LengthCallback> callback2 = new testing::LengthCallback(); |
654 | 0 | rv = qi->AsyncLengthWait(callback2, GetCurrentThreadSerialEventTarget()); |
655 | 0 | ASSERT_EQ(NS_OK, rv); |
656 | 0 |
|
657 | 0 | MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback2->Called(); })); |
658 | 0 | ASSERT_TRUE(!callback1->Called()); |
659 | 0 | ASSERT_EQ(-1, callback2->Size()); |
660 | 0 | } |