Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/image/test/gtest/TestStreamingLexer.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "gtest/gtest.h"
6
7
#include "Common.h"
8
#include "mozilla/Vector.h"
9
#include "StreamingLexer.h"
10
11
using namespace mozilla;
12
using namespace mozilla::image;
13
14
enum class TestState
15
{
16
  ONE,
17
  TWO,
18
  THREE,
19
  UNBUFFERED,
20
  TRUNCATED_SUCCESS,
21
  TRUNCATED_FAILURE
22
};
23
24
void
25
CheckLexedData(const char* aData,
26
               size_t aLength,
27
               size_t aOffset,
28
               size_t aExpectedLength)
29
0
{
30
0
  EXPECT_TRUE(aLength == aExpectedLength);
31
0
32
0
  for (size_t i = 0; i < aLength; ++i) {
33
0
    EXPECT_EQ(aData[i], char(aOffset + i + 1));
34
0
  }
35
0
}
36
37
LexerTransition<TestState>
38
DoLex(TestState aState, const char* aData, size_t aLength)
39
0
{
40
0
  switch (aState) {
41
0
    case TestState::ONE:
42
0
      CheckLexedData(aData, aLength, 0, 3);
43
0
      return Transition::To(TestState::TWO, 3);
44
0
    case TestState::TWO:
45
0
      CheckLexedData(aData, aLength, 3, 3);
46
0
      return Transition::To(TestState::THREE, 3);
47
0
    case TestState::THREE:
48
0
      CheckLexedData(aData, aLength, 6, 3);
49
0
      return Transition::TerminateSuccess();
50
0
    case TestState::TRUNCATED_SUCCESS:
51
0
      return Transition::TerminateSuccess();
52
0
    case TestState::TRUNCATED_FAILURE:
53
0
      return Transition::TerminateFailure();
54
0
    default:
55
0
      MOZ_CRASH("Unexpected or unhandled TestState");
56
0
  }
57
0
}
58
59
LexerTransition<TestState>
60
DoLexWithUnbuffered(TestState aState, const char* aData, size_t aLength,
61
                    Vector<char>& aUnbufferedVector)
62
0
{
63
0
  switch (aState) {
64
0
    case TestState::ONE:
65
0
      CheckLexedData(aData, aLength, 0, 3);
66
0
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
67
0
    case TestState::TWO:
68
0
      CheckLexedData(aUnbufferedVector.begin(), aUnbufferedVector.length(), 3, 3);
69
0
      return Transition::To(TestState::THREE, 3);
70
0
    case TestState::THREE:
71
0
      CheckLexedData(aData, aLength, 6, 3);
72
0
      return Transition::TerminateSuccess();
73
0
    case TestState::UNBUFFERED:
74
0
      EXPECT_TRUE(aLength <= 3);
75
0
      EXPECT_TRUE(aUnbufferedVector.append(aData, aLength));
76
0
      return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
77
0
    default:
78
0
      MOZ_CRASH("Unexpected or unhandled TestState");
79
0
  }
80
0
}
81
82
LexerTransition<TestState>
83
DoLexWithUnbufferedTerminate(TestState aState, const char* aData, size_t aLength)
84
0
{
85
0
  switch (aState) {
86
0
    case TestState::ONE:
87
0
      CheckLexedData(aData, aLength, 0, 3);
88
0
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
89
0
    case TestState::UNBUFFERED:
90
0
      return Transition::TerminateSuccess();
91
0
    default:
92
0
      MOZ_CRASH("Unexpected or unhandled TestState");
93
0
  }
94
0
}
95
96
LexerTransition<TestState>
97
DoLexWithYield(TestState aState, const char* aData, size_t aLength)
98
0
{
99
0
  switch (aState) {
100
0
    case TestState::ONE:
101
0
      CheckLexedData(aData, aLength, 0, 3);
102
0
      return Transition::ToAfterYield(TestState::TWO);
103
0
    case TestState::TWO:
104
0
      CheckLexedData(aData, aLength, 0, 3);
105
0
      return Transition::To(TestState::THREE, 6);
106
0
    case TestState::THREE:
107
0
      CheckLexedData(aData, aLength, 3, 6);
108
0
      return Transition::TerminateSuccess();
109
0
    default:
110
0
      MOZ_CRASH("Unexpected or unhandled TestState");
111
0
  }
112
0
}
113
114
LexerTransition<TestState>
115
DoLexWithTerminateAfterYield(TestState aState, const char* aData, size_t aLength)
116
0
{
117
0
  switch (aState) {
118
0
    case TestState::ONE:
119
0
      CheckLexedData(aData, aLength, 0, 3);
120
0
      return Transition::ToAfterYield(TestState::TWO);
121
0
    case TestState::TWO:
122
0
      return Transition::TerminateSuccess();
123
0
    default:
124
0
      MOZ_CRASH("Unexpected or unhandled TestState");
125
0
  }
126
0
}
127
128
LexerTransition<TestState>
129
DoLexWithZeroLengthStates(TestState aState, const char* aData, size_t aLength)
130
0
{
131
0
  switch (aState) {
132
0
    case TestState::ONE:
133
0
      EXPECT_TRUE(aLength == 0);
134
0
      return Transition::To(TestState::TWO, 0);
135
0
    case TestState::TWO:
136
0
      EXPECT_TRUE(aLength == 0);
137
0
      return Transition::To(TestState::THREE, 9);
138
0
    case TestState::THREE:
139
0
      CheckLexedData(aData, aLength, 0, 9);
140
0
      return Transition::TerminateSuccess();
141
0
    default:
142
0
      MOZ_CRASH("Unexpected or unhandled TestState");
143
0
  }
144
0
}
145
146
LexerTransition<TestState>
147
DoLexWithZeroLengthStatesAtEnd(TestState aState, const char* aData, size_t aLength)
148
0
{
149
0
  switch (aState) {
150
0
    case TestState::ONE:
151
0
      CheckLexedData(aData, aLength, 0, 9);
152
0
      return Transition::To(TestState::TWO, 0);
153
0
    case TestState::TWO:
154
0
      EXPECT_TRUE(aLength == 0);
155
0
      return Transition::To(TestState::THREE, 0);
156
0
    case TestState::THREE:
157
0
      EXPECT_TRUE(aLength == 0);
158
0
      return Transition::TerminateSuccess();
159
0
    default:
160
0
      MOZ_CRASH("Unexpected or unhandled TestState");
161
0
  }
162
0
}
163
164
LexerTransition<TestState>
165
DoLexWithZeroLengthYield(TestState aState, const char* aData, size_t aLength)
166
0
{
167
0
  switch (aState) {
168
0
    case TestState::ONE:
169
0
      EXPECT_EQ(0u, aLength);
170
0
      return Transition::ToAfterYield(TestState::TWO);
171
0
    case TestState::TWO:
172
0
      EXPECT_EQ(0u, aLength);
173
0
      return Transition::To(TestState::THREE, 9);
174
0
    case TestState::THREE:
175
0
      CheckLexedData(aData, aLength, 0, 9);
176
0
      return Transition::TerminateSuccess();
177
0
    default:
178
0
      MOZ_CRASH("Unexpected or unhandled TestState");
179
0
  }
180
0
}
181
182
LexerTransition<TestState>
183
DoLexWithZeroLengthStatesUnbuffered(TestState aState,
184
                                    const char* aData,
185
                                    size_t aLength)
186
0
{
187
0
  switch (aState) {
188
0
    case TestState::ONE:
189
0
      EXPECT_TRUE(aLength == 0);
190
0
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 0);
191
0
    case TestState::TWO:
192
0
      EXPECT_TRUE(aLength == 0);
193
0
      return Transition::To(TestState::THREE, 9);
194
0
    case TestState::THREE:
195
0
      CheckLexedData(aData, aLength, 0, 9);
196
0
      return Transition::TerminateSuccess();
197
0
    case TestState::UNBUFFERED:
198
0
      ADD_FAILURE() << "Should not enter zero-length unbuffered state";
199
0
      return Transition::TerminateFailure();
200
0
    default:
201
0
      MOZ_CRASH("Unexpected or unhandled TestState");
202
0
  }
203
0
}
204
205
LexerTransition<TestState>
206
DoLexWithZeroLengthStatesAfterUnbuffered(TestState aState,
207
                                         const char* aData,
208
                                         size_t aLength)
209
0
{
210
0
  switch (aState) {
211
0
    case TestState::ONE:
212
0
      EXPECT_TRUE(aLength == 0);
213
0
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 9);
214
0
    case TestState::TWO:
215
0
      EXPECT_TRUE(aLength == 0);
216
0
      return Transition::To(TestState::THREE, 0);
217
0
    case TestState::THREE:
218
0
      EXPECT_TRUE(aLength == 0);
219
0
      return Transition::TerminateSuccess();
220
0
    case TestState::UNBUFFERED:
221
0
      CheckLexedData(aData, aLength, 0, 9);
222
0
      return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
223
0
    default:
224
0
      MOZ_CRASH("Unexpected or unhandled TestState");
225
0
  }
226
0
}
227
228
class ImageStreamingLexer : public ::testing::Test
229
{
230
public:
231
  // Note that mLexer is configured to enter TerminalState::FAILURE immediately
232
  // if the input data is truncated. We don't expect that to happen in most
233
  // tests, so we want to detect that issue. If a test needs a different
234
  // behavior, we create a special StreamingLexer just for that test.
235
  ImageStreamingLexer()
236
    : mLexer(Transition::To(TestState::ONE, 3), Transition::TerminateFailure())
237
    , mSourceBuffer(new SourceBuffer)
238
    , mIterator(mSourceBuffer->Iterator())
239
    , mExpectNoResume(new ExpectNoResume)
240
    , mCountResumes(new CountResumes)
241
0
  { }
242
243
protected:
244
  void CheckTruncatedState(StreamingLexer<TestState>& aLexer,
245
                           TerminalState aExpectedTerminalState,
246
                           nsresult aCompletionStatus = NS_OK)
247
0
  {
248
0
    for (unsigned i = 0; i < 9; ++i) {
249
0
      if (i < 2) {
250
0
        mSourceBuffer->Append(mData + i, 1);
251
0
      } else if (i == 2) {
252
0
        mSourceBuffer->Complete(aCompletionStatus);
253
0
      }
254
0
255
0
      LexerResult result = aLexer.Lex(mIterator, mCountResumes, DoLex);
256
0
257
0
      if (i >= 2) {
258
0
        EXPECT_TRUE(result.is<TerminalState>());
259
0
        EXPECT_EQ(aExpectedTerminalState, result.as<TerminalState>());
260
0
      } else {
261
0
        EXPECT_TRUE(result.is<Yield>());
262
0
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
263
0
      }
264
0
    }
265
0
266
0
    EXPECT_EQ(2u, mCountResumes->Count());
267
0
  }
268
269
  AutoInitializeImageLib mInit;
270
  const char mData[9] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
271
  StreamingLexer<TestState> mLexer;
272
  RefPtr<SourceBuffer> mSourceBuffer;
273
  SourceBufferIterator mIterator;
274
  RefPtr<ExpectNoResume> mExpectNoResume;
275
  RefPtr<CountResumes> mCountResumes;
276
};
277
278
TEST_F(ImageStreamingLexer, ZeroLengthData)
279
0
{
280
0
  // Test a zero-length input.
281
0
  mSourceBuffer->Complete(NS_OK);
282
0
283
0
  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
284
0
285
0
  EXPECT_TRUE(result.is<TerminalState>());
286
0
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
287
0
}
288
289
TEST_F(ImageStreamingLexer, ZeroLengthDataUnbuffered)
290
0
{
291
0
  // Test a zero-length input.
292
0
  mSourceBuffer->Complete(NS_OK);
293
0
294
0
  // Create a special StreamingLexer for this test because we want the first
295
0
  // state to be unbuffered.
296
0
  StreamingLexer<TestState> lexer(Transition::ToUnbuffered(TestState::ONE,
297
0
                                                           TestState::UNBUFFERED,
298
0
                                                           sizeof(mData)),
299
0
                                  Transition::TerminateFailure());
300
0
301
0
  LexerResult result = lexer.Lex(mIterator, mExpectNoResume, DoLex);
302
0
  EXPECT_TRUE(result.is<TerminalState>());
303
0
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
304
0
}
305
306
TEST_F(ImageStreamingLexer, StartWithTerminal)
307
0
{
308
0
  // Create a special StreamingLexer for this test because we want the first
309
0
  // state to be a terminal state. This doesn't really make sense, but we should
310
0
  // handle it.
311
0
  StreamingLexer<TestState> lexer(Transition::TerminateSuccess(),
312
0
                                  Transition::TerminateFailure());
313
0
  LexerResult result = lexer.Lex(mIterator, mExpectNoResume, DoLex);
314
0
  EXPECT_TRUE(result.is<TerminalState>());
315
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
316
0
317
0
  mSourceBuffer->Complete(NS_OK);
318
0
}
319
320
TEST_F(ImageStreamingLexer, SingleChunk)
321
0
{
322
0
  // Test delivering all the data at once.
323
0
  mSourceBuffer->Append(mData, sizeof(mData));
324
0
  mSourceBuffer->Complete(NS_OK);
325
0
326
0
  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
327
0
328
0
  EXPECT_TRUE(result.is<TerminalState>());
329
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
330
0
}
331
332
TEST_F(ImageStreamingLexer, SingleChunkWithUnbuffered)
333
0
{
334
0
  Vector<char> unbufferedVector;
335
0
336
0
  // Test delivering all the data at once.
337
0
  mSourceBuffer->Append(mData, sizeof(mData));
338
0
  mSourceBuffer->Complete(NS_OK);
339
0
340
0
  LexerResult result =
341
0
    mLexer.Lex(mIterator, mExpectNoResume,
342
0
               [&](TestState aState, const char* aData, size_t aLength) {
343
0
      return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
344
0
  });
345
0
346
0
  EXPECT_TRUE(result.is<TerminalState>());
347
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
348
0
}
349
350
TEST_F(ImageStreamingLexer, SingleChunkWithYield)
351
0
{
352
0
  // Test delivering all the data at once.
353
0
  mSourceBuffer->Append(mData, sizeof(mData));
354
0
  mSourceBuffer->Complete(NS_OK);
355
0
356
0
  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLexWithYield);
357
0
  ASSERT_TRUE(result.is<Yield>());
358
0
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
359
0
360
0
  result = mLexer.Lex(mIterator, mExpectNoResume, DoLexWithYield);
361
0
  ASSERT_TRUE(result.is<TerminalState>());
362
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
363
0
}
364
365
TEST_F(ImageStreamingLexer, ChunkPerState)
366
0
{
367
0
  // Test delivering in perfectly-sized chunks, one per state.
368
0
  for (unsigned i = 0; i < 3; ++i) {
369
0
    mSourceBuffer->Append(mData + 3 * i, 3);
370
0
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
371
0
372
0
    if (i == 2) {
373
0
      EXPECT_TRUE(result.is<TerminalState>());
374
0
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
375
0
    } else {
376
0
      EXPECT_TRUE(result.is<Yield>());
377
0
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
378
0
    }
379
0
  }
380
0
381
0
  EXPECT_EQ(2u, mCountResumes->Count());
382
0
  mSourceBuffer->Complete(NS_OK);
383
0
}
384
385
TEST_F(ImageStreamingLexer, ChunkPerStateWithUnbuffered)
386
0
{
387
0
  Vector<char> unbufferedVector;
388
0
389
0
  // Test delivering in perfectly-sized chunks, one per state.
390
0
  for (unsigned i = 0; i < 3; ++i) {
391
0
    mSourceBuffer->Append(mData + 3 * i, 3);
392
0
    LexerResult result =
393
0
      mLexer.Lex(mIterator, mCountResumes,
394
0
                 [&](TestState aState, const char* aData, size_t aLength) {
395
0
        return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
396
0
    });
397
0
398
0
    if (i == 2) {
399
0
      EXPECT_TRUE(result.is<TerminalState>());
400
0
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
401
0
    } else {
402
0
      EXPECT_TRUE(result.is<Yield>());
403
0
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
404
0
    }
405
0
  }
406
0
407
0
  EXPECT_EQ(2u, mCountResumes->Count());
408
0
  mSourceBuffer->Complete(NS_OK);
409
0
}
410
411
TEST_F(ImageStreamingLexer, ChunkPerStateWithYield)
412
0
{
413
0
  // Test delivering in perfectly-sized chunks, one per state.
414
0
  mSourceBuffer->Append(mData, 3);
415
0
  LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
416
0
  EXPECT_TRUE(result.is<Yield>());
417
0
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
418
0
419
0
  result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
420
0
  EXPECT_TRUE(result.is<Yield>());
421
0
  EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
422
0
423
0
  mSourceBuffer->Append(mData + 3, 6);
424
0
  result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
425
0
  EXPECT_TRUE(result.is<TerminalState>());
426
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
427
0
428
0
  EXPECT_EQ(1u, mCountResumes->Count());
429
0
  mSourceBuffer->Complete(NS_OK);
430
0
}
431
432
TEST_F(ImageStreamingLexer, ChunkPerStateWithUnbufferedYield)
433
0
{
434
0
  size_t unbufferedCallCount = 0;
435
0
  Vector<char> unbufferedVector;
436
0
  auto lexerFunc = [&](TestState aState, const char* aData, size_t aLength)
437
0
                     -> LexerTransition<TestState> {
438
0
    switch (aState) {
439
0
      case TestState::ONE:
440
0
        CheckLexedData(aData, aLength, 0, 3);
441
0
        return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
442
0
      case TestState::TWO:
443
0
        CheckLexedData(unbufferedVector.begin(), unbufferedVector.length(), 3, 3);
444
0
        return Transition::To(TestState::THREE, 3);
445
0
      case TestState::THREE:
446
0
        CheckLexedData(aData, aLength, 6, 3);
447
0
        return Transition::TerminateSuccess();
448
0
      case TestState::UNBUFFERED:
449
0
        switch (unbufferedCallCount) {
450
0
          case 0:
451
0
            CheckLexedData(aData, aLength, 3, 3);
452
0
            EXPECT_TRUE(unbufferedVector.append(aData, 2));
453
0
            unbufferedCallCount++;
454
0
455
0
            // Continue after yield, telling StreamingLexer we consumed 2 bytes.
456
0
            return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 2);
457
0
458
0
          case 1:
459
0
            CheckLexedData(aData, aLength, 5, 1);
460
0
            EXPECT_TRUE(unbufferedVector.append(aData, 1));
461
0
            unbufferedCallCount++;
462
0
463
0
            // Continue after yield, telling StreamingLexer we consumed 1 byte.
464
0
            // We should end up in the TWO state.
465
0
            return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
466
0
        }
467
0
        ADD_FAILURE() << "Too many invocations of TestState::UNBUFFERED";
468
0
        return Transition::TerminateFailure();
469
0
      default:
470
0
        MOZ_CRASH("Unexpected or unhandled TestState");
471
0
    }
472
0
  };
473
0
474
0
  // Test delivering in perfectly-sized chunks, one per state.
475
0
  for (unsigned i = 0; i < 3; ++i) {
476
0
    mSourceBuffer->Append(mData + 3 * i, 3);
477
0
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
478
0
479
0
    switch (i) {
480
0
      case 0:
481
0
        EXPECT_TRUE(result.is<Yield>());
482
0
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
483
0
        EXPECT_EQ(0u, unbufferedCallCount);
484
0
        break;
485
0
486
0
      case 1:
487
0
        EXPECT_TRUE(result.is<Yield>());
488
0
        EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
489
0
        EXPECT_EQ(1u, unbufferedCallCount);
490
0
491
0
        result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
492
0
        EXPECT_TRUE(result.is<Yield>());
493
0
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
494
0
        EXPECT_EQ(2u, unbufferedCallCount);
495
0
        break;
496
0
497
0
      case 2:
498
0
        EXPECT_TRUE(result.is<TerminalState>());
499
0
        EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
500
0
        break;
501
0
    }
502
0
  }
503
0
504
0
  EXPECT_EQ(2u, mCountResumes->Count());
505
0
  mSourceBuffer->Complete(NS_OK);
506
0
507
0
  LexerResult result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
508
0
  EXPECT_TRUE(result.is<TerminalState>());
509
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
510
0
}
511
512
TEST_F(ImageStreamingLexer, OneByteChunks)
513
0
{
514
0
  // Test delivering in one byte chunks.
515
0
  for (unsigned i = 0; i < 9; ++i) {
516
0
    mSourceBuffer->Append(mData + i, 1);
517
0
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
518
0
519
0
    if (i == 8) {
520
0
      EXPECT_TRUE(result.is<TerminalState>());
521
0
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
522
0
    } else {
523
0
      EXPECT_TRUE(result.is<Yield>());
524
0
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
525
0
    }
526
0
  }
527
0
528
0
  EXPECT_EQ(8u, mCountResumes->Count());
529
0
  mSourceBuffer->Complete(NS_OK);
530
0
}
531
532
TEST_F(ImageStreamingLexer, OneByteChunksWithUnbuffered)
533
0
{
534
0
  Vector<char> unbufferedVector;
535
0
536
0
  // Test delivering in one byte chunks.
537
0
  for (unsigned i = 0; i < 9; ++i) {
538
0
    mSourceBuffer->Append(mData + i, 1);
539
0
    LexerResult result =
540
0
      mLexer.Lex(mIterator, mCountResumes,
541
0
                 [&](TestState aState, const char* aData, size_t aLength) {
542
0
        return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
543
0
    });
544
0
545
0
    if (i == 8) {
546
0
      EXPECT_TRUE(result.is<TerminalState>());
547
0
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
548
0
    } else {
549
0
      EXPECT_TRUE(result.is<Yield>());
550
0
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
551
0
    }
552
0
  }
553
0
554
0
  EXPECT_EQ(8u, mCountResumes->Count());
555
0
  mSourceBuffer->Complete(NS_OK);
556
0
}
557
558
TEST_F(ImageStreamingLexer, OneByteChunksWithYield)
559
0
{
560
0
  // Test delivering in one byte chunks.
561
0
  for (unsigned i = 0; i < 9; ++i) {
562
0
    mSourceBuffer->Append(mData + i, 1);
563
0
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
564
0
565
0
    switch (i) {
566
0
      case 2:
567
0
        EXPECT_TRUE(result.is<Yield>());
568
0
        EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
569
0
570
0
        result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
571
0
        EXPECT_TRUE(result.is<Yield>());
572
0
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
573
0
        break;
574
0
575
0
      case 8:
576
0
        EXPECT_TRUE(result.is<TerminalState>());
577
0
        EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
578
0
        break;
579
0
580
0
      default:
581
0
        EXPECT_TRUE(i < 9);
582
0
        EXPECT_TRUE(result.is<Yield>());
583
0
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
584
0
    }
585
0
  }
586
0
587
0
  EXPECT_EQ(8u, mCountResumes->Count());
588
0
  mSourceBuffer->Complete(NS_OK);
589
0
}
590
591
TEST_F(ImageStreamingLexer, ZeroLengthState)
592
0
{
593
0
  mSourceBuffer->Append(mData, sizeof(mData));
594
0
  mSourceBuffer->Complete(NS_OK);
595
0
596
0
  // Create a special StreamingLexer for this test because we want the first
597
0
  // state to be zero length.
598
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
599
0
                                  Transition::TerminateFailure());
600
0
601
0
  LexerResult result =
602
0
    lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStates);
603
0
604
0
  EXPECT_TRUE(result.is<TerminalState>());
605
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
606
0
}
607
608
TEST_F(ImageStreamingLexer, ZeroLengthStatesAtEnd)
609
0
{
610
0
  mSourceBuffer->Append(mData, sizeof(mData));
611
0
  mSourceBuffer->Complete(NS_OK);
612
0
613
0
  // Create a special StreamingLexer for this test because we want the first
614
0
  // state to consume the full input.
615
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 9),
616
0
                                  Transition::TerminateFailure());
617
0
618
0
  LexerResult result =
619
0
    lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesAtEnd);
620
0
621
0
  EXPECT_TRUE(result.is<TerminalState>());
622
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
623
0
}
624
625
TEST_F(ImageStreamingLexer, ZeroLengthStateWithYield)
626
0
{
627
0
  // Create a special StreamingLexer for this test because we want the first
628
0
  // state to be zero length.
629
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
630
0
                                  Transition::TerminateFailure());
631
0
632
0
  mSourceBuffer->Append(mData, 3);
633
0
  LexerResult result =
634
0
    lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthYield);
635
0
  ASSERT_TRUE(result.is<Yield>());
636
0
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
637
0
638
0
  result = lexer.Lex(mIterator, mCountResumes, DoLexWithZeroLengthYield);
639
0
  ASSERT_TRUE(result.is<Yield>());
640
0
  EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
641
0
642
0
  mSourceBuffer->Append(mData + 3, sizeof(mData) - 3);
643
0
  mSourceBuffer->Complete(NS_OK);
644
0
  result = lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthYield);
645
0
  ASSERT_TRUE(result.is<TerminalState>());
646
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
647
0
  EXPECT_EQ(1u, mCountResumes->Count());
648
0
}
649
650
TEST_F(ImageStreamingLexer, ZeroLengthStateWithUnbuffered)
651
0
{
652
0
  mSourceBuffer->Append(mData, sizeof(mData));
653
0
  mSourceBuffer->Complete(NS_OK);
654
0
655
0
  // Create a special StreamingLexer for this test because we want the first
656
0
  // state to be both zero length and unbuffered.
657
0
  StreamingLexer<TestState> lexer(Transition::ToUnbuffered(TestState::ONE,
658
0
                                                           TestState::UNBUFFERED,
659
0
                                                           0),
660
0
                                  Transition::TerminateFailure());
661
0
662
0
  LexerResult result =
663
0
    lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesUnbuffered);
664
0
665
0
  EXPECT_TRUE(result.is<TerminalState>());
666
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
667
0
}
668
669
TEST_F(ImageStreamingLexer, ZeroLengthStateAfterUnbuffered)
670
0
{
671
0
  mSourceBuffer->Append(mData, sizeof(mData));
672
0
  mSourceBuffer->Complete(NS_OK);
673
0
674
0
  // Create a special StreamingLexer for this test because we want the first
675
0
  // state to be zero length.
676
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
677
0
                                  Transition::TerminateFailure());
678
0
679
0
  LexerResult result =
680
0
    lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesAfterUnbuffered);
681
0
682
0
  EXPECT_TRUE(result.is<TerminalState>());
683
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
684
0
}
685
686
TEST_F(ImageStreamingLexer, ZeroLengthStateWithUnbufferedYield)
687
0
{
688
0
  size_t unbufferedCallCount = 0;
689
0
  auto lexerFunc = [&](TestState aState, const char* aData, size_t aLength)
690
0
                     -> LexerTransition<TestState> {
691
0
    switch (aState) {
692
0
      case TestState::ONE:
693
0
        EXPECT_EQ(0u, aLength);
694
0
        return Transition::TerminateSuccess();
695
0
696
0
      case TestState::UNBUFFERED:
697
0
        switch (unbufferedCallCount) {
698
0
          case 0:
699
0
            CheckLexedData(aData, aLength, 0, 3);
700
0
            unbufferedCallCount++;
701
0
702
0
            // Continue after yield, telling StreamingLexer we consumed 0 bytes.
703
0
            return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 0);
704
0
705
0
          case 1:
706
0
            CheckLexedData(aData, aLength, 0, 3);
707
0
            unbufferedCallCount++;
708
0
709
0
            // Continue after yield, telling StreamingLexer we consumed 2 bytes.
710
0
            return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 2);
711
0
712
0
          case 2:
713
0
            EXPECT_EQ(1u, aLength);
714
0
            CheckLexedData(aData, aLength, 2, 1);
715
0
            unbufferedCallCount++;
716
0
717
0
            // Continue after yield, telling StreamingLexer we consumed 1 bytes.
718
0
            return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 1);
719
0
720
0
          case 3:
721
0
            CheckLexedData(aData, aLength, 3, 6);
722
0
            unbufferedCallCount++;
723
0
724
0
            // Continue after yield, telling StreamingLexer we consumed 6 bytes.
725
0
            // We should transition to TestState::ONE when we return from the
726
0
            // yield.
727
0
            return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 6);
728
0
        }
729
0
730
0
        ADD_FAILURE() << "Too many invocations of TestState::UNBUFFERED";
731
0
        return Transition::TerminateFailure();
732
0
733
0
      default:
734
0
        MOZ_CRASH("Unexpected or unhandled TestState");
735
0
    }
736
0
  };
737
0
738
0
  // Create a special StreamingLexer for this test because we want the first
739
0
  // state to be unbuffered.
740
0
  StreamingLexer<TestState> lexer(Transition::ToUnbuffered(TestState::ONE,
741
0
                                                           TestState::UNBUFFERED,
742
0
                                                           sizeof(mData)),
743
0
                                  Transition::TerminateFailure());
744
0
745
0
  mSourceBuffer->Append(mData, 3);
746
0
  LexerResult result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
747
0
  ASSERT_TRUE(result.is<Yield>());
748
0
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
749
0
  EXPECT_EQ(1u, unbufferedCallCount);
750
0
751
0
  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
752
0
  ASSERT_TRUE(result.is<Yield>());
753
0
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
754
0
  EXPECT_EQ(2u, unbufferedCallCount);
755
0
756
0
  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
757
0
  ASSERT_TRUE(result.is<Yield>());
758
0
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
759
0
  EXPECT_EQ(3u, unbufferedCallCount);
760
0
761
0
  result = lexer.Lex(mIterator, mCountResumes, lexerFunc);
762
0
  ASSERT_TRUE(result.is<Yield>());
763
0
  EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
764
0
  EXPECT_EQ(3u, unbufferedCallCount);
765
0
766
0
  mSourceBuffer->Append(mData + 3, 6);
767
0
  mSourceBuffer->Complete(NS_OK);
768
0
  EXPECT_EQ(1u, mCountResumes->Count());
769
0
  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
770
0
  ASSERT_TRUE(result.is<Yield>());
771
0
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
772
0
  EXPECT_EQ(4u, unbufferedCallCount);
773
0
774
0
  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
775
0
  ASSERT_TRUE(result.is<TerminalState>());
776
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
777
0
}
778
779
TEST_F(ImageStreamingLexer, TerminateSuccess)
780
0
{
781
0
  mSourceBuffer->Append(mData, sizeof(mData));
782
0
  mSourceBuffer->Complete(NS_OK);
783
0
784
0
  // Test that Terminate is "sticky".
785
0
  SourceBufferIterator iterator = mSourceBuffer->Iterator();
786
0
  LexerResult result =
787
0
    mLexer.Lex(iterator, mExpectNoResume,
788
0
               [&](TestState aState, const char* aData, size_t aLength) {
789
0
      EXPECT_TRUE(aState == TestState::ONE);
790
0
      return Transition::TerminateSuccess();
791
0
  });
792
0
  EXPECT_TRUE(result.is<TerminalState>());
793
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
794
0
795
0
  SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
796
0
  result =
797
0
    mLexer.Lex(iterator2, mExpectNoResume,
798
0
               [&](TestState aState, const char* aData, size_t aLength) {
799
0
      EXPECT_TRUE(false);  // Shouldn't get here.
800
0
      return Transition::TerminateFailure();
801
0
  });
802
0
  EXPECT_TRUE(result.is<TerminalState>());
803
0
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
804
0
}
805
806
TEST_F(ImageStreamingLexer, TerminateFailure)
807
0
{
808
0
  mSourceBuffer->Append(mData, sizeof(mData));
809
0
  mSourceBuffer->Complete(NS_OK);
810
0
811
0
  // Test that Terminate is "sticky".
812
0
  SourceBufferIterator iterator = mSourceBuffer->Iterator();
813
0
  LexerResult result =
814
0
    mLexer.Lex(iterator, mExpectNoResume,
815
0
               [&](TestState aState, const char* aData, size_t aLength) {
816
0
      EXPECT_TRUE(aState == TestState::ONE);
817
0
      return Transition::TerminateFailure();
818
0
  });
819
0
  EXPECT_TRUE(result.is<TerminalState>());
820
0
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
821
0
822
0
  SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
823
0
  result =
824
0
    mLexer.Lex(iterator2, mExpectNoResume,
825
0
               [&](TestState aState, const char* aData, size_t aLength) {
826
0
      EXPECT_TRUE(false);  // Shouldn't get here.
827
0
      return Transition::TerminateFailure();
828
0
  });
829
0
  EXPECT_TRUE(result.is<TerminalState>());
830
0
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
831
0
}
832
833
TEST_F(ImageStreamingLexer, TerminateUnbuffered)
834
0
{
835
0
  // Test that Terminate works during an unbuffered read.
836
0
  for (unsigned i = 0; i < 9; ++i) {
837
0
    mSourceBuffer->Append(mData + i, 1);
838
0
    LexerResult result =
839
0
      mLexer.Lex(mIterator, mCountResumes, DoLexWithUnbufferedTerminate);
840
0
841
0
    if (i > 2) {
842
0
      EXPECT_TRUE(result.is<TerminalState>());
843
0
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
844
0
    } else {
845
0
      EXPECT_TRUE(result.is<Yield>());
846
0
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
847
0
    }
848
0
  }
849
0
850
0
  // We expect 3 resumes because TestState::ONE consumes 3 bytes and then
851
0
  // transitions to TestState::UNBUFFERED, which calls TerminateSuccess() as
852
0
  // soon as it receives a single byte. That's four bytes total,  which are
853
0
  // delivered one at a time, requiring 3 resumes.
854
0
  EXPECT_EQ(3u, mCountResumes->Count());
855
0
856
0
  mSourceBuffer->Complete(NS_OK);
857
0
}
858
859
TEST_F(ImageStreamingLexer, TerminateAfterYield)
860
0
{
861
0
  // Test that Terminate works after yielding.
862
0
  for (unsigned i = 0; i < 9; ++i) {
863
0
    mSourceBuffer->Append(mData + i, 1);
864
0
    LexerResult result =
865
0
      mLexer.Lex(mIterator, mCountResumes, DoLexWithTerminateAfterYield);
866
0
867
0
    if (i > 2) {
868
0
      EXPECT_TRUE(result.is<TerminalState>());
869
0
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
870
0
    } else if (i == 2) {
871
0
      EXPECT_TRUE(result.is<Yield>());
872
0
      EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
873
0
    } else {
874
0
      EXPECT_TRUE(result.is<Yield>());
875
0
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
876
0
    }
877
0
  }
878
0
879
0
  // We expect 2 resumes because TestState::ONE consumes 3 bytes and then
880
0
  // yields. When the lexer resumes at TestState::TWO, which receives the same 3
881
0
  // bytes, TerminateSuccess() gets called immediately.  That's three bytes
882
0
  // total, which are delivered one at a time, requiring 2 resumes.
883
0
  EXPECT_EQ(2u, mCountResumes->Count());
884
0
885
0
  mSourceBuffer->Complete(NS_OK);
886
0
}
887
888
TEST_F(ImageStreamingLexer, SourceBufferImmediateComplete)
889
0
{
890
0
  // Test calling SourceBuffer::Complete() without appending any data. This
891
0
  // causes the SourceBuffer to automatically have a failing completion status,
892
0
  // no matter what you pass, so we expect TerminalState::FAILURE below.
893
0
  mSourceBuffer->Complete(NS_OK);
894
0
895
0
  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
896
0
897
0
  EXPECT_TRUE(result.is<TerminalState>());
898
0
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
899
0
}
900
901
TEST_F(ImageStreamingLexer, SourceBufferTruncatedTerminalStateSuccess)
902
0
{
903
0
  // Test that using a terminal state (in this case TerminalState::SUCCESS) as a
904
0
  // truncated state works.
905
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
906
0
                                  Transition::TerminateSuccess());
907
0
908
0
  CheckTruncatedState(lexer, TerminalState::SUCCESS);
909
0
}
910
911
TEST_F(ImageStreamingLexer, SourceBufferTruncatedTerminalStateFailure)
912
0
{
913
0
  // Test that using a terminal state (in this case TerminalState::FAILURE) as a
914
0
  // truncated state works.
915
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
916
0
                                  Transition::TerminateFailure());
917
0
918
0
  CheckTruncatedState(lexer, TerminalState::FAILURE);
919
0
}
920
921
TEST_F(ImageStreamingLexer, SourceBufferTruncatedStateReturningSuccess)
922
0
{
923
0
  // Test that a truncated state that returns TerminalState::SUCCESS works. When
924
0
  // |lexer| discovers that the data is truncated, it invokes the
925
0
  // TRUNCATED_SUCCESS state, which returns TerminalState::SUCCESS.
926
0
  // CheckTruncatedState() verifies that this happens.
927
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
928
0
                                  Transition::To(TestState::TRUNCATED_SUCCESS, 0));
929
0
930
0
  CheckTruncatedState(lexer, TerminalState::SUCCESS);
931
0
}
932
933
TEST_F(ImageStreamingLexer, SourceBufferTruncatedStateReturningFailure)
934
0
{
935
0
  // Test that a truncated state that returns TerminalState::FAILURE works. When
936
0
  // |lexer| discovers that the data is truncated, it invokes the
937
0
  // TRUNCATED_FAILURE state, which returns TerminalState::FAILURE.
938
0
  // CheckTruncatedState() verifies that this happens.
939
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
940
0
                                  Transition::To(TestState::TRUNCATED_FAILURE, 0));
941
0
942
0
  CheckTruncatedState(lexer, TerminalState::FAILURE);
943
0
}
944
945
TEST_F(ImageStreamingLexer, SourceBufferTruncatedFailingCompleteStatus)
946
0
{
947
0
  // Test that calling SourceBuffer::Complete() with a failing status results in
948
0
  // an immediate TerminalState::FAILURE result. (Note that |lexer|'s truncated
949
0
  // state is TerminalState::SUCCESS, so if we ignore the failing status, the
950
0
  // test will fail.)
951
0
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
952
0
                                  Transition::TerminateSuccess());
953
0
954
0
  CheckTruncatedState(lexer, TerminalState::FAILURE, NS_ERROR_FAILURE);
955
0
}
956
957
TEST_F(ImageStreamingLexer, NoSourceBufferResumable)
958
0
{
959
0
  // Test delivering in one byte chunks with no IResumable.
960
0
  for (unsigned i = 0; i < 9; ++i) {
961
0
    mSourceBuffer->Append(mData + i, 1);
962
0
    LexerResult result = mLexer.Lex(mIterator, nullptr, DoLex);
963
0
964
0
    if (i == 8) {
965
0
      EXPECT_TRUE(result.is<TerminalState>());
966
0
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
967
0
    } else {
968
0
      EXPECT_TRUE(result.is<Yield>());
969
0
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
970
0
    }
971
0
  }
972
0
973
0
  mSourceBuffer->Complete(NS_OK);
974
0
}