From e3c4b3391515e89b98eb8e950b0420c17ad45d80 Mon Sep 17 00:00:00 2001 From: thebusytypist Date: Thu, 10 Jul 2014 22:27:25 +0800 Subject: [PATCH] Add unittests for state transition. --- include/rapidjson/reader.h | 8 +- test/unittest/readertest.cpp | 141 +++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 372016f..9c83775 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -799,7 +799,7 @@ private: cIterativeParsingTokenCount }; - IterativeParsingToken GuessToken(Ch c) { + IterativeParsingToken Tokenize(Ch c) { switch (c) { case '[': return IterativeParsingLeftBracketToken; case ']': return IterativeParsingRightBracketToken; @@ -815,7 +815,7 @@ private: } } - IterativeParsingState Deduce(IterativeParsingState state, IterativeParsingToken token) { + IterativeParsingState Predict(IterativeParsingState state, IterativeParsingToken token) { // current state x one lookahead token -> new state static const IterativeParsingState G[cIterativeParsingStateCount][cIterativeParsingTokenCount] = { // Start @@ -1127,8 +1127,8 @@ private: SkipWhitespace(is); while (is.Peek() != '\0') { - IterativeParsingToken t = GuessToken(is.Peek()); - IterativeParsingState n = Deduce(state, t); + IterativeParsingToken t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit(state, t, n, is, handler); if (d == IterativeParsingErrorState) { diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 05c434f..b4107d1 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -730,6 +730,147 @@ TEST(Reader, IterativeParsing_ErrorHandling) { TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket); } +// Test iterative parsing. +template > +struct IterativeParsingReaderHandler { + typedef typename Encoding::Ch Ch; + + IterativeParsingReaderHandler() : + IsNullTriggered(false), + IsBoolTriggered(false), + IsIntTriggered(false), + IsUintTriggered(false), + IsInt64Triggered(false), + IsUint64Triggered(false), + IsDoubleTriggered(false), + IsStringTriggered(false), + IsStartObjectTriggered(false), + IsEndObjectTriggered(false), + MemberCount(0), + IsStartArrayTriggered(false), + ElementCount(0) { + } + + bool IsNullTriggered; + void Null() { IsNullTriggered = true; } + + bool IsBoolTriggered; + void Bool(bool) { IsBoolTriggered = true; } + + bool IsIntTriggered; + void Int(int) { IsIntTriggered = true; } + + bool IsUintTriggered; + void Uint(unsigned) { IsUintTriggered = true; } + + bool IsInt64Triggered; + void Int64(int64_t) { IsInt64Triggered = true; } + + bool IsUint64Triggered; + void Uint64(uint64_t) { IsUint64Triggered = true; } + + bool IsDoubleTriggered; + void Double(double) { IsDoubleTriggered = true; } + + bool IsStringTriggered; + void String(const Ch*, SizeType, bool) { IsStringTriggered = true; } + + bool IsStartObjectTriggered; + void StartObject() { IsStartObjectTriggered = true; } + + bool IsEndObjectTriggered; + SizeType MemberCount; + void EndObject(SizeType c) { IsEndObjectTriggered = true; MemberCount = c; } + + bool IsStartArrayTriggered; + void StartArray() { IsStartArrayTriggered = true; } + + bool IsEndArrayTriggered; + SizeType ElementCount; + void EndArray(SizeType c) { IsEndArrayTriggered = true; ElementCount = c; } +}; + +TEST(Reader, IterativeParsing_StateTransition_Start) { + // Start->ArrayInitial + { + IterativeParsingReaderHandler<> handler; + Reader reader; + StringStream is("["); + + Reader::IterativeParsingState n = reader.Predict(Reader::IterativeParsingStartState, Reader::IterativeParsingLeftBracketToken); + Reader::IterativeParsingState d = reader.Transit(Reader::IterativeParsingStartState, Reader::IterativeParsingLeftBracketToken, n, is, handler); + + EXPECT_FALSE(reader.HasParseError()); + EXPECT_EQ(Reader::IterativeParsingArrayInitialState, d); + EXPECT_TRUE(handler.IsStartArrayTriggered); + } + + // Start->ObjectInitial + { + IterativeParsingReaderHandler<> handler; + Reader reader; + StringStream is("{"); + + Reader::IterativeParsingState n = reader.Predict(Reader::IterativeParsingStartState, Reader::IterativeParsingLeftCurlyBracketToken); + Reader::IterativeParsingState d = reader.Transit(Reader::IterativeParsingStartState, Reader::IterativeParsingLeftCurlyBracketToken, n, is, handler); + + EXPECT_FALSE(reader.HasParseError()); + EXPECT_EQ(Reader::IterativeParsingObjectInitialState, d); + EXPECT_TRUE(handler.IsStartObjectTriggered); + } +} + +TEST(Reader, IterativeParsing_StateTransition_ObjectInitial) { + // ObjectInitial -> ObjectFinish -> Finish + { + IterativeParsingReaderHandler<> handler; + Reader reader; + StringStream is("{}"); + + Reader::IterativeParsingState s = reader.Transit( + Reader::IterativeParsingStartState, + Reader::IterativeParsingLeftCurlyBracketToken, + Reader::IterativeParsingObjectInitialState, + is, handler); + + EXPECT_EQ(Reader::IterativeParsingObjectInitialState, s); + Reader::IterativeParsingState d = reader.Transit( + s, + Reader::IterativeParsingRightCurlyBracketToken, + Reader::IterativeParsingObjectFinishState, + is, handler); + + EXPECT_FALSE(reader.HasParseError()); + EXPECT_EQ(Reader::IterativeParsingFinishState, d); + EXPECT_TRUE(handler.IsEndObjectTriggered); + EXPECT_EQ(0, handler.MemberCount); + } + + // ObjectInitial -> MemberKey + { + IterativeParsingReaderHandler<> handler; + Reader reader; + StringStream is("{\"key\""); + + Reader::IterativeParsingState s = reader.Transit( + Reader::IterativeParsingStartState, + Reader::IterativeParsingLeftCurlyBracketToken, + Reader::IterativeParsingObjectInitialState, + is, handler); + + EXPECT_EQ(Reader::IterativeParsingObjectInitialState, s); + Reader::IterativeParsingState d = reader.Transit( + s, + Reader::IterativeParsingStringToken, + Reader::IterativeParsingMemberKeyState, + is, handler); + + EXPECT_FALSE(reader.HasParseError()); + EXPECT_EQ(Reader::IterativeParsingMemberKeyState, d); + EXPECT_TRUE(handler.IsStringTriggered); + } +} + #ifdef __GNUC__ #pragma GCC diagnostic pop #endif