2015-09-19 09:12:27 +03:00
|
|
|
/* 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 "mozilla/Vector.h"
|
|
|
|
#include "StreamingLexer.h"
|
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::image;
|
|
|
|
|
|
|
|
enum class TestState
|
|
|
|
{
|
|
|
|
ONE,
|
|
|
|
TWO,
|
|
|
|
THREE,
|
2015-10-28 11:30:20 +03:00
|
|
|
UNBUFFERED
|
2015-09-19 09:12:27 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
CheckData(const char* aData, size_t aLength)
|
|
|
|
{
|
|
|
|
EXPECT_TRUE(aLength == 3);
|
|
|
|
EXPECT_EQ(1, aData[0]);
|
|
|
|
EXPECT_EQ(2, aData[1]);
|
|
|
|
EXPECT_EQ(3, aData[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
LexerTransition<TestState>
|
|
|
|
DoLex(TestState aState, const char* aData, size_t aLength)
|
|
|
|
{
|
|
|
|
switch (aState) {
|
|
|
|
case TestState::ONE:
|
|
|
|
CheckData(aData, aLength);
|
|
|
|
return Transition::To(TestState::TWO, 3);
|
|
|
|
case TestState::TWO:
|
|
|
|
CheckData(aData, aLength);
|
|
|
|
return Transition::To(TestState::THREE, 3);
|
|
|
|
case TestState::THREE:
|
|
|
|
CheckData(aData, aLength);
|
2015-10-28 11:30:20 +03:00
|
|
|
return Transition::TerminateSuccess();
|
2015-09-19 09:12:27 +03:00
|
|
|
default:
|
2015-10-28 11:30:20 +03:00
|
|
|
MOZ_CRASH("Unknown TestState");
|
2015-09-19 09:12:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LexerTransition<TestState>
|
|
|
|
DoLexWithUnbuffered(TestState aState, const char* aData, size_t aLength,
|
|
|
|
Vector<char>& aUnbufferedVector)
|
|
|
|
{
|
|
|
|
switch (aState) {
|
|
|
|
case TestState::ONE:
|
|
|
|
CheckData(aData, aLength);
|
|
|
|
return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
|
|
|
|
case TestState::UNBUFFERED:
|
|
|
|
EXPECT_TRUE(aLength <= 3);
|
2016-01-14 17:19:21 +03:00
|
|
|
EXPECT_TRUE(aUnbufferedVector.append(aData, aLength));
|
2015-09-19 09:12:27 +03:00
|
|
|
return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
|
|
|
|
case TestState::TWO:
|
|
|
|
CheckData(aUnbufferedVector.begin(), aUnbufferedVector.length());
|
|
|
|
return Transition::To(TestState::THREE, 3);
|
|
|
|
case TestState::THREE:
|
|
|
|
CheckData(aData, aLength);
|
2015-10-28 11:30:20 +03:00
|
|
|
return Transition::TerminateSuccess();
|
2015-09-19 09:12:27 +03:00
|
|
|
default:
|
2015-10-28 11:30:20 +03:00
|
|
|
MOZ_CRASH("Unknown TestState");
|
2015-09-19 09:12:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LexerTransition<TestState>
|
|
|
|
DoLexWithUnbufferedTerminate(TestState aState, const char* aData, size_t aLength)
|
|
|
|
{
|
|
|
|
switch (aState) {
|
|
|
|
case TestState::ONE:
|
|
|
|
CheckData(aData, aLength);
|
|
|
|
return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
|
|
|
|
case TestState::UNBUFFERED:
|
2015-10-28 11:30:20 +03:00
|
|
|
return Transition::TerminateSuccess();
|
2015-09-19 09:12:27 +03:00
|
|
|
default:
|
2015-10-28 11:30:20 +03:00
|
|
|
MOZ_CRASH("Unknown TestState");
|
2015-09-19 09:12:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, SingleChunk)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
|
|
|
|
// Test delivering all the data at once.
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result = lexer.Lex(data, sizeof(data), DoLex);
|
2015-09-19 09:12:27 +03:00
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, SingleChunkWithUnbuffered)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
Vector<char> unbufferedVector;
|
|
|
|
|
|
|
|
// Test delivering all the data at once.
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result =
|
2015-09-19 09:12:27 +03:00
|
|
|
lexer.Lex(data, sizeof(data),
|
|
|
|
[&](TestState aState, const char* aData, size_t aLength) {
|
|
|
|
return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
|
|
|
|
});
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, ChunkPerState)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
|
|
|
|
// Test delivering in perfectly-sized chunks, one per state.
|
2016-02-27 08:01:49 +03:00
|
|
|
for (unsigned i = 0; i < 3; ++i) {
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result = lexer.Lex(data + 3 * i, 3, DoLex);
|
2015-09-19 09:12:27 +03:00
|
|
|
|
|
|
|
if (i == 2) {
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
} else {
|
|
|
|
EXPECT_TRUE(result.isNothing());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, ChunkPerStateWithUnbuffered)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
Vector<char> unbufferedVector;
|
|
|
|
|
|
|
|
// Test delivering in perfectly-sized chunks, one per state.
|
2016-02-27 08:01:49 +03:00
|
|
|
for (unsigned i = 0; i < 3; ++i) {
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result =
|
2015-09-19 09:12:27 +03:00
|
|
|
lexer.Lex(data + 3 * i, 3,
|
|
|
|
[&](TestState aState, const char* aData, size_t aLength) {
|
|
|
|
return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (i == 2) {
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
} else {
|
|
|
|
EXPECT_TRUE(result.isNothing());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, OneByteChunks)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
|
|
|
|
// Test delivering in one byte chunks.
|
2016-02-27 08:01:49 +03:00
|
|
|
for (unsigned i = 0; i < 9; ++i) {
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result = lexer.Lex(data + i, 1, DoLex);
|
2015-09-19 09:12:27 +03:00
|
|
|
|
|
|
|
if (i == 8) {
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
} else {
|
|
|
|
EXPECT_TRUE(result.isNothing());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, OneByteChunksWithUnbuffered)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
Vector<char> unbufferedVector;
|
|
|
|
|
|
|
|
// Test delivering in one byte chunks.
|
2016-02-27 08:01:49 +03:00
|
|
|
for (unsigned i = 0; i < 9; ++i) {
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result =
|
2015-09-19 09:12:27 +03:00
|
|
|
lexer.Lex(data + i, 1,
|
|
|
|
[&](TestState aState, const char* aData, size_t aLength) {
|
|
|
|
return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (i == 8) {
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
} else {
|
|
|
|
EXPECT_TRUE(result.isNothing());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, TerminateSuccess)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
|
|
|
|
// Test that Terminate is "sticky".
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result =
|
2015-09-19 09:12:27 +03:00
|
|
|
lexer.Lex(data, sizeof(data),
|
|
|
|
[&](TestState aState, const char* aData, size_t aLength) {
|
|
|
|
EXPECT_TRUE(aState == TestState::ONE);
|
2015-10-28 11:30:20 +03:00
|
|
|
return Transition::TerminateSuccess();
|
2015-09-19 09:12:27 +03:00
|
|
|
});
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
|
|
|
|
result =
|
|
|
|
lexer.Lex(data, sizeof(data),
|
|
|
|
[&](TestState aState, const char* aData, size_t aLength) {
|
|
|
|
EXPECT_TRUE(false); // Shouldn't get here.
|
2015-10-28 11:30:20 +03:00
|
|
|
return Transition::TerminateFailure();
|
2015-09-19 09:12:27 +03:00
|
|
|
});
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, TerminateFailure)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
|
|
|
|
// Test that Terminate is "sticky".
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result =
|
2015-09-19 09:12:27 +03:00
|
|
|
lexer.Lex(data, sizeof(data),
|
|
|
|
[&](TestState aState, const char* aData, size_t aLength) {
|
|
|
|
EXPECT_TRUE(aState == TestState::ONE);
|
2015-10-28 11:30:20 +03:00
|
|
|
return Transition::TerminateFailure();
|
2015-09-19 09:12:27 +03:00
|
|
|
});
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::FAILURE), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
|
|
|
|
result =
|
|
|
|
lexer.Lex(data, sizeof(data),
|
|
|
|
[&](TestState aState, const char* aData, size_t aLength) {
|
|
|
|
EXPECT_TRUE(false); // Shouldn't get here.
|
2015-10-28 11:30:20 +03:00
|
|
|
return Transition::TerminateFailure();
|
2015-09-19 09:12:27 +03:00
|
|
|
});
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::FAILURE), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ImageStreamingLexer, TerminateUnbuffered)
|
|
|
|
{
|
|
|
|
StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3));
|
|
|
|
char data[9] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
|
|
|
|
|
|
|
|
// Test that Terminate works during an unbuffered read.
|
2016-02-27 08:01:49 +03:00
|
|
|
for (unsigned i = 0; i < 9; ++i) {
|
2015-10-28 11:30:20 +03:00
|
|
|
Maybe<TerminalState> result =
|
2015-09-19 09:12:27 +03:00
|
|
|
lexer.Lex(data + i, 1, DoLexWithUnbufferedTerminate);
|
|
|
|
|
|
|
|
if (i > 2) {
|
|
|
|
EXPECT_TRUE(result.isSome());
|
2015-10-28 11:30:20 +03:00
|
|
|
EXPECT_EQ(Some(TerminalState::SUCCESS), result);
|
2015-09-19 09:12:27 +03:00
|
|
|
} else {
|
|
|
|
EXPECT_TRUE(result.isNothing());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|