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";
namespace isc {
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
Element::str() const {
std::stringstream ss;
......@@ -425,7 +438,7 @@ fromStringstreamNumber(std::istream& in, const std::string& file,
if (number.find_first_of(".eE") < number.size()) {
try {
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&) {
throwJSONError(std::string("Number overflow: ") + number,
file, line, start_pos);
......@@ -433,7 +446,7 @@ fromStringstreamNumber(std::istream& in, const std::string& file,
} else {
try {
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&) {
throwJSONError(std::string("Number overflow: ") + number, file,
line, start_pos);
......@@ -453,9 +466,11 @@ fromStringstreamBool(std::istream& in, const std::string& file,
const std::string word = wordFromStringstream(in, pos);
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")) {
return (Element::create(false, Element::Position(line, start_pos)));
return (Element::create(false, Element::Position(file, line,
start_pos)));
} else {
throwJSONError(std::string("Bad boolean value: ") + word, file,
line, start_pos);
......@@ -473,7 +488,7 @@ fromStringstreamNull(std::istream& in, const std::string& file,
// This will move the pos to the end of the value.
const std::string word = wordFromStringstream(in, pos);
if (boost::iequals(word, "null")) {
return (Element::create(Element::Position(line, start_pos)));
return (Element::create(Element::Position(file, line, start_pos)));
} else {
throwJSONError(std::string("Bad null value: ") + word, file,
line, start_pos);
......@@ -490,7 +505,8 @@ fromStringstreamString(std::istream& in, const std::string& file, int& line,
const uint32_t start_pos = pos;
// This will move the pos to the end of the value.
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
......@@ -498,7 +514,7 @@ fromStringstreamList(std::istream& in, const std::string& file, int& line,
int& pos)
{
int c = 0;
ElementPtr list = Element::createList(Element::Position(line, pos));
ElementPtr list = Element::createList(Element::Position(file, line, pos));
ConstElementPtr cur_list_element;
skipChars(in, WHITESPACE, line, pos);
......@@ -519,7 +535,7 @@ ElementPtr
fromStringstreamMap(std::istream& in, const std::string& file, int& line,
int& pos)
{
ElementPtr map = Element::createMap(Element::Position(line, pos));
ElementPtr map = Element::createMap(Element::Position(file, line, pos));
skipChars(in, WHITESPACE, line, pos);
int c = in.peek();
if (c == EOF) {
......
......@@ -77,8 +77,8 @@ public:
/// \brief Represents the position of the data element within a
/// configuration string.
///
/// Position comprises a line number and an offset within this line
/// where the element value starts. For example, if the JSON string is
/// Position comprises a file name, line number and an offset within this
/// line where the element value starts. For example, if the JSON string is
///
/// \code
/// { "foo": "some string",
......@@ -94,26 +94,35 @@ public:
/// uint32_t arguments holding line number and position within the line are
/// not confused with the @c Element values passed to these functions.
struct Position {
std::string file_; ///< File name.
uint32_t line_; ///< Line number.
uint32_t pos_; ///< Position within the line.
/// \brief Constructor.
///
/// \param file File name.
/// \param line Line number.
/// \param pos Position within the line.
Position(const uint32_t line, const uint32_t pos)
: line_(line), pos_(pos) {
Position(const std::string& file, const uint32_t line,
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
/// methods creating @c Element objects. The returned value is static
/// so as it is not created everytime the function with the default
/// position argument is called.
static const Position& ZERO_POSITION() {
static Position position(0, 0);
static Position position("", 0, 0);
return (position);
}
......@@ -657,6 +666,19 @@ ConstElementPtr removeIdentical(ConstElementPtr a, ConstElementPtr b);
/// Raises a TypeError if either ElementPtr is not a MapElement
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.
///
......
......@@ -30,6 +30,15 @@ using std::setw;
using std::string;
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) {
// this tests checks whether the getType() function returns the
// correct type
......@@ -931,10 +940,7 @@ TEST(Element, merge) {
}
TEST(Element, getPosition) {
// 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
// the position is set correctly for the elements.
ElementPtr top = Element::fromJSON("{\n"
std::istringstream ss("{\n"
" \"a\": 2,\n"
" \"b\":true,\n"
" \"cy\": \"a string\",\n"
......@@ -947,6 +953,11 @@ TEST(Element, getPosition) {
" \"g\": [ 5, 6,\n"
" 7 ]\n"
"}\n");
// 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
// the position is set correctly for the elements.
ElementPtr top = Element::fromJSON(ss, "kea.conf");
ASSERT_TRUE(top);
// Element "a"
......@@ -954,36 +965,42 @@ TEST(Element, getPosition) {
ASSERT_TRUE(level1_el);
EXPECT_EQ(2, level1_el->getPosition().line_);
EXPECT_EQ(11, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "b"
level1_el = top->get("b");
ASSERT_TRUE(level1_el);
EXPECT_EQ(3, level1_el->getPosition().line_);
EXPECT_EQ(9, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "cy"
level1_el = top->get("cy");
ASSERT_TRUE(level1_el);
EXPECT_EQ(4, level1_el->getPosition().line_);
EXPECT_EQ(11, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "dyz"
level1_el = top->get("dyz");
ASSERT_TRUE(level1_el);
EXPECT_EQ(5, level1_el->getPosition().line_);
EXPECT_EQ(13, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// Element "e" is a sub element of "dyz".
ConstElementPtr level2_el = level1_el->get("e");
ASSERT_TRUE(level2_el);
EXPECT_EQ(7, level2_el->getPosition().line_);
EXPECT_EQ(12, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Element "f" is also a sub element of "dyz"
level2_el = level1_el->get("f");
ASSERT_TRUE(level2_el);
EXPECT_EQ(8, level2_el->getPosition().line_);
EXPECT_EQ(14, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Element "g" is a list.
level1_el = top->get("g");
......@@ -991,24 +1008,28 @@ TEST(Element, getPosition) {
EXPECT_EQ(11, level1_el->getPosition().line_);
// Position indicates where the values start (excluding the "[" character)"
EXPECT_EQ(11, level1_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level1_el->getPosition().file_);
// First element from the list.
level2_el = level1_el->get(0);
ASSERT_TRUE(level2_el);
EXPECT_EQ(11, level2_el->getPosition().line_);
EXPECT_EQ(12, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Second element from the list.
level2_el = level1_el->get(1);
ASSERT_TRUE(level2_el);
EXPECT_EQ(11, level2_el->getPosition().line_);
EXPECT_EQ(15, level2_el->getPosition().pos_);
EXPECT_EQ("kea.conf", level2_el->getPosition().file_);
// Third element from the list.
level2_el = level1_el->get(2);
ASSERT_TRUE(level2_el);
EXPECT_EQ(12, level2_el->getPosition().line_);
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