Coverage Report

Created: 2018-09-25 14:53

/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
}