Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions source/parser/config_reader/config_node_.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

namespace sim {

ConfigNode::ConfigNode(YAML::Node a_node, std::optional<std::string> a_name)
: m_node(std::move(a_node)), m_name(std::move(a_name)) {
ConfigNode::ConfigNode(
const YAML::Node& a_node, const std::optional<std::string>& a_name,
const std::optional<std::filesystem::path>& a_config_path)
: m_node(std::move(a_node)),
m_name(std::move(a_name)),
m_config_path(std::move(a_config_path)) {
if (!m_node) {
throw std::runtime_error(
"Can not construct ConfigNode: given YAML::Node is "
Expand All @@ -27,11 +31,16 @@ const std::string& ConfigNode::get_name_or_throw() const {
std::runtime_error ConfigNode::create_parsing_error(
std::string_view error) const {
std::stringstream ss;
ss << "Error while parsing node " << *this << ":\n";
ss << "Error while parsing node " << *this;
Comment thread
S1mpotyaga marked this conversation as resolved.
Outdated
ss << error << '\n';
return std::runtime_error(ss.str());
}

const std::optional<std::filesystem::path>& ConfigNode::get_config_path()
const {
return m_config_path;
}

std::ostream& operator<<(std::ostream& out, const ConfigNode& node) {
YAML::Mark mark = node.m_node.Mark();
if (node.m_name) {
Expand All @@ -40,6 +49,11 @@ std::ostream& operator<<(std::ostream& out, const ConfigNode& node) {
out << "without name";
}
if (mark.line >= 0 && mark.column >= 0) {
if (node.m_config_path.has_value()) {
out << "config path: " << node.m_config_path.value().string();
} else {
out << "config path: null";
}
out << " at line " << mark.line + 1 << " column " << mark.column + 1;
} else {
out << " at unknown location";
Expand All @@ -65,7 +79,9 @@ const std::string& ConfigNode::Tag() const noexcept { return m_node.Tag(); }
// size/iterator
std::size_t ConfigNode::size() const noexcept { return m_node.size(); }

ConfigNode::Iterator::Iterator(YAML::const_iterator a_it) : m_iterator(a_it) {}
ConfigNode::Iterator::Iterator(YAML::const_iterator a_it,
const ConfigNode& a_owner)
: m_iterator(a_it), m_owner(a_owner) {}

ConfigNode::Iterator& ConfigNode::Iterator::operator++() {
++m_iterator;
Expand Down Expand Up @@ -97,7 +113,7 @@ ConfigNode ConfigNode::Iterator::operator*() const {
// - value_1
// ...
YAML::Node node = *m_iterator;
return ConfigNode(node, std::nullopt);
return ConfigNode(node, std::nullopt, m_owner.get_config_path());
} else {
// iterator goes over "named" nodes like
// list:
Expand All @@ -112,35 +128,37 @@ ConfigNode ConfigNode::Iterator::operator*() const {
"nodes are invalid");
}
std::string key = key_node.as<std::string>();
return ConfigNode(value_node, key);
return ConfigNode(value_node, key, m_owner.get_config_path());
}
}

ConfigNode::Iterator ConfigNode::begin() const {
return Iterator(m_node.begin());
return Iterator(m_node.begin(), *this);
}

ConfigNode::Iterator ConfigNode::end() const { return Iterator(m_node.end()); }
ConfigNode::Iterator ConfigNode::end() const {
return Iterator(m_node.end(), *this);
}

ConfigNodeExpected ConfigNode::operator[](std::string_view key) const {
const YAML::Node child_node = m_node[key];
if (!child_node) {
std::stringstream ss;
ss << "Key error: node " << *this << ":\n";
ss << "Key error: node " << *this;
Comment thread
S1mpotyaga marked this conversation as resolved.
Outdated
ss << "does not have key `" << key << '`';
return std::unexpected(ss.str());
}
if (child_node.IsNull()) {
// if node is null, its name should be empty
return ConfigNodeExpected(
ConfigNode(std::move(child_node), std::nullopt));
ConfigNode(std::move(child_node), std::nullopt, m_config_path));
}
return ConfigNodeExpected(
ConfigNode(std::move(child_node), std::string(key)));
ConfigNode(std::move(child_node), std::string(key), m_config_path));
};

ConfigNode load_file(std::filesystem::path path) {
return ConfigNode(YAML::LoadFile(path.string()));
return ConfigNode(YAML::LoadFile(path.string()), std::nullopt, path);
}

} // namespace sim
14 changes: 11 additions & 3 deletions source/parser/config_reader/config_node_.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ class ConfigNodeExpected;

class ConfigNode {
public:
explicit ConfigNode(YAML::Node a_node = YAML::Node(YAML::NodeType::Null),
std::optional<std::string> a_name = std::nullopt);
explicit ConfigNode(
const YAML::Node& a_node = YAML::Node(YAML::NodeType::Null),
const std::optional<std::string>& a_name = std::nullopt,
const std::optional<std::filesystem::path>& a_config_path =
std::nullopt);

// Some functional over yaml-cpp

Expand All @@ -28,6 +31,8 @@ class ConfigNode {
[[nodiscard]] std::runtime_error create_parsing_error(
std::string_view error) const;

const std::optional<std::filesystem::path>& get_config_path() const;

friend std::ostream& operator<<(std::ostream& out, const ConfigNode& node);

std::string to_string() const;
Expand Down Expand Up @@ -64,7 +69,7 @@ class ConfigNode {

class Iterator {
public:
Iterator(YAML::const_iterator a_it);
Iterator(YAML::const_iterator a_it, const ConfigNode& a_owner);

Iterator& operator++();

Expand All @@ -79,6 +84,7 @@ class ConfigNode {
private:
// Invariant: m_stacktrace_node is not null
YAML::const_iterator m_iterator;
const ConfigNode& m_owner;
};

Iterator begin() const;
Expand All @@ -92,6 +98,8 @@ class ConfigNode {
const YAML::Node m_node;

const std::optional<std::string> m_name;

const std::optional<std::filesystem::path> m_config_path;
};

ConfigNode load_file(std::filesystem::path path);
Expand Down
5 changes: 5 additions & 0 deletions source/parser/config_reader/config_node_with_preset_.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ std::ostream& operator<<(std::ostream& out, const ConfigNodeWithPreset& node) {
return out << node.get_node();
}

const std::optional<std::filesystem::path>&
ConfigNodeWithPreset::get_config_path() const {
return m_node.get_config_path();
}

const std::string& ConfigNodeWithPreset::get_name_or_throw() const {
return m_node.get_name_or_throw();
}
Expand Down
2 changes: 2 additions & 0 deletions source/parser/config_reader/config_node_with_preset_.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class ConfigNodeWithPreset {
return as<T>().value_or_throw();
}

const std::optional<std::filesystem::path>& get_config_path() const;

[[nodiscard]] const std::string& get_name_or_throw() const;

const std::optional<ConfigNode> get_presets_node() const noexcept;
Expand Down
83 changes: 83 additions & 0 deletions test/parser/config_reader/check_paths.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include <gtest/gtest.h>

#include "parser/config_reader/config_node.hpp"
#include "parser/config_reader/config_node_with_preset.hpp"

namespace sim {
namespace test2 {

TEST(PathConfigNode, NoPath) {
YAML::Node root = YAML::Load(R"(
a:
b:
c: 1
)");
ConfigNode node(root, std::nullopt);
auto a = node["a"].value();
auto b = a["b"].value();
auto c = b["c"].value();

ASSERT_EQ(b.get_config_path(), std::nullopt);
ASSERT_EQ(c.get_config_path(), std::nullopt);
}

TEST(PathConfigNode, PathExists) {
std::filesystem::path check_path =
std::filesystem::path(__FILE__).parent_path() / "check_paths.yml";
ConfigNode node = load_file(check_path);
auto result = node["connections"]["connection-1->1"].value();
printf("path: %s\n", check_path);
printf("result path: %s\n", result.get_config_path());
fflush(stdout);
Comment thread
S1mpotyaga marked this conversation as resolved.
Outdated
ASSERT_EQ(result.get_config_path(), check_path);
}

TEST(PathConfigNodeWithPreset, NoPath) {
YAML::Node root = YAML::Load(R"(
a:
b:
c: 1
)");
ConfigNode tmp(root, std::nullopt, "root");
ConfigNodeWithPreset node(tmp);
auto a = node["a"].value();
auto b = a["b"].value();
auto c = b["c"].value();

ASSERT_EQ(b.get_config_path(), "root");
ASSERT_EQ(c.get_config_path(), "root");
}

TEST(PathConfigNodeWithPreset, PathExists) {
std::filesystem::path bus_topology_path =
std::filesystem::path(__FILE__).parent_path() / "check_paths.yml";
ConfigNodeWithPreset node = load_file_with_presets(bus_topology_path);
auto result = node["connections"]["connection-1->1"].value();

ASSERT_EQ(result.get_config_path(), bus_topology_path);
}

TEST(PathConfigNode, IterateMap) {
std::filesystem::path check_path =
std::filesystem::path(__FILE__).parent_path() / "iterate_map.yml";

ConfigNode node = load_file(check_path);
auto map = node["map"].value();
for (auto it : map) {
ASSERT_EQ(it.get_config_path(), check_path);
}
}

TEST(PathConfigNode, IterateList) {
std::filesystem::path check_path =
std::filesystem::path(__FILE__).parent_path() / "iterate_list.yml";

ConfigNode node = load_file(check_path);
auto list = node["list"].value();
for (auto it : list) {
ASSERT_EQ(it.get_config_path(), check_path);
}
}

} // namespace test2
} // namespace sim
21 changes: 21 additions & 0 deletions test/parser/config_reader/check_paths.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
topology_config_path: "check_paths.yml"
Comment thread
S1mpotyaga marked this conversation as resolved.
Outdated

presets:
default-connection:
type: mplb-connection
mplb:
type: single-cc
packet-size: 1500B
cc:
type: tahoe
path-chooser:
type: round-robin
flows:
flow:
type: tcp

connections:
connection-1->1:
preset-name: default-connection
sender_id: sender1
receiver_id: receiver1
4 changes: 4 additions & 0 deletions test/parser/config_reader/iterate_list.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
list:
- a: {}
- b: {}
- c: {}
4 changes: 4 additions & 0 deletions test/parser/config_reader/iterate_map.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
map:
a: {}
b: {}
c: {}
Loading