aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Kerr <charles.kerr@canonical.com>2015-04-09 13:08:24 -0500
committerCharles Kerr <charles.kerr@canonical.com>2015-04-09 13:08:24 -0500
commit8d282df37c72ff27a006ff928f1b151d98aa0e45 (patch)
tree89d5ecc46c7e674e753e907f48d8e8acd4935d1a
parentd5002c6b27cf0e00828555a10e89778008d6cd01 (diff)
parent49f49d4c18c2cc77a1a305c93a74e9e8ec903526 (diff)
downloadayatana-indicator-datetime-8d282df37c72ff27a006ff928f1b151d98aa0e45.tar.gz
ayatana-indicator-datetime-8d282df37c72ff27a006ff928f1b151d98aa0e45.tar.bz2
ayatana-indicator-datetime-8d282df37c72ff27a006ff928f1b151d98aa0e45.zip
sync with trunk
-rw-r--r--data/com.canonical.indicator.datetime.gschema.xml.in2
-rw-r--r--debian/changelog17
-rw-r--r--debian/control19
-rw-r--r--include/datetime/alarm-queue-simple.h18
-rw-r--r--include/datetime/alarm-queue.h2
-rw-r--r--include/datetime/appointment.h23
-rw-r--r--include/datetime/clock-mock.h2
-rw-r--r--include/datetime/clock.h2
-rw-r--r--include/datetime/date-time.h6
-rw-r--r--include/datetime/planner-snooze.h3
-rw-r--r--include/datetime/snap.h3
-rw-r--r--include/datetime/wakeup-timer-mainloop.h4
-rw-r--r--include/datetime/wakeup-timer-powerd.h4
-rw-r--r--include/datetime/wakeup-timer.h2
-rw-r--r--src/actions-live.cpp19
-rw-r--r--src/actions.cpp4
-rw-r--r--src/alarm-queue-simple.cpp215
-rw-r--r--src/appointment.cpp12
-rw-r--r--src/awake.cpp63
-rw-r--r--src/date-time.cpp38
-rw-r--r--src/engine-eds.cpp189
-rw-r--r--src/main.cpp12
-rw-r--r--src/planner-snooze.cpp16
-rw-r--r--src/snap.cpp16
-rw-r--r--tests/CMakeLists.txt37
-rw-r--r--tests/manual-test-snap.cpp10
-rw-r--r--tests/print-to.h45
-rwxr-xr-xtests/run-eds-test.sh57
-rw-r--r--tests/test-alarm-queue.cpp17
-rw-r--r--tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source21
-rw-r--r--tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics47
-rw-r--r--tests/test-eds-valarms.cpp101
-rw-r--r--tests/test-exporter.cpp2
-rw-r--r--tests/test-live-actions.cpp6
-rw-r--r--tests/test-snap.cpp20
-rw-r--r--tests/timezone-mock.h1
-rw-r--r--tests/wakeup-timer-mock.h78
37 files changed, 874 insertions, 259 deletions
diff --git a/data/com.canonical.indicator.datetime.gschema.xml.in b/data/com.canonical.indicator.datetime.gschema.xml.in
index edcede2..044f694 100644
--- a/data/com.canonical.indicator.datetime.gschema.xml.in
+++ b/data/com.canonical.indicator.datetime.gschema.xml.in
@@ -148,7 +148,7 @@
</key>
<key name="alarm-duration-minutes" type="u">
<range min="1" max="60"/>
- <default>30</default>
+ <default>10</default>
<_summary>The alarm's duration.</_summary>
<_description>
How long the alarm's sound will be looped if its snap decision is not dismissed by the user.
diff --git a/debian/changelog b/debian/changelog
index 40df883..4ec36ff 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,20 @@
+indicator-datetime (13.10.0+15.04.20150406-0ubuntu1) vivid; urgency=medium
+
+ [ Charles Kerr ]
+ * Improve valarm support to honor calendar events' valarm triggers.
+ (LP: #1419001)
+
+ -- CI Train Bot <ci-train-bot@canonical.com> Mon, 06 Apr 2015 23:35:46 +0000
+
+indicator-datetime (13.10.0+15.04.20150331-0ubuntu1) vivid; urgency=medium
+
+ [ Charles Kerr ]
+ * Reduce the forced screen-on time for alarms to reduce battery
+ consumption. Also, lower the default alarm duration from 30 minutes
+ to 10 minutes. (LP: #1434637)
+
+ -- CI Train Bot <ci-train-bot@canonical.com> Tue, 31 Mar 2015 20:25:38 +0000
+
indicator-datetime (13.10.0+15.04.20150317-0ubuntu1) vivid; urgency=medium
[ Charles Kerr ]
diff --git a/debian/control b/debian/control
index 4b5f893..e9f14ec 100644
--- a/debian/control
+++ b/debian/control
@@ -2,18 +2,10 @@ Source: indicator-datetime
Section: misc
Priority: optional
Maintainer: Ubuntu Desktop Team <ubuntu-desktop@lists.ubuntu.com>
-# g++-4.9: since we use c++11 features, explicitly select a g++ version
-# to protect from ABI breaks in libstdc++
-# language-pack-en-base: needed so unit tests can use 12h and 24h locales
Build-Depends: cmake,
- g++-4.9,
dbus,
- dbus-test-runner,
- python3-dbusmock,
debhelper (>= 9),
dh-translations,
- language-pack-touch-en | language-pack-en-base,
- libgtest-dev,
libglib2.0-dev (>= 2.35.4),
libnotify-dev (>= 0.7.6),
libgstreamer1.0-dev,
@@ -22,8 +14,19 @@ Build-Depends: cmake,
libedataserver1.2-dev (>= 3.5),
liburl-dispatcher1-dev,
libproperties-cpp-dev,
+# for safeguarding against ABI breaks in libstdc++, explicitly select a g++ version
+ g++-4.9,
+# for the test harness:
+ libgtest-dev,
libdbustest1-dev,
+ dbus-test-runner,
+ python3-dbusmock,
+# for 12h/24h locale unit tests:
locales,
+ language-pack-touch-en | language-pack-en-base,
+# for running live EDS tests:
+ evolution-data-server,
+ gvfs-daemons,
Standards-Version: 3.9.3
Homepage: https://launchpad.net/indicator-datetime
# If you aren't a member of ~indicator-applet-developers but need to upload
diff --git a/include/datetime/alarm-queue-simple.h b/include/datetime/alarm-queue-simple.h
index d191aec..838d28a 100644
--- a/include/datetime/alarm-queue-simple.h
+++ b/include/datetime/alarm-queue-simple.h
@@ -20,6 +20,8 @@
#ifndef INDICATOR_DATETIME_ALARM_QUEUE_SIMPLE_H
#define INDICATOR_DATETIME_ALARM_QUEUE_SIMPLE_H
+#include <memory> // std::shared_ptr
+
#include <datetime/alarm-queue.h>
#include <datetime/clock.h>
#include <datetime/planner.h>
@@ -39,20 +41,12 @@ public:
const std::shared_ptr<Planner>& upcoming_planner,
const std::shared_ptr<WakeupTimer>& timer);
~SimpleAlarmQueue();
- core::Signal<const Appointment&>& alarm_reached();
+ core::Signal<const Appointment&, const Alarm&>& alarm_reached() override;
private:
- void requeue();
- bool find_next_alarm(Appointment& setme) const;
- std::vector<Appointment> find_current_alarms() const;
- void check_alarms();
-
- std::set<std::pair<std::string,DateTime>> m_triggered;
- const std::shared_ptr<Clock> m_clock;
- const std::shared_ptr<Planner> m_planner;
- const std::shared_ptr<WakeupTimer> m_timer;
- core::Signal<const Appointment&> m_alarm_reached;
- DateTime m_datetime;
+ class Impl;
+ friend class Impl;
+ std::unique_ptr<Impl> impl;
};
diff --git a/include/datetime/alarm-queue.h b/include/datetime/alarm-queue.h
index ea51957..98abd7a 100644
--- a/include/datetime/alarm-queue.h
+++ b/include/datetime/alarm-queue.h
@@ -45,7 +45,7 @@ class AlarmQueue
public:
AlarmQueue() =default;
virtual ~AlarmQueue() =default;
- virtual core::Signal<const Appointment&>& alarm_reached() = 0;
+ virtual core::Signal<const Appointment&, const Alarm&>& alarm_reached() =0;
};
/***
diff --git a/include/datetime/appointment.h b/include/datetime/appointment.h
index ab89c2f..e323c9c 100644
--- a/include/datetime/appointment.h
+++ b/include/datetime/appointment.h
@@ -21,14 +21,28 @@
#define INDICATOR_DATETIME_APPOINTMENT_H
#include <datetime/date-time.h>
+
#include <string>
+#include <vector>
namespace unity {
namespace indicator {
namespace datetime {
/**
- * \brief Plain Old Data Structure that represents a calendar appointment.
+ * \brief Basic information required to raise a notification about some Appointment.
+ */
+struct Alarm
+{
+ std::string text;
+ std::string audio_url;
+ DateTime time;
+
+ bool operator== (const Alarm& that) const;
+};
+
+/**
+ * \brief An instance of an appointment; e.g. a calendar event or clock-app alarm
*
* @see Planner
*/
@@ -39,14 +53,15 @@ public:
Type type = EVENT;
bool is_ubuntu_alarm() const { return type == UBUNTU_ALARM; }
+ std::string uid;
std::string color;
std::string summary;
- std::string url;
- std::string uid;
- std::string audio_url;
+ std::string activation_url;
DateTime begin;
DateTime end;
+ std::vector<Alarm> alarms;
+
bool operator== (const Appointment& that) const;
};
diff --git a/include/datetime/clock-mock.h b/include/datetime/clock-mock.h
index 84fd860..011d079 100644
--- a/include/datetime/clock-mock.h
+++ b/include/datetime/clock-mock.h
@@ -39,7 +39,7 @@ public:
explicit MockClock(const DateTime& dt): m_localtime(dt) {}
~MockClock() =default;
- DateTime localtime() const { return m_localtime; }
+ DateTime localtime() const override { return m_localtime; }
void set_localtime(const DateTime& dt)
{
diff --git a/include/datetime/clock.h b/include/datetime/clock.h
index 8745d24..4a0642f 100644
--- a/include/datetime/clock.h
+++ b/include/datetime/clock.h
@@ -76,7 +76,7 @@ class LiveClock: public Clock
public:
LiveClock (const std::shared_ptr<const Timezone>& zones);
virtual ~LiveClock();
- virtual DateTime localtime() const;
+ virtual DateTime localtime() const override;
private:
class Impl;
diff --git a/include/datetime/date-time.h b/include/datetime/date-time.h
index 7dfc207..ea9ea36 100644
--- a/include/datetime/date-time.h
+++ b/include/datetime/date-time.h
@@ -22,6 +22,7 @@
#include <glib.h> // GDateTime
+#include <chrono>
#include <ctime> // time_t
#include <memory> // std::shared_ptr
@@ -36,13 +37,16 @@ class DateTime
{
public:
static DateTime NowLocal();
+ static DateTime Local(time_t);
static DateTime Local(int year, int month, int day, int hour, int minute, double seconds);
DateTime();
- explicit DateTime(time_t t);
+ DateTime(GTimeZone* tz, time_t t);
DateTime(GTimeZone* tz, GDateTime* dt);
DateTime(GTimeZone* tz, int year, int month, int day, int hour, int minute, double seconds);
DateTime& operator=(const DateTime& in);
+ DateTime& operator+=(const std::chrono::minutes&);
+ DateTime& operator+=(const std::chrono::seconds&);
DateTime to_timezone(const std::string& zone) const;
DateTime start_of_month() const;
DateTime start_of_day() const;
diff --git a/include/datetime/planner-snooze.h b/include/datetime/planner-snooze.h
index e2619fa..fc08d27 100644
--- a/include/datetime/planner-snooze.h
+++ b/include/datetime/planner-snooze.h
@@ -39,9 +39,8 @@ public:
SnoozePlanner(const std::shared_ptr<Settings>&,
const std::shared_ptr<Clock>&);
~SnoozePlanner();
- void add(const Appointment&);
-
core::Property<std::vector<Appointment>>& appointments() override;
+ void add(const Appointment&, const Alarm&);
protected:
class Impl;
diff --git a/include/datetime/snap.h b/include/datetime/snap.h
index 572158d..cc091d3 100644
--- a/include/datetime/snap.h
+++ b/include/datetime/snap.h
@@ -42,8 +42,9 @@ public:
const std::shared_ptr<const Settings>& settings);
virtual ~Snap();
- typedef std::function<void(const Appointment&)> appointment_func;
+ typedef std::function<void(const Appointment&, const Alarm&)> appointment_func;
void operator()(const Appointment& appointment,
+ const Alarm& alarm,
appointment_func snooze,
appointment_func ok);
diff --git a/include/datetime/wakeup-timer-mainloop.h b/include/datetime/wakeup-timer-mainloop.h
index 86da8cf..5acb150 100644
--- a/include/datetime/wakeup-timer-mainloop.h
+++ b/include/datetime/wakeup-timer-mainloop.h
@@ -41,8 +41,8 @@ class MainloopWakeupTimer: public WakeupTimer
public:
explicit MainloopWakeupTimer(const std::shared_ptr<Clock>&);
~MainloopWakeupTimer();
- void set_wakeup_time (const DateTime&);
- core::Signal<>& timeout();
+ void set_wakeup_time (const DateTime&) override;
+ core::Signal<>& timeout() override;
private:
MainloopWakeupTimer(const MainloopWakeupTimer&) =delete;
diff --git a/include/datetime/wakeup-timer-powerd.h b/include/datetime/wakeup-timer-powerd.h
index f11febe..5237fb9 100644
--- a/include/datetime/wakeup-timer-powerd.h
+++ b/include/datetime/wakeup-timer-powerd.h
@@ -41,8 +41,8 @@ class PowerdWakeupTimer: public WakeupTimer
public:
explicit PowerdWakeupTimer(const std::shared_ptr<Clock>&);
~PowerdWakeupTimer();
- void set_wakeup_time(const DateTime&);
- core::Signal<>& timeout();
+ void set_wakeup_time(const DateTime&) override;
+ core::Signal<>& timeout() override;
private:
PowerdWakeupTimer(const PowerdWakeupTimer&) =delete;
diff --git a/include/datetime/wakeup-timer.h b/include/datetime/wakeup-timer.h
index 0a9923c..3e5344c 100644
--- a/include/datetime/wakeup-timer.h
+++ b/include/datetime/wakeup-timer.h
@@ -41,7 +41,7 @@ public:
WakeupTimer() =default;
virtual ~WakeupTimer() =default;
virtual void set_wakeup_time (const DateTime&) =0;
- virtual core::Signal<>& timeout() = 0;
+ virtual core::Signal<>& timeout() =0;
};
/***
diff --git a/src/actions-live.cpp b/src/actions-live.cpp
index 4d1f770..3cbfb78 100644
--- a/src/actions-live.cpp
+++ b/src/actions-live.cpp
@@ -135,12 +135,19 @@ void LiveActions::phone_open_alarm_app()
void LiveActions::phone_open_appointment(const Appointment& appt)
{
- if (!appt.url.empty())
- dispatch_url(appt.url);
- else if (appt.is_ubuntu_alarm())
- phone_open_alarm_app();
- else
- phone_open_calendar_app(DateTime::NowLocal());
+ if (!appt.activation_url.empty())
+ {
+ dispatch_url(appt.activation_url);
+ }
+ else switch (appt.type)
+ {
+ case Appointment::UBUNTU_ALARM:
+ phone_open_alarm_app();
+ break;
+
+ default:
+ phone_open_calendar_app(appt.begin);
+ }
}
void LiveActions::phone_open_calendar_app(const DateTime&)
diff --git a/src/actions.cpp b/src/actions.cpp
index 839c9cd..930e100 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -43,7 +43,7 @@ DateTime datetime_from_timet_variant(GVariant* v)
t = g_variant_get_int64(v);
if (t != 0)
- return DateTime(t);
+ return DateTime::Local(t);
else
return DateTime::NowLocal();
}
@@ -143,7 +143,7 @@ void on_calendar_activated(GSimpleAction * /*action*/,
g_return_if_fail(t != 0);
- auto dt = DateTime(t).start_of_day();
+ auto dt = DateTime::Local(t).start_of_day();
static_cast<Actions*>(gself)->set_calendar_date(dt);
}
diff --git a/src/alarm-queue-simple.cpp b/src/alarm-queue-simple.cpp
index f45e61a..921e8d2 100644
--- a/src/alarm-queue-simple.cpp
+++ b/src/alarm-queue-simple.cpp
@@ -20,134 +20,165 @@
#include <datetime/alarm-queue-simple.h>
#include <cmath>
+#include <set>
namespace unity {
namespace indicator {
namespace datetime {
/***
-**** Public API
+****
***/
-SimpleAlarmQueue::SimpleAlarmQueue(const std::shared_ptr<Clock>& clock,
- const std::shared_ptr<Planner>& planner,
- const std::shared_ptr<WakeupTimer>& timer):
- m_clock(clock),
- m_planner(planner),
- m_timer(timer),
- m_datetime(clock->localtime())
+class SimpleAlarmQueue::Impl
{
- m_planner->appointments().changed().connect([this](const std::vector<Appointment>&){
- g_debug("AlarmQueue %p calling requeue() due to appointments changed", this);
- requeue();
- });
-
- m_clock->minute_changed.connect([=]{
- const auto now = m_clock->localtime();
- constexpr auto skew_threshold_usec = int64_t{90} * G_USEC_PER_SEC;
- const bool clock_jumped = std::abs(now - m_datetime) > skew_threshold_usec;
- m_datetime = now;
- if (clock_jumped) {
- g_debug("AlarmQueue %p calling requeue() due to clock skew", this);
+public:
+
+ Impl(const std::shared_ptr<Clock>& clock,
+ const std::shared_ptr<Planner>& planner,
+ const std::shared_ptr<WakeupTimer>& timer):
+ m_clock{clock},
+ m_planner{planner},
+ m_timer{timer},
+ m_datetime{clock->localtime()}
+ {
+ m_planner->appointments().changed().connect([this](const std::vector<Appointment>&){
+ g_debug("AlarmQueue %p calling requeue() due to appointments changed", this);
requeue();
- }
- });
+ });
+
+ m_clock->minute_changed.connect([this]{
+ const auto now = m_clock->localtime();
+ constexpr auto skew_threshold_usec = int64_t{90} * G_USEC_PER_SEC;
+ const bool clock_jumped = std::abs(now - m_datetime) > skew_threshold_usec;
+ m_datetime = now;
+ if (clock_jumped) {
+ g_debug("AlarmQueue %p calling requeue() due to clock skew", this);
+ requeue();
+ }
+ });
+
+ m_timer->timeout().connect([this](){
+ g_debug("AlarmQueue %p calling requeue() due to timeout", this);
+ requeue();
+ });
- m_timer->timeout().connect([this](){
- g_debug("AlarmQueue %p calling requeue() due to timeout", this);
requeue();
- });
+ }
- requeue();
-}
+ ~Impl()
+ {
+ }
-SimpleAlarmQueue::~SimpleAlarmQueue()
-{
-}
+ core::Signal<const Appointment&, const Alarm&>& alarm_reached()
+ {
+ return m_alarm_reached;
+ }
-core::Signal<const Appointment&>& SimpleAlarmQueue::alarm_reached()
-{
- return m_alarm_reached;
-}
+private:
-/***
-****
-***/
+ void requeue()
+ {
+ const auto appointments = m_planner->appointments().get();
+ const Alarm* alarm;
+
+ // kick any current alarms
+ for (const auto& appointment : appointments)
+ {
+ if ((alarm = appointment_get_current_alarm(appointment)))
+ {
+ m_triggered.insert(std::make_pair(appointment.uid, alarm->time));
+ m_alarm_reached(appointment, *alarm);
+ }
+ }
-void SimpleAlarmQueue::requeue()
-{
- // kick any current alarms
- for (auto current : find_current_alarms())
+ // idle until the next alarm
+ if ((alarm = find_next_alarm(appointments)))
+ {
+ g_debug ("setting timer to wake up for next appointment '%s' at %s",
+ alarm->text.c_str(),
+ alarm->time.format("%F %T").c_str());
+
+ m_timer->set_wakeup_time(alarm->time);
+ }
+ }
+
+ bool already_triggered (const Appointment& appt, const Alarm& alarm) const
{
- const std::pair<std::string,DateTime> trig {current.uid, current.begin};
- m_triggered.insert(trig);
- m_alarm_reached(current);
+ const std::pair<const std::string&,const DateTime&> key{appt.uid, alarm.time};
+ return m_triggered.count(key) != 0;
}
- // idle until the next alarm
- Appointment next;
- if (find_next_alarm(next))
+ // return the next Alarm (if any) that will kick now or in the future
+ const Alarm* find_next_alarm(const std::vector<Appointment>& appointments) const
{
- g_debug ("setting timer to wake up for next appointment '%s' at %s",
- next.summary.c_str(),
- next.begin.format("%F %T").c_str());
+ const Alarm* best {};
+ const auto now = m_clock->localtime();
+ const auto beginning_of_minute = now.start_of_minute();
- m_timer->set_wakeup_time(next.begin);
- }
-}
+ g_debug ("planner has %zu appointments in it", (size_t)appointments.size());
-// find the next alarm that will kick now or in the future
-bool SimpleAlarmQueue::find_next_alarm(Appointment& setme) const
-{
- bool found = false;
- Appointment tmp;
- const auto now = m_clock->localtime();
- const auto beginning_of_minute = now.start_of_minute();
+ for(const auto& appointment : appointments)
+ {
+ for(const auto& alarm : appointment.alarms)
+ {
+ if (already_triggered(appointment, alarm))
+ continue;
- const auto appointments = m_planner->appointments().get();
- g_debug ("planner has %zu appointments in it", (size_t)appointments.size());
+ if (alarm.time < beginning_of_minute) // has this one already passed?
+ continue;
- for(const auto& walk : appointments)
- {
- const std::pair<std::string,DateTime> trig {walk.uid, walk.begin};
- if (m_triggered.count(trig))
- continue;
+ if (best && (best->time < alarm.time)) // do we already have a better match?
+ continue;
- if (walk.begin < beginning_of_minute) // has this one already passed?
- continue;
+ best = &alarm;
+ }
+ }
- if (found && (tmp.begin < walk.begin)) // do we already have a better match?
- continue;
+ return best;
+ }
+
+ // return the Appointment's current Alarm (if any)
+ const Alarm* appointment_get_current_alarm(const Appointment& appointment) const
+ {
+ const auto now = m_clock->localtime();
- tmp = walk;
- found = true;
+ for (const auto& alarm : appointment.alarms)
+ if (!already_triggered(appointment, alarm) && DateTime::is_same_minute(now, alarm.time))
+ return &alarm;
+
+ return nullptr;
}
- if (found)
- setme = tmp;
- return found;
-}
+ std::set<std::pair<std::string,DateTime>> m_triggered;
+ const std::shared_ptr<Clock> m_clock;
+ const std::shared_ptr<Planner> m_planner;
+ const std::shared_ptr<WakeupTimer> m_timer;
+ core::Signal<const Appointment&, const Alarm&> m_alarm_reached;
+ DateTime m_datetime;
+};
-// find the alarm(s) that should kick right now
-std::vector<Appointment> SimpleAlarmQueue::find_current_alarms() const
-{
- std::vector<Appointment> appointments;
+/***
+**** Public API
+***/
- const auto now = m_clock->localtime();
- for(const auto& walk : m_planner->appointments().get())
- {
- const std::pair<std::string,DateTime> trig {walk.uid, walk.begin};
- if (m_triggered.count(trig)) // did we already use this one?
- continue;
- if (!DateTime::is_same_minute(now, walk.begin))
- continue;
+SimpleAlarmQueue::SimpleAlarmQueue(const std::shared_ptr<Clock>& clock,
+ const std::shared_ptr<Planner>& planner,
+ const std::shared_ptr<WakeupTimer>& timer):
+ impl{new Impl{clock, planner, timer}}
+{
+}
- appointments.push_back(walk);
- }
+SimpleAlarmQueue::~SimpleAlarmQueue()
+{
+}
- return appointments;
+core::Signal<const Appointment&, const Alarm&>&
+SimpleAlarmQueue::alarm_reached()
+{
+ return impl->alarm_reached();
}
/***
diff --git a/src/appointment.cpp b/src/appointment.cpp
index ae71459..1edd93c 100644
--- a/src/appointment.cpp
+++ b/src/appointment.cpp
@@ -27,16 +27,22 @@ namespace datetime {
*****
****/
+bool Alarm::operator==(const Alarm& that) const
+{
+ return (text==that.text)
+ && (audio_url==that.audio_url)
+ && (this->time==that.time);
+}
+
bool Appointment::operator==(const Appointment& that) const
{
return (type==that.type)
&& (uid==that.uid)
&& (color==that.color)
&& (summary==that.summary)
- && (url==that.url)
- && (audio_url==that.audio_url)
&& (begin==that.begin)
- && (end==that.end);
+ && (end==that.end)
+ && (alarms==that.alarms);
}
/****
diff --git a/src/awake.cpp b/src/awake.cpp
index 57358ab..e1bec6c 100644
--- a/src/awake.cpp
+++ b/src/awake.cpp
@@ -48,10 +48,16 @@ public:
g_cancellable_cancel (m_cancellable);
g_object_unref (m_cancellable);
+ if (m_display_on_timer)
+ {
+ g_source_remove (m_display_on_timer);
+ m_display_on_timer = 0;
+ }
+
if (m_system_bus != nullptr)
{
unforce_awake ();
- unforce_screen ();
+ remove_display_on_request ();
g_object_unref (m_system_bus);
}
}
@@ -106,7 +112,7 @@ private:
G_DBUS_CALL_FLAGS_NONE,
-1,
self->m_cancellable,
- on_force_screen_response,
+ on_keep_display_on_response,
self);
g_object_unref (system_bus);
@@ -146,9 +152,9 @@ private:
}
}
- static void on_force_screen_response (GObject * connection,
- GAsyncResult * res,
- gpointer gself)
+ static void on_keep_display_on_response (GObject * connection,
+ GAsyncResult * res,
+ gpointer gself)
{
GError * error;
GVariant * args;
@@ -171,14 +177,29 @@ private:
{
auto self = static_cast<Impl*>(gself);
- self->m_screen_cookie = NO_SCREEN_COOKIE;
- g_variant_get (args, "(i)", &self->m_screen_cookie);
- g_debug ("m_screen_cookie is now '%d'", self->m_screen_cookie);
+ self->m_display_on_cookie = NO_DISPLAY_ON_COOKIE;
+ g_variant_get (args, "(i)", &self->m_display_on_cookie);
+ g_debug ("m_display_on_cookie is now '%d'", self->m_display_on_cookie);
+
+ self->m_display_on_timer = g_timeout_add_seconds (self->m_display_on_seconds,
+ on_display_on_timer,
+ gself);
g_variant_unref (args);
}
}
+ static gboolean on_display_on_timer (gpointer gself)
+ {
+ auto self = static_cast<Impl*>(gself);
+
+ self->m_display_on_timer = 0;
+ self->remove_display_on_request();
+
+ return G_SOURCE_REMOVE;
+ }
+
+
void unforce_awake ()
{
g_return_if_fail (G_IS_DBUS_CONNECTION(m_system_bus));
@@ -202,18 +223,18 @@ private:
}
}
- void unforce_screen ()
+ void remove_display_on_request ()
{
g_return_if_fail (G_IS_DBUS_CONNECTION(m_system_bus));
- if (m_screen_cookie != NO_SCREEN_COOKIE)
+ if (m_display_on_cookie != NO_DISPLAY_ON_COOKIE)
{
g_dbus_connection_call (m_system_bus,
BUS_SCREEN_NAME,
BUS_SCREEN_PATH,
BUS_SCREEN_INTERFACE,
"removeDisplayOnRequest",
- g_variant_new("(i)", m_screen_cookie),
+ g_variant_new("(i)", m_display_on_cookie),
nullptr,
G_DBUS_CALL_FLAGS_NONE,
-1,
@@ -221,7 +242,7 @@ private:
nullptr,
nullptr);
- m_screen_cookie = NO_SCREEN_COOKIE;
+ m_display_on_cookie = NO_DISPLAY_ON_COOKIE;
}
}
@@ -229,9 +250,21 @@ private:
GCancellable * m_cancellable = nullptr;
GDBusConnection * m_system_bus = nullptr;
char * m_awake_cookie = nullptr;
- int32_t m_screen_cookie = NO_SCREEN_COOKIE;
- static constexpr int32_t NO_SCREEN_COOKIE { std::numeric_limits<int32_t>::min() };
+ /**
+ * As described by bug #1434637, alarms should have the display turn on,
+ * dim, and turn off "just like it would if you'd woken it up yourself".
+ * USC may be adding an intent-based bus API to handle this use case,
+ * e.g. turnDisplayOnTemporarily(intent), but there's no timeframe for it.
+ *
+ * Until that's avaialble, we can get close to Design's specs by
+ * requesting a display-on cookie and then releasing the cookie
+ * a moment later. */
+ const guint m_display_on_seconds = 1;
+ guint m_display_on_timer = 0;
+ int32_t m_display_on_cookie = NO_DISPLAY_ON_COOKIE;
+
+ static constexpr int32_t NO_DISPLAY_ON_COOKIE { std::numeric_limits<int32_t>::min() };
};
/***
@@ -239,7 +272,7 @@ private:
***/
Awake::Awake(const std::string& app_name):
- impl(new Impl (app_name))
+ impl(new Impl(app_name))
{
}
diff --git a/src/date-time.cpp b/src/date-time.cpp
index 689688c..4930bf6 100644
--- a/src/date-time.cpp
+++ b/src/date-time.cpp
@@ -55,13 +55,23 @@ DateTime& DateTime::operator=(const DateTime& that)
return *this;
}
-DateTime::DateTime(time_t t)
+DateTime& DateTime::operator+=(const std::chrono::minutes& minutes)
{
- auto gtz = g_time_zone_new_local();
- auto gdt = g_date_time_new_from_unix_local(t);
+ return (*this = add_full(0, 0, 0, 0, minutes.count(), 0));
+}
+
+DateTime& DateTime::operator+=(const std::chrono::seconds& seconds)
+{
+ return (*this = add_full(0, 0, 0, 0, 0, seconds.count()));
+}
+
+DateTime::DateTime(GTimeZone* gtz, time_t t)
+{
+ auto utc = g_date_time_new_from_unix_utc(t);
+ auto gdt = g_date_time_to_timezone (utc, gtz);
reset(gtz, gdt);
- g_time_zone_unref(gtz);
g_date_time_unref(gdt);
+ g_date_time_unref(utc);
}
DateTime DateTime::NowLocal()
@@ -74,6 +84,16 @@ DateTime DateTime::NowLocal()
return dt;
}
+DateTime DateTime::Local(time_t t)
+{
+ auto gtz = g_time_zone_new_local();
+ auto gdt = g_date_time_new_from_unix_local(t);
+ DateTime dt(gtz, gdt);
+ g_time_zone_unref(gtz);
+ g_date_time_unref(gdt);
+ return dt;
+}
+
DateTime DateTime::Local(int year, int month, int day, int hour, int minute, double seconds)
{
auto gtz = g_time_zone_new_local();
@@ -244,10 +264,12 @@ bool DateTime::is_same_day(const DateTime& a, const DateTime& b)
if (!a.m_dt || !b.m_dt)
return false;
- const auto adt = a.get();
- const auto bdt = b.get();
- return (g_date_time_get_year(adt) == g_date_time_get_year(bdt))
- && (g_date_time_get_day_of_year(adt) == g_date_time_get_day_of_year(bdt));
+ int ay, am, ad;
+ int by, bm, bd;
+ g_date_time_get_ymd(a.get(), &ay, &am, &ad);
+ g_date_time_get_ymd(b.get(), &by, &bm, &bd);
+
+ return (ay==by) && (am==bm) && (ad==bd);
}
bool DateTime::is_same_minute(const DateTime& a, const DateTime& b)
diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp
index a47ab4a..b91fd71 100644
--- a/src/engine-eds.cpp
+++ b/src/engine-eds.cpp
@@ -25,6 +25,7 @@
#include <libedataserver/libedataserver.h>
#include <algorithm> // std::sort()
+#include <array>
#include <ctime> // time()
#include <map>
#include <set>
@@ -128,12 +129,18 @@ public:
auto extension = e_source_get_extension(source, E_SOURCE_EXTENSION_CALENDAR);
const auto color = e_source_selectable_get_color(E_SOURCE_SELECTABLE(extension));
g_debug("calling e_cal_client_generate_instances for %p", (void*)client);
+ auto subtask = new AppointmentSubtask(main_task,
+ client,
+ color,
+ default_timezone,
+ begin_timet,
+ end_timet);
e_cal_client_generate_instances(client,
begin_timet,
end_timet,
m_cancellable,
my_get_appointments_foreach,
- new AppointmentSubtask (main_task, client, color),
+ subtask,
[](gpointer g){delete static_cast<AppointmentSubtask*>(g);});
}
}
@@ -411,14 +418,70 @@ private:
std::shared_ptr<Task> task;
ECalClient* client;
std::string color;
- AppointmentSubtask(const std::shared_ptr<Task>& task_in, ECalClient* client_in, const char* color_in):
- task(task_in), client(client_in)
+ icaltimezone* default_timezone;
+ time_t begin;
+ time_t end;
+
+ AppointmentSubtask(const std::shared_ptr<Task>& task_in,
+ ECalClient* client_in,
+ const char* color_in,
+ icaltimezone* default_tz,
+ time_t begin_,
+ time_t end_):
+ task(task_in),
+ client(client_in),
+ default_timezone(default_tz),
+ begin(begin_),
+ end(end_)
{
if (color_in)
color = color_in;
}
};
+ static std::string get_alarm_text(ECalComponentAlarm * alarm)
+ {
+ std::string ret;
+
+ ECalComponentAlarmAction action;
+ e_cal_component_alarm_get_action(alarm, &action);
+ if (action == E_CAL_COMPONENT_ALARM_DISPLAY)
+ {
+ ECalComponentText text {};
+ e_cal_component_alarm_get_description(alarm, &text);
+ if (text.value)
+ ret = text.value;
+ }
+
+ return ret;
+ }
+
+ static std::string get_alarm_sound_url(ECalComponentAlarm * alarm)
+ {
+ std::string ret;
+
+ ECalComponentAlarmAction action;
+ e_cal_component_alarm_get_action(alarm, &action);
+ if (action == E_CAL_COMPONENT_ALARM_AUDIO)
+ {
+ icalattach* attach = nullptr;
+ e_cal_component_alarm_get_attach(alarm, &attach);
+ if (attach != nullptr)
+ {
+ if (icalattach_get_is_url (attach))
+ {
+ const char* url = icalattach_get_url(attach);
+ if (url != nullptr)
+ ret = url;
+ }
+
+ icalattach_unref(attach);
+ }
+ }
+
+ return ret;
+ }
+
static gboolean
my_get_appointments_foreach(ECalComponent* component,
time_t begin,
@@ -436,11 +499,16 @@ private:
auto status = ICAL_STATUS_NONE;
e_cal_component_get_status(component, &status);
- const auto begin_dt = DateTime(begin);
- const auto end_dt = DateTime(end);
+ // get the timezone we want to use for generated Appointments/Alarms
+ const char * location = icaltimezone_get_location(subtask->default_timezone);
+ auto gtz = g_time_zone_new(location);
+ g_debug("timezone abbreviation is %s", g_time_zone_get_abbreviation (gtz, 0));
+
+ const DateTime begin_dt { gtz, begin };
+ const DateTime end_dt { gtz, end };
g_debug ("got appointment from %s to %s, uid %s status %d",
- begin_dt.format("%F %T").c_str(),
- end_dt.format("%F %T").c_str(),
+ begin_dt.format("%F %T %z").c_str(),
+ end_dt.format("%F %T %z").c_str(),
uid,
(int)status);
@@ -463,10 +531,10 @@ private:
(status != ICAL_STATUS_COMPLETED) &&
(status != ICAL_STATUS_CANCELLED))
{
+ constexpr std::array<ECalComponentAlarmAction,1> omit = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1
Appointment appointment;
- ECalComponentText text;
- text.value = nullptr;
+ ECalComponentText text {};
e_cal_component_get_summary(component, &text);
if (text.value)
appointment.summary = text.value;
@@ -495,49 +563,80 @@ private:
appointment.uid = uid;
appointment.type = type;
- // Look through all of this component's alarms
- // for DISPLAY or AUDIO url attachments.
- // If we find any, use them for appointment.url and audio_sound
- auto alarm_uids = e_cal_component_get_alarm_uids(component);
- for(auto walk=alarm_uids; appointment.url.empty() && walk!=nullptr; walk=walk->next)
+ icalcomponent * icc = e_cal_component_get_icalcomponent(component);
+ g_debug("%s", icalcomponent_as_ical_string(icc)); // libical owns this string; no leak
+
+ auto e_alarms = e_cal_util_generate_alarms_for_comp(component,
+ subtask->begin,
+ subtask->end,
+ const_cast<ECalComponentAlarmAction*>(omit.data()),
+ e_cal_client_resolve_tzid_cb,
+ subtask->client,
+ subtask->default_timezone);
+
+ std::map<DateTime,Alarm> alarms;
+
+ if (e_alarms != nullptr)
{
- auto alarm = e_cal_component_get_alarm(component, static_cast<const char*>(walk->data));
+ for (auto l=e_alarms->alarms; l!=nullptr; l=l->next)
+ {
+ auto ai = static_cast<ECalComponentAlarmInstance*>(l->data);
+ auto a = e_cal_component_get_alarm(component, ai->auid);
+
+ if (a != nullptr)
+ {
+ const DateTime alarm_begin{gtz, ai->trigger};
+ auto& alarm = alarms[alarm_begin];
+
+ if (alarm.text.empty())
+ alarm.text = get_alarm_text(a);
+ if (alarm.audio_url.empty())
+ alarm.audio_url = get_alarm_sound_url(a);
+ if (!alarm.time.is_set())
+ alarm.time = alarm_begin;
- ECalComponentAlarmAction action;
- e_cal_component_alarm_get_action(alarm, &action);
- if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) || (action == E_CAL_COMPONENT_ALARM_AUDIO))
+ e_cal_component_alarm_free(a);
+ }
+ }
+
+ e_cal_component_alarms_free(e_alarms);
+ }
+ // Hm, no alarm triggers?
+ // That's a bug in alarms created by some versions of ubuntu-ui-toolkit.
+ // If that's what's happening here, let's handle those alarms anyway
+ // by effectively injecting a TRIGGER;VALUE=DURATION;RELATED=START:PT0S
+ else if (appointment.is_ubuntu_alarm())
+ {
+ Alarm tmp;
+ tmp.time = appointment.begin;
+
+ auto auids = e_cal_component_get_alarm_uids(component);
+ for(auto l=auids; l!=nullptr; l=l->next)
{
- icalattach* attach = nullptr;
- e_cal_component_alarm_get_attach(alarm, &attach);
- if (attach != nullptr)
+ const auto auid = static_cast<const char*>(l->data);
+ auto a = e_cal_component_get_alarm(component, auid);
+ if (a != nullptr)
{
- if (icalattach_get_is_url (attach))
- {
- const char* url = icalattach_get_url(attach);
- if (url != nullptr)
- {
- if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) && appointment.url.empty())
- {
- appointment.url = url;
- }
- else if ((action == E_CAL_COMPONENT_ALARM_AUDIO) && appointment.audio_url.empty())
- {
- appointment.audio_url = url;
- }
- }
- }
-
- icalattach_unref(attach);
+ if (tmp.text.empty())
+ tmp.text = get_alarm_text(a);
+ if (tmp.audio_url.empty())
+ tmp.audio_url = get_alarm_sound_url(a);
+ e_cal_component_alarm_free(a);
}
}
+ cal_obj_uid_list_free(auids);
- e_cal_component_alarm_free(alarm);
+ alarms[tmp.time] = tmp;
}
- cal_obj_uid_list_free(alarm_uids);
- g_debug("adding appointment '%s' '%s'", appointment.summary.c_str(), appointment.url.c_str());
+ appointment.alarms.reserve(alarms.size());
+ for (const auto& it : alarms)
+ appointment.alarms.push_back(it.second);
+
subtask->task->appointments.push_back(appointment);
}
+
+ g_time_zone_unref(gtz);
}
return G_SOURCE_CONTINUE;
@@ -611,10 +710,10 @@ private:
std::set<ESource*> m_sources;
std::map<ESource*,ECalClient*> m_clients;
std::map<ESource*,ECalClientView*> m_views;
- GCancellable* m_cancellable = nullptr;
- ESourceRegistry* m_source_registry = nullptr;
- guint m_rebuild_tag = 0;
- time_t m_rebuild_deadline = 0;
+ GCancellable* m_cancellable {};
+ ESourceRegistry* m_source_registry {};
+ guint m_rebuild_tag {};
+ time_t m_rebuild_deadline {};
};
/***
diff --git a/src/main.cpp b/src/main.cpp
index 9aa502c..907d49f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -138,11 +138,13 @@ main(int /*argc*/, char** /*argv*/)
auto notification_engine = std::make_shared<uin::Engine>("indicator-datetime-service");
std::unique_ptr<Snap> snap (new Snap(notification_engine, state->settings));
auto alarm_queue = create_simple_alarm_queue(state->clock, snooze_planner, engine, timezone_);
- auto on_snooze = [snooze_planner](const Appointment& a) {snooze_planner->add(a);};
- auto on_ok = [](const Appointment&){};
- auto on_alarm_reached = [&engine, &snap, &on_snooze, &on_ok](const Appointment& a) {
- (*snap)(a, on_snooze, on_ok);
- engine->disable_ubuntu_alarm(a);
+ auto on_snooze = [snooze_planner](const Appointment& appointment, const Alarm& alarm) {
+ snooze_planner->add(appointment, alarm);
+ };
+ auto on_ok = [](const Appointment&, const Alarm&){};
+ auto on_alarm_reached = [&engine, &snap, &on_snooze, &on_ok](const Appointment& appointment, const Alarm& alarm) {
+ (*snap)(appointment, alarm, on_snooze, on_ok);
+ engine->disable_ubuntu_alarm(appointment);
};
alarm_queue->alarm_reached().connect(on_alarm_reached);
diff --git a/src/planner-snooze.cpp b/src/planner-snooze.cpp
index 29d5f06..e4062d2 100644
--- a/src/planner-snooze.cpp
+++ b/src/planner-snooze.cpp
@@ -51,14 +51,18 @@ public:
return m_appointments;
}
- void add(const Appointment& appt_in)
+ void add(const Appointment& appt_in, const Alarm& alarm)
{
+ // make a copy of the appointment with only this alarm
Appointment appt = appt_in;
+ appt.alarms.clear();
+ appt.alarms.push_back(alarm);
// reschedule the alarm to go off N minutes from now
- const auto alarm_duration_secs = appt.end - appt.begin;
- appt.begin = m_clock->localtime().add_full(0,0,0,0,m_settings->snooze_duration.get(),0);
- appt.end = appt.begin.add_full(0,0,0,0,0,alarm_duration_secs);
+ const auto offset = std::chrono::minutes(m_settings->snooze_duration.get());
+ appt.begin += offset;
+ appt.end += offset;
+ appt.alarms[0].time += offset;
// give it a new ID
gchar* uid = e_uid_new();
@@ -95,9 +99,9 @@ SnoozePlanner::~SnoozePlanner()
}
void
-SnoozePlanner::add(const Appointment& appointment)
+SnoozePlanner::add(const Appointment& appointment, const Alarm& alarm)
{
- impl->add(appointment);
+ impl->add(appointment, alarm);
}
core::Property<std::vector<Appointment>>&
diff --git a/src/snap.cpp b/src/snap.cpp
index e655d2d..ae0a62a 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -79,6 +79,7 @@ public:
}
void operator()(const Appointment& appointment,
+ const Alarm& alarm,
appointment_func snooze,
appointment_func ok)
{
@@ -96,7 +97,7 @@ public:
if (appointment.is_ubuntu_alarm() || !silent_mode()) {
// create the sound.
const auto role = appointment.is_ubuntu_alarm() ? "alarm" : "alert";
- const auto uri = get_alarm_uri(appointment, m_settings);
+ const auto uri = get_alarm_uri(alarm, m_settings);
const auto volume = m_settings->alarm_volume.get();
const bool loop = interactive;
sound = std::make_shared<uin::Sound>(role, uri, volume, loop);
@@ -140,12 +141,12 @@ public:
// add 'sound', 'haptic', and 'awake' objects to the capture so
// they stay alive until the closed callback is called; i.e.,
// for the lifespan of the notficiation
- b.set_closed_callback([appointment, snooze, ok, sound, awake, haptic]
+ b.set_closed_callback([appointment, alarm, snooze, ok, sound, awake, haptic]
(const std::string& action){
if (action == "snooze")
- snooze(appointment);
+ snooze(appointment, alarm);
else
- ok(appointment);
+ ok(appointment, alarm);
});
const auto key = m_engine->show(b);
@@ -180,12 +181,12 @@ private:
&& (accounts_service_sound_get_silent_mode(m_accounts_service_sound_proxy));
}
- std::string get_alarm_uri(const Appointment& appointment,
+ std::string get_alarm_uri(const Alarm& alarm,
const std::shared_ptr<const Settings>& settings) const
{
const char* FALLBACK {"/usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg"};
- const std::string candidates[] = { appointment.audio_url,
+ const std::string candidates[] = { alarm.audio_url,
settings->alarm_sound.get(),
FALLBACK };
@@ -236,10 +237,11 @@ Snap::~Snap()
void
Snap::operator()(const Appointment& appointment,
+ const Alarm& alarm,
appointment_func show,
appointment_func ok)
{
- (*impl)(appointment, show, ok);
+ (*impl)(appointment, alarm, show, ok);
}
/***
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 25fe5dc..8b6ec5d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -39,12 +39,10 @@ include_directories (${DBUSTEST_INCLUDE_DIRS})
add_definitions (-DSANDBOX="${CMAKE_CURRENT_BINARY_DIR}")
-
function(add_test_by_name name)
set (TEST_NAME ${name})
add_executable (${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled)
add_test (${TEST_NAME} ${TEST_NAME})
- add_dependencies (${TEST_NAME} libindicatordatetimeservice)
target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
endfunction()
add_test_by_name(test-datetime)
@@ -65,9 +63,41 @@ add_test_by_name(test-utils)
set (TEST_NAME manual-test-snap)
add_executable (${TEST_NAME} ${TEST_NAME}.cpp)
-add_dependencies (${TEST_NAME} libindicatordatetimeservice)
target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+##
+## EDS Tests
+##
+
+find_program(DBUS_RUNNER dbus-test-runner)
+find_program(EVOLUTION_CALENDAR_FACTORY evolution-calendar-factory PATHS /usr/lib/evolution/)
+find_program(EVOLUTION_SOURCE_REGISTRY evolution-source-registry PATHS /usr/lib/evolution/)
+find_program(GVFSD gvfsd PATHS /usr/lib/gvfs/)
+OPTION(EVOLUTION_SOURCE_SERVICE_NAME "DBus name for source registry")
+if(NOT EVOLUTION_SOURCE_SERVICE_NAME)
+ set(EVOLUTION_SOURCE_SERVICE_NAME "org.gnome.evolution.dataserver.Sources3")
+endif()
+
+function(add_eds_test_by_name name)
+ set (TEST_NAME ${name})
+ add_executable(${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled)
+ target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+ add_test (${TEST_NAME}
+ ${CMAKE_CURRENT_SOURCE_DIR}/run-eds-test.sh
+ ${DBUS_RUNNER} # arg1: dbus-test-runner exec
+ ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} # arg2: test executable path
+ ${TEST_NAME} # arg3: test name
+ ${EVOLUTION_CALENDAR_FACTORY} # arg4: evolution-calendar-factory exec
+ ${EVOLUTION_SOURCE_SERVICE_NAME} # arg5: dbus name for source registry
+ ${EVOLUTION_SOURCE_REGISTRY} # arg6: evolution-source-registry exec
+ ${GVFSD} # arg7: gvfsd exec
+ ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_NAME}-config-files) # arg8: canned config files
+endfunction()
+add_eds_test_by_name(test-eds-valarms)
+
+
+
+
# disabling the timezone unit tests because they require
# https://code.launchpad.net/~ted/dbus-test-runner/multi-interface-test/+merge/199724
# which hasn't landed yet. These can be re-enabled as soon as that lands.
@@ -75,7 +105,6 @@ target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEP
# set (TEST_NAME ${name})
# add_executable (${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled)
# add_test (${TEST_NAME} ${TEST_NAME})
-# add_dependencies (${TEST_NAME} libindicatordatetimeservice)
# target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GTEST_LIBS})
#endfunction()
#add_dbusmock_test_by_name(test-timezone-geoclue)
diff --git a/tests/manual-test-snap.cpp b/tests/manual-test-snap.cpp
index 22ef137..d04cf14 100644
--- a/tests/manual-test-snap.cpp
+++ b/tests/manual-test-snap.cpp
@@ -67,18 +67,18 @@ int main(int argc, const char* argv[])
Appointment a;
a.color = "green";
a.summary = "Alarm";
- a.url = "alarm:///hello-world";
a.uid = "D4B57D50247291478ED31DED17FF0A9838DED402";
a.type = Appointment::UBUNTU_ALARM;
a.begin = DateTime::Local(2014, 12, 25, 0, 0, 0);
a.end = a.begin.end_of_day();
+ a.alarms.push_back(Alarm{"Alarm Text", "", a.begin});
auto loop = g_main_loop_new(nullptr, false);
- auto on_snooze = [loop](const Appointment& appt){
- g_message("You clicked 'Snooze' for appt url '%s'", appt.url.c_str());
+ auto on_snooze = [loop](const Appointment& appt, const Alarm&){
+ g_message("You clicked 'Snooze' for appt url '%s'", appt.summary.c_str());
g_idle_add(quit_idle, loop);
};
- auto on_ok = [loop](const Appointment&){
+ auto on_ok = [loop](const Appointment&, const Alarm&){
g_message("You clicked 'OK'");
g_idle_add(quit_idle, loop);
};
@@ -93,7 +93,7 @@ int main(int argc, const char* argv[])
auto notification_engine = std::make_shared<uin::Engine>("indicator-datetime-service");
Snap snap (notification_engine, settings);
- snap(a, on_snooze, on_ok);
+ snap(a, a.alarms.front(), on_snooze, on_ok);
g_main_loop_run(loop);
g_main_loop_unref(loop);
diff --git a/tests/print-to.h b/tests/print-to.h
new file mode 100644
index 0000000..78cf574
--- /dev/null
+++ b/tests/print-to.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 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_TESTS_PRINT_TO
+#define INDICATOR_DATETIME_TESTS_PRINT_TO
+
+#include <algorithm>
+
+#include <datetime/appointment.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/***
+**** PrintTo() functions for GTest to represent objects as strings
+***/
+
+void
+PrintTo(const Alarm& alarm, std::ostream* os)
+{
+ *os << "{text:'" << alarm.text << "', audio_url:'" << alarm.audio_url << "', time:'"<<alarm.time.format("%F %T")<<"'}";
+}
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif
diff --git a/tests/run-eds-test.sh b/tests/run-eds-test.sh
new file mode 100755
index 0000000..0183350
--- /dev/null
+++ b/tests/run-eds-test.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+echo ARG0=$0 # this script
+echo ARG1=$1 # full executable path of dbus-test-runner
+echo ARG2=$2 # full executable path of test app
+echo ARG3=$3 # test name
+echo ARG4=$4 # full executable path of evolution-calendar-factory
+echo ARG5=$5 # bus service name of calendar factory
+echo ARG6=$6 # full exectuable path of evolution-source-registry
+echo ARG7=$7 # full executable path of gvfs
+echo ARG8=$8 # config files
+
+# set up the tmpdir and tell the shell to purge it when we exit
+export TEST_TMP_DIR=$(mktemp -p "${TMPDIR:-/tmp}" -d $3-XXXXXXXXXX) || exit 1
+echo "running test '$3' in ${TEST_TMP_DIR}"
+
+# set up the environment variables
+export QT_QPA_PLATFORM=minimal
+export HOME=${TEST_TMP_DIR}
+export XDG_RUNTIME_DIR=${TEST_TMP_DIR}
+export XDG_CACHE_HOME=${TEST_TMP_DIR}/.cache
+export XDG_CONFIG_HOME=${TEST_TMP_DIR}/.config
+export XDG_DATA_HOME=${TEST_TMP_DIR}/.local/share
+export XDG_DESKTOP_DIR=${TEST_TMP_DIR}
+export XDG_DOCUMENTS_DIR=${TEST_TMP_DIR}
+export XDG_DOWNLOAD_DIR=${TEST_TMP_DIR}
+export XDG_MUSIC_DIR=${TEST_TMP_DIR}
+export XDG_PICTURES_DIR=${TEST_TMP_DIR}
+export XDG_PUBLICSHARE_DIR=${TEST_TMP_DIR}
+export XDG_TEMPLATES_DIR=${TEST_TMP_DIR}
+export XDG_VIDEOS_DIR=${TEST_TMP_DIR}
+export QORGANIZER_EDS_DEBUG=On
+export GIO_USE_VFS=local # needed to ensure GVFS shuts down cleanly after the test is over
+
+echo HOMEDIR=${HOME}
+rm -rf ${XDG_DATA_HOME}
+
+# if there are canned config files for this test, move them into place now
+if [ -d $8 ]; then
+ echo "copying files from $8 to $HOME"
+ cp --verbose --archive $8/. $HOME
+fi
+
+# run dbus-test-runner
+$1 --keep-env --max-wait=90 \
+--task $2 --task-name $3 --wait-until-complete --wait-for=org.gnome.evolution.dataserver.Calendar4 \
+--task $4 --task-name "evolution" --wait-until-complete -r
+#--task $6 --task-name "source-registry" --wait-for=org.gtk.vfs.Daemon -r \
+#--task $7 --task-name "gvfsd" -r
+rv=$?
+
+# if the test passed, blow away the tmpdir
+if [ $rv -eq 0 ]; then
+ rm -rf $TEST_TMP_DIR
+fi
+
+return $rv
diff --git a/tests/test-alarm-queue.cpp b/tests/test-alarm-queue.cpp
index 3fdf787..aa35668 100644
--- a/tests/test-alarm-queue.cpp
+++ b/tests/test-alarm-queue.cpp
@@ -48,7 +48,7 @@ protected:
m_range_planner.reset(new MockRangePlanner);
m_upcoming.reset(new UpcomingPlanner(m_range_planner, m_state->clock->localtime()));
m_watcher.reset(new SimpleAlarmQueue(m_state->clock, m_upcoming, m_wakeup_timer));
- m_watcher->alarm_reached().connect([this](const Appointment& appt){
+ m_watcher->alarm_reached().connect([this](const Appointment& appt, const Alarm& /*alarm*/){
m_triggered.push_back(appt.uid);
});
@@ -71,7 +71,7 @@ protected:
const auto tomorrow_begin = now.add_days(1).start_of_day();
const auto tomorrow_end = tomorrow_begin.end_of_day();
- Appointment a1; // an alarm clock appointment
+ Appointment a1; // an ubuntu alarm
a1.color = "red";
a1.summary = "Alarm";
a1.summary = "http://www.example.com/";
@@ -79,18 +79,20 @@ protected:
a1.type = Appointment::UBUNTU_ALARM;
a1.begin = tomorrow_begin;
a1.end = tomorrow_end;
+ a1.alarms.push_back(Alarm{"Alarm Text", "", a1.begin});
const auto ubermorgen_begin = now.add_days(2).start_of_day();
const auto ubermorgen_end = ubermorgen_begin.end_of_day();
- Appointment a2; // a non-alarm appointment
+ Appointment a2; // something else
a2.color = "green";
a2.summary = "Other Text";
a2.summary = "http://www.monkey.com/";
a2.uid = "monkey";
- a1.type = Appointment::EVENT;
+ a2.type = Appointment::EVENT;
a2.begin = ubermorgen_begin;
a2.end = ubermorgen_end;
+ a2.alarms.push_back(Alarm{"Alarm Text", "", a2.begin});
return std::vector<Appointment>({a1, a2});
}
@@ -105,7 +107,7 @@ TEST_F(AlarmQueueFixture, 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();
+ a[0].begin = a[0].alarms.front().time = m_state->clock->localtime();
m_range_planner->appointments().set(a);
// Confirm that it got fired
@@ -135,7 +137,8 @@ TEST_F(AlarmQueueFixture, MoreThanOne)
{
const auto now = m_state->clock->localtime();
std::vector<Appointment> a = build_some_appointments();
- a[0].begin = a[1].begin = now;
+ a[0].alarms.front().time = now;
+ a[1].alarms.front().time = now;
m_range_planner->appointments().set(a);
ASSERT_EQ(2, m_triggered.size());
@@ -151,7 +154,7 @@ TEST_F(AlarmQueueFixture, NoDuplicates)
const std::vector<Appointment> appointments = build_some_appointments();
std::vector<Appointment> a;
a.push_back(appointments[0]);
- a[0].begin = now;
+ a[0].alarms.front().time = now;
m_range_planner->appointments().set(a);
ASSERT_EQ(1, m_triggered.size());
EXPECT_EQ(a[0].uid, m_triggered[0]);
diff --git a/tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source b/tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source
new file mode 100644
index 0000000..4b2f666
--- /dev/null
+++ b/tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source
@@ -0,0 +1,21 @@
+
+[Data Source]
+DisplayName=Default Proxy Settings
+Enabled=true
+Parent=
+
+[Proxy]
+Method=default
+IgnoreHosts=localhost;127.0.0.0/8;::1;
+AutoconfigUrl=
+FtpHost=
+FtpPort=0
+HttpAuthPassword=
+HttpAuthUser=
+HttpHost=
+HttpPort=8080
+HttpUseAuth=false
+HttpsHost=
+HttpsPort=0
+SocksHost=
+SocksPort=0
diff --git a/tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics b/tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics
new file mode 100644
index 0000000..fe526f4
--- /dev/null
+++ b/tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics
@@ -0,0 +1,47 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Ximian//NONSGML Evolution Calendar//EN
+VERSION:2.0
+X-EVOLUTION-DATA-REVISION:2015-04-05T21:32:47.354433Z(2)
+BEGIN:VEVENT
+UID:20150405T213247Z-4371-32011-1698-1@ubuntu-phablet
+DTSTAMP:20150405T213247Z
+DTSTART:20150424T183500Z
+DTEND:20150424T193554Z
+X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:Can't parse as RECUR value
+ in RRULE property. Removing entire property: ERROR: No Value
+SUMMARY:London Sprint Flight
+CREATED:20150405T213247Z
+LAST-MODIFIED:20150405T213247Z
+BEGIN:VALARM
+X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-2@ubuntu-phablet
+ACTION:AUDIO
+TRIGGER;VALUE=DURATION;RELATED=START:-P1D
+REPEAT:3
+DURATION:PT2M
+END:VALARM
+BEGIN:VALARM
+X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-3@ubuntu-phablet
+ACTION:DISPLAY
+DESCRIPTION:Time to pack!
+TRIGGER;VALUE=DURATION;RELATED=START:-P1D
+REPEAT:3
+DURATION:PT2M
+END:VALARM
+BEGIN:VALARM
+X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-5@ubuntu-phablet
+ACTION:AUDIO
+TRIGGER;VALUE=DURATION;RELATED=START:-PT3H
+REPEAT:3
+DURATION:PT2M
+END:VALARM
+BEGIN:VALARM
+X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-6@ubuntu-phablet
+ACTION:DISPLAY
+DESCRIPTION:Go to the airport!
+TRIGGER;VALUE=DURATION;RELATED=START:-PT3H
+REPEAT:3
+DURATION:PT2M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/tests/test-eds-valarms.cpp b/tests/test-eds-valarms.cpp
new file mode 100644
index 0000000..47f29e7
--- /dev/null
+++ b/tests/test-eds-valarms.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015 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 <algorithm>
+
+#include <datetime/alarm-queue-simple.h>
+#include <datetime/clock-mock.h>
+#include <datetime/engine-eds.h>
+#include <datetime/planner-range.h>
+
+#include <gtest/gtest.h>
+
+#include "glib-fixture.h"
+#include "print-to.h"
+#include "timezone-mock.h"
+#include "wakeup-timer-mock.h"
+
+using namespace unity::indicator::datetime;
+using VAlarmFixture = GlibFixture;
+
+/***
+****
+***/
+
+TEST_F(VAlarmFixture, MultipleAppointments)
+{
+ // start the EDS engine
+ auto engine = std::make_shared<EdsEngine>();
+
+ // we need a consistent timezone for the planner and our local DateTimes
+ constexpr char const * zone_str {"America/Chicago"};
+ auto tz = std::make_shared<MockTimezone>(zone_str);
+ auto gtz = g_time_zone_new(zone_str);
+
+ // make a planner that looks at the first half of 2015 in EDS
+ auto planner = std::make_shared<SimpleRangePlanner>(engine, tz);
+ const DateTime range_begin {gtz, 2015,1, 1, 0, 0, 0.0};
+ const DateTime range_end {gtz, 2015,6,31,23,59,59.5};
+ planner->range().set(std::make_pair(range_begin, range_end));
+
+ // give EDS a moment to load
+ if (planner->appointments().get().empty()) {
+ g_message("waiting a moment for EDS to load...");
+ auto on_appointments_changed = [this](const std::vector<Appointment>& appointments){
+ g_message("ah, they loaded");
+ if (!appointments.empty())
+ g_main_loop_quit(loop);
+ };
+ core::ScopedConnection conn(planner->appointments().changed().connect(on_appointments_changed));
+ constexpr int max_wait_sec = 10;
+ wait_msec(max_wait_sec * G_TIME_SPAN_MILLISECOND);
+ }
+
+ // the planner should match what we've got in the calendar.ics file
+ const auto appts = planner->appointments().get();
+ ASSERT_EQ(1, appts.size());
+ const auto& appt = appts.front();
+ ASSERT_EQ(8, appt.alarms.size());
+ EXPECT_EQ(Alarm({"Time to pack!", "", DateTime(gtz,2015,4,23,13,35,0)}), appt.alarms[0]);
+ EXPECT_EQ(Alarm({"Time to pack!", "", DateTime(gtz,2015,4,23,13,37,0)}), appt.alarms[1]);
+ EXPECT_EQ(Alarm({"Time to pack!", "", DateTime(gtz,2015,4,23,13,39,0)}), appt.alarms[2]);
+ EXPECT_EQ(Alarm({"Time to pack!", "", DateTime(gtz,2015,4,23,13,41,0)}), appt.alarms[3]);
+ EXPECT_EQ(Alarm({"Go to the airport!", "", DateTime(gtz,2015,4,24,10,35,0)}), appt.alarms[4]);
+ EXPECT_EQ(Alarm({"Go to the airport!", "", DateTime(gtz,2015,4,24,10,37,0)}), appt.alarms[5]);
+ EXPECT_EQ(Alarm({"Go to the airport!", "", DateTime(gtz,2015,4,24,10,39,0)}), appt.alarms[6]);
+ EXPECT_EQ(Alarm({"Go to the airport!", "", DateTime(gtz,2015,4,24,10,41,0)}), appt.alarms[7]);
+
+ // now let's try this out with AlarmQueue...
+ // hook the planner up to a SimpleAlarmQueue and confirm that it triggers for each of the reminders
+ auto mock_clock = std::make_shared<MockClock>(range_begin);
+ std::shared_ptr<Clock> clock = mock_clock;
+ std::shared_ptr<WakeupTimer> wakeup_timer = std::make_shared<MockWakeupTimer>(clock);
+ auto alarm_queue = std::make_shared<SimpleAlarmQueue>(clock, planner, wakeup_timer);
+ int triggered_count = 0;
+ alarm_queue->alarm_reached().connect([&triggered_count, appt](const Appointment&, const Alarm& active_alarm) {
+ EXPECT_TRUE(std::find(appt.alarms.begin(), appt.alarms.end(), active_alarm) != appt.alarms.end());
+ ++triggered_count;
+ });
+ for (auto now=range_begin; now<range_end; now+=std::chrono::minutes{1})
+ mock_clock->set_localtime(now);
+ EXPECT_EQ(appt.alarms.size(), triggered_count);
+
+ // cleanup
+ g_time_zone_unref(gtz);
+}
diff --git a/tests/test-exporter.cpp b/tests/test-exporter.cpp
index be8fcc3..d5118ac 100644
--- a/tests/test-exporter.cpp
+++ b/tests/test-exporter.cpp
@@ -222,7 +222,7 @@ TEST_F(ExporterFixture, AlarmProperties)
g_clear_pointer (&haptic, g_free);
/***
- **** Try chaning the DBus properties -- do the Settings change to match it?
+ **** Try changing the DBus properties -- do the Settings change to match it?
***/
expected_volume = 100;
diff --git a/tests/test-live-actions.cpp b/tests/test-live-actions.cpp
index 1a34511..4f84f25 100644
--- a/tests/test-live-actions.cpp
+++ b/tests/test-live-actions.cpp
@@ -319,10 +319,6 @@ TEST_F(LiveActionsFixture, PhoneOpenAppointment)
a.type = Appointment::UBUNTU_ALARM;
m_actions->phone_open_appointment(a);
EXPECT_EQ(clock_app_url, m_live_actions->last_url);
-
- a.url = "appid://blah";
- m_actions->phone_open_appointment(a);
- EXPECT_EQ(a.url, m_live_actions->last_url);
}
TEST_F(LiveActionsFixture, PhoneOpenCalendarApp)
@@ -392,7 +388,6 @@ TEST_F(LiveActionsFixture, CalendarState)
Appointment a1;
a1.color = "green";
a1.summary = "write unit tests";
- a1.url = "http://www.ubuntu.com/";
a1.uid = "D4B57D50247291478ED31DED17FF0A9838DED402";
a1.begin = tomorrow_begin;
a1.end = tomorrow_end;
@@ -403,7 +398,6 @@ TEST_F(LiveActionsFixture, CalendarState)
Appointment a2;
a2.color = "orange";
a2.summary = "code review";
- a2.url = "http://www.ubuntu.com/";
a2.uid = "2756ff7de3745bbffd65d2e4779c37c7ca60d843";
a2.begin = ubermorgen_begin;
a2.end = ubermorgen_end;
diff --git a/tests/test-snap.cpp b/tests/test-snap.cpp
index 3dd4501..46fbd10 100644
--- a/tests/test-snap.cpp
+++ b/tests/test-snap.cpp
@@ -106,12 +106,12 @@ protected:
// init the Appointment
appt.color = "green";
appt.summary = "Alarm";
- appt.url = "alarm:///hello-world";
appt.uid = "D4B57D50247291478ED31DED17FF0A9838DED402";
appt.type = Appointment::EVENT;
const auto christmas = DateTime::Local(2015,12,25,0,0,0);
appt.begin = christmas.start_of_day();
appt.end = christmas.end_of_day();
+ appt.alarms.push_back(Alarm{"Alarm Text", "", appt.begin});
service = dbus_test_service_new(nullptr);
@@ -343,8 +343,8 @@ TEST_F(SnapFixture, InteractiveDuration)
make_interactive();
// call the Snap Decision
- auto func = [this](const Appointment&){g_idle_add(quit_idle, loop);};
- snap(appt, func, func);
+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
+ snap(appt, appt.alarms.front(), func, func);
// confirm that Notify got called once
guint len = 0;
@@ -393,8 +393,8 @@ TEST_F(SnapFixture, InhibitSleep)
make_interactive();
// invoke the notification
- auto func = [this](const Appointment&){g_idle_add(quit_idle, loop);};
- (*snap)(appt, func, func);
+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
+ (*snap)(appt, appt.alarms.front(), func, func);
wait_msec(1000);
@@ -448,8 +448,8 @@ TEST_F(SnapFixture, ForceScreen)
make_interactive();
// invoke the notification
- auto func = [this](const Appointment&){g_idle_add(quit_idle, loop);};
- (*snap)(appt, func, func);
+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
+ (*snap)(appt, appt.alarms.front(), func, func);
wait_msec(1000);
@@ -484,14 +484,14 @@ TEST_F(SnapFixture, HapticModes)
{
auto settings = std::make_shared<Settings>();
auto ne = std::make_shared<unity::indicator::notifications::Engine>(APP_NAME);
- auto func = [this](const Appointment&){g_idle_add(quit_idle, loop);};
+ auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
GError * error = nullptr;
// invoke a snap decision while haptic feedback is set to "pulse",
// confirm that VibratePattern got called
settings->alarm_haptic.set("pulse");
auto snap = new Snap (ne, settings);
- (*snap)(appt, func, func);
+ (*snap)(appt, appt.alarms.front(), func, func);
wait_msec(100);
EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (haptic_mock,
haptic_obj,
@@ -506,7 +506,7 @@ TEST_F(SnapFixture, HapticModes)
dbus_test_dbus_mock_object_clear_method_calls (haptic_mock, haptic_obj, &error);
settings->alarm_haptic.set("none");
snap = new Snap (ne, settings);
- (*snap)(appt, func, func);
+ (*snap)(appt, appt.alarms.front(), func, func);
wait_msec(100);
EXPECT_FALSE (dbus_test_dbus_mock_object_check_method_call (haptic_mock,
haptic_obj,
diff --git a/tests/timezone-mock.h b/tests/timezone-mock.h
index 67584cb..55151aa 100644
--- a/tests/timezone-mock.h
+++ b/tests/timezone-mock.h
@@ -30,6 +30,7 @@ class MockTimezone: public Timezone
{
public:
MockTimezone() =default;
+ explicit MockTimezone(const std::string& zone) {timezone.set(zone);}
~MockTimezone() =default;
};
diff --git a/tests/wakeup-timer-mock.h b/tests/wakeup-timer-mock.h
new file mode 100644
index 0000000..8a59c97
--- /dev/null
+++ b/tests/wakeup-timer-mock.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015 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_WAKEUP_TIMER_MOCK_H
+#define INDICATOR_DATETIME_WAKEUP_TIMER_MOCK_H
+
+#include <datetime/clock.h>
+#include <datetime/wakeup-timer.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/***
+****
+***/
+
+/**
+ * \brief A one-shot timer that emits a signal when its timeout is reached.
+ */
+class MockWakeupTimer: public WakeupTimer
+{
+public:
+ explicit MockWakeupTimer(const std::shared_ptr<Clock>& clock):
+ m_clock(clock)
+ {
+ m_clock->minute_changed.connect([this](){
+ test_for_wakeup();
+ });
+ }
+
+ virtual ~MockWakeupTimer() =default;
+
+ virtual void set_wakeup_time (const DateTime& wakeup_time) override {
+ m_wakeup_time = wakeup_time;
+ test_for_wakeup();
+ }
+
+ virtual core::Signal<>& timeout() override { return m_timeout; }
+
+private:
+
+ void test_for_wakeup()
+ {
+ if (DateTime::is_same_minute(m_clock->localtime(), m_wakeup_time))
+ m_timeout();
+ }
+
+ core::Signal<> m_timeout;
+ const std::shared_ptr<Clock>& m_clock;
+ DateTime m_wakeup_time;
+};
+
+/***
+****
+***/
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_WAKEUP_TIMER_MOCK_H