Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ CheckOptions:
- key: hicpp-move-const-arg.CheckTriviallyCopyableMove
value: '0'
- key: misc-include-cleaner.IgnoreHeaders
value: 'systemd/.*|sdbus-c\+\+/.*|gtest/.*|gmock/.*|bits/chrono.h|bits/basic_string.h|time.h|poll.h|stdlib.h'
value: 'systemd/.*|sdbus-c\+\+/.*|gtest/.*|gmock/.*|bits/chrono.h|bits/basic_string.h|time.h|poll.h|stdlib.h|stdio.h'
- key: readability-simplify-boolean-expr.IgnoreMacros
value: '1'
- key: cppcoreguidelines-rvalue-reference-param-not-moved.IgnoreUnnamedParams
Expand Down
10 changes: 9 additions & 1 deletion include/sdbus-c++/Message.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,15 @@ namespace sdbus {
void seal();
void rewind(bool complete);

enum class DumpFlags : uint64_t // NOLINT(performance-enum-size): using size from sd-bus
{
Default = 0ULL,
WithHeader = 1ULL << 0,
SubtreeOnly = 1ULL << 1,
SubtreeOnlyWithHeader = WithHeader | SubtreeOnly
};
[[nodiscard]] std::string dumpToString(DumpFlags flags) const;

pid_t getCredsPid() const;
uid_t getCredsUid() const;
uid_t getCredsEuid() const;
Expand Down Expand Up @@ -260,7 +269,6 @@ namespace sdbus {

friend Factory;


void* msg_{};
internal::IConnection* connection_{};
mutable bool ok_{true};
Expand Down
7 changes: 7 additions & 0 deletions include/sdbus-c++/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ namespace sdbus {
return val;
}

[[nodiscard]] std::string dumpToString() const
{
msg_.rewind(false);

return msg_.dumpToString(Message::DumpFlags::SubtreeOnly);
}

// Only allow conversion operator for true D-Bus type representations in C++
// NOLINTNEXTLINE(modernize-use-constraints): TODO for future: Use `requires signature_of<_ValueType>::is_valid` (when we stop supporting C++17 in public API)
template <typename ValueType, typename = std::enable_if_t<signature_of<ValueType>::is_valid>>
Expand Down
24 changes: 24 additions & 0 deletions src/Message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
#include "ScopeGuard.h"

#include <cassert>
#include <cerrno>
#include <cstdint> // int16_t, uint64_t, ...
#include <cstdio>
#include <cstdlib> // atexit
#include <cstring>
#include <string>
Expand Down Expand Up @@ -628,6 +630,28 @@ void Message::rewind(bool complete)
SDBUS_THROW_ERROR_IF(r < 0, "Failed to rewind the message", -r);
}

std::string Message::dumpToString(DumpFlags flags) const
{
#if LIBSYSTEMD_VERSION>=245 && !defined(SDBUS_basu)
char* buffer{};
SCOPE_EXIT{ free(buffer); }; // NOLINT(cppcoreguidelines-no-malloc,hicpp-no-malloc,cppcoreguidelines-owning-memory)
size_t size{};

const std::unique_ptr<FILE, int(*)(FILE*)> stream{open_memstream(&buffer, &size), fclose};
SDBUS_THROW_ERROR_IF(!stream, "Failed to open memory stream", errno);

auto r = sd_bus_message_dump(static_cast<sd_bus_message*>(msg_), stream.get(), static_cast<uint64_t>(flags));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to dump the message", -r);

(void)fflush(stream.get());

return {buffer, size};
#else
(void)flags;
throw Error(Error::Name{SD_BUS_ERROR_NOT_SUPPORTED}, "Dumping sd-bus message not supported by underlying version of libsystemd");
#endif
}

const char* Message::getInterfaceName() const
{
return sd_bus_message_get_interface(static_cast<sd_bus_message*>(msg_));
Expand Down
52 changes: 52 additions & 0 deletions tests/unittests/Types_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

using ::testing::Eq;
using ::testing::Gt;
using ::testing::HasSubstr;
using namespace std::string_literals;

namespace
Expand Down Expand Up @@ -148,6 +149,24 @@ TEST(ASimpleVariant, ReturnsTheSimpleValueWhenAsked)
ASSERT_THAT(variant.get<int>(), Eq(value));
}

#ifndef SDBUS_basu // Dumping message or variant to a string is not supported on basu backend
TEST(ASimpleVariant, CanBeDumpedToAString)
{
const int value = 5;
const sdbus::Variant variant(value);

// This should produce something like:
// VARIANT "i" {
// INT32 5;
// };
const auto str = variant.dumpToString();

EXPECT_THAT(str, ::HasSubstr("VARIANT \"i\""));
EXPECT_THAT(str, ::HasSubstr("INT32"));
EXPECT_THAT(str, ::HasSubstr("5"));
}
#endif // SDBUS_basu

TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
Expand All @@ -158,6 +177,39 @@ TEST(AComplexVariant, ReturnsTheComplexValueWhenAsked)
ASSERT_THAT(variant.get<ComplexType>(), Eq(value));
}

#ifndef SDBUS_basu // Dumping message or variant to a string is not supported on basu backend
TEST(AComplexVariant, CanBeDumpedToAString)
{
using ComplexType = std::map<uint64_t, std::vector<sdbus::Struct<std::string, double>>>;
const ComplexType value{ {ANY_UINT64, ComplexType::mapped_type{{"hello"s, ANY_DOUBLE}, {"world"s, ANY_DOUBLE}}} };
const sdbus::Variant variant(value);

// This should produce something like:
// VARIANT "a{ta(sd)}" {
// ARRAY "{ta(sd)}" {
// DICT_ENTRY "ta(sd)" {
// UINT64 84578348354;
// ARRAY "(sd)" {
// STRUCT "sd" {
// STRING "hello";
// DOUBLE 3.14;
// };
// STRUCT "sd" {
// STRING "world";
// DOUBLE 3.14;
// };
// };
// };
// };
// };
const auto str = variant.dumpToString();

EXPECT_THAT(str, ::HasSubstr("VARIANT \"a{ta(sd)}\""));
EXPECT_THAT(str, ::HasSubstr("hello"));
EXPECT_THAT(str, ::HasSubstr("world"));
}
#endif // SDBUS_basu

TEST(AVariant, HasConceptuallyNonmutableGetMethodWhichCanBeCalledXTimes)
{
const std::string value{"I am a string"};
Expand Down