/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace ousia {
namespace parser_stack {
// Build an instance of the StandaloneEnvironment used for this unit test
static TerminalLogger logger(std::cerr, true);
// static ConcreteLogger logger;
static StandaloneEnvironment env(logger);
namespace {
class Parser : public ParserCallbacks {
TokenId registerToken(const std::string &token) override
{
return Tokens::Empty;
}
void unregisterToken(TokenId id) override
{
// Do nothing here
}
};
static Parser parser;
struct Tracker {
int startCommandCount;
int startAnnotationCount;
int startTokenCount;
int endTokenCount;
int endCount;
int fieldStartCount;
int fieldEndCount;
int dataCount;
bool startCommandResult;
bool startAnnotationResult;
bool startTokenResult;
EndTokenResult endTokenResult;
bool fieldStartResult;
bool dataResult;
Variant::mapType startCommandArgs;
Variant::mapType startAnnotationArgs;
bool fieldStartReturnValue;
size_t fieldStartIdx;
bool fieldStartIsDefault;
bool fieldStartSetIsDefault;
Variant dataData;
Tracker() { reset(); }
void reset()
{
startCommandCount = 0;
startAnnotationCount = 0;
startTokenCount = 0;
endTokenCount = 0;
endCount = 0;
fieldStartCount = 0;
fieldEndCount = 0;
dataCount = 0;
startCommandResult = true;
startAnnotationResult = true;
startTokenResult = true;
endTokenResult = EndTokenResult();
fieldStartResult = true;
dataResult = true;
startCommandArgs = Variant::mapType{};
startAnnotationArgs = Variant::mapType{};
fieldStartIdx = 0;
fieldStartIsDefault = false;
fieldStartSetIsDefault = false;
dataData = Variant{};
}
void expect(int startCommandCount, int endCount, int fieldStartCount,
int fieldEndCount, int dataCount, int startAnnotationCount = 0,
int startTokenCount = 0, int endTokenCount = 0)
{
EXPECT_EQ(startCommandCount, this->startCommandCount);
EXPECT_EQ(startAnnotationCount, this->startAnnotationCount);
EXPECT_EQ(startTokenCount, this->startTokenCount);
EXPECT_EQ(endTokenCount, this->endTokenCount);
EXPECT_EQ(endCount, this->endCount);
EXPECT_EQ(fieldStartCount, this->fieldStartCount);
EXPECT_EQ(fieldEndCount, this->fieldEndCount);
EXPECT_EQ(dataCount, this->dataCount);
}
};
static Tracker tracker;
class TestHandler : public Handler {
private:
TestHandler(const HandlerData &handlerData) : Handler(handlerData) {}
public:
bool startCommand(Variant::mapType &args) override
{
tracker.startCommandArgs = args;
tracker.startCommandCount++;
if (!tracker.startCommandResult) {
logger().error(
"TestHandler was told not to allow a command start. "
"TestHandler always obeys its master.");
}
return tracker.startCommandResult;
}
bool startAnnotation(Variant::mapType &args) override
{
tracker.startAnnotationArgs = args;
tracker.startAnnotationCount++;
return tracker.startAnnotationResult;
}
bool startToken(Handle node) override
{
tracker.startTokenCount++;
return tracker.startTokenResult;
}
EndTokenResult endToken(Handle node, size_t maxStackDepth) override
{
tracker.endTokenCount++;
return tracker.endTokenResult;
}
void end() override { tracker.endCount++; }
bool fieldStart(bool &isDefault, size_t fieldIdx) override
{
tracker.fieldStartIsDefault = isDefault;
tracker.fieldStartIdx = fieldIdx;
if (tracker.fieldStartSetIsDefault) {
isDefault = true;
}
tracker.fieldStartCount++;
return tracker.fieldStartResult;
}
void fieldEnd() override { tracker.fieldEndCount++; }
bool data() override
{
tracker.dataData = readData();
tracker.dataCount++;
return tracker.dataResult;
}
static Handler *create(const HandlerData &handlerData)
{
return new TestHandler(handlerData);
}
};
}
namespace States {
static const State Document =
StateBuilder().parent(&None).elementHandler(TestHandler::create);
static const State Body =
StateBuilder().parent(&Document).elementHandler(TestHandler::create);
static const State Empty =
StateBuilder().parent(&Document).elementHandler(TestHandler::create);
static const State Special =
StateBuilder().parent(&All).elementHandler(TestHandler::create);
static const State Arguments =
StateBuilder().parent(&None).elementHandler(TestHandler::create).arguments(
{Argument::Int("a"), Argument::String("b")});
static const State BodyChildren =
StateBuilder().parent(&Body).elementHandler(TestHandler::create);
static const State Any =
StateBuilder().parents({&None, &Any}).elementHandler(TestHandler::create);
static const std::multimap TestHandlers{
{"document", &Document},
{"body", &Body},
{"empty", &Empty},
{"special", &Special},
{"arguments", &Arguments},
{"*", &BodyChildren}};
static const std::multimap AnyHandlers{{"*", &Any}};
}
TEST(Stack, basicTest)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::TestHandlers};
EXPECT_EQ("", s.currentCommandName());
EXPECT_EQ(&States::None, &s.currentState());
s.commandStart("document", {});
s.fieldStart(true);
s.data("test1");
EXPECT_EQ("document", s.currentCommandName());
EXPECT_EQ(&States::Document, &s.currentState());
tracker.expect(1, 0, 1, 0, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("body", {});
s.fieldStart(true);
s.data("test2");
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
tracker.expect(2, 0, 2, 0, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("inner", {});
s.fieldStart(true);
EXPECT_EQ("inner", s.currentCommandName());
EXPECT_EQ(&States::BodyChildren, &s.currentState());
s.fieldEnd();
tracker.expect(3, 0, 3, 1, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldEnd();
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
tracker.expect(3, 1, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("body", {});
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
tracker.expect(4, 2, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(true);
s.data("test3");
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
s.fieldEnd();
tracker.expect(4, 2, 4, 3, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
s.fieldEnd();
tracker.expect(4, 3, 4, 4, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("document", s.currentCommandName());
EXPECT_EQ(&States::Document, &s.currentState());
}
tracker.expect(4, 4, 4, 4, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, basicTestRangeCommands)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::TestHandlers};
EXPECT_EQ("", s.currentCommandName());
EXPECT_EQ(&States::None, &s.currentState());
s.commandStart("document", {}, true);
EXPECT_EQ("document", s.currentCommandName());
EXPECT_EQ(&States::Document, &s.currentState());
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.data("test1");
tracker.expect(1, 0, 1, 0, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("body", {}, true);
tracker.expect(2, 0, 1, 0, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
s.data("test2");
tracker.expect(2, 0, 2, 0, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
s.commandStart("inner", {}, true);
tracker.expect(3, 0, 2, 0, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("inner", s.currentCommandName());
EXPECT_EQ(&States::BodyChildren, &s.currentState());
s.rangeEnd();
tracker.expect(3, 1, 3, 1, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
s.rangeEnd();
tracker.expect(3, 2, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("body", {}, true);
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
tracker.expect(4, 2, 3, 2, 2); // scc, ec, fsc, fse, dc, sac, stc, etc
s.fieldStart(true);
tracker.expect(4, 2, 4, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.data("test3");
tracker.expect(4, 2, 4, 2, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
s.fieldEnd();
tracker.expect(4, 2, 4, 3, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("body", s.currentCommandName());
EXPECT_EQ(&States::Body, &s.currentState());
s.rangeEnd();
tracker.expect(4, 3, 4, 3, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("document", s.currentCommandName());
EXPECT_EQ(&States::Document, &s.currentState());
s.rangeEnd();
tracker.expect(4, 4, 4, 4, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(4, 4, 4, 4, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, errorInvalidCommands)
{
Stack s{parser, env.context, States::TestHandlers};
tracker.reset();
EXPECT_THROW(s.commandStart("body", {}), LoggableException);
s.commandStart("document", {});
s.fieldStart(true);
EXPECT_THROW(s.commandStart("document", {}), LoggableException);
s.commandStart("empty", {});
s.fieldStart(true);
EXPECT_THROW(s.commandStart("body", {}), LoggableException);
s.commandStart("special", {});
s.fieldStart(true);
s.fieldEnd();
s.fieldEnd();
s.fieldEnd();
logger.reset();
s.fieldEnd();
ASSERT_TRUE(logger.hasError());
EXPECT_THROW(s.data("test"), LoggableException);
EXPECT_EQ(&States::None, &s.currentState());
}
TEST(Stack, validation)
{
Stack s{parser, env.context, States::TestHandlers};
tracker.reset();
logger.reset();
s.commandStart("arguments", {});
EXPECT_TRUE(logger.hasError());
s.fieldStart(true);
s.fieldEnd();
logger.reset();
s.commandStart("arguments", {{"a", 5}}, false);
EXPECT_TRUE(logger.hasError());
s.fieldStart(true);
s.fieldEnd();
logger.reset();
s.commandStart("arguments", {{"a", 5}, {"b", "test"}}, false);
EXPECT_FALSE(logger.hasError());
s.fieldStart(true);
s.fieldEnd();
}
TEST(Stack, invalidCommandName)
{
tracker.reset();
logger.reset();
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(true);
s.fieldEnd();
tracker.expect(1, 0, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("a_", {});
tracker.expect(2, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(true);
s.fieldEnd();
tracker.expect(2, 1, 2, 2, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("a_:b", {});
tracker.expect(3, 2, 2, 2, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(true);
s.fieldEnd();
tracker.expect(3, 2, 3, 3, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_THROW(s.commandStart("_a", {}), LoggableException);
tracker.expect(3, 3, 3, 3, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_THROW(s.commandStart("a:", {}), LoggableException);
tracker.expect(3, 3, 3, 3, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_THROW(s.commandStart("a:_b", {}), LoggableException);
tracker.expect(3, 3, 3, 3, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
TEST(Stack, multipleFields)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {{"a", false}}, false);
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("a", s.currentCommandName());
EXPECT_EQ(Variant::mapType({{"a", false}}), tracker.startCommandArgs);
s.fieldStart(false);
tracker.expect(1, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_FALSE(tracker.fieldStartIsDefault);
EXPECT_EQ(0U, tracker.fieldStartIdx);
s.data("test");
tracker.expect(1, 0, 1, 0, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("test", tracker.dataData.asString());
s.fieldEnd();
tracker.expect(1, 0, 1, 1, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(false);
tracker.expect(1, 0, 2, 1, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_FALSE(tracker.fieldStartIsDefault);
EXPECT_EQ(1U, tracker.fieldStartIdx);
s.data("test2");
tracker.expect(1, 0, 2, 1, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("test2", tracker.dataData.asString());
s.fieldEnd();
tracker.expect(1, 0, 2, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(true);
tracker.expect(1, 0, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_TRUE(tracker.fieldStartIsDefault);
EXPECT_EQ(2U, tracker.fieldStartIdx);
s.data("test3");
tracker.expect(1, 0, 3, 2, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ("test3", tracker.dataData.asString());
s.fieldEnd();
tracker.expect(1, 0, 3, 3, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 3, 3, 3); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, implicitDefaultFieldOnNewCommand)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("b", {});
tracker.expect(2, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(2, 2, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, implicitDefaultFieldOnNewCommandWithExplicitDefaultField)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("a", s.currentCommandName());
s.commandStart("b", {});
tracker.expect(2, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("b", s.currentCommandName());
s.fieldStart(true);
s.fieldEnd();
tracker.expect(2, 0, 2, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("b", s.currentCommandName());
}
tracker.expect(2, 2, 2, 2, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, noImplicitDefaultFieldOnIncompatibleCommand)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("a", s.currentCommandName());
tracker.fieldStartResult = false;
s.commandStart("b", {});
tracker.expect(2, 1, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("b", s.currentCommandName());
}
tracker.expect(2, 2, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, noImplicitDefaultFieldIfDefaultFieldGiven)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("a", s.currentCommandName());
s.fieldStart(true);
tracker.expect(1, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("a", s.currentCommandName());
s.fieldEnd();
tracker.expect(1, 0, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("a", s.currentCommandName());
s.commandStart("b", {});
tracker.expect(2, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("b", s.currentCommandName());
}
tracker.expect(2, 2, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, noEndIfStartFails)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_EQ("a", s.currentCommandName());
tracker.startCommandResult = false;
s.commandStart("b", {});
tracker.expect(3, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
EXPECT_EQ(&States::None, &s.currentState());
}
tracker.expect(3, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_TRUE(logger.hasError());
}
TEST(Stack, implicitDefaultFieldOnData)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.data("test");
tracker.expect(1, 0, 1, 0, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 1, 1, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, autoFieldEnd)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, autoImplicitFieldEnd)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
s.commandStart("b", {});
s.commandStart("c", {});
s.commandStart("d", {});
s.commandStart("e", {});
s.fieldStart(true);
s.fieldEnd();
tracker.expect(5, 0, 5, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(5, 5, 5, 5, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, invalidDefaultField)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.fieldStartResult = false;
s.fieldStart(true);
s.fieldEnd();
tracker.expect(1, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, errorInvalidDefaultFieldData)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.fieldStartResult = false;
s.fieldStart(true);
ASSERT_FALSE(logger.hasError());
s.data("test");
ASSERT_TRUE(logger.hasError());
s.fieldEnd();
tracker.expect(1, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
TEST(Stack, errorInvalidFieldData)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.fieldStartResult = false;
ASSERT_FALSE(logger.hasError());
s.fieldStart(false);
ASSERT_TRUE(logger.hasError());
s.data("test");
s.fieldEnd();
tracker.expect(1, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
TEST(Stack, errorFieldStartNoCommand)
{
tracker.reset();
logger.reset();
Stack s{parser, env.context, States::AnyHandlers};
ASSERT_THROW(s.fieldStart(false), LoggableException);
ASSERT_THROW(s.fieldStart(true), LoggableException);
tracker.expect(0, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
TEST(Stack, errorMultipleFieldStarts)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(false);
ASSERT_FALSE(logger.hasError());
s.fieldStart(false);
ASSERT_TRUE(logger.hasError());
tracker.expect(1, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldEnd();
tracker.expect(1, 0, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
TEST(Stack, errorMultipleFieldEnds)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(false);
s.fieldEnd();
ASSERT_FALSE(logger.hasError());
tracker.expect(1, 0, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldEnd();
ASSERT_TRUE(logger.hasError());
tracker.expect(1, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(1, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
TEST(Stack, errorOpenField)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(false);
ASSERT_FALSE(logger.hasError());
}
ASSERT_TRUE(logger.hasError());
tracker.expect(1, 1, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
TEST(Stack, fieldEndWhenImplicitDefaultFieldOpen)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
s.fieldStart(true);
s.commandStart("b", {});
s.data("test");
s.fieldEnd();
tracker.expect(2, 1, 2, 2, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(2, 2, 2, 2, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, fieldAfterDefaultField)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
s.commandStart("a", {});
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(true);
tracker.expect(1, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("b", {});
tracker.expect(2, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldStart(false);
tracker.expect(2, 0, 2, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.data("f1");
tracker.expect(2, 0, 2, 0, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldEnd();
tracker.expect(2, 0, 2, 1, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
tracker.fieldStartSetIsDefault = true;
s.fieldStart(false);
tracker.fieldStartSetIsDefault = false;
tracker.expect(2, 0, 3, 1, 1); // scc, ec, fsc, fec, dc, sac, stc, etc
s.data("f2");
tracker.expect(2, 0, 3, 1, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldEnd();
tracker.expect(2, 0, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
s.fieldStart(false);
ASSERT_TRUE(logger.hasError());
logger.reset();
tracker.expect(2, 0, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.data("f3");
tracker.expect(2, 0, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldEnd();
tracker.expect(2, 0, 3, 2, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
s.fieldEnd();
tracker.expect(2, 1, 3, 3, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(2, 2, 3, 3, 2); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
TEST(Stack, rangeCommandUnranged)
{
tracker.reset();
logger.reset();
{
Stack s{parser, env.context, States::AnyHandlers};
tracker.expect(0, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("a", {}, true);
tracker.expect(1, 0, 0, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.commandStart("b", {});
tracker.expect(2, 0, 1, 0, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
s.rangeEnd();
tracker.expect(2, 2, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
}
tracker.expect(2, 2, 1, 1, 0); // scc, ec, fsc, fec, dc, sac, stc, etc
ASSERT_FALSE(logger.hasError());
}
}
}