utility/timer: Make movable

Now that we can update the callbacks of our sources, we can move the
timer object freely by updating the callback when moved.

Tested:
    Unit tests pass, and we no longer see any valgrind issues when
    moving the timer object.

Change-Id: I15baf97538459ca8b9c48b75dba77d09b7b5075b
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/sdeventplus/utility/timer.cpp b/src/sdeventplus/utility/timer.cpp
index 979c0af..2f28257 100644
--- a/src/sdeventplus/utility/timer.cpp
+++ b/src/sdeventplus/utility/timer.cpp
@@ -2,6 +2,7 @@
 #include <sdeventplus/clock.hpp>
 #include <sdeventplus/utility/timer.hpp>
 #include <stdexcept>
+#include <utility>
 
 namespace sdeventplus
 {
@@ -9,6 +10,36 @@
 {
 
 template <ClockId Id>
+Timer<Id>::Timer(Timer&& other) :
+    expired(std::move(other.expired)),
+    initialized(std::move(other.initialized)),
+    callback(std::move(other.callback)), clock(std::move(other.clock)),
+    interval(std::move(other.interval)), timeSource(std::move(other.timeSource))
+{
+    timeSource.set_callback(std::bind(&Timer::internalCallback, this,
+                                      std::placeholders::_1,
+                                      std::placeholders::_2));
+}
+
+template <ClockId Id>
+Timer<Id>& Timer<Id>::operator=(Timer&& other)
+{
+    if (this != &other)
+    {
+        expired = std::move(other.expired);
+        initialized = std::move(other.initialized);
+        callback = std::move(other.callback);
+        clock = std::move(other.clock);
+        interval = std::move(other.interval);
+        timeSource = std::move(other.timeSource);
+        timeSource.set_callback(std::bind(&Timer::internalCallback, this,
+                                          std::placeholders::_1,
+                                          std::placeholders::_2));
+    }
+    return *this;
+}
+
+template <ClockId Id>
 Timer<Id>::Timer(const Event& event, Callback&& callback,
                  std::optional<Duration> interval,
                  typename source::Time<Id>::Accuracy accuracy) :
diff --git a/src/sdeventplus/utility/timer.hpp b/src/sdeventplus/utility/timer.hpp
index f5d4766..e45cf46 100644
--- a/src/sdeventplus/utility/timer.hpp
+++ b/src/sdeventplus/utility/timer.hpp
@@ -38,9 +38,9 @@
     using Callback = std::function<void(Timer<Id>&)>;
 
     Timer(const Timer& other) = delete;
-    Timer(Timer&& other) = default;
+    Timer(Timer&& other);
     Timer& operator=(const Timer& other) = delete;
-    Timer& operator=(Timer&& other) = default;
+    Timer& operator=(Timer&& other);
     virtual ~Timer() = default;
 
     /** @brief Creates a new timer on the given event loop.
diff --git a/test/utility/timer.cpp b/test/utility/timer.cpp
index 6d5dff0..6c04e87 100644
--- a/test/utility/timer.cpp
+++ b/test/utility/timer.cpp
@@ -47,8 +47,11 @@
     sd_event* const expected_event = reinterpret_cast<sd_event*>(1234);
     sd_event_source* const expected_source =
         reinterpret_cast<sd_event_source*>(2345);
+    sd_event_source* const expected_source2 =
+        reinterpret_cast<sd_event_source*>(3456);
     const milliseconds interval{134};
     const milliseconds starting_time{10};
+    const milliseconds starting_time2{30};
     sd_event_time_handler_t handler = nullptr;
     void* handler_userdata;
     std::unique_ptr<Event> event;
@@ -340,6 +343,44 @@
     EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
 }
 
+TEST_F(TimerTest, CallbackMove)
+{
+    size_t called = 0;
+    callback = [&]() { ++called; };
+
+    expectNow(starting_time2);
+    EXPECT_CALL(mock,
+                sd_event_source_set_userdata(expected_source2, testing::_))
+        .WillOnce(Return(nullptr));
+    EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_,
+                                        static_cast<clockid_t>(testClock),
+                                        microseconds(starting_time2).count(),
+                                        1000, testing::_, nullptr))
+        .WillOnce(DoAll(SetArgPointee<1>(expected_source2), Return(0)));
+    EXPECT_CALL(mock, sd_event_source_unref(expected_source2))
+        .WillOnce(Return(nullptr));
+    EXPECT_CALL(mock,
+                sd_event_source_set_enabled(
+                    expected_source2, static_cast<int>(source::Enabled::Off)))
+        .WillOnce(Return(0))
+        .WillOnce(Return(0));
+    TestTimer local_timer(*event, nullptr);
+
+    // Move assign
+    local_timer = std::move(*timer);
+    timer.reset();
+
+    // Move construct
+    timer = std::make_unique<TestTimer>(std::move(local_timer));
+
+    // handler_userdata should have been updated and the callback should work
+    const milliseconds new_time(90);
+    expectNow(new_time);
+    expectSetTime(new_time + interval);
+    EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
+    EXPECT_EQ(1, called);
+}
+
 TEST_F(TimerTest, SetValuesExpiredTimer)
 {
     const milliseconds new_time(90);