From ea6d2f3807d8dfddc0e495eb92de61495e477d6d Mon Sep 17 00:00:00 2001 From: Przemyslaw Rokosz Date: Thu, 29 Aug 2024 22:25:16 +0200 Subject: [PATCH] gradient improvements (#28) --- .vscode/settings.json | 3 +- src/manager.cpp | 2 +- src/telemetry/CMakeLists.txt | 2 - src/telemetry/datapoint.h | 4 +- src/telemetry/field.cpp | 1 + src/telemetry/field.h | 1 + src/telemetry/fit_parser.cpp | 32 ++--- src/telemetry/fit_parser.h | 6 +- src/telemetry/parser.cpp | 206 ++++++++++++++++++----------- src/telemetry/parser.h | 21 ++- src/telemetry/telemetry.cpp | 22 +-- src/telemetry/telemetry.h | 10 +- src/telemetry/value.h | 17 --- src/utils/argument_parser.cpp | 2 +- src/video/generator.cpp | 2 +- test/telemetry/fit_parser_test.cpp | 14 +- test/testdata/layout.xml | 19 ++- test/utils/logging/logger_test.cpp | 2 - 18 files changed, 206 insertions(+), 160 deletions(-) delete mode 100644 src/telemetry/value.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 609cf2f..f8262bc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -90,6 +90,7 @@ "typeindex": "cpp", "util": "cpp", "export": "cpp", - "assert": "cpp" + "assert": "cpp", + "ranges": "cpp" } } \ No newline at end of file diff --git a/src/manager.cpp b/src/manager.cpp index 8eba337..e68fafd 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -68,7 +68,7 @@ void manager::run() log.info("Telemetry processing time: {:.3f} s", std::chrono::duration_cast(t2 - t1).count()/1000.0); - log.info("Overlay pre-setup time: {:.3f} s", + log.info("Overlay setup time: {:.3f} s", std::chrono::duration_cast(t3 - t2).count()/1000.0); log.info("Video generation time: {:.3f} s", std::chrono::duration_cast(t4 - t3).count()/1000.0); diff --git a/src/telemetry/CMakeLists.txt b/src/telemetry/CMakeLists.txt index 87134a7..2005320 100644 --- a/src/telemetry/CMakeLists.txt +++ b/src/telemetry/CMakeLists.txt @@ -9,9 +9,7 @@ target_sources(vgraph_lib PUBLIC datapoint.h field.h - value.h parser.h fit_parser.h telemetry.h - ) diff --git a/src/telemetry/datapoint.h b/src/telemetry/datapoint.h index f375f0b..544130b 100644 --- a/src/telemetry/datapoint.h +++ b/src/telemetry/datapoint.h @@ -2,7 +2,6 @@ #define DATAPOINT_H #include "field.h" -#include "value.h" #include #include @@ -17,7 +16,8 @@ struct datapoint { std::map fields; }; -using datapoint_sequence = std::vector>; +using datapoint_ptr = std::shared_ptr; +using datapoint_seq = std::vector; } // namespace telemetry } // namespace vgraph diff --git a/src/telemetry/field.cpp b/src/telemetry/field.cpp index 878b11d..b61f9cd 100644 --- a/src/telemetry/field.cpp +++ b/src/telemetry/field.cpp @@ -19,6 +19,7 @@ namespace consts { {"power", EField::Power}, {"power3s", EField::Power3s}, {"power10s", EField::Power10s}, + {"power30s", EField::Power30s}, {"respiration_rate", EField::RespirationRate}, {"heart_rate", EField::HeartRate}, {"grit", EField::Grit}, diff --git a/src/telemetry/field.h b/src/telemetry/field.h index 05cb84b..179791b 100644 --- a/src/telemetry/field.h +++ b/src/telemetry/field.h @@ -21,6 +21,7 @@ enum class EField Power, Power3s, Power10s, + Power30s, RespirationRate, HeartRate, Grit, diff --git a/src/telemetry/fit_parser.cpp b/src/telemetry/fit_parser.cpp index 376611e..dabf056 100644 --- a/src/telemetry/fit_parser.cpp +++ b/src/telemetry/fit_parser.cpp @@ -9,18 +9,18 @@ namespace consts { const unsigned int garmin_epoch = 631065600; // seconds since 1970-01-01 00:00:00 to 1989-12-31 00:00:00 } -std::shared_ptr fit_parser::parse_impl(const std::filesystem::path& path) +datapoint_seq fit_parser::parse_impl(const std::filesystem::path& path) { log.info("Decoding FIT file {}", path.string()); if (!std::filesystem::exists(path)) { log.error("File does not exist: {}", path.string()); - return nullptr; + return {}; } if (path.extension() != ".fit") { log.error("File extension is not .fit: {}", path.string()); - return nullptr; + return {}; } std::fstream file; @@ -28,18 +28,18 @@ std::shared_ptr fit_parser::parse_impl(const std::filesystem if (!file.is_open()) { log.error("Error opening file {}", path.string()); - return nullptr; + return {}; } - std::shared_ptr ptr = parse_filestream(file); - if (ptr) { + datapoint_seq seq(parse_filestream(file)); + if (!seq.empty()) { log.info("Decoded FIT file {}", path.string()); } - return ptr; + return std::move(seq); } -std::shared_ptr fit_parser::parse_filestream(std::fstream& file) +datapoint_seq fit_parser::parse_filestream(std::fstream& file) { fit::Decode decode; if (!decode.CheckIntegrity(file)) { @@ -49,8 +49,8 @@ std::shared_ptr fit_parser::parse_filestream(std::fstream& f using std::placeholders::_1; fit::MesgBroadcaster msg_broadcaster; - std::shared_ptr seq = std::make_shared(); - listener listen(std::bind(&fit_parser::handle_record, this, _1, seq)); + datapoint_seq seq; + listener listen(std::bind(&fit_parser::handle_record, this, _1, std::ref(seq))); msg_broadcaster.AddListener(listen); @@ -61,20 +61,20 @@ std::shared_ptr fit_parser::parse_filestream(std::fstream& f catch (const fit::RuntimeException& e) { log.error("Exception decoding file: {}", e.what()); - return nullptr; + return {}; } catch (...) { log.error("Exception decoding file"); - return nullptr; + return {}; } - return seq; + return std::move(seq); } -void fit_parser::handle_record(fit::RecordMesg& record, std::shared_ptr out_seq) +void fit_parser::handle_record(fit::RecordMesg& record, datapoint_seq& out_seq) { - std::shared_ptr data = std::make_shared(); + datapoint_ptr data = std::make_shared(); if (record.IsTimestampValid()) data->timestamp = parse_timestamp(record.GetTimestamp()); @@ -107,7 +107,7 @@ void fit_parser::handle_record(fit::RecordMesg& record, std::shared_ptrfields[EField::Flow] = record.GetFlow(); - out_seq->push_back(data); + out_seq.push_back(std::move(data)); } // timestamp: seconds since UTC 00:00 Dec 31 1989 diff --git a/src/telemetry/fit_parser.h b/src/telemetry/fit_parser.h index d0a05cd..0b3279e 100644 --- a/src/telemetry/fit_parser.h +++ b/src/telemetry/fit_parser.h @@ -22,9 +22,9 @@ class fit_parser : public parser { private: utils::logging::logger log{"fit_parser"}; - std::shared_ptr parse_impl(const std::filesystem::path& path) override; - std::shared_ptr parse_filestream(std::fstream& file); - void handle_record(fit::RecordMesg& record, std::shared_ptr out_seq); + datapoint_seq parse_impl(const std::filesystem::path& path) override; + datapoint_seq parse_filestream(std::fstream& file); + void handle_record(fit::RecordMesg& record, datapoint_seq& out_seq); std::chrono::time_point parse_timestamp(FIT_UINT32 timestamp); class listener : public fit::RecordMesgListener diff --git a/src/telemetry/parser.cpp b/src/telemetry/parser.cpp index 5fbc081..fa66459 100644 --- a/src/telemetry/parser.cpp +++ b/src/telemetry/parser.cpp @@ -1,10 +1,27 @@ #include "parser.h" #include "utils/geo.h" +#include +#include +#include + namespace vgraph { namespace telemetry { namespace consts { double min_dist_gradient(10);// meters in 10s + + // gradient windows in meters + int gradient_window_behind(15); + int gradient_window_ahead(15); + int gradient_cap_window_behind(gradient_window_behind*4); + int gradient_cap_window_ahead(gradient_window_ahead*4); +} +namespace helper { + int km_to_m(double km) + { + return static_cast(std::round(km*1000)); + } + } struct stats { @@ -13,7 +30,7 @@ struct stats { double avg = 0; int count = 0; - void add(std::shared_ptr& data, EField field) { + void add(const datapoint_ptr& data, EField field) { if (data->fields.contains(field)) { double val = data->fields.at(field); @@ -24,122 +41,109 @@ struct stats { } }; -std::shared_ptr parser::parse(const std::filesystem::path& path) +datapoint_seq parser::parse(const std::filesystem::path& path) { - std::shared_ptr seq = parse_impl(path); + datapoint_seq seq = parse_impl(path); - if (seq) { + if (!seq.empty()) { update_calculated_fields(seq); print_stats(seq); } - return seq; + return std::move(seq); } -void parser::update_calculated_fields(std::shared_ptr& seq) +void parser::update_calculated_fields(datapoint_seq& seq) { log.info("Calculating additional data fields"); - double total_dist = 0; - - std::shared_ptr first = seq->front(); + datapoint_ptr first = seq.front(); + datapoint_ptr last = first; - std::deque> last10s; - std::deque> last3s; - std::shared_ptr last; + double track_dist = 0; + std::multimap seq_by_dist; - for (std::shared_ptr& data : *seq) { - // handling of moving time windows - last10s.push_back(data); - last3s.push_back(data); + for (auto it = seq.begin(); it != seq.end(); it++) { + datapoint_ptr& data = *it; - if (last10s.size() > 10) { - last10s.pop_front(); - } - if (last3s.size() > 3) { - last3s.pop_front(); - } + // track distance calculation + track_dist += utils::geo_distance( + last->fields.at(EField::Latitude), last->fields.at(EField::Longitude), + data->fields.at(EField::Latitude), data->fields.at(EField::Longitude)) / 1000.0; - // handling track distance - if (last) { - total_dist += utils::geo_distance( - last->fields.at(EField::Latitude), - last->fields.at(EField::Longitude), - data->fields.at(EField::Latitude), - data->fields.at(EField::Longitude)) / 1000.0; - } + // set track distance field + data->fields[EField::TrackDistance] = track_dist; - // handling distance if not parsed from file - data->fields[EField::TrackDistance] = total_dist; + // set distance field from track distance if not parsed from file if (!data->fields.contains(EField::Distance)) { - data->fields[EField::Distance] = total_dist; + data->fields[EField::Distance] = track_dist; } - // handling average power and smoothed altitude - std::optional power3s = field_avg(last3s, EField::Power); - if (power3s) { - data->fields[EField::Power3s] = *power3s; - } - std::optional power10s = field_avg(last10s, EField::Power); - if (power10s) { - data->fields[EField::Power10s] = *power10s; - } - std::optional s_alt = field_avg(last10s, EField::Altitude); - if (s_alt) { - data->fields[EField::SmoothAltitude] = *s_alt; - } - - // handling speed if not parsed from file if (!data->fields.contains(EField::Speed)) { - double hours = std::chrono::duration_cast((data->timestamp - first->timestamp)).count() / 3600.0; - data->fields[EField::Speed] = data->fields[EField::Distance] / hours; - } + double h = std::chrono::duration_cast((data->timestamp - last->timestamp)).count() / 3600; + double km = data->fields.at(EField::Distance) - last->fields.at(EField::Distance); - bool calculate_gradient = !data->fields.contains(EField::Gradient) && - data->fields.contains(EField::SmoothAltitude) && - data->fields.contains(EField::TrackDistance); - if (calculate_gradient) { - double dist = 1000 * (last10s.back()->fields[EField::TrackDistance] - last10s.front()->fields[EField::TrackDistance]); - if (dist > consts::min_dist_gradient) { - double elev = last10s.back()->fields[EField::SmoothAltitude] - last10s.front()->fields[EField::SmoothAltitude]; - data->fields[EField::Gradient] = utils::gradient(dist, elev); - } + data->fields[EField::Speed] = km / h; } + // setting time averaged fields + set_if_ok(data, EField::Power3s, field_avg(std::make_reverse_iterator(it+1), seq.rend(), EField::Power, 3)); + set_if_ok(data, EField::Power10s, field_avg(std::make_reverse_iterator(it+1), seq.rend(), EField::Power, 10)); + set_if_ok(data, EField::Power30s, field_avg(std::make_reverse_iterator(it+1), seq.rend(), EField::Power, 30)); + set_if_ok(data, EField::SmoothAltitude, field_avg(std::make_reverse_iterator(it+1), seq.rend(), EField::Altitude, 10)); + + // store point into sequence by distance + seq_by_dist.insert(std::make_pair(helper::km_to_m(data->fields.at(EField::Distance)), data)); + + // store last point last = data; } + + log.info("Calculating gradients"); + for (datapoint_ptr& data : seq) { + if (!data->fields.contains(EField::Gradient) && data->fields.contains(EField::SmoothAltitude)) { + int dst_m = helper::km_to_m(data->fields.at(EField::Distance)); + double grad = gradient_between(seq_by_dist, dst_m - consts::gradient_window_behind, dst_m + consts::gradient_window_ahead); + double cap = gradient_between(seq_by_dist, dst_m - consts::gradient_cap_window_behind, dst_m + consts::gradient_cap_window_ahead); + + if (std::abs(grad) > std::abs(cap)) { + grad = grad*cap > 0 ? cap : -cap; + // convert cap to gradient sign if needed + } + + data->fields[EField::Gradient] = grad*100;//convert to pct + } + } } -void parser::print_stats(std::shared_ptr& seq) +void parser::print_stats(datapoint_seq& seq) { stats altitude; stats gradient; stats speed; stats power; stats cadence; - stats heartrate; stats respiration; - for (auto data : *seq) { + for (auto data : seq) { altitude.add(data, EField::Altitude); gradient.add(data, EField::Gradient); speed.add(data, EField::Speed); power.add(data, EField::Power); cadence.add(data, EField::Cadence); - heartrate.add(data, EField::HeartRate); respiration.add(data, EField::RespirationRate); } - auto first = seq->front(); - auto last = seq->back(); + const datapoint_ptr& first = seq.front(); + const datapoint_ptr& last = seq.back(); double distance = 0; if (last->fields.contains(EField::Distance)) - distance = last->fields[EField::Distance]; + distance = last->fields.at(EField::Distance); double track_distance = 0; if (last->fields.contains(EField::TrackDistance)) - track_distance = last->fields[EField::TrackDistance]; + track_distance = last->fields.at(EField::TrackDistance); auto time = last->timestamp - first->timestamp; double hours = std::chrono::duration_cast((time)).count() / 3600.0; @@ -153,24 +157,70 @@ void parser::print_stats(std::shared_ptr& seq) log.info(" Gradient Min/Avg/Max: {:7.2f} / {:7.2f} / {:7.2f} %", gradient.min, gradient.avg, gradient.max); log.info(" Power Min/Avg/Max: {:7.2f} / {:7.2f} / {:7.2f} W", power.min, power.avg, power.max); log.info(" Cadence Min/Avg/Max: {:7.2f} / {:7.2f} / {:7.2f} rpm", cadence.min, cadence.avg, cadence.max); - log.info(" Heart Rate Min/Avg/Max: {:7.2f} / {:7.2f} / {:7.2f} bpm", heartrate.min, heartrate.avg, heartrate.max); log.info("Respiration Rate Min/Avg/Max: {:7.2f} / {:7.2f} / {:7.2f} brpm", respiration.min, respiration.avg, respiration.max); } -std::optional parser::field_avg(std::deque> points, EField field) +double parser::gradient_between(const std::multimap& dist_points, int dist_a, int dist_b) { - bool ok = false; - double sum = 0.0; + if (dist_a >= dist_b) { + return 0; + } - for (std::shared_ptr& data : points) { - if (data->fields.contains(field)) { - sum += data->fields.at(field); - ok = true; + double alt_a = get_by_distance(dist_points, dist_a, EField::SmoothAltitude); + double alt_b = get_by_distance(dist_points, dist_b, EField::SmoothAltitude); + + double grad = (alt_b - alt_a)/(dist_b - dist_a); + return grad; +} + +double parser::get_by_distance(const std::multimap& dist_points, int dist, EField field, bool last) +{ + std::vector res; + + double ret = 0; + + if (dist_points.contains(dist)) { + auto [it1, it2] = dist_points.equal_range(dist); + + if (last) { + ret = (--it2)->second->fields.at(field); + } else { + ret = it1->second->fields.at(field); + } + } else { + auto it = dist_points.upper_bound(dist); + + if (it == dist_points.end()) { + ret = (--it)->second->fields.at(field); + } else { + ret = it->second->fields.at(field); + } + } + + return ret; +} + +void parser::set_if_ok(datapoint_ptr& data, EField field, std::optional value) +{ + if (value) { + data->fields[field] = *value; + } +} + +std::optional parser::field_avg(datapoint_seq::const_reverse_iterator it, + datapoint_seq::const_reverse_iterator rend, + EField field, int count) +{ + int i = 0; + double total = 0.0; + for (i=0; it != rend && ifields.contains(field)) { + total += (*it)->fields.at(field); } } - if (ok) { - return sum / points.size(); + if (i) { + return total/i; } return std::nullopt; } diff --git a/src/telemetry/parser.h b/src/telemetry/parser.h index 5c1ab08..a147166 100644 --- a/src/telemetry/parser.h +++ b/src/telemetry/parser.h @@ -6,8 +6,7 @@ #include "utils/logging/logger.h" #include -#include -#include +#include namespace vgraph { namespace telemetry { @@ -17,18 +16,26 @@ class parser { parser() = default; ~parser() = default; - std::shared_ptr parse(const std::filesystem::path& path); + datapoint_seq parse(const std::filesystem::path& path); protected: - virtual std::shared_ptr parse_impl(const std::filesystem::path& path) = 0; + virtual datapoint_seq parse_impl(const std::filesystem::path& path) = 0; private: utils::logging::logger log{"parser"}; - void update_calculated_fields(std::shared_ptr& seq); - void print_stats(std::shared_ptr& seq); + void update_calculated_fields(datapoint_seq& seq); + void print_stats(datapoint_seq& seq); - std::optional field_avg(std::deque> points, EField field); + double gradient_between(const std::multimap& dist_points, int dist_a, int dist_b); + + //last - if there are multiple values for key, return last, otherwise return first + double get_by_distance(const std::multimap& dist_points, int dist, EField field, bool last=true); + + void set_if_ok(datapoint_ptr& data, EField field, std::optional value); + std::optional field_avg(datapoint_seq::const_reverse_iterator it, + datapoint_seq::const_reverse_iterator rend, + EField field, int count); }; } // namespace telemetry diff --git a/src/telemetry/telemetry.cpp b/src/telemetry/telemetry.cpp index 9824155..f4f9d68 100644 --- a/src/telemetry/telemetry.cpp +++ b/src/telemetry/telemetry.cpp @@ -11,21 +11,21 @@ namespace helper { } } -telemetry::telemetry(std::shared_ptr seq, long offset) : - points(*seq) +telemetry::telemetry(datapoint_seq seq, long offset) : + points(seq) { - if (!seq) { + if (points.empty()) { log.warning("No telemetry loaded"); return; } - auto first_timestamp = seq->front()->timestamp; - auto prev_timestamp = seq->front()->timestamp; + auto first_timestamp = points.front()->timestamp; + auto prev_timestamp = points.front()->timestamp; long sum = 0; bool first = true; - for (auto& data : *seq) { + for (auto& data : points) { long us = std::chrono::duration_cast(data->timestamp - first_timestamp).count(); time_points[us+offset] = data; @@ -37,10 +37,10 @@ telemetry::telemetry(std::shared_ptr seq, long offset) : first = false; } - avg_interval = first / seq->size(); + avg_interval = first / points.size(); } -std::shared_ptr telemetry::get(double timestamp) const +datapoint_ptr telemetry::get(double timestamp) const { long us = helper::in_microseconds(timestamp); @@ -54,7 +54,7 @@ std::shared_ptr telemetry::get(double timestamp) const return (--time_points.lower_bound(us))->second; } -const std::vector>& telemetry::get_all() const +const std::vector& telemetry::get_all() const { return points; } @@ -63,11 +63,11 @@ std::shared_ptr telemetry::load(const std::string& path, std::optiona { utils::logging::logger log{"telemetry::load"}; - std::shared_ptr seq; + datapoint_seq seq; if (path.ends_with(".fit")) { seq = fit_parser().parse(path); - if (!seq) { + if (seq.empty()) { log.error("Failed to parse FIT file: {}", path); return nullptr; } diff --git a/src/telemetry/telemetry.h b/src/telemetry/telemetry.h index e12f87e..e3aa85c 100644 --- a/src/telemetry/telemetry.h +++ b/src/telemetry/telemetry.h @@ -11,11 +11,11 @@ namespace telemetry { class telemetry { public: - telemetry(std::shared_ptr seq, long offset=0); + telemetry(datapoint_seq seq, long offset=0); ~telemetry() = default; - std::shared_ptr get(double timestamp) const; - const std::vector>& get_all() const; + datapoint_ptr get(double timestamp) const; + const datapoint_seq& get_all() const; static std::shared_ptr load(const std::string& path, std::optional offset); // optional offset in seconds @@ -24,8 +24,8 @@ class telemetry { long avg_interval = 0; - std::vector> points; - std::map> time_points; + datapoint_seq points; + std::map time_points; }; } // namespace telemetry diff --git a/src/telemetry/value.h b/src/telemetry/value.h deleted file mode 100644 index f95878e..0000000 --- a/src/telemetry/value.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef VALUE_H -#define VALUE_H - -namespace vgraph { -namespace telemetry { - -class value { -public: - value() = default; - ~value() = default; -}; -//TODO to be implemented, templated for different types of values - -} // namespace telemetry -} // namespace vgraph - -#endif // VALUE_H \ No newline at end of file diff --git a/src/utils/argument_parser.cpp b/src/utils/argument_parser.cpp index ed9a287..6e2d4fe 100644 --- a/src/utils/argument_parser.cpp +++ b/src/utils/argument_parser.cpp @@ -170,7 +170,7 @@ int argument_parser::get(const std::string& key) const throw argument_exception(std::format("Value '{}' of argument '{}' is out of range", val[0], key)); } return ret; -}//FIXME to be refactored after merging with improved arguments parser +} template <> std::vector argument_parser::get(const std::string& key) const diff --git a/src/video/generator.cpp b/src/video/generator.cpp index 0a84025..9f61bb5 100644 --- a/src/video/generator.cpp +++ b/src/video/generator.cpp @@ -362,7 +362,7 @@ bool generator::link_elements(const pipeline_element& src, const pipeline_elemen } bool generator::config_elements() -{//FIXME try to incorporate congig params into path vectors and auto configure them (note: different types) +{//FIXME try to incorporate config params into path vectors and auto configure them (note: different types) log.debug("Pipeline elements_ basic config"); bool ok = true; diff --git a/test/telemetry/fit_parser_test.cpp b/test/telemetry/fit_parser_test.cpp index f387467..0c90595 100644 --- a/test/telemetry/fit_parser_test.cpp +++ b/test/telemetry/fit_parser_test.cpp @@ -31,26 +31,24 @@ class fit_parser_test : public ::testing::Test { TEST_F(fit_parser_test, parse_incorrect_path_returns_nullptr) { - ASSERT_EQ(nullptr, uut->parse(consts::nonexistant_path)); + ASSERT_EQ(0, uut->parse(consts::nonexistant_path).size()); } TEST_F(fit_parser_test, parse_wrong_file_extension_returns_nullptr) { - ASSERT_EQ(nullptr, uut->parse(consts::gpx_path)); + ASSERT_EQ(0, uut->parse(consts::gpx_path).size()); } TEST_F(fit_parser_test, parse_broken_file_returns_nullptr) { - auto retval = uut->parse(consts::broken_fit_path); - ASSERT_EQ(nullptr, retval); + auto retval = uut->parse(consts::broken_fit_path).size(); + ASSERT_EQ(0, retval); } TEST_F(fit_parser_test, parse_correct_file_returns_sequence) { - auto retval = uut->parse(consts::fit_path); - ASSERT_NE(nullptr, retval); - - //TODO to be implemented + auto retval = uut->parse(consts::fit_path).size(); + ASSERT_NE(0, retval); } } // namespace telemetry diff --git a/test/testdata/layout.xml b/test/testdata/layout.xml index eb2008e..9d43627 100644 --- a/test/testdata/layout.xml +++ b/test/testdata/layout.xml @@ -14,32 +14,41 @@ - + + + + + - + - + - + + + + + - + + diff --git a/test/utils/logging/logger_test.cpp b/test/utils/logging/logger_test.cpp index 44eb049..1f65a42 100644 --- a/test/utils/logging/logger_test.cpp +++ b/test/utils/logging/logger_test.cpp @@ -249,8 +249,6 @@ TEST_F(logger_test, error_sink_receives_error_logs_only_with_args) ASSERT_EQ(consts::expected_error_args, sink_stream.str()); } -//FIXME tests for set_log_level - } // namespace logging } // namespace utils } // namespace vgraph