Fix vtable CI error

The CI reports failure in VtableTest.SameContent, where the case is
comparing the binary of example vtables constructed from sdbusplus and
macros defined in systemd.

The root cause has two parts.

Part I:
When systemd is updated, the members in struct
sd_bus_vtable is updated, e.g.
* From v239 to v242, sd_bus_vtable.x.start is updated from
      struct {
              size_t element_size;
      } start;
  to:
      struct {
              size_t element_size;
              uint64_t features;
      } start;
  and sd_bus_vtable.x.method is updated from
      struct {
              const char *member;
              const char *signature;
              const char *result;
              sd_bus_message_handler_t handler;
              size_t offset;
      } method;
  to:
      struct {
              const char *member;
              const char *signature;
              const char *result;
              sd_bus_message_handler_t handler;
              size_t offset;
              const char *names;
      } method;
* From v242 to v243, sd_bus_vtable.x.start is updated to
      struct {
              size_t element_size;
              uint64_t features;
              const unsigned *vtable_format_reference;
      } start;

The code in vtable.hpp only assign the members in v239, the new
members are intialized with 0, so it differs from the vtable
constructed from macros defined by systemd.

The fix is to use macros from systemd in vtable.hpp as well,
which is suggested by systemd:

> Please do not initialize this structure directly, use the
> macros below instead

Part II:
The `const char *names` in struct method and signal introduced
between systemd v239 and v242 is a pointer to const strings.

By default they are "empty" strings, but there is no guarantee
that the compiler will use the same pointer for the same string.

So the test case can not assume the binaries are the same for
two vtables even they are constructed with the same parameters.

Update the test case to use real `const char*` and handler/get/set
functions and check each member of the struct instead of comparing the
binary data by memcmp.

Tested: Verify the CI passes.

Change-Id: I9e94ff16075dd3f12d73e96438c0d864203bdcf4
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/sdbusplus/vtable.hpp b/sdbusplus/vtable.hpp
index 939346e..1a15526 100644
--- a/sdbusplus/vtable.hpp
+++ b/sdbusplus/vtable.hpp
@@ -113,27 +113,19 @@
 
 constexpr vtable_t start(decltype(vtable_t::flags) flags)
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_START;
-    v.flags = flags;
-    v.x.start = decltype(v.x.start){sizeof(vtable_t)};
-
-    return v;
+    return SD_BUS_VTABLE_START(flags);
 }
 
 constexpr vtable_t end()
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_END;
-
-    return v;
+    return SD_BUS_VTABLE_END;
 }
 
 constexpr vtable_t method(const char* member, const char* signature,
                           const char* result, sd_bus_message_handler_t handler,
                           decltype(vtable_t::flags) flags)
 {
-    return method_o(member, signature, result, handler, 0, flags);
+    return SD_BUS_METHOD(member, signature, result, handler, flags);
 }
 
 constexpr vtable_t method_o(const char* member, const char* signature,
@@ -141,36 +133,21 @@
                             sd_bus_message_handler_t handler, size_t offset,
                             decltype(vtable_t::flags) flags)
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_METHOD;
-    v.flags = flags;
-    v.x.method =
-        decltype(v.x.method){member, signature, result, handler, offset};
-
-    return v;
+    return SD_BUS_METHOD_WITH_OFFSET(member, signature, result, handler, offset,
+                                     flags);
 }
 
 constexpr vtable_t signal(const char* member, const char* signature,
                           decltype(vtable_t::flags) flags)
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_SIGNAL;
-    v.flags = flags;
-    v.x.signal = decltype(v.x.signal){member, signature};
-
-    return v;
+    return SD_BUS_SIGNAL(member, signature, flags);
 }
 
 constexpr vtable_t property(const char* member, const char* signature,
                             sd_bus_property_get_t get,
                             decltype(vtable_t::flags) flags)
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_PROPERTY;
-    v.flags = flags;
-    v.x.property = decltype(v.x.property){member, signature, get, nullptr, 0};
-
-    return v;
+    return SD_BUS_PROPERTY(member, signature, get, 0, flags);
 }
 
 constexpr vtable_t property(const char* member, const char* signature,
@@ -178,37 +155,21 @@
                             sd_bus_property_set_t set,
                             decltype(vtable_t::flags) flags)
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_WRITABLE_PROPERTY;
-    v.flags = flags;
-    v.x.property = decltype(v.x.property){member, signature, get, set, 0};
-
-    return v;
+    return SD_BUS_WRITABLE_PROPERTY(member, signature, get, set, 0, flags);
 }
 
 constexpr vtable_t property_o(const char* member, const char* signature,
                               size_t offset, decltype(vtable_t::flags) flags)
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_PROPERTY;
-    v.flags = flags;
-    v.x.property =
-        decltype(v.x.property){member, signature, nullptr, nullptr, offset};
-
-    return v;
+    return SD_BUS_PROPERTY(member, signature, nullptr, offset, flags);
 }
 
 constexpr vtable_t property_o(const char* member, const char* signature,
                               sd_bus_property_set_t set, size_t offset,
                               decltype(vtable_t::flags) flags)
 {
-    vtable_t v{};
-    v.type = _SD_BUS_VTABLE_WRITABLE_PROPERTY;
-    v.flags = flags;
-    v.x.property =
-        decltype(v.x.property){member, signature, nullptr, set, offset};
-
-    return v;
+    return SD_BUS_WRITABLE_PROPERTY(member, signature, nullptr, set, offset,
+                                    flags);
 }
 
 } // namespace vtable
diff --git a/test/vtable/vtable.cpp b/test/vtable/vtable.cpp
index 399630c..bab3da4 100644
--- a/test/vtable/vtable.cpp
+++ b/test/vtable/vtable.cpp
@@ -2,29 +2,90 @@
 
 #include <gtest/gtest.h>
 
-static const sdbusplus::vtable::vtable_t example[] = {
-    sdbusplus::vtable::start(),
-    sdbusplus::vtable::method((const char*)1, (const char*)2, (const char*)3,
-                              (sd_bus_message_handler_t)4),
-    sdbusplus::vtable::signal((const char*)5, (const char*)6),
-    sdbusplus::vtable::property((const char*)7, (const char*)8,
-                                (sd_bus_property_get_t)9,
-                                sdbusplus::vtable::property_::const_),
-    sdbusplus::vtable::property((const char*)10, (const char*)11,
-                                (sd_bus_property_get_t)12,
-                                (sd_bus_property_set_t)13),
-    sdbusplus::vtable::property_o((const char*)14, (const char*)15, 16),
-    sdbusplus::vtable::end()};
+extern "C" {
+int test_handler(sd_bus_message* m, void* userdata, sd_bus_error* ret_error);
+int test_get(sd_bus* bus, const char* path, const char* interface,
+             const char* property, sd_bus_message* reply, void* userdata,
+             sd_bus_error* ret_error);
+int test_set(sd_bus* bus, const char* path, const char* interface,
+             const char* property, sd_bus_message* value, void* userdata,
+             sd_bus_error* ret_error);
 
 extern const sd_bus_vtable example2[];
 extern const size_t example2_size;
+}
+
+static const sdbusplus::vtable::vtable_t example[] = {
+    sdbusplus::vtable::start(),
+    sdbusplus::vtable::method("1", "2", "3", &test_handler, 0),
+    sdbusplus::vtable::signal("5", "6"),
+    sdbusplus::vtable::property("7", "8", &test_get,
+                                sdbusplus::vtable::property_::const_),
+    sdbusplus::vtable::property("10", "11", &test_get, &test_set),
+    sdbusplus::vtable::property_o("14", "15", 16),
+    sdbusplus::vtable::end()};
 
 TEST(VtableTest, SameSize)
 {
     ASSERT_EQ(sizeof(example), example2_size);
 }
 
+constexpr bool operator==(const sd_bus_vtable& t1, const sd_bus_vtable& t2)
+{
+    if (t1.type != t2.type || t1.flags != t2.flags)
+    {
+        return false;
+    }
+
+    switch (t1.type)
+    {
+        case _SD_BUS_VTABLE_START:
+            return t1.x.start.element_size == t2.x.start.element_size &&
+                   t1.x.start.features == t2.x.start.features;
+            // FIXME: In systemd 243, there is the new vtable_format_reference
+            // member, but current CI is using libsystemd 242, so we can not
+            // check it yet.
+            // && t1.x.start.vtable_format_reference
+            //      == t2.x.start.vtable_format_reference;
+            break;
+        case _SD_BUS_VTABLE_END:
+        {
+            // The union x shall be all zeros for END
+            constexpr uint8_t allZeors[sizeof(t1.x)] = {0};
+            return memcmp(&t1.x, allZeors, sizeof(t1.x)) == 0 &&
+                   memcmp(&t2.x, allZeors, sizeof(t2.x)) == 0;
+            break;
+        }
+        case _SD_BUS_VTABLE_METHOD:
+            return strcmp(t1.x.method.member, t2.x.method.member) == 0 &&
+                   strcmp(t1.x.method.signature, t2.x.method.signature) == 0 &&
+                   strcmp(t1.x.method.result, t2.x.method.result) == 0 &&
+                   t1.x.method.handler == t2.x.method.handler &&
+                   t1.x.method.offset == t2.x.method.offset &&
+                   strcmp(t1.x.method.names, t2.x.method.names) == 0;
+            break;
+        case _SD_BUS_VTABLE_SIGNAL:
+            return strcmp(t1.x.signal.member, t2.x.signal.member) == 0 &&
+                   strcmp(t1.x.signal.signature, t2.x.signal.signature) == 0 &&
+                   strcmp(t1.x.signal.names, t2.x.signal.names) == 0;
+            break;
+        case _SD_BUS_VTABLE_PROPERTY:
+        case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
+            return strcmp(t1.x.property.member, t2.x.property.member) == 0 &&
+                   strcmp(t1.x.property.signature, t2.x.property.signature) ==
+                       0 &&
+                   t1.x.property.get == t2.x.property.get &&
+                   t1.x.property.set == t2.x.property.set &&
+                   t1.x.property.offset == t2.x.property.offset;
+            break;
+    }
+    return false;
+}
+
 TEST(VtableTest, SameContent)
 {
-    ASSERT_EQ(0, memcmp(example, example2, example2_size));
+    for (size_t i = 0; i < sizeof(example) / sizeof(example[0]); ++i)
+    {
+        EXPECT_EQ(example[i], example2[i]);
+    }
 }
diff --git a/test/vtable/vtable_c.c b/test/vtable/vtable_c.c
index d01506b..105409f 100644
--- a/test/vtable/vtable_c.c
+++ b/test/vtable/vtable_c.c
@@ -1,16 +1,50 @@
 #include <systemd/sd-bus.h>
 
+#define UNUSED(x) (void)(x)
+
+int test_handler(sd_bus_message* m, void* userdata, sd_bus_error* ret_error)
+{
+    UNUSED(m);
+    UNUSED(userdata);
+    UNUSED(ret_error);
+    return 0;
+}
+int test_get(sd_bus* bus, const char* path, const char* interface,
+             const char* property, sd_bus_message* reply, void* userdata,
+             sd_bus_error* ret_error)
+{
+    UNUSED(bus);
+    UNUSED(path);
+    UNUSED(interface);
+    UNUSED(property);
+    UNUSED(reply);
+    UNUSED(userdata);
+    UNUSED(ret_error);
+    return 0;
+}
+int test_set(sd_bus* bus, const char* path, const char* interface,
+             const char* property, sd_bus_message* value, void* userdata,
+             sd_bus_error* ret_error)
+{
+    UNUSED(bus);
+    UNUSED(path);
+    UNUSED(interface);
+    UNUSED(property);
+    UNUSED(value);
+    UNUSED(userdata);
+    UNUSED(ret_error);
+    return 0;
+}
+
+typedef int (*sd_bus_message_handler_t)(sd_bus_message* m, void* userdata,
+                                        sd_bus_error* ret_error);
 const sd_bus_vtable example2[] = {
     SD_BUS_VTABLE_START(0),
-    SD_BUS_METHOD((const char*)1, (const char*)2, (const char*)3,
-                  (sd_bus_message_handler_t)4, 0),
-    SD_BUS_SIGNAL((const char*)5, (const char*)6, 0),
-    SD_BUS_PROPERTY((const char*)7, (const char*)8, (sd_bus_property_get_t)9, 0,
-                    SD_BUS_VTABLE_PROPERTY_CONST),
-    SD_BUS_WRITABLE_PROPERTY((const char*)10, (const char*)11,
-                             (sd_bus_property_get_t)12,
-                             (sd_bus_property_set_t)13, 0, 0),
-    SD_BUS_PROPERTY((const char*)14, (const char*)15, NULL, 16, 0),
+    SD_BUS_METHOD("1", "2", "3", &test_handler, 0),
+    SD_BUS_SIGNAL("5", "6", 0),
+    SD_BUS_PROPERTY("7", "8", &test_get, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+    SD_BUS_WRITABLE_PROPERTY("10", "11", &test_get, &test_set, 0, 0),
+    SD_BUS_PROPERTY("14", "15", NULL, 16, 0),
     SD_BUS_VTABLE_END,
 };