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;
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);
} 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);
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);
// 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);
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
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);
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) {
/// \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",
/// 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 {
- uint32_t line_; ///< Line number.
- uint32_t pos_; ///< Position within the line.
+ 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);
}
/// 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.
///
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
}
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
// 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"
- " \"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");
+ ElementPtr top = Element::fromJSON(ss, "kea.conf");
ASSERT_TRUE(top);
// Element "a"
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");
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_);
}