Commit bfe07f02 authored by Marcin Siodelski's avatar Marcin Siodelski

[3409] Updated Element data structure to hold the file name.

parent 2dbdfeb0
...@@ -41,6 +41,19 @@ const char* const WHITESPACE = " \b\f\n\r\t"; ...@@ -41,6 +41,19 @@ const char* const WHITESPACE = " \b\f\n\r\t";
namespace isc { namespace isc {
namespace data { namespace data {
std::string
Element::Position::str() const {
std::ostringstream ss;
ss << file_ << ":" << line_ << ":" << pos_;
return (ss.str());
}
std::ostream&
operator<<(std::ostream& out, const Element::Position& pos) {
out << pos.str();
return (out);
}
std::string std::string
Element::str() const { Element::str() const {
std::stringstream ss; std::stringstream ss;
...@@ -425,7 +438,7 @@ fromStringstreamNumber(std::istream& in, const std::string& file, ...@@ -425,7 +438,7 @@ fromStringstreamNumber(std::istream& in, const std::string& file,
if (number.find_first_of(".eE") < number.size()) { if (number.find_first_of(".eE") < number.size()) {
try { try {
return (Element::create(boost::lexical_cast<double>(number), return (Element::create(boost::lexical_cast<double>(number),
Element::Position(line, start_pos))); Element::Position(file, line, start_pos)));
} catch (const boost::bad_lexical_cast&) { } catch (const boost::bad_lexical_cast&) {
throwJSONError(std::string("Number overflow: ") + number, throwJSONError(std::string("Number overflow: ") + number,
file, line, start_pos); file, line, start_pos);
...@@ -433,7 +446,7 @@ fromStringstreamNumber(std::istream& in, const std::string& file, ...@@ -433,7 +446,7 @@ fromStringstreamNumber(std::istream& in, const std::string& file,
} else { } else {
try { try {
return (Element::create(boost::lexical_cast<int64_t>(number), return (Element::create(boost::lexical_cast<int64_t>(number),
Element::Position(line, start_pos))); Element::Position(file, line, start_pos)));
} catch (const boost::bad_lexical_cast&) { } catch (const boost::bad_lexical_cast&) {
throwJSONError(std::string("Number overflow: ") + number, file, throwJSONError(std::string("Number overflow: ") + number, file,
line, start_pos); line, start_pos);
...@@ -453,9 +466,11 @@ fromStringstreamBool(std::istream& in, const std::string& file, ...@@ -453,9 +466,11 @@ fromStringstreamBool(std::istream& in, const std::string& file,
const std::string word = wordFromStringstream(in, pos); const std::string word = wordFromStringstream(in, pos);
if (boost::iequals(word, "True")) { if (boost::iequals(word, "True")) {
return (Element::create(true, Element::Position(line, start_pos))); return (Element::create(true, Element::Position(file, line,
start_pos)));
} else if (boost::iequals(word, "False")) { } else if (boost::iequals(word, "False")) {
return (Element::create(false, Element::Position(line, start_pos))); return (Element::create(false, Element::Position(file, line,
start_pos)));
} else { } else {
throwJSONError(std::string("Bad boolean value: ") + word, file, throwJSONError(std::string("Bad boolean value: ") + word, file,
line, start_pos); line, start_pos);
...@@ -473,7 +488,7 @@ fromStringstreamNull(std::istream& in, const std::string& file, ...@@ -473,7 +488,7 @@ fromStringstreamNull(std::istream& in, const std::string& file,
// This will move the pos to the end of the value. // This will move the pos to the end of the value.
const std::string word = wordFromStringstream(in, pos); const std::string word = wordFromStringstream(in, pos);
if (boost::iequals(word, "null")) { if (boost::iequals(word, "null")) {
return (Element::create(Element::Position(line, start_pos))); return (Element::create(Element::Position(file, line, start_pos)));
} else { } else {
throwJSONError(std::string("Bad null value: ") + word, file, throwJSONError(std::string("Bad null value: ") + word, file,
line, start_pos); line, start_pos);
...@@ -490,7 +505,8 @@ fromStringstreamString(std::istream& in, const std::string& file, int& line, ...@@ -490,7 +505,8 @@ fromStringstreamString(std::istream& in, const std::string& file, int& line,
const uint32_t start_pos = pos; const uint32_t start_pos = pos;
// This will move the pos to the end of the value. // This will move the pos to the end of the value.
const std::string string_value = strFromStringstream(in, file, line, pos); const std::string string_value = strFromStringstream(in, file, line, pos);
return (Element::create(string_value, Element::Position(line, start_pos))); return (Element::create(string_value, Element::Position(file, line,
start_pos)));
} }
ElementPtr ElementPtr
...@@ -498,7 +514,7 @@ fromStringstreamList(std::istream& in, const std::string& file, int& line, ...@@ -498,7 +514,7 @@ fromStringstreamList(std::istream& in, const std::string& file, int& line,
int& pos) int& pos)
{ {
int c = 0; int c = 0;
ElementPtr list = Element::createList(Element::Position(line, pos)); ElementPtr list = Element::createList(Element::Position(file, line, pos));
ConstElementPtr cur_list_element; ConstElementPtr cur_list_element;
skipChars(in, WHITESPACE, line, pos); skipChars(in, WHITESPACE, line, pos);
...@@ -519,7 +535,7 @@ ElementPtr ...@@ -519,7 +535,7 @@ ElementPtr
fromStringstreamMap(std::istream& in, const std::string& file, int& line, fromStringstreamMap(std::istream& in, const std::string& file, int& line,
int& pos) int& pos)
{ {
ElementPtr map = Element::createMap(Element::Position(line, pos)); ElementPtr map = Element::createMap(Element::Position(file, line, pos));
skipChars(in, WHITESPACE, line, pos); skipChars(in, WHITESPACE, line, pos);
int c = in.peek(); int c = in.peek();
if (c == EOF) { if (c == EOF) {
......
...@@ -77,8 +77,8 @@ public: ...@@ -77,8 +77,8 @@ public:
/// \brief Represents the position of the data element within a /// \brief Represents the position of the data element within a
/// configuration string. /// configuration string.
/// ///
/// Position comprises a line number and an offset within this line /// Position comprises a file name, line number and an offset within this
/// where the element value starts. For example, if the JSON string is /// line where the element value starts. For example, if the JSON string is
/// ///
/// \code /// \code
/// { "foo": "some string", /// { "foo": "some string",
...@@ -94,26 +94,35 @@ public: ...@@ -94,26 +94,35 @@ public:
/// uint32_t arguments holding line number and position within the line are /// uint32_t arguments holding line number and position within the line are
/// not confused with the @c Element values passed to these functions. /// not confused with the @c Element values passed to these functions.
struct Position { struct Position {
uint32_t line_; ///< Line number. std::string file_; ///< File name.
uint32_t pos_; ///< Position within the line. uint32_t line_; ///< Line number.
uint32_t pos_; ///< Position within the line.
/// \brief Constructor. /// \brief Constructor.
/// ///
/// \param file File name.
/// \param line Line number. /// \param line Line number.
/// \param pos Position within the line. /// \param pos Position within the line.
Position(const uint32_t line, const uint32_t pos) Position(const std::string& file, const uint32_t line,
: line_(line), pos_(pos) { const uint32_t pos)
: file_(file), line_(line), pos_(pos) {
} }
/// \brief Returns the position in the textual format.
///
/// The returned position has the following format: file:line:pos.
std::string str() const;
}; };
/// \brief Returns @c Position object with line_ and pos_ set to 0. /// \brief Returns @c Position object with line_ and pos_ set to 0, and
/// with an empty file name.
/// ///
/// The object containing two zeros is a default for most of the /// The object containing two zeros is a default for most of the
/// methods creating @c Element objects. The returned value is static /// methods creating @c Element objects. The returned value is static
/// so as it is not created everytime the function with the default /// so as it is not created everytime the function with the default
/// position argument is called. /// position argument is called.
static const Position& ZERO_POSITION() { static const Position& ZERO_POSITION() {
static Position position(0, 0); static Position position("", 0, 0);
return (position); return (position);
} }
...@@ -657,6 +666,19 @@ ConstElementPtr removeIdentical(ConstElementPtr a, ConstElementPtr b); ...@@ -657,6 +666,19 @@ ConstElementPtr removeIdentical(ConstElementPtr a, ConstElementPtr b);
/// Raises a TypeError if either ElementPtr is not a MapElement /// Raises a TypeError if either ElementPtr is not a MapElement
void merge(ElementPtr element, ConstElementPtr other); void merge(ElementPtr element, ConstElementPtr other);
///
/// \brief Insert Element::Position as a string into stream.
///
/// This operator converts the \c Element::Position into a string and
/// inserts it into the output stream \c out.
///
/// \param out A \c std::ostream object on which the insertion operation is
/// performed.
/// \param pos The \c Element::Position structure to insert.
/// \return A reference to the same \c std::ostream object referenced by
/// parameter \c out after the insertion operation.
std::ostream& operator<<(std::ostream& out, const Element::Position& pos);
/// ///
/// \brief Insert the Element as a string into stream. /// \brief Insert the Element as a string into stream.
/// ///
......
...@@ -30,6 +30,15 @@ using std::setw; ...@@ -30,6 +30,15 @@ using std::setw;
using std::string; using std::string;
namespace { namespace {
TEST(Position, str) {
Element::Position position("kea.conf", 30, 20);
EXPECT_EQ("kea.conf:30:20", position.str());
Element::Position position2("another.conf", 123, 24);
EXPECT_EQ("another.conf:123:24", position2.str());
}
TEST(Element, type) { TEST(Element, type) {
// this tests checks whether the getType() function returns the // this tests checks whether the getType() function returns the
// correct type // correct type
...@@ -931,22 +940,24 @@ TEST(Element, merge) { ...@@ -931,22 +940,24 @@ TEST(Element, merge) {
} }
TEST(Element, getPosition) { TEST(Element, getPosition) {
std::istringstream ss("{\n"
" \"a\": 2,\n"
" \"b\":true,\n"
" \"cy\": \"a string\",\n"
" \"dyz\": {\n"
"\n"
" \"e\": 3,\n"
" \"f\": null\n"
"\n"
" },\n"
" \"g\": [ 5, 6,\n"
" 7 ]\n"
"}\n");
// Create a JSON string holding different type of values. Some of the // Create a JSON string holding different type of values. Some of the
// values in the config string are not aligned, so as we can check that // values in the config string are not aligned, so as we can check that
// the position is set correctly for the elements. // the position is set correctly for the elements.
ElementPtr top = Element::fromJSON("{\n" ElementPtr top = Element::fromJSON(ss, "kea.conf");
" \"a\": 2,\n"
" \"b\":true,\n"
" \"cy\": \"a string\",\n"
" \"dyz\": {\n"
"\n"
" \"e\": 3,\n"
" \"f\": null\n"
"\n"
" },\n"
" \"g\": [ 5, 6,\n"
" 7 ]\n"
"}\n");
ASSERT_TRUE(top); ASSERT_TRUE(top);
// Element "a" // Element "a"
...@@ -954,36 +965,42 @@ TEST(Element, getPosition) { ...@@ -954,36 +965,42 @@ TEST(Element, getPosition) {
ASSERT_TRUE(level1_el); ASSERT_TRUE(level1_el);
EXPECT_EQ(2, level1_el->getPosition().line_); EXPECT_EQ(2, level1_el->getPosition().line_);
EXPECT_EQ(11, level1_el->getPosition().pos_); EXPECT_EQ(11, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "b" // Element "b"
level1_el = top->get("b"); level1_el = top->get("b");
ASSERT_TRUE(level1_el); ASSERT_TRUE(level1_el);
EXPECT_EQ(3, level1_el->getPosition().line_); EXPECT_EQ(3, level1_el->getPosition().line_);
EXPECT_EQ(9, level1_el->getPosition().pos_); EXPECT_EQ(9, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "cy" // Element "cy"
level1_el = top->get("cy"); level1_el = top->get("cy");
ASSERT_TRUE(level1_el); ASSERT_TRUE(level1_el);
EXPECT_EQ(4, level1_el->getPosition().line_); EXPECT_EQ(4, level1_el->getPosition().line_);
EXPECT_EQ(11, level1_el->getPosition().pos_); EXPECT_EQ(11, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "dyz" // Element "dyz"
level1_el = top->get("dyz"); level1_el = top->get("dyz");
ASSERT_TRUE(level1_el); ASSERT_TRUE(level1_el);
EXPECT_EQ(5, level1_el->getPosition().line_); EXPECT_EQ(5, level1_el->getPosition().line_);
EXPECT_EQ(13, level1_el->getPosition().pos_); EXPECT_EQ(13, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "e" is a sub element of "dyz". // Element "e" is a sub element of "dyz".
ConstElementPtr level2_el = level1_el->get("e"); ConstElementPtr level2_el = level1_el->get("e");
ASSERT_TRUE(level2_el); ASSERT_TRUE(level2_el);
EXPECT_EQ(7, level2_el->getPosition().line_); EXPECT_EQ(7, level2_el->getPosition().line_);
EXPECT_EQ(12, level2_el->getPosition().pos_); EXPECT_EQ(12, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Element "f" is also a sub element of "dyz" // Element "f" is also a sub element of "dyz"
level2_el = level1_el->get("f"); level2_el = level1_el->get("f");
ASSERT_TRUE(level2_el); ASSERT_TRUE(level2_el);
EXPECT_EQ(8, level2_el->getPosition().line_); EXPECT_EQ(8, level2_el->getPosition().line_);
EXPECT_EQ(14, level2_el->getPosition().pos_); EXPECT_EQ(14, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Element "g" is a list. // Element "g" is a list.
level1_el = top->get("g"); level1_el = top->get("g");
...@@ -991,24 +1008,28 @@ TEST(Element, getPosition) { ...@@ -991,24 +1008,28 @@ TEST(Element, getPosition) {
EXPECT_EQ(11, level1_el->getPosition().line_); EXPECT_EQ(11, level1_el->getPosition().line_);
// Position indicates where the values start (excluding the "[" character)" // Position indicates where the values start (excluding the "[" character)"
EXPECT_EQ(11, level1_el->getPosition().pos_); EXPECT_EQ(11, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// First element from the list. // First element from the list.
level2_el = level1_el->get(0); level2_el = level1_el->get(0);
ASSERT_TRUE(level2_el); ASSERT_TRUE(level2_el);
EXPECT_EQ(11, level2_el->getPosition().line_); EXPECT_EQ(11, level2_el->getPosition().line_);
EXPECT_EQ(12, level2_el->getPosition().pos_); EXPECT_EQ(12, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Second element from the list. // Second element from the list.
level2_el = level1_el->get(1); level2_el = level1_el->get(1);
ASSERT_TRUE(level2_el); ASSERT_TRUE(level2_el);
EXPECT_EQ(11, level2_el->getPosition().line_); EXPECT_EQ(11, level2_el->getPosition().line_);
EXPECT_EQ(15, level2_el->getPosition().pos_); EXPECT_EQ(15, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Third element from the list. // Third element from the list.
level2_el = level1_el->get(2); level2_el = level1_el->get(2);
ASSERT_TRUE(level2_el); ASSERT_TRUE(level2_el);
EXPECT_EQ(12, level2_el->getPosition().line_); EXPECT_EQ(12, level2_el->getPosition().line_);
EXPECT_EQ(14, level2_el->getPosition().pos_); EXPECT_EQ(14, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment