const int JSONFeed::INNER_JSON_ST;
const int JSONFeed::STRING_JSON_ST;
const int JSONFeed::ESCAPE_JSON_ST;
+const int JSONFeed::OLD_COMMENT_ST;
+const int JSONFeed::NEW_COMMENT_ST;
+const int JSONFeed::CPP_COMMENT_ST;
+const int JSONFeed::C_COMMENT_ST;
+const int JSONFeed::END_C_COMMENT_ST;
const int JSONFeed::JSON_END_ST;
const int JSONFeed::FEED_OK_ST;
const int JSONFeed::FEED_FAILED_ST;
std::bind(&JSONFeed::stringJSONHandler, this));
defineState(ESCAPE_JSON_ST, "ESCAPE_JSON_ST",
std::bind(&JSONFeed::escapeJSONHandler, this));
+ defineState(OLD_COMMENT_ST, "OLD_COMMENT_ST",
+ std::bind(&JSONFeed::oldCommentHandler, this));
+ defineState(NEW_COMMENT_ST, "NEW_COMMENT_ST",
+ std::bind(&JSONFeed::newCommentHandler, this));
+ defineState(CPP_COMMENT_ST, "CPP_COMMENT_ST",
+ std::bind(&JSONFeed::cppCommentHandler, this));
+ defineState(C_COMMENT_ST, "C_COMMENT_ST",
+ std::bind(&JSONFeed::cCommentHandler, this));
+ defineState(END_C_COMMENT_ST, "END_C_COMMENT_ST",
+ std::bind(&JSONFeed::endCCommentHandler, this));
defineState(JSON_END_ST, "JSON_END_ST",
std::bind(&JSONFeed::endJSONHandler, this));
}
JSONFeed::innerJSONHandler() {
char c = getNextFromBuffer();
if (getNextEvent() != NEED_MORE_DATA_EVT) {
- output_.push_back(c);
-
switch(c) {
case '{':
case '[':
+ output_.push_back(c);
transition(getCurrState(), DATA_READ_OK_EVT);
++open_scopes_;
break;
case '}':
case ']':
+ output_.push_back(c);
if (--open_scopes_ == 0) {
transition(JSON_END_ST, FEED_OK_EVT);
break;
case '"':
+ output_.push_back(c);
transition(STRING_JSON_ST, DATA_READ_OK_EVT);
break;
+ case '#':
+ transition(OLD_COMMENT_ST, DATA_READ_OK_EVT);
+ break;
+
+ case '/':
+ transition(NEW_COMMENT_ST, DATA_READ_OK_EVT);
+ break;
+
default:
+ output_.push_back(c);
postNextEvent(DATA_READ_OK_EVT);
}
}
}
}
+void
+JSONFeed::oldCommentHandler() {
+ char c = getNextFromBuffer();
+ if (getNextEvent() != NEED_MORE_DATA_EVT) {
+ switch (c) {
+ case '\n':
+ output_.push_back(c);
+ transition(INNER_JSON_ST, DATA_READ_OK_EVT);
+ break;
+
+ default:
+ postNextEvent(DATA_READ_OK_EVT);
+ break;
+ }
+ }
+}
+
+void
+JSONFeed::newCommentHandler() {
+ char c = getNextFromBuffer();
+ if (getNextEvent() != NEED_MORE_DATA_EVT) {
+ switch (c) {
+ case '/':
+ transition(CPP_COMMENT_ST, DATA_READ_OK_EVT);
+ break;
+
+ case '*':
+ transition(C_COMMENT_ST, DATA_READ_OK_EVT);
+ break;
+
+ default:
+ feedFailure("invalid characters /" + std::string(1, c));
+ }
+ }
+}
+
+void
+JSONFeed::cppCommentHandler() {
+ char c = getNextFromBuffer();
+ if (getNextEvent() != NEED_MORE_DATA_EVT) {
+ switch (c) {
+ case '\n':
+ transition(INNER_JSON_ST, DATA_READ_OK_EVT);
+ break;
+
+ default:
+ postNextEvent(DATA_READ_OK_EVT);
+ break;
+ }
+ }
+}
+
+void
+JSONFeed::cCommentHandler() {
+ char c = getNextFromBuffer();
+ if (getNextEvent() != NEED_MORE_DATA_EVT) {
+ switch (c) {
+ case '*':
+ transition(END_C_COMMENT_ST, DATA_READ_OK_EVT);
+ break;
+
+ case '\n':
+ output_.push_back(c);
+ postNextEvent(DATA_READ_OK_EVT);
+ break;
+
+ default:
+ postNextEvent(DATA_READ_OK_EVT);
+ break;
+ }
+ }
+}
+
+void
+JSONFeed::endCCommentHandler() {
+ char c = getNextFromBuffer();
+ if (getNextEvent() != NEED_MORE_DATA_EVT) {
+ switch (c) {
+ case '/':
+ transition(INNER_JSON_ST, DATA_READ_OK_EVT);
+ break;
+
+ case '\n':
+ output_.push_back(c);
+ transition(C_COMMENT_ST, DATA_READ_OK_EVT);
+ break;
+
+ default:
+ transition(C_COMMENT_ST, DATA_READ_OK_EVT);
+ break;
+ }
+ }
+}
+
void
JSONFeed::endJSONHandler() {
switch (getNextEvent()) {
/// @brief JSON escape next character.
static const int ESCAPE_JSON_ST = SM_DERIVED_STATE_MIN + 11;
+ /// @brief Skipping an old style comment.
+ static const int OLD_COMMENT_ST = SM_DERIVED_STATE_MIN + 12;
+
+ /// @brief Skipping a new style comment.
+ static const int NEW_COMMENT_ST = SM_DERIVED_STATE_MIN + 13;
+
+ /// @brief Skipping a C++ style comment.
+ static const int CPP_COMMENT_ST = SM_DERIVED_STATE_MIN + 14;
+
+ /// @brief Skipping a C style comment.
+ static const int C_COMMENT_ST = SM_DERIVED_STATE_MIN + 15;
+
+ /// @brief Ending a C style comment.
+ static const int END_C_COMMENT_ST = SM_DERIVED_STATE_MIN + 16;
+
/// @brief Found last closing brace or square bracket.
- static const int JSON_END_ST = SM_DERIVED_STATE_MIN + 12;
+ static const int JSON_END_ST = SM_DERIVED_STATE_MIN + 17;
/// @brief Found opening and closing brace or square bracket.
///
/// @brief Handler for the ESCAPE_JSON_ST;
void escapeJSONHandler();
+ /// @brief Handler for OLD_COMMENT_ST.
+ void oldCommentHandler();
+
+ /// @brief Handler for NEW_COMMENT_ST.
+ void newCommentHandler();
+
+ /// @brief Handler for CPP_COMMENT_ST.
+ void cppCommentHandler();
+
+ /// @brief Handler for C_COMMENT_ST.
+ void cCommentHandler();
+
+ /// @brief Handler for END_C_COMMENT_ST.
+ void endCCommentHandler();
+
/// @brief Handler for the JSON_END_ST.
void endJSONHandler();
testRead(json, expected);
}
-// This test verifies that shell style comments before JSON are ignored.
-TEST_F(JSONFeedTest, shellCommentBefore) {
+// This test verifies that bash style comments before JSON are ignored.
+TEST_F(JSONFeedTest, bashCommentBefore) {
std::string json = "# ahah\n # foo\"bar\n{ }\n";
std::string expected = "{ }";
testRead(json, expected);
}
// This test verifies that an error is signalled a slash does not begin
-// a C++ or C style comment.
+// a C++ or C style comment before JSON.
TEST_F(JSONFeedTest, badCommentBefore) {
std::string json = "/# foo\n [ ]\n";
std::string err_msg = "invalid characters /#";
testInvalidRead(json, err_msg);
}
+// This test verifies that bash style comments are ignored.
+TEST_F(JSONFeedTest, bashComments) {
+ std::string json = "{ # ahah\n \"foo\": # value?\n \"bar\" }";
+ std::string expected = "{ \n \"foo\": \n \"bar\" }";
+ testRead(json, expected);
+}
+
+// This test verifies that C++ style comments are ignored.
+TEST_F(JSONFeedTest, cppComments) {
+ std::string json = "[ # ahah\n \"foo\", # value?\n \"bar\" ]";
+ std::string expected = "[ \n \"foo\", \n \"bar\" ]";
+ testRead(json, expected);
+}
+
+// This test verifies that multi-line comments are ignored.
+TEST_F(JSONFeedTest, multiLineComments) {
+ std::string json = "{ /* ahah\n \"// foobar*/\n \"foo\": \"bar\" }\n";
+ std::string expected = "{ \n\n \"foo\": \"bar\" }";
+ testRead(json, expected);
+}
+
+// This test verifies that an error is signalled a slash does not begin
+// a C++ or C style comment.
+TEST_F(JSONFeedTest, badComment) {
+ std::string json = "[ /# foo\n ]\n";
+ std::string err_msg = "invalid characters /#";
+ testInvalidRead(json, err_msg);
+}
+
// This test verifies that trailing garbage is ignored.
TEST_F(JSONFeedTest, trailing) {
JSONFeed feed;
EXPECT_EQ(expected, feed.getProcessedText());
}
+// Example from DHCPv4 unit tests.
+TEST_F(JSONFeedTest, bashComment4) {
+ JSONFeed feed;
+ ASSERT_NO_THROW(feed.initModel());
+ std::string json = "{ \"Dhcp4\": { \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},\n"
+ "# this is a comment\n"
+ "\"rebind-timer\": 2000, \n"
+ "# lots of comments here\n"
+ "# and here\n"
+ "\"renew-timer\": 1000, \n"
+ "\"subnet4\": [ { "
+ " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
+ " \"subnet\": \"192.0.2.0/24\", "
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 } }";
+ feed.postBuffer(&json[0], json.size());
+ feed.poll();
+ EXPECT_FALSE(feed.needData());
+ EXPECT_TRUE(feed.feedOk());
+ EXPECT_NO_THROW(feed.toElement());
+}
+
+// Example from DHCPv4 unit tests.
+TEST_F(JSONFeedTest, bashCommentsInline4) {
+ JSONFeed feed;
+ ASSERT_NO_THROW(feed.initModel());
+ std::string json = "{ \"Dhcp4\": { \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},\n"
+ "\"rebind-timer\": 2000, # everything after # is ignored\n"
+ "\"renew-timer\": 1000, # this will be ignored, too\n"
+ "\"subnet4\": [ { "
+ " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
+ " \"subnet\": \"192.0.2.0/24\", "
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 } }";
+ feed.postBuffer(&json[0], json.size());
+ feed.poll();
+ EXPECT_FALSE(feed.needData());
+ EXPECT_TRUE(feed.feedOk());
+ EXPECT_NO_THROW(feed.toElement());
+}
+
+// Example from DHCPv6 unit tests.
+TEST_F(JSONFeedTest, cppComments6) {
+ JSONFeed feed;
+ ASSERT_NO_THROW(feed.initModel());
+ std::string json = "{ \"Dhcp6\": { \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},\n"
+ "\"preferred-lifetime\": 3000, // this is a comment \n"
+ "\"rebind-timer\": 2000, // everything after // is ignored\n"
+ "\"renew-timer\": 1000, // this will be ignored, too\n"
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 } }";
+ feed.postBuffer(&json[0], json.size());
+ feed.poll();
+ EXPECT_FALSE(feed.needData());
+ EXPECT_TRUE(feed.feedOk());
+ EXPECT_NO_THROW(feed.toElement());
+}
+
+// Example from DHCPv6 unit tests.
+TEST_F(JSONFeedTest, multilineComments6) {
+ JSONFeed feed;
+ ASSERT_NO_THROW(feed.initModel());
+ std::string json = "{ \"Dhcp6\": { \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},\n"
+ "\"preferred-lifetime\": 3000, /* this is a C style comment\n"
+ "that\n can \n span \n multiple \n lines */ \n"
+ "\"rebind-timer\": 2000,\n"
+ "\"renew-timer\": 1000, \n"
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 } }";
+ feed.postBuffer(&json[0], json.size());
+ feed.poll();
+ EXPECT_FALSE(feed.needData());
+ EXPECT_TRUE(feed.feedOk());
+ EXPECT_NO_THROW(feed.toElement());
+}
+
} // end of anonymous namespace.