Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/image/test/gtest/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 33 kB image not shown  

Quelle  TestStreamingLexer.cpp   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "gtest/gtest.h"

#include "Common.h"
#include "mozilla/Vector.h"
#include "StreamingLexer.h"

using namespace mozilla;
using namespace mozilla::image;

enum class TestState {
  ONE,
  TWO,
  THREE,
  UNBUFFERED,
  TRUNCATED_SUCCESS,
  TRUNCATED_FAILURE
};

void CheckLexedData(const char* aData, size_t aLength, size_t aOffset,
                    size_t aExpectedLength) {
  EXPECT_TRUE(aLength == aExpectedLength);

  for (size_t i = 0; i < aLength; ++i) {
    EXPECT_EQ(aData[i], char(aOffset + i + 1));
  }
}

LexerTransition<TestState> DoLex(TestState aState, const char* aData,
                                 size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      CheckLexedData(aData, aLength, 0, 3);
      return Transition::To(TestState::TWO, 3);
    case TestState::TWO:
      CheckLexedData(aData, aLength, 3, 3);
      return Transition::To(TestState::THREE, 3);
    case TestState::THREE:
      CheckLexedData(aData, aLength, 6, 3);
      return Transition::TerminateSuccess();
    case TestState::TRUNCATED_SUCCESS:
      return Transition::TerminateSuccess();
    case TestState::TRUNCATED_FAILURE:
      return Transition::TerminateFailure();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithUnbuffered(
    TestState aState, const char* aData, size_t aLength,
    Vector<char>& aUnbufferedVector) {
  switch (aState) {
    case TestState::ONE:
      CheckLexedData(aData, aLength, 0, 3);
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
    case TestState::TWO:
      CheckLexedData(aUnbufferedVector.begin(), aUnbufferedVector.length(), 3,
                     3);
      return Transition::To(TestState::THREE, 3);
    case TestState::THREE:
      CheckLexedData(aData, aLength, 6, 3);
      return Transition::TerminateSuccess();
    case TestState::UNBUFFERED:
      EXPECT_TRUE(aLength <= 3);
      EXPECT_TRUE(aUnbufferedVector.append(aData, aLength));
      return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithUnbufferedTerminate(TestState aState,
                                                        const char* aData,
                                                        size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      CheckLexedData(aData, aLength, 0, 3);
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
    case TestState::UNBUFFERED:
      return Transition::TerminateSuccess();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithYield(TestState aState, const char* aData,
                                          size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      CheckLexedData(aData, aLength, 0, 3);
      return Transition::ToAfterYield(TestState::TWO);
    case TestState::TWO:
      CheckLexedData(aData, aLength, 0, 3);
      return Transition::To(TestState::THREE, 6);
    case TestState::THREE:
      CheckLexedData(aData, aLength, 3, 6);
      return Transition::TerminateSuccess();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithTerminateAfterYield(TestState aState,
                                                        const char* aData,
                                                        size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      CheckLexedData(aData, aLength, 0, 3);
      return Transition::ToAfterYield(TestState::TWO);
    case TestState::TWO:
      return Transition::TerminateSuccess();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithZeroLengthStates(TestState aState,
                                                     const char* aData,
                                                     size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      EXPECT_TRUE(aLength == 0);
      return Transition::To(TestState::TWO, 0);
    case TestState::TWO:
      EXPECT_TRUE(aLength == 0);
      return Transition::To(TestState::THREE, 9);
    case TestState::THREE:
      CheckLexedData(aData, aLength, 0, 9);
      return Transition::TerminateSuccess();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithZeroLengthStatesAtEnd(TestState aState,
                                                          const char* aData,
                                                          size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      CheckLexedData(aData, aLength, 0, 9);
      return Transition::To(TestState::TWO, 0);
    case TestState::TWO:
      EXPECT_TRUE(aLength == 0);
      return Transition::To(TestState::THREE, 0);
    case TestState::THREE:
      EXPECT_TRUE(aLength == 0);
      return Transition::TerminateSuccess();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithZeroLengthYield(TestState aState,
                                                    const char* aData,
                                                    size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      EXPECT_EQ(0u, aLength);
      return Transition::ToAfterYield(TestState::TWO);
    case TestState::TWO:
      EXPECT_EQ(0u, aLength);
      return Transition::To(TestState::THREE, 9);
    case TestState::THREE:
      CheckLexedData(aData, aLength, 0, 9);
      return Transition::TerminateSuccess();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithZeroLengthStatesUnbuffered(
    TestState aState, const char* aData, size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      EXPECT_TRUE(aLength == 0);
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 0);
    case TestState::TWO:
      EXPECT_TRUE(aLength == 0);
      return Transition::To(TestState::THREE, 9);
    case TestState::THREE:
      CheckLexedData(aData, aLength, 0, 9);
      return Transition::TerminateSuccess();
    case TestState::UNBUFFERED:
      ADD_FAILURE() << "Should not enter zero-length unbuffered state";
      return Transition::TerminateFailure();
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

LexerTransition<TestState> DoLexWithZeroLengthStatesAfterUnbuffered(
    TestState aState, const char* aData, size_t aLength) {
  switch (aState) {
    case TestState::ONE:
      EXPECT_TRUE(aLength == 0);
      return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 9);
    case TestState::TWO:
      EXPECT_TRUE(aLength == 0);
      return Transition::To(TestState::THREE, 0);
    case TestState::THREE:
      EXPECT_TRUE(aLength == 0);
      return Transition::TerminateSuccess();
    case TestState::UNBUFFERED:
      CheckLexedData(aData, aLength, 0, 9);
      return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
    default:
      MOZ_CRASH("Unexpected or unhandled TestState");
  }
}

class ImageStreamingLexer : public ::testing::Test {
 public:
  // Note that mLexer is configured to enter TerminalState::FAILURE immediately
  // if the input data is truncated. We don't expect that to happen in most
  // tests, so we want to detect that issue. If a test needs a different
  // behavior, we create a special StreamingLexer just for that test.
  ImageStreamingLexer()
      : mLexer(Transition::To(TestState::ONE, 3),
               Transition::TerminateFailure()),
        mSourceBuffer(new SourceBuffer),
        mIterator(mSourceBuffer->Iterator()),
        mExpectNoResume(new ExpectNoResume),
        mCountResumes(new CountResumes) {}

 protected:
  void CheckTruncatedState(StreamingLexer<TestState>& aLexer,
                           TerminalState aExpectedTerminalState,
                           nsresult aCompletionStatus = NS_OK) {
    for (unsigned i = 0; i < 9; ++i) {
      if (i < 2) {
        mSourceBuffer->Append(mData + i, 1);
      } else if (i == 2) {
        mSourceBuffer->Complete(aCompletionStatus);
      }

      LexerResult result = aLexer.Lex(mIterator, mCountResumes, DoLex);

      if (i >= 2) {
        EXPECT_TRUE(result.is<TerminalState>());
        EXPECT_EQ(aExpectedTerminalState, result.as<TerminalState>());
      } else {
        EXPECT_TRUE(result.is<Yield>());
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
      }
    }

    EXPECT_EQ(2u, mCountResumes->Count());
  }

  AutoInitializeImageLib mInit;
  const char mData[9]{1, 2, 3, 4, 5, 6, 7, 8, 9};
  StreamingLexer<TestState> mLexer;
  RefPtr<SourceBuffer> mSourceBuffer;
  SourceBufferIterator mIterator;
  RefPtr<ExpectNoResume> mExpectNoResume;
  RefPtr<CountResumes> mCountResumes;
};

TEST_F(ImageStreamingLexer, ZeroLengthData) {
  // Test a zero-length input.
  mSourceBuffer->Complete(NS_OK);

  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, ZeroLengthDataUnbuffered) {
  // Test a zero-length input.
  mSourceBuffer->Complete(NS_OK);

  // Create a special StreamingLexer for this test because we want the first
  // state to be unbuffered.
  StreamingLexer<TestState> lexer(
      Transition::ToUnbuffered(TestState::ONE, TestState::UNBUFFERED,
                               sizeof(mData)),
      Transition::TerminateFailure());

  LexerResult result = lexer.Lex(mIterator, mExpectNoResume, DoLex);
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, StartWithTerminal) {
  // Create a special StreamingLexer for this test because we want the first
  // state to be a terminal state. This doesn't really make sense, but we should
  // handle it.
  StreamingLexer<TestState> lexer(Transition::TerminateSuccess(),
                                  Transition::TerminateFailure());
  LexerResult result = lexer.Lex(mIterator, mExpectNoResume, DoLex);
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());

  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, SingleChunk) {
  // Test delivering all the data at once.
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, SingleChunkWithUnbuffered) {
  Vector<char> unbufferedVector;

  // Test delivering all the data at once.
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  LexerResult result = mLexer.Lex(
      mIterator, mExpectNoResume,
      [&](TestState aState, const char* aData, size_t aLength) {
        return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
      });

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, SingleChunkWithYield) {
  // Test delivering all the data at once.
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLexWithYield);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());

  result = mLexer.Lex(mIterator, mExpectNoResume, DoLexWithYield);
  ASSERT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, ChunkPerState) {
  // Test delivering in perfectly-sized chunks, one per state.
  for (unsigned i = 0; i < 3; ++i) {
    mSourceBuffer->Append(mData + 3 * i, 3);
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);

    if (i == 2) {
      EXPECT_TRUE(result.is<TerminalState>());
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
    } else {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  EXPECT_EQ(2u, mCountResumes->Count());
  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, ChunkPerStateWithUnbuffered) {
  Vector<char> unbufferedVector;

  // Test delivering in perfectly-sized chunks, one per state.
  for (unsigned i = 0; i < 3; ++i) {
    mSourceBuffer->Append(mData + 3 * i, 3);
    LexerResult result = mLexer.Lex(
        mIterator, mCountResumes,
        [&](TestState aState, const char* aData, size_t aLength) {
          return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
        });

    if (i == 2) {
      EXPECT_TRUE(result.is<TerminalState>());
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
    } else {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  EXPECT_EQ(2u, mCountResumes->Count());
  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, ChunkPerStateWithYield) {
  // Test delivering in perfectly-sized chunks, one per state.
  mSourceBuffer->Append(mData, 3);
  LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
  EXPECT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());

  result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
  EXPECT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());

  mSourceBuffer->Append(mData + 3, 6);
  result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());

  EXPECT_EQ(1u, mCountResumes->Count());
  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, ChunkPerStateWithUnbufferedYield) {
  size_t unbufferedCallCount = 0;
  Vector<char> unbufferedVector;
  auto lexerFunc = [&](TestState aState, const char* aData,
                       size_t aLength) -> LexerTransition<TestState> {
    switch (aState) {
      case TestState::ONE:
        CheckLexedData(aData, aLength, 0, 3);
        return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED,
                                        3);
      case TestState::TWO:
        CheckLexedData(unbufferedVector.begin(), unbufferedVector.length(), 3,
                       3);
        return Transition::To(TestState::THREE, 3);
      case TestState::THREE:
        CheckLexedData(aData, aLength, 6, 3);
        return Transition::TerminateSuccess();
      case TestState::UNBUFFERED:
        switch (unbufferedCallCount) {
          case 0:
            CheckLexedData(aData, aLength, 3, 3);
            EXPECT_TRUE(unbufferedVector.append(aData, 2));
            unbufferedCallCount++;

            // Continue after yield, telling StreamingLexer we consumed 2 bytes.
            return Transition::ContinueUnbufferedAfterYield(
                TestState::UNBUFFERED, 2);

          case 1:
            CheckLexedData(aData, aLength, 5, 1);
            EXPECT_TRUE(unbufferedVector.append(aData, 1));
            unbufferedCallCount++;

            // Continue after yield, telling StreamingLexer we consumed 1 byte.
            // We should end up in the TWO state.
            return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
        }
        ADD_FAILURE() << "Too many invocations of TestState::UNBUFFERED";
        return Transition::TerminateFailure();
      default:
        MOZ_CRASH("Unexpected or unhandled TestState");
    }
  };

  // Test delivering in perfectly-sized chunks, one per state.
  for (unsigned i = 0; i < 3; ++i) {
    mSourceBuffer->Append(mData + 3 * i, 3);
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);

    switch (i) {
      case 0:
        EXPECT_TRUE(result.is<Yield>());
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
        EXPECT_EQ(0u, unbufferedCallCount);
        break;

      case 1:
        EXPECT_TRUE(result.is<Yield>());
        EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
        EXPECT_EQ(1u, unbufferedCallCount);

        result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
        EXPECT_TRUE(result.is<Yield>());
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
        EXPECT_EQ(2u, unbufferedCallCount);
        break;

      case 2:
        EXPECT_TRUE(result.is<TerminalState>());
        EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
        break;
    }
  }

  EXPECT_EQ(2u, mCountResumes->Count());
  mSourceBuffer->Complete(NS_OK);

  LexerResult result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, OneByteChunks) {
  // Test delivering in one byte chunks.
  for (unsigned i = 0; i < 9; ++i) {
    mSourceBuffer->Append(mData + i, 1);
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);

    if (i == 8) {
      EXPECT_TRUE(result.is<TerminalState>());
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
    } else {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  EXPECT_EQ(8u, mCountResumes->Count());
  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, OneByteChunksWithUnbuffered) {
  Vector<char> unbufferedVector;

  // Test delivering in one byte chunks.
  for (unsigned i = 0; i < 9; ++i) {
    mSourceBuffer->Append(mData + i, 1);
    LexerResult result = mLexer.Lex(
        mIterator, mCountResumes,
        [&](TestState aState, const char* aData, size_t aLength) {
          return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
        });

    if (i == 8) {
      EXPECT_TRUE(result.is<TerminalState>());
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
    } else {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  EXPECT_EQ(8u, mCountResumes->Count());
  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, OneByteChunksWithYield) {
  // Test delivering in one byte chunks.
  for (unsigned i = 0; i < 9; ++i) {
    mSourceBuffer->Append(mData + i, 1);
    LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);

    switch (i) {
      case 2:
        EXPECT_TRUE(result.is<Yield>());
        EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());

        result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
        EXPECT_TRUE(result.is<Yield>());
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
        break;

      case 8:
        EXPECT_TRUE(result.is<TerminalState>());
        EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
        break;

      default:
        EXPECT_TRUE(i < 9);
        EXPECT_TRUE(result.is<Yield>());
        EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  EXPECT_EQ(8u, mCountResumes->Count());
  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, ZeroLengthState) {
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  // Create a special StreamingLexer for this test because we want the first
  // state to be zero length.
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
                                  Transition::TerminateFailure());

  LexerResult result =
      lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStates);

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, ZeroLengthStatesAtEnd) {
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  // Create a special StreamingLexer for this test because we want the first
  // state to consume the full input.
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 9),
                                  Transition::TerminateFailure());

  LexerResult result =
      lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesAtEnd);

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, ZeroLengthStateWithYield) {
  // Create a special StreamingLexer for this test because we want the first
  // state to be zero length.
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
                                  Transition::TerminateFailure());

  mSourceBuffer->Append(mData, 3);
  LexerResult result =
      lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthYield);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());

  result = lexer.Lex(mIterator, mCountResumes, DoLexWithZeroLengthYield);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());

  mSourceBuffer->Append(mData + 3, sizeof(mData) - 3);
  mSourceBuffer->Complete(NS_OK);
  result = lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthYield);
  ASSERT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
  EXPECT_EQ(1u, mCountResumes->Count());
}

TEST_F(ImageStreamingLexer, ZeroLengthStateWithUnbuffered) {
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  // Create a special StreamingLexer for this test because we want the first
  // state to be both zero length and unbuffered.
  StreamingLexer<TestState> lexer(
      Transition::ToUnbuffered(TestState::ONE, TestState::UNBUFFERED, 0),
      Transition::TerminateFailure());

  LexerResult result = lexer.Lex(mIterator, mExpectNoResume,
                                 DoLexWithZeroLengthStatesUnbuffered);

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, ZeroLengthStateAfterUnbuffered) {
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  // Create a special StreamingLexer for this test because we want the first
  // state to be zero length.
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
                                  Transition::TerminateFailure());

  LexerResult result = lexer.Lex(mIterator, mExpectNoResume,
                                 DoLexWithZeroLengthStatesAfterUnbuffered);

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, ZeroLengthStateWithUnbufferedYield) {
  size_t unbufferedCallCount = 0;
  auto lexerFunc = [&](TestState aState, const char* aData,
                       size_t aLength) -> LexerTransition<TestState> {
    switch (aState) {
      case TestState::ONE:
        EXPECT_EQ(0u, aLength);
        return Transition::TerminateSuccess();

      case TestState::UNBUFFERED:
        switch (unbufferedCallCount) {
          case 0:
            CheckLexedData(aData, aLength, 0, 3);
            unbufferedCallCount++;

            // Continue after yield, telling StreamingLexer we consumed 0 bytes.
            return Transition::ContinueUnbufferedAfterYield(
                TestState::UNBUFFERED, 0);

          case 1:
            CheckLexedData(aData, aLength, 0, 3);
            unbufferedCallCount++;

            // Continue after yield, telling StreamingLexer we consumed 2 bytes.
            return Transition::ContinueUnbufferedAfterYield(
                TestState::UNBUFFERED, 2);

          case 2:
            EXPECT_EQ(1u, aLength);
            CheckLexedData(aData, aLength, 2, 1);
            unbufferedCallCount++;

            // Continue after yield, telling StreamingLexer we consumed 1 bytes.
            return Transition::ContinueUnbufferedAfterYield(
                TestState::UNBUFFERED, 1);

          case 3:
            CheckLexedData(aData, aLength, 3, 6);
            unbufferedCallCount++;

            // Continue after yield, telling StreamingLexer we consumed 6 bytes.
            // We should transition to TestState::ONE when we return from the
            // yield.
            return Transition::ContinueUnbufferedAfterYield(
                TestState::UNBUFFERED, 6);
        }

        ADD_FAILURE() << "Too many invocations of TestState::UNBUFFERED";
        return Transition::TerminateFailure();

      default:
        MOZ_CRASH("Unexpected or unhandled TestState");
    }
  };

  // Create a special StreamingLexer for this test because we want the first
  // state to be unbuffered.
  StreamingLexer<TestState> lexer(
      Transition::ToUnbuffered(TestState::ONE, TestState::UNBUFFERED,
                               sizeof(mData)),
      Transition::TerminateFailure());

  mSourceBuffer->Append(mData, 3);
  LexerResult result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
  EXPECT_EQ(1u, unbufferedCallCount);

  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
  EXPECT_EQ(2u, unbufferedCallCount);

  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
  EXPECT_EQ(3u, unbufferedCallCount);

  result = lexer.Lex(mIterator, mCountResumes, lexerFunc);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
  EXPECT_EQ(3u, unbufferedCallCount);

  mSourceBuffer->Append(mData + 3, 6);
  mSourceBuffer->Complete(NS_OK);
  EXPECT_EQ(1u, mCountResumes->Count());
  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
  ASSERT_TRUE(result.is<Yield>());
  EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
  EXPECT_EQ(4u, unbufferedCallCount);

  result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
  ASSERT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, TerminateSuccess) {
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  // Test that Terminate is "sticky".
  SourceBufferIterator iterator = mSourceBuffer->Iterator();
  LexerResult result =
      mLexer.Lex(iterator, mExpectNoResume,
                 [&](TestState aState, const char* aData, size_t aLength) {
                   EXPECT_TRUE(aState == TestState::ONE);
                   return Transition::TerminateSuccess();
                 });
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());

  SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
  result = mLexer.Lex(iterator2, mExpectNoResume,
                      [&](TestState aState, const char* aData, size_t aLength) {
                        EXPECT_TRUE(false);  // Shouldn't get here.
                        return Transition::TerminateFailure();
                      });
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, TerminateFailure) {
  mSourceBuffer->Append(mData, sizeof(mData));
  mSourceBuffer->Complete(NS_OK);

  // Test that Terminate is "sticky".
  SourceBufferIterator iterator = mSourceBuffer->Iterator();
  LexerResult result =
      mLexer.Lex(iterator, mExpectNoResume,
                 [&](TestState aState, const char* aData, size_t aLength) {
                   EXPECT_TRUE(aState == TestState::ONE);
                   return Transition::TerminateFailure();
                 });
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());

  SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
  result = mLexer.Lex(iterator2, mExpectNoResume,
                      [&](TestState aState, const char* aData, size_t aLength) {
                        EXPECT_TRUE(false);  // Shouldn't get here.
                        return Transition::TerminateFailure();
                      });
  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, TerminateUnbuffered) {
  // Test that Terminate works during an unbuffered read.
  for (unsigned i = 0; i < 9; ++i) {
    mSourceBuffer->Append(mData + i, 1);
    LexerResult result =
        mLexer.Lex(mIterator, mCountResumes, DoLexWithUnbufferedTerminate);

    if (i > 2) {
      EXPECT_TRUE(result.is<TerminalState>());
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
    } else {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  // We expect 3 resumes because TestState::ONE consumes 3 bytes and then
  // transitions to TestState::UNBUFFERED, which calls TerminateSuccess() as
  // soon as it receives a single byte. That's four bytes total,  which are
  // delivered one at a time, requiring 3 resumes.
  EXPECT_EQ(3u, mCountResumes->Count());

  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, TerminateAfterYield) {
  // Test that Terminate works after yielding.
  for (unsigned i = 0; i < 9; ++i) {
    mSourceBuffer->Append(mData + i, 1);
    LexerResult result =
        mLexer.Lex(mIterator, mCountResumes, DoLexWithTerminateAfterYield);

    if (i > 2) {
      EXPECT_TRUE(result.is<TerminalState>());
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
    } else if (i == 2) {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
    } else {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  // We expect 2 resumes because TestState::ONE consumes 3 bytes and then
  // yields. When the lexer resumes at TestState::TWO, which receives the same 3
  // bytes, TerminateSuccess() gets called immediately.  That's three bytes
  // total, which are delivered one at a time, requiring 2 resumes.
  EXPECT_EQ(2u, mCountResumes->Count());

  mSourceBuffer->Complete(NS_OK);
}

TEST_F(ImageStreamingLexer, SourceBufferImmediateComplete) {
  // Test calling SourceBuffer::Complete() without appending any data. This
  // causes the SourceBuffer to automatically have a failing completion status,
  // no matter what you pass, so we expect TerminalState::FAILURE below.
  mSourceBuffer->Complete(NS_OK);

  LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);

  EXPECT_TRUE(result.is<TerminalState>());
  EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
}

TEST_F(ImageStreamingLexer, SourceBufferTruncatedTerminalStateSuccess) {
  // Test that using a terminal state (in this case TerminalState::SUCCESS) as a
  // truncated state works.
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
                                  Transition::TerminateSuccess());

  CheckTruncatedState(lexer, TerminalState::SUCCESS);
}

TEST_F(ImageStreamingLexer, SourceBufferTruncatedTerminalStateFailure) {
  // Test that using a terminal state (in this case TerminalState::FAILURE) as a
  // truncated state works.
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
                                  Transition::TerminateFailure());

  CheckTruncatedState(lexer, TerminalState::FAILURE);
}

TEST_F(ImageStreamingLexer, SourceBufferTruncatedStateReturningSuccess) {
  // Test that a truncated state that returns TerminalState::SUCCESS works. When
  // |lexer| discovers that the data is truncated, it invokes the
  // TRUNCATED_SUCCESS state, which returns TerminalState::SUCCESS.
  // CheckTruncatedState() verifies that this happens.
  StreamingLexer<TestState> lexer(
      Transition::To(TestState::ONE, 3),
      Transition::To(TestState::TRUNCATED_SUCCESS, 0));

  CheckTruncatedState(lexer, TerminalState::SUCCESS);
}

TEST_F(ImageStreamingLexer, SourceBufferTruncatedStateReturningFailure) {
  // Test that a truncated state that returns TerminalState::FAILURE works. When
  // |lexer| discovers that the data is truncated, it invokes the
  // TRUNCATED_FAILURE state, which returns TerminalState::FAILURE.
  // CheckTruncatedState() verifies that this happens.
  StreamingLexer<TestState> lexer(
      Transition::To(TestState::ONE, 3),
      Transition::To(TestState::TRUNCATED_FAILURE, 0));

  CheckTruncatedState(lexer, TerminalState::FAILURE);
}

TEST_F(ImageStreamingLexer, SourceBufferTruncatedFailingCompleteStatus) {
  // Test that calling SourceBuffer::Complete() with a failing status results in
  // an immediate TerminalState::FAILURE result. (Note that |lexer|'s truncated
  // state is TerminalState::SUCCESS, so if we ignore the failing status, the
  // test will fail.)
  StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
                                  Transition::TerminateSuccess());

  CheckTruncatedState(lexer, TerminalState::FAILURE, NS_ERROR_FAILURE);
}

TEST_F(ImageStreamingLexer, NoSourceBufferResumable) {
  // Test delivering in one byte chunks with no IResumable.
  for (unsigned i = 0; i < 9; ++i) {
    mSourceBuffer->Append(mData + i, 1);
    LexerResult result = mLexer.Lex(mIterator, nullptr, DoLex);

    if (i == 8) {
      EXPECT_TRUE(result.is<TerminalState>());
      EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
    } else {
      EXPECT_TRUE(result.is<Yield>());
      EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
    }
  }

  mSourceBuffer->Complete(NS_OK);
}

Messung V0.5
C=87 H=97 G=91

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.