Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/test/gtest/TestPartiallySeekableInputStream.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "gtest/gtest.h"
2
3
#include "Helpers.h"
4
#include "nsCOMPtr.h"
5
#include "nsIPipe.h"
6
#include "nsStreamUtils.h"
7
#include "nsString.h"
8
#include "nsStringStream.h"
9
#include "mozilla/net/PartiallySeekableInputStream.h"
10
11
using mozilla::GetCurrentThreadSerialEventTarget;
12
using mozilla::net::PartiallySeekableInputStream;
13
using mozilla::SpinEventLoopUntil;
14
15
class NonSeekableStream final : public nsIInputStream
16
{
17
  nsCOMPtr<nsIInputStream> mStream;
18
19
public:
20
  NS_DECL_THREADSAFE_ISUPPORTS
21
22
  explicit NonSeekableStream(const nsACString& aBuffer)
23
0
  {
24
0
    NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer);
25
0
  }
26
27
  NS_IMETHOD
28
  Available(uint64_t* aLength) override
29
0
  {
30
0
    return mStream->Available(aLength);
31
0
  }
32
33
  NS_IMETHOD
34
  Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
35
0
  {
36
0
    return mStream->Read(aBuffer, aCount, aReadCount);
37
0
  }
38
39
  NS_IMETHOD
40
  ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
41
               uint32_t aCount, uint32_t *aResult) override
42
0
  {
43
0
    return mStream->ReadSegments(aWriter, aClosure, aCount, aResult);
44
0
  }
45
46
  NS_IMETHOD
47
  Close() override
48
0
  {
49
0
    return mStream->Close();
50
0
  }
51
52
  NS_IMETHOD
53
  IsNonBlocking(bool* aNonBlocking) override
54
0
  {
55
0
    return mStream->IsNonBlocking(aNonBlocking);
56
0
  }
57
58
private:
59
0
  ~NonSeekableStream() {}
60
};
61
62
NS_IMPL_ISUPPORTS(NonSeekableStream, nsIInputStream)
63
64
// Helper function for creating a non-seekable nsIInputStream + a
65
// PartiallySeekableInputStream.
66
PartiallySeekableInputStream*
67
CreateStream(uint32_t aSize, uint64_t aStreamSize, nsCString& aBuffer)
68
0
{
69
0
  aBuffer.SetLength(aSize);
70
0
  for (uint32_t i = 0; i < aSize; ++i) {
71
0
    aBuffer.BeginWriting()[i] = i % 10;
72
0
  }
73
0
74
0
  RefPtr<NonSeekableStream> stream = new NonSeekableStream(aBuffer);
75
0
  return new PartiallySeekableInputStream(stream.forget(), aStreamSize);
76
0
}
77
78
// Simple reading.
79
0
TEST(TestPartiallySeekableInputStream, SimpleRead) {
80
0
  const size_t kBufSize = 10;
81
0
82
0
  nsCString buf;
83
0
  RefPtr<PartiallySeekableInputStream> psi = CreateStream(kBufSize, 5, buf);
84
0
85
0
  uint64_t length;
86
0
  ASSERT_EQ(NS_OK, psi->Available(&length));
87
0
  ASSERT_EQ((uint64_t)kBufSize, length);
88
0
89
0
  char buf2[kBufSize];
90
0
  uint32_t count;
91
0
  ASSERT_EQ(NS_OK, psi->Read(buf2, sizeof(buf2), &count));
92
0
  ASSERT_EQ(count, buf.Length());
93
0
  ASSERT_TRUE(nsCString(buf.get(), kBufSize).Equals(nsCString(buf2, count)));
94
0
95
0
  // At this point, after reading more than the buffer size, seek is not
96
0
  // allowed.
97
0
  ASSERT_EQ(NS_ERROR_NOT_IMPLEMENTED,
98
0
            psi->Seek(nsISeekableStream::NS_SEEK_SET, 0));
99
0
100
0
  ASSERT_EQ(NS_ERROR_NOT_IMPLEMENTED,
101
0
            psi->Seek(nsISeekableStream::NS_SEEK_END, 0));
102
0
103
0
  ASSERT_EQ(NS_ERROR_NOT_IMPLEMENTED,
104
0
            psi->Seek(nsISeekableStream::NS_SEEK_CUR, 0));
105
0
106
0
  // Position is at the end of the stream.
107
0
  int64_t pos;
108
0
  ASSERT_EQ(NS_OK, psi->Tell(&pos));
109
0
  ASSERT_EQ((int64_t)kBufSize, pos);
110
0
}
111
112
// Simple seek
113
0
TEST(TestPartiallySeekableInputStream, SimpleSeek) {
114
0
  const size_t kBufSize = 10;
115
0
116
0
  nsCString buf;
117
0
  RefPtr<PartiallySeekableInputStream> psi = CreateStream(kBufSize, 5, buf);
118
0
119
0
  uint64_t length;
120
0
  ASSERT_EQ(NS_OK, psi->Available(&length));
121
0
  ASSERT_EQ((uint64_t)kBufSize, length);
122
0
123
0
  uint32_t count;
124
0
125
0
  {
126
0
    char buf2[3];
127
0
    ASSERT_EQ(NS_OK, psi->Read(buf2, sizeof(buf2), &count));
128
0
    ASSERT_EQ(count, sizeof(buf2));
129
0
    ASSERT_TRUE(nsCString(buf.get(), sizeof(buf2)).Equals(nsCString(buf2, sizeof(buf2))));
130
0
131
0
    int64_t pos;
132
0
    ASSERT_EQ(NS_OK, psi->Tell(&pos));
133
0
    ASSERT_EQ((int64_t)sizeof(buf2), pos);
134
0
135
0
    uint64_t length;
136
0
    ASSERT_EQ(NS_OK, psi->Available(&length));
137
0
    ASSERT_EQ((uint64_t)kBufSize - sizeof(buf2), length);
138
0
  }
139
0
140
0
  // Let's seek back to the beginning using NS_SEEK_SET
141
0
  ASSERT_EQ(NS_OK, psi->Seek(nsISeekableStream::NS_SEEK_SET, 0));
142
0
143
0
  {
144
0
    uint64_t length;
145
0
    ASSERT_EQ(NS_OK, psi->Available(&length));
146
0
    ASSERT_EQ((uint64_t)kBufSize, length);
147
0
148
0
    char buf2[3];
149
0
    ASSERT_EQ(NS_OK, psi->Read(buf2, sizeof(buf2), &count));
150
0
    ASSERT_EQ(count, sizeof(buf2));
151
0
    ASSERT_TRUE(nsCString(buf.get(), sizeof(buf2)).Equals(nsCString(buf2, sizeof(buf2))));
152
0
153
0
    int64_t pos;
154
0
    ASSERT_EQ(NS_OK, psi->Tell(&pos));
155
0
    ASSERT_EQ((int64_t)sizeof(buf2), pos);
156
0
157
0
    ASSERT_EQ(NS_OK, psi->Available(&length));
158
0
    ASSERT_EQ((uint64_t)kBufSize - sizeof(buf2), length);
159
0
  }
160
0
161
0
  // Let's seek back of 2 bytes using NS_SEEK_CUR
162
0
  ASSERT_EQ(NS_OK, psi->Seek(nsISeekableStream::NS_SEEK_CUR, -2));
163
0
164
0
  {
165
0
    uint64_t length;
166
0
    ASSERT_EQ(NS_OK, psi->Available(&length));
167
0
    ASSERT_EQ((uint64_t)kBufSize - 1, length);
168
0
169
0
    char buf2[3];
170
0
    ASSERT_EQ(NS_OK, psi->Read(buf2, sizeof(buf2), &count));
171
0
    ASSERT_EQ(count, sizeof(buf2));
172
0
    ASSERT_TRUE(nsCString(buf.get() + 1, sizeof(buf2)).Equals(nsCString(buf2, sizeof(buf2))));
173
0
174
0
    int64_t pos;
175
0
    ASSERT_EQ(NS_OK, psi->Tell(&pos));
176
0
    ASSERT_EQ((int64_t)sizeof(buf2) + 1, pos);
177
0
178
0
    ASSERT_EQ(NS_OK, psi->Available(&length));
179
0
    ASSERT_EQ((uint64_t)kBufSize - sizeof(buf2) - 1, length);
180
0
  }
181
0
182
0
  // Let's seek back to the beginning using NS_SEEK_SET
183
0
  ASSERT_EQ(NS_OK, psi->Seek(nsISeekableStream::NS_SEEK_SET, 0));
184
0
185
0
  {
186
0
    uint64_t length;
187
0
    ASSERT_EQ(NS_OK, psi->Available(&length));
188
0
    ASSERT_EQ((uint64_t)kBufSize, length);
189
0
190
0
    char buf2[kBufSize];
191
0
    ASSERT_EQ(NS_OK, psi->Read(buf2, sizeof(buf2), &count));
192
0
    ASSERT_EQ(count, buf.Length());
193
0
    ASSERT_TRUE(nsCString(buf.get(), kBufSize).Equals(nsCString(buf2, count)));
194
0
  }
195
0
}
196
197
// Full in cache
198
0
TEST(TestPartiallySeekableInputStream, FullCachedSeek) {
199
0
  const size_t kBufSize = 10;
200
0
201
0
  nsCString buf;
202
0
  RefPtr<PartiallySeekableInputStream> psi = CreateStream(kBufSize, 4096, buf);
203
0
204
0
  uint64_t length;
205
0
  ASSERT_EQ(NS_OK, psi->Available(&length));
206
0
  ASSERT_EQ((uint64_t)kBufSize, length);
207
0
208
0
  char buf2[kBufSize];
209
0
  uint32_t count;
210
0
  ASSERT_EQ(NS_OK, psi->Read(buf2, sizeof(buf2), &count));
211
0
  ASSERT_EQ(count, buf.Length());
212
0
  ASSERT_TRUE(nsCString(buf.get(), kBufSize).Equals(nsCString(buf2, count)));
213
0
214
0
  ASSERT_EQ(NS_OK, psi->Available(&length));
215
0
  ASSERT_EQ((uint64_t)0, length);
216
0
217
0
  ASSERT_EQ(NS_OK, psi->Seek(nsISeekableStream::NS_SEEK_SET, 0));
218
0
219
0
  ASSERT_EQ(NS_OK, psi->Available(&length));
220
0
  ASSERT_EQ((uint64_t)kBufSize, length);
221
0
222
0
  ASSERT_EQ(NS_OK, psi->Read(buf2, sizeof(buf2), &count));
223
0
  ASSERT_EQ(count, buf.Length());
224
0
  ASSERT_TRUE(nsCString(buf.get(), kBufSize).Equals(nsCString(buf2, count)));
225
0
226
0
  ASSERT_EQ(NS_OK, psi->Available(&length));
227
0
  ASSERT_EQ((uint64_t)0, length);
228
0
}
229
230
0
TEST(TestPartiallySeekableInputStream, QIInputStreamLength) {
231
0
  nsCString buf;
232
0
  buf.AssignLiteral("Hello world");
233
0
234
0
  for (int i = 0; i < 4; i++) {
235
0
    nsCOMPtr<nsIInputStream> psis;
236
0
    {
237
0
      RefPtr<testing::LengthInputStream> stream =
238
0
        new testing::LengthInputStream(buf, i % 2, i > 1);
239
0
      psis = new PartiallySeekableInputStream(stream.forget());
240
0
    }
241
0
242
0
    {
243
0
      nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(psis);
244
0
      ASSERT_EQ(!!(i % 2), !!qi);
245
0
    }
246
0
247
0
    {
248
0
      nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(psis);
249
0
      ASSERT_EQ(i > 1, !!qi);
250
0
    }
251
0
  }
252
0
}
253
254
0
TEST(TestPartiallySeekableInputStream, InputStreamLength) {
255
0
  nsCString buf;
256
0
  buf.AssignLiteral("Hello world");
257
0
258
0
  nsCOMPtr<nsIInputStream> psis;
259
0
  {
260
0
    RefPtr<testing::LengthInputStream> stream =
261
0
      new testing::LengthInputStream(buf, true, false);
262
0
    psis = new PartiallySeekableInputStream(stream.forget());
263
0
  }
264
0
265
0
  nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(psis);
266
0
  ASSERT_TRUE(!!qi);
267
0
268
0
  int64_t size;
269
0
  nsresult rv = qi->Length(&size);
270
0
  ASSERT_EQ(NS_OK, rv);
271
0
  ASSERT_EQ(buf.Length(), size);
272
0
}
273
274
0
TEST(TestPartiallySeekableInputStream, NegativeInputStreamLength) {
275
0
  nsCString buf;
276
0
  buf.AssignLiteral("Hello world");
277
0
278
0
  nsCOMPtr<nsIInputStream> psis;
279
0
  {
280
0
    RefPtr<testing::LengthInputStream> stream =
281
0
      new testing::LengthInputStream(buf, true, false, NS_OK, true);
282
0
    psis = new PartiallySeekableInputStream(stream.forget());
283
0
  }
284
0
285
0
  nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(psis);
286
0
  ASSERT_TRUE(!!qi);
287
0
288
0
  int64_t size;
289
0
  nsresult rv = qi->Length(&size);
290
0
  ASSERT_EQ(NS_OK, rv);
291
0
  ASSERT_EQ(-1, size);
292
0
}
293
294
0
TEST(TestPartiallySeekableInputStream, AsyncInputStreamLength) {
295
0
  nsCString buf;
296
0
  buf.AssignLiteral("Hello world");
297
0
298
0
  nsCOMPtr<nsIInputStream> psis;
299
0
  {
300
0
    RefPtr<testing::LengthInputStream> stream =
301
0
      new testing::LengthInputStream(buf, false, true);
302
0
    psis = new PartiallySeekableInputStream(stream.forget());
303
0
  }
304
0
305
0
  nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(psis);
306
0
  ASSERT_TRUE(!!qi);
307
0
308
0
  RefPtr<testing::LengthCallback> callback = new testing::LengthCallback();
309
0
310
0
  nsresult rv = qi->AsyncLengthWait(callback, GetCurrentThreadSerialEventTarget());
311
0
  ASSERT_EQ(NS_OK, rv);
312
0
313
0
  MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback->Called(); }));
314
0
  ASSERT_EQ(buf.Length(), callback->Size());
315
0
}
316
317
0
TEST(TestPartiallySeekableInputStream, NegativeAsyncInputStreamLength) {
318
0
  nsCString buf;
319
0
  buf.AssignLiteral("Hello world");
320
0
321
0
  nsCOMPtr<nsIInputStream> psis;
322
0
  {
323
0
    RefPtr<testing::LengthInputStream> stream =
324
0
      new testing::LengthInputStream(buf, false, true, NS_OK, true);
325
0
    psis = new PartiallySeekableInputStream(stream.forget());
326
0
  }
327
0
328
0
  nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(psis);
329
0
  ASSERT_TRUE(!!qi);
330
0
331
0
  RefPtr<testing::LengthCallback> callback = new testing::LengthCallback();
332
0
333
0
  nsresult rv = qi->AsyncLengthWait(callback, GetCurrentThreadSerialEventTarget());
334
0
  ASSERT_EQ(NS_OK, rv);
335
0
336
0
  MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback->Called(); }));
337
0
  ASSERT_EQ(-1, callback->Size());
338
0
}
339
340
0
TEST(TestPartiallySeekableInputStream, AbortLengthCallback) {
341
0
  nsCString buf;
342
0
  buf.AssignLiteral("Hello world");
343
0
344
0
  nsCOMPtr<nsIInputStream> psis;
345
0
  {
346
0
    RefPtr<testing::LengthInputStream> stream =
347
0
      new testing::LengthInputStream(buf, false, true, NS_OK, true);
348
0
    psis = new PartiallySeekableInputStream(stream.forget());
349
0
  }
350
0
351
0
  nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(psis);
352
0
  ASSERT_TRUE(!!qi);
353
0
354
0
  RefPtr<testing::LengthCallback> callback1 = new testing::LengthCallback();
355
0
  nsresult rv = qi->AsyncLengthWait(callback1, GetCurrentThreadSerialEventTarget());
356
0
  ASSERT_EQ(NS_OK, rv);
357
0
358
0
  RefPtr<testing::LengthCallback> callback2 = new testing::LengthCallback();
359
0
  rv = qi->AsyncLengthWait(callback2, GetCurrentThreadSerialEventTarget());
360
0
  ASSERT_EQ(NS_OK, rv);
361
0
362
0
  MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback2->Called(); }));
363
0
  ASSERT_TRUE(!callback1->Called());
364
0
  ASSERT_EQ(-1, callback2->Size());
365
0
}