diff options
author | Charles Kerr <charles.kerr@canonical.com> | 2014-02-02 22:37:22 -0600 |
---|---|---|
committer | Charles Kerr <charles.kerr@canonical.com> | 2014-02-02 22:37:22 -0600 |
commit | fcc1ab27cbc36983be51589800d269b055356b2b (patch) | |
tree | 7e28bd8686bdd8fb3a7675c58ef370922c2d2cf6 | |
parent | a03811363619c178fd5156fa94eb5d5a4897afa5 (diff) | |
download | ayatana-indicator-datetime-fcc1ab27cbc36983be51589800d269b055356b2b.tar.gz ayatana-indicator-datetime-fcc1ab27cbc36983be51589800d269b055356b2b.tar.bz2 ayatana-indicator-datetime-fcc1ab27cbc36983be51589800d269b055356b2b.zip |
from alarm dev branch: add the alarm watcher and its unit tests
-rw-r--r-- | include/datetime/clock-watcher.h | 72 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/clock-watcher.cpp | 71 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/test-clock-watcher.cpp | 166 |
5 files changed, 311 insertions, 0 deletions
diff --git a/include/datetime/clock-watcher.h b/include/datetime/clock-watcher.h new file mode 100644 index 0000000..e93b468 --- /dev/null +++ b/include/datetime/clock-watcher.h @@ -0,0 +1,72 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Charles Kerr <charles.kerr@canonical.com> + */ + +#ifndef INDICATOR_DATETIME_CLOCK_WATCHER_H +#define INDICATOR_DATETIME_CLOCK_WATCHER_H + +#include <datetime/state.h> +#include <datetime/appointment.h> + +#include <core/signal.h> + +#include <memory> +#include <set> +#include <string> + +namespace unity { +namespace indicator { +namespace datetime { + + +/** + * \brief Watches the clock and appointments to notify when an + * appointment's time is reached. + */ +class ClockWatcher +{ +public: + ClockWatcher() =default; + virtual ~ClockWatcher() =default; + virtual core::Signal<const Appointment&>& alarm_reached() = 0; +}; + + +/** + * \brief A #ClockWatcher implementation + */ +class ClockWatcherImpl: public ClockWatcher +{ +public: + ClockWatcherImpl(const std::shared_ptr<const State>& state); + ~ClockWatcherImpl() =default; + core::Signal<const Appointment&>& alarm_reached(); + +private: + void pulse(); + std::set<std::string> m_triggered; + std::shared_ptr<const State> m_state; + core::Signal<const Appointment&> m_alarm_reached; +}; + + +} // namespace datetime +} // namespace indicator +} // namespace unity + +#endif // INDICATOR_DATETIME_CLOCK_WATCHER_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 810e299..12a5b74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,7 @@ add_library (${SERVICE_LIB} STATIC appointment.cpp clock.cpp clock-live.cpp + clock-watcher.cpp date-time.cpp exporter.cpp formatter.cpp diff --git a/src/clock-watcher.cpp b/src/clock-watcher.cpp new file mode 100644 index 0000000..a2e700d --- /dev/null +++ b/src/clock-watcher.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Charles Kerr <charles.kerr@canonical.com> + */ + +#include <datetime/clock-watcher.h> + +namespace unity { +namespace indicator { +namespace datetime { + +/*** +**** +***/ + +ClockWatcherImpl::ClockWatcherImpl(const std::shared_ptr<const State>& state): + m_state(state) +{ + m_state->planner->upcoming.changed().connect([this](const std::vector<Appointment>&){ + g_debug("ClockWatcher pulse because upcoming appointments changed"); + pulse(); + }); + m_state->clock->minute_changed.connect([this](){ + g_debug("ClockWatcher pulse because clock minute_changed"); + pulse(); + }); + pulse(); +} + +core::Signal<const Appointment&>& ClockWatcherImpl::alarm_reached() +{ + return m_alarm_reached; +} + +void ClockWatcherImpl::pulse() +{ + const auto now = m_state->clock->localtime(); + + for(const auto& appointment : m_state->planner->upcoming.get()) + { + if (m_triggered.count(appointment.uid)) + continue; + if (!DateTime::is_same_minute(now, appointment.begin)) + continue; + + m_triggered.insert(appointment.uid); + m_alarm_reached(appointment); + } +} + +/*** +**** +***/ + +} // namespace datetime +} // namespace indicator +} // namespace unity diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3dcd151..06e40a7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -42,6 +42,7 @@ function(add_test_by_name name) endfunction() add_test_by_name(test-actions) add_test_by_name(test-clock) +add_test_by_name(test-clock-watcher) add_test_by_name(test-exporter) add_test_by_name(test-formatter) add_test_by_name(test-live-actions) diff --git a/tests/test-clock-watcher.cpp b/tests/test-clock-watcher.cpp new file mode 100644 index 0000000..79b8485 --- /dev/null +++ b/tests/test-clock-watcher.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Charles Kerr <charles.kerr@canonical.com> + */ + +#include <datetime/clock-watcher.h> + +#include <gtest/gtest.h> + +#include "state-fixture.h" + +using namespace unity::indicator::datetime; + +class ClockWatcherFixture: public StateFixture +{ +private: + + typedef StateFixture super; + +protected: + + std::vector<std::string> m_triggered; + std::unique_ptr<ClockWatcher> m_watcher; + + void SetUp() + { + super::SetUp(); + + m_watcher.reset(new ClockWatcherImpl(m_state)); + m_watcher->alarm_reached().connect([this](const Appointment& appt){ + m_triggered.push_back(appt.uid); + }); + + EXPECT_TRUE(m_triggered.empty()); + } + + void TearDown() + { + m_triggered.clear(); + m_watcher.reset(); + + super::TearDown(); + } + + std::vector<Appointment> build_some_appointments() + { + const auto now = m_state->clock->localtime(); + auto tomorrow = g_date_time_add_days (now.get(), 1); + auto tomorrow_begin = g_date_time_add_full (tomorrow, 0, 0, 0, + -g_date_time_get_hour(tomorrow), + -g_date_time_get_minute(tomorrow), + -g_date_time_get_seconds(tomorrow)); + auto tomorrow_end = g_date_time_add_full (tomorrow_begin, 0, 0, 1, 0, 0, -1); + + Appointment a1; // an alarm clock appointment + a1.color = "red"; + a1.summary = "Alarm"; + a1.summary = "http://www.example.com/"; + a1.uid = "example"; + a1.has_alarms = true; + a1.begin = tomorrow_begin; + a1.end = tomorrow_end; + + auto ubermorgen_begin = g_date_time_add_days (tomorrow, 1); + auto ubermorgen_end = g_date_time_add_full (tomorrow_begin, 0, 0, 1, 0, 0, -1); + + Appointment a2; // a non-alarm appointment + a2.color = "green"; + a2.summary = "Other Text"; + a2.summary = "http://www.monkey.com/"; + a2.uid = "monkey"; + a2.has_alarms = false; + a2.begin = ubermorgen_begin; + a2.end = ubermorgen_end; + + // cleanup + g_date_time_unref(ubermorgen_end); + g_date_time_unref(ubermorgen_begin); + g_date_time_unref(tomorrow_end); + g_date_time_unref(tomorrow_begin); + g_date_time_unref(tomorrow); + + return std::vector<Appointment>({a1, a2}); + } +}; + +/*** +**** +***/ + +TEST_F(ClockWatcherFixture, AppointmentsChanged) +{ + // Add some appointments to the planner. + // One of these matches our state's localtime, so that should get triggered. + std::vector<Appointment> a = build_some_appointments(); + a[0].begin = m_state->clock->localtime(); + m_state->planner->upcoming.set(a); + + // Confirm that it got fired + EXPECT_EQ(1, m_triggered.size()); + EXPECT_EQ(a[0].uid, m_triggered[0]); +} + + +TEST_F(ClockWatcherFixture, TimeChanged) +{ + // Add some appointments to the planner. + // Neither of these match the state's localtime, so nothing should be triggered. + std::vector<Appointment> a = build_some_appointments(); + m_state->planner->upcoming.set(a); + EXPECT_TRUE(m_triggered.empty()); + + // Set the state's clock to a time that matches one of the appointments. + // That appointment should get triggered. + m_mock_state->mock_clock->set_localtime(a[1].begin); + EXPECT_EQ(1, m_triggered.size()); + EXPECT_EQ(a[1].uid, m_triggered[0]); +} + + +TEST_F(ClockWatcherFixture, MoreThanOne) +{ + const auto now = m_state->clock->localtime(); + std::vector<Appointment> a = build_some_appointments(); + a[0].begin = a[1].begin = now; + m_state->planner->upcoming.set(a); + + EXPECT_EQ(2, m_triggered.size()); + EXPECT_EQ(a[0].uid, m_triggered[0]); + EXPECT_EQ(a[1].uid, m_triggered[1]); +} + + +TEST_F(ClockWatcherFixture, NoDuplicates) +{ + // Setup: add an appointment that gets triggered. + const auto now = m_state->clock->localtime(); + const std::vector<Appointment> appointments = build_some_appointments(); + std::vector<Appointment> a; + a.push_back(appointments[0]); + a[0].begin = now; + m_state->planner->upcoming.set(a); + EXPECT_EQ(1, m_triggered.size()); + EXPECT_EQ(a[0].uid, m_triggered[0]); + + // Now change the appointment vector by adding one to it. + // Confirm that the ClockWatcher doesn't re-trigger a[0] + a.push_back(appointments[1]); + m_state->planner->upcoming.set(a); + EXPECT_EQ(1, m_triggered.size()); + EXPECT_EQ(a[0].uid, m_triggered[0]); +} |