source/*: Implement heap based userdata

This makes no immediate change to the external interface, but it will
enable us to do things like making copies of the event sources and
support for floating event source types.

Change-Id: Ida73e773eb0869f6f6f21c1e03c61e9ce2b5625c
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/source/base.cpp b/test/source/base.cpp
index 27e5bc3..3673e24 100644
--- a/test/source/base.cpp
+++ b/test/source/base.cpp
@@ -1,4 +1,5 @@
 #include <cerrno>
+#include <functional>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <memory>
@@ -8,8 +9,10 @@
 #include <sdeventplus/internal/sdevent.hpp>
 #include <sdeventplus/source/base.hpp>
 #include <sdeventplus/test/sdevent.hpp>
+#include <sdeventplus/types.hpp>
 #include <string>
 #include <systemd/sd-event.h>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 
@@ -27,24 +30,48 @@
 
 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>;
 
+class BaseImplData;
+
 class BaseImpl : public Base
 {
   public:
-    BaseImpl(const Event& event, sd_event_source* source, std::false_type) :
-        Base(event, source, std::false_type())
+    BaseImpl(const Event& event, sd_event_source* source, std::false_type);
+
+    BaseImpl(const BaseImpl& other, sdeventplus::internal::NoOwn) :
+        Base(other, sdeventplus::internal::NoOwn())
     {
     }
 
     using Base::get_prepare;
 };
 
+class BaseImplData : public BaseImpl, public detail::BaseData
+{
+  public:
+    BaseImplData(const BaseImpl& base) :
+        BaseImpl(base, sdeventplus::internal::NoOwn()), BaseData(base)
+    {
+    }
+};
+
+BaseImpl::BaseImpl(const Event& event, sd_event_source* source,
+                   std::false_type) :
+    Base(event, source, std::false_type())
+{
+    set_userdata(std::make_unique<BaseImplData>(*this));
+}
+
 class BaseTest : public testing::Test
 {
   protected:
     testing::StrictMock<test::SdEventMock> mock;
     sd_event_source* const expected_source =
         reinterpret_cast<sd_event_source*>(1234);
+    sd_event_source* const expected_source2 =
+        reinterpret_cast<sd_event_source*>(3456);
     sd_event* const expected_event = reinterpret_cast<sd_event*>(2345);
+    sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567);
+
     UniqueEvent event = make_event(expected_event);
 
     UniqueEvent make_event(sd_event* event)
@@ -59,21 +86,30 @@
 
     // Using a unique_ptr to make sure we don't get any superfluous moves or
     // copies.
-    std::unique_ptr<BaseImpl> make_base(const Event& event,
-                                        sd_event_source* source)
+    std::tuple<std::unique_ptr<BaseImpl>, std::function<void()>>
+        make_base(const Event& event, sd_event_source* source)
     {
         EXPECT_CALL(mock, sd_event_ref(event.get()))
             .WillOnce(Return(event.get()));
+        sd_event_destroy_t destroy;
         void* userdata;
-        EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_))
-            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        {
+            testing::InSequence seq;
+            EXPECT_CALL(
+                mock, sd_event_source_set_destroy_callback(source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+            EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_))
+                .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+        }
         auto ret = std::make_unique<BaseImpl>(event, source, std::false_type());
-        EXPECT_EQ(ret.get(), userdata);
+        EXPECT_CALL(mock, sd_event_source_get_userdata(source))
+            .WillRepeatedly(Return(userdata));
+        EXPECT_NE(ret.get(), userdata);
         EXPECT_EQ(source, ret->get());
         EXPECT_NE(&event, &ret->get_event());
         EXPECT_EQ(event.get(), ret->get_event().get());
         EXPECT_FALSE(ret->get_prepare());
-        return ret;
+        return {std::move(ret), std::bind(destroy, userdata)};
     }
 
     void set_prepare_placeholder(BaseImpl& base)
@@ -86,152 +122,107 @@
 
     void empty_base(BaseImpl&& other)
     {
-        void* userdata;
-        EXPECT_CALL(mock, sd_event_source_set_userdata(other.get(), testing::_))
-            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
         BaseImpl mover(std::move(other));
-        EXPECT_EQ(&mover, userdata);
         EXPECT_THROW(other.get(), std::bad_optional_access);
         EXPECT_THROW(other.get_event().get(), std::bad_optional_access);
-        EXPECT_FALSE(other.get_prepare());
+        EXPECT_THROW(other.get_prepare(), std::bad_optional_access);
 
         expect_base_destruct(mover.get_event(), mover.get());
     }
 
     void expect_base_destruct(const Event& event, sd_event_source* source)
     {
-        {
-            testing::InSequence seq;
-            EXPECT_CALL(mock, sd_event_source_set_enabled(source, SD_EVENT_OFF))
-                .WillOnce(Return(0));
-            EXPECT_CALL(mock, sd_event_source_unref(source))
-                .WillOnce(Return(nullptr));
-        }
+        EXPECT_CALL(mock, sd_event_source_unref(source))
+            .WillOnce(Return(nullptr));
         EXPECT_CALL(mock, sd_event_unref(event.get()))
             .WillOnce(Return(nullptr));
     }
 };
 
+TEST_F(BaseTest, NewBaseFail)
+{
+    EXPECT_CALL(mock, sd_event_ref(expected_event))
+        .WillOnce(Return(expected_event));
+    EXPECT_CALL(
+        mock, sd_event_source_set_destroy_callback(expected_source, testing::_))
+        .WillOnce(Return(-EINVAL));
+    expect_base_destruct(*event, expected_source);
+    EXPECT_THROW(BaseImpl(*event, expected_source, std::false_type()),
+                 SdEventError);
+}
+
 TEST_F(BaseTest, NewBaseNoRef)
 {
     EXPECT_CALL(mock, sd_event_ref(expected_event))
         .WillOnce(Return(expected_event));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    {
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
+        EXPECT_CALL(mock,
+                    sd_event_source_set_userdata(expected_source, testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
+    }
     BaseImpl source(*event, expected_source, std::false_type());
-    EXPECT_EQ(&source, userdata);
+    EXPECT_NE(&source, userdata);
     EXPECT_EQ(expected_source, source.get());
     EXPECT_NE(event.get(), &source.get_event());
     EXPECT_EQ(expected_event, source.get_event().get());
+
+    EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+        .WillOnce(Return(userdata));
     EXPECT_FALSE(source.get_prepare());
 
     expect_base_destruct(*event, expected_source);
+    destroy(userdata);
 }
 
-TEST_F(BaseTest, MoveConstruct)
+TEST_F(BaseTest, UserdataOutlives)
 {
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
+    EXPECT_CALL(mock, sd_event_ref(expected_event))
+        .WillOnce(Return(expected_event));
+    sd_event_destroy_t destroy;
     void* userdata;
-    EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
-        .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
-    BaseImpl source2(std::move(*source1));
-    EXPECT_EQ(&source2, userdata);
-    EXPECT_THROW(source1->get(), std::bad_optional_access);
-    EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
-    EXPECT_FALSE(source1->get_prepare());
-    EXPECT_EQ(expected_source, source2.get());
-    EXPECT_EQ(expected_event, source2.get_event().get());
-    EXPECT_TRUE(source2.get_prepare());
-
-    expect_base_destruct(*event, expected_source);
-}
-
-TEST_F(BaseTest, MoveAssignSelf)
-{
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
-    *source1 = std::move(*source1);
-    EXPECT_EQ(expected_source, source1->get());
-    EXPECT_EQ(expected_event, source1->get_event().get());
-    EXPECT_TRUE(source1->get_prepare());
-
-    expect_base_destruct(*event, expected_source);
-}
-
-TEST_F(BaseTest, MoveAssignEmpty)
-{
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
-    std::unique_ptr<BaseImpl> source2 = make_base(*event, expected_source);
-    empty_base(std::move(*source2));
-
     {
-        void* userdata;
+        testing::InSequence seq;
+        EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
+                                                               testing::_))
+            .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
         EXPECT_CALL(mock,
                     sd_event_source_set_userdata(expected_source, testing::_))
             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
-        *source2 = std::move(*source1);
-        EXPECT_EQ(source2.get(), userdata);
     }
-    EXPECT_THROW(source1->get(), std::bad_optional_access);
-    EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
-    EXPECT_FALSE(source1->get_prepare());
-    EXPECT_EQ(expected_source, source2->get());
-    EXPECT_EQ(expected_event, source2->get_event().get());
-    EXPECT_TRUE(source2->get_prepare());
+    auto source =
+        std::make_unique<BaseImpl>(*event, expected_source, std::false_type());
+    EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
+        .WillRepeatedly(Return(userdata));
+    EXPECT_FALSE(source->get_prepare());
 
-    // Make sure source1 is deleted to ensure it isn't holding a reference
-    source1.reset();
     expect_base_destruct(*event, expected_source);
-}
-
-TEST_F(BaseTest, MoveAssignExisting)
-{
-    sd_event_source* const expected_source2 =
-        reinterpret_cast<sd_event_source*>(3456);
-    sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567);
-
-    std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
-    set_prepare_placeholder(*source1);
-
-    UniqueEvent event2 = make_event(expected_event2);
-    std::unique_ptr<BaseImpl> source2 = make_base(*event2, expected_source2);
-
-    {
-        expect_base_destruct(*event2, expected_source2);
-        void* userdata;
-        EXPECT_CALL(mock,
-                    sd_event_source_set_userdata(expected_source, testing::_))
-            .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
-        *source2 = std::move(*source1);
-        EXPECT_EQ(source2.get(), userdata);
-    }
-    EXPECT_THROW(source1->get(), std::bad_optional_access);
-    EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
-    EXPECT_FALSE(source1->get_prepare());
-    EXPECT_EQ(expected_source, source2->get());
-    EXPECT_EQ(expected_event, source2->get_event().get());
-    EXPECT_TRUE(source2->get_prepare());
-
-    // Make sure source1 is deleted to ensure it isn't holding a reference
-    source1.reset();
-    expect_base_destruct(*event, expected_source);
+    source.reset();
+    EXPECT_FALSE(reinterpret_cast<BaseImpl*>(userdata)->get_prepare());
+    destroy(userdata);
 }
 
 class BaseMethodTest : public BaseTest
 {
   protected:
-    std::unique_ptr<BaseImpl> base = make_base(*event, expected_source);
+    std::unique_ptr<BaseImpl> base;
+    std::function<void()> destroy;
+
+    void SetUp()
+    {
+        std::tie(base, destroy) = make_base(*event, expected_source);
+    }
 
     void TearDown()
     {
         expect_base_destruct(base->get_event(), base->get());
         base.reset();
+        destroy();
     }
 };