json_feed_unittests.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <cc/data.h>
  8. #include <cc/json_feed.h>
  9. #include <gtest/gtest.h>
  10. #include <sstream>
  11. #include <string>
  12. using namespace isc::config;
  13. using namespace isc::data;
  14. namespace {
  15. /// @brief Test fixture class for @ref JSONFeed class.
  16. class JSONFeedTest : public ::testing::Test {
  17. public:
  18. /// @brief Constructor.
  19. ///
  20. /// Initializes @ref json_map_ and @ref json_list_ which hold reference
  21. /// JSON structures.
  22. JSONFeedTest()
  23. : json_map_(), json_list_() {
  24. ElementPtr m = Element::fromJSON(createJSON());
  25. ElementPtr l = Element::createList();
  26. l->add(m);
  27. json_map_ = m;
  28. json_list_ = l;
  29. }
  30. /// @brief Creates a JSON map holding 20 elements.
  31. ///
  32. /// Each map value is a list of 20 elements.
  33. std::string createJSON() const {
  34. // Create a list of 20 elements.
  35. ElementPtr list_element = Element::createList();
  36. for (unsigned i = 0; i < 20; ++i) {
  37. std::ostringstream s;
  38. s << "list_element" << i;
  39. list_element->add(Element::create(s.str()));
  40. }
  41. // Create a map of 20 elements. Each map element holds a list
  42. // of 20 elements.
  43. ElementPtr map_element = Element::createMap();
  44. for (unsigned i = 0; i < 20; ++i) {
  45. std::ostringstream s;
  46. s << "map_element" << i;
  47. map_element->set(s.str(), list_element);
  48. }
  49. return (prettyPrint(map_element));
  50. }
  51. /// @brief Test that the JSONFeed correctly recognizes the beginning
  52. /// and the end of the JSON structure.
  53. ///
  54. /// @param input_json A string holding an input JSON structure.
  55. /// @param expected_output A structure holding expected output from the
  56. /// @ref JSONFeed::toElement.
  57. void testRead(const std::string& input_json,
  58. const ConstElementPtr& expected_output) {
  59. JSONFeed feed;
  60. ASSERT_NO_THROW(feed.initModel());
  61. // Post the data into the feed in 10 bytes long chunks.
  62. size_t chunk = 10;
  63. for (size_t i = 0; i < input_json.size(); i += chunk) {
  64. bool done = false;
  65. // When we're near the end of the data stream, the chunk length may
  66. // vary.
  67. if (i + chunk >= input_json.size()) {
  68. chunk = input_json.size() - i;
  69. done = true;
  70. }
  71. // Feed the parser with a data chunk and parse it.
  72. feed.postBuffer(&input_json[i], chunk);
  73. feed.poll();
  74. if (!done) {
  75. ASSERT_TRUE(feed.needData());
  76. }
  77. }
  78. // Convert parsed/collected data in the feed into the structure of
  79. // elements.
  80. ConstElementPtr element_from_feed = feed.toElement();
  81. EXPECT_TRUE(element_from_feed->equals(*expected_output));
  82. }
  83. /// @brief Test that the @ref JSONFeed signals an error when the input
  84. /// string holds invalid data.
  85. ///
  86. /// @param input_json A string holding an input JSON structure.
  87. void testInvalidRead(const std::string& input_json) {
  88. JSONFeed feed;
  89. ASSERT_NO_THROW(feed.initModel());
  90. ASSERT_NO_THROW(feed.postBuffer(&input_json[0], input_json.size()));
  91. ASSERT_NO_THROW(feed.poll());
  92. EXPECT_FALSE(feed.needData());
  93. EXPECT_FALSE(feed.feedOk());
  94. }
  95. /// @brief JSON map holding a number of lists.
  96. ConstElementPtr json_map_;
  97. /// @brief JSON list holding a map of lists.
  98. ConstElementPtr json_list_;
  99. };
  100. // This test verifies that a JSON structure starting with '{' is accepted
  101. // and parsed.
  102. TEST_F(JSONFeedTest, startWithBrace) {
  103. std::string json = createJSON();
  104. testRead(json, json_map_);
  105. }
  106. // This test verifies that a JSON structure starting with '[' is accepted
  107. // and parsed.
  108. TEST_F(JSONFeedTest, startWithSquareBracket) {
  109. std::string json = createJSON();
  110. json = std::string("[") + json + std::string("]");
  111. testRead(json, json_list_);
  112. }
  113. // This test verifies that input JSON can be preceded with whitespaces.
  114. TEST_F(JSONFeedTest, startWithWhitespace) {
  115. std::string json = createJSON();
  116. json = std::string(" \r\r\t ") + json;
  117. testRead(json, json_map_);
  118. }
  119. // This test verifies that an empty map is accepted and parsed.
  120. TEST_F(JSONFeedTest, emptyMap) {
  121. std::string json = "{}";
  122. testRead(json, Element::createMap());
  123. }
  124. // This test verifies that an empty list is accepted and parsed.
  125. TEST_F(JSONFeedTest, emptyList) {
  126. std::string json = "[ ]";
  127. testRead(json, Element::createList());
  128. }
  129. // This test verifies that an error is signalled when a JSON structure
  130. // is preceded by invalid character.
  131. TEST_F(JSONFeedTest, unexpectedCharacter) {
  132. std::string json = "a {}";
  133. testInvalidRead(json);
  134. }
  135. // This test verfies that an error is signalled when a JSON structure
  136. // lacks an opening brace character.
  137. TEST_F(JSONFeedTest, noOpeningBrace) {
  138. std::string json = "\"x\": \"y\" }";
  139. testInvalidRead(json);
  140. }
  141. // This test verifies that an error is signalled when a JSON structure
  142. // lacks an opening square bracket.
  143. TEST_F(JSONFeedTest, noOpeningSquareBracket) {
  144. std::string json = "\"x\", \"y\" ]";
  145. testInvalidRead(json);
  146. }
  147. } // end of anonymous namespace.