aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorRobert Tari <robert@tari.in>2021-08-30 01:26:19 +0200
committerRobert Tari <robert@tari.in>2021-08-30 01:26:19 +0200
commit22e66866c7b17fc655479ca911269b86cb80a744 (patch)
treee0aa6e6a8f50fd8451e03efc17b89d8c8c3de781 /tests
parent1f8263dedf9b7e6f9e06492bd69f2436e36171a2 (diff)
parent38e5efecbb3154a83a70c1c762802ec7927b3caa (diff)
downloadayatana-indicator-datetime-22e66866c7b17fc655479ca911269b86cb80a744.tar.gz
ayatana-indicator-datetime-22e66866c7b17fc655479ca911269b86cb80a744.tar.bz2
ayatana-indicator-datetime-22e66866c7b17fc655479ca911269b86cb80a744.zip
Merge branch 'tari01-pr/ubports-patches'
Attributes GH PR #46: https://github.com/AyatanaIndicators/ayatana-indicator-datetime/pull/46
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt41
-rw-r--r--tests/accounts.dbbin0 -> 19456 bytes
-rw-r--r--tests/actions-mock.h42
-rw-r--r--tests/glib-fixture.h120
-rw-r--r--tests/libdbusmock-fixture.h148
-rw-r--r--tests/manual-test-snap.cpp21
-rw-r--r--tests/notification-fixture.h (renamed from tests/test-snap.cpp)307
-rw-r--r--tests/print-to.h10
-rwxr-xr-xtests/run-eds-ics-test.sh8
-rw-r--r--tests/test-actions.cpp20
-rw-r--r--tests/test-eds-ics-all-day-events.cpp3
-rw-r--r--tests/test-eds-ics-missing-trigger.cpp7
-rw-r--r--tests/test-eds-ics-non-attending-alarms.cpp89
-rw-r--r--tests/test-eds-ics-non-attending-alarms.ics.in53
-rw-r--r--tests/test-eds-ics-non-selected-source.cpp94
-rw-r--r--tests/test-eds-ics-non-selected-source.ics.in28
-rw-r--r--tests/test-eds-ics-nonrepeating-events.cpp5
-rw-r--r--tests/test-eds-ics-repeating-events-with-individual-change.cpp110
-rw-r--r--tests/test-eds-ics-repeating-events-with-individual-change.ics.in969
-rw-r--r--tests/test-eds-ics-repeating-events.cpp5
-rw-r--r--tests/test-eds-ics-repeating-valarms.cpp3
-rw-r--r--tests/test-eds-ics-tzids-2.cpp3
-rw-r--r--tests/test-eds-ics-tzids-utc.cpp98
-rw-r--r--tests/test-eds-ics-tzids-utc.ics.in15
-rw-r--r--tests/test-eds-ics-tzids.cpp3
-rw-r--r--tests/test-formatter.cpp11
-rw-r--r--tests/test-live-actions.cpp124
-rw-r--r--tests/test-menu-appointments.cpp263
-rw-r--r--tests/test-notification-response.cpp144
-rw-r--r--tests/test-notification.cpp198
-rw-r--r--tests/test-settings.cpp92
-rw-r--r--tests/test-sound.cpp182
-rw-r--r--tests/test-timezone-timedated.cpp131
-rw-r--r--tests/timedated-fixture.h331
34 files changed, 2918 insertions, 760 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5206259..4a38890 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,11 +1,6 @@
-# build libgtest
-add_library (gtest STATIC
- ${GTEST_SOURCE_DIR}/gtest-all.cc
- ${GTEST_SOURCE_DIR}/gtest_main.cc)
-set_target_properties (gtest PROPERTIES INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES} ${GTEST_INCLUDE_DIR})
-set_target_properties (gtest PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -w")
+find_package(GMock REQUIRED)
-SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${COMPILE_FLAGS}")
+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${COMPILE_FLAGS}")
# dbustest
pkg_check_modules(DBUSTEST REQUIRED
@@ -42,13 +37,17 @@ add_definitions (-DG_LOG_DOMAIN="ayatana-indicator-datetime")
function(add_test_by_name name)
set (TEST_NAME ${name})
+ set (COVERAGE_TEST_TARGETS ${COVERAGE_TEST_TARGETS} ${TEST_NAME} PARENT_SCOPE)
add_executable (${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled)
+ target_link_options(${TEST_NAME} PRIVATE -no-pie)
add_test (${TEST_NAME} ${TEST_NAME})
- target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS} ${URLDISPATCHER_LIBRARIES})
+ target_link_libraries (${TEST_NAME} indicatordatetimeservice ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES})
endfunction()
add_test_by_name(test-datetime)
if(HAVE_UT_ACCTSERVICE_SYSTEMSOUND_SETTINGS)
-add_test_by_name(test-snap)
+add_test_by_name(test-sound)
+add_test_by_name(test-notification)
+add_test_by_name(test-notification-response)
endif()
add_test_by_name(test-actions)
add_test_by_name(test-alarm-queue)
@@ -58,6 +57,7 @@ add_test_by_name(test-exporter)
add_test_by_name(test-formatter)
add_test_by_name(test-live-actions)
add_test_by_name(test-locations)
+add_test_by_name(test-menu-appointments)
add_test_by_name(test-menus)
add_test_by_name(test-planner)
add_test_by_name(test-settings)
@@ -66,8 +66,10 @@ add_test_by_name(test-utils)
if(HAVE_UT_ACCTSERVICE_SYSTEMSOUND_SETTINGS)
set (TEST_NAME manual-test-snap)
+ set (COVERAGE_TEST_TARGETS ${COVERAGE_TEST_TARGETS} ${TEST_NAME})
add_executable (${TEST_NAME} ${TEST_NAME}.cpp)
- target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+ target_link_options(${TEST_NAME} PRIVATE -no-pie)
+ target_link_libraries (${TEST_NAME} indicatordatetimeservice ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES})
endif()
##
@@ -78,17 +80,20 @@ find_program(DBUS_RUNNER dbus-test-runner)
function(add_eds_ics_test_by_name name)
set (TEST_NAME ${name})
+ set (COVERAGE_TEST_TARGETS ${COVERAGE_TEST_TARGETS} ${TEST_NAME} PARENT_SCOPE)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${TEST_NAME}.ics.in"
"${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.ics")
add_executable(${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled)
- target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+ target_link_options(${TEST_NAME} PRIVATE -no-pie)
+ target_link_libraries (${TEST_NAME} indicatordatetimeservice ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES})
add_test (${TEST_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/run-eds-ics-test.sh
${DBUS_RUNNER} # arg1: dbus-test-runner exec
${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} # arg2: test executable path
${TEST_NAME} # arg3: test name
${CMAKE_CURRENT_SOURCE_DIR}/test-eds-ics-config-files # arg4: base directory for config file template
- ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.ics) # arg5: the ical file for this test
+ ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.ics # arg5: the ical file for this test
+ ${CMAKE_CURRENT_SOURCE_DIR}/accounts.db) # arg6: online accounts database
endfunction()
add_eds_ics_test_by_name(test-eds-ics-all-day-events)
add_eds_ics_test_by_name(test-eds-ics-repeating-events)
@@ -97,15 +102,25 @@ add_eds_ics_test_by_name(test-eds-ics-repeating-valarms)
add_eds_ics_test_by_name(test-eds-ics-missing-trigger)
add_eds_ics_test_by_name(test-eds-ics-tzids)
add_eds_ics_test_by_name(test-eds-ics-tzids-2)
+add_eds_ics_test_by_name(test-eds-ics-tzids-utc)
+add_eds_ics_test_by_name(test-eds-ics-non-attending-alarms)
+add_eds_ics_test_by_name(test-eds-ics-repeating-events-with-individual-change)
# 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.
#function(add_dbusmock_test_by_name name)
# set (TEST_NAME ${name})
+# set (COVERAGE_TEST_TARGETS ${COVERAGE_TEST_TARGETS} ${TEST_NAME} PARENT_SCOPE)
# add_executable (${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled)
# add_test (${TEST_NAME} ${TEST_NAME})
-# target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GTEST_LIBS})
+# target_link_libraries (${TEST_NAME} indicatordatetimeservice ${SERVICE_DEPS_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES})
#endfunction()
#add_dbusmock_test_by_name(test-timezone-geoclue)
#add_dbusmock_test_by_name(test-timezones)
+
+set(
+ COVERAGE_TEST_TARGETS
+ ${COVERAGE_TEST_TARGETS}
+ PARENT_SCOPE
+)
diff --git a/tests/accounts.db b/tests/accounts.db
new file mode 100644
index 0000000..ece5b2f
--- /dev/null
+++ b/tests/accounts.db
Binary files differ
diff --git a/tests/actions-mock.h b/tests/actions-mock.h
index 59a0912..a02a7e2 100644
--- a/tests/actions-mock.h
+++ b/tests/actions-mock.h
@@ -34,14 +34,10 @@ public:
explicit MockActions(const std::shared_ptr<State>& state_in): Actions(state_in) {}
~MockActions() =default;
- enum Action { DesktopOpenAlarmApp,
- DesktopOpenAppt,
- DesktopOpenCalendarApp,
- DesktopOpenSettingsApp,
- PhoneOpenAlarmApp,
- PhoneOpenAppt,
- PhoneOpenCalendarApp,
- PhoneOpenSettingsApp,
+ enum Action { OpenAlarmApp,
+ OpenAppt,
+ OpenCalendarApp,
+ OpenSettingsApp,
SetLocation };
const std::vector<Action>& history() const { return m_history; }
@@ -54,34 +50,20 @@ public:
bool desktop_has_calendar_app() const {
return m_desktop_has_calendar_app;
}
- void desktop_open_alarm_app() {
- m_history.push_back(DesktopOpenAlarmApp);
+ void open_alarm_app() {
+ m_history.push_back(OpenAlarmApp);
}
- void desktop_open_appointment(const Appointment& appt) {
+ void open_appointment(const Appointment& appt, const DateTime& dt) {
m_appt = appt;
- m_history.push_back(DesktopOpenAppt);
- }
- void desktop_open_calendar_app(const DateTime& dt) {
m_date_time = dt;
- m_history.push_back(DesktopOpenCalendarApp);
- }
- void desktop_open_settings_app() {
- m_history.push_back(DesktopOpenSettingsApp);
- }
-
- void phone_open_alarm_app() {
- m_history.push_back(PhoneOpenAlarmApp);
- }
- void phone_open_appointment(const Appointment& appt) {
- m_appt = appt;
- m_history.push_back(PhoneOpenAppt);
+ m_history.push_back(OpenAppt);
}
- void phone_open_calendar_app(const DateTime& dt) {
+ void open_calendar_app(const DateTime& dt) {
m_date_time = dt;
- m_history.push_back(PhoneOpenCalendarApp);
+ m_history.push_back(OpenCalendarApp);
}
- void phone_open_settings_app() {
- m_history.push_back(PhoneOpenSettingsApp);
+ void open_settings_app() {
+ m_history.push_back(OpenSettingsApp);
}
void set_location(const std::string& zone_, const std::string& name_) {
diff --git a/tests/glib-fixture.h b/tests/glib-fixture.h
index 4d309e6..88ee384 100644
--- a/tests/glib-fixture.h
+++ b/tests/glib-fixture.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 Canonical Ltd.
+ * Copyright 2013-2016 Canonical Ltd.
*
* Authors:
* Charles Kerr <charles.kerr@canonical.com>
@@ -17,10 +17,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H
-#define INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H
+#pragma once
+#include <chrono>
+#include <functional> // std::function
#include <map>
+#include <memory> // std::shared_ptr
#include <glib.h>
#include <glib/gstdio.h>
@@ -109,7 +111,115 @@ class GlibFixture : public ::testing::Test
g_source_remove(id);
}
- GMainLoop * loop;
+ bool wait_for(std::function<bool()> test_function, guint timeout_msec=1000)
+ {
+ auto timer = std::shared_ptr<GTimer>(g_timer_new(), [](GTimer* t){g_timer_destroy(t);});
+ const auto timeout_sec = timeout_msec / 1000.0;
+ for (;;) {
+ if (test_function())
+ return true;
+ //g_message("%f ... %f", g_timer_elapsed(timer.get(), nullptr), timeout_sec);
+ if (g_timer_elapsed(timer.get(), nullptr) >= timeout_sec)
+ return false;
+ wait_msec();
+ }
+ }
+
+ bool wait_for_name_owned(GDBusConnection* connection,
+ const gchar* name,
+ guint timeout_msec=1000,
+ GBusNameWatcherFlags flags=G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
+ {
+ struct Data {
+ GMainLoop* loop = nullptr;
+ bool owned = false;
+ };
+ Data data;
+
+ auto on_name_appeared = [](GDBusConnection* /*connection*/,
+ const gchar* /*name_*/,
+ const gchar* name_owner,
+ gpointer gdata)
+ {
+ if (name_owner == nullptr)
+ return;
+ auto tmp = static_cast<Data*>(gdata);
+ tmp->owned = true;
+ g_main_loop_quit(tmp->loop);
+ };
+
+ const auto timeout_id = g_timeout_add(timeout_msec, wait_msec__timeout, loop);
+ data.loop = loop;
+ const auto watch_id = g_bus_watch_name_on_connection(connection,
+ name,
+ flags,
+ on_name_appeared,
+ nullptr, /* name_vanished */
+ &data,
+ nullptr); /* user_data_free_func */
+ g_main_loop_run(loop);
+
+ g_bus_unwatch_name(watch_id);
+ g_source_remove(timeout_id);
+
+ return data.owned;
+ }
+
+ void EXPECT_NAME_OWNED_EVENTUALLY(GDBusConnection* connection,
+ const gchar* name,
+ guint timeout_msec=1000,
+ GBusNameWatcherFlags flags=G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
+ {
+ EXPECT_TRUE(wait_for_name_owned(connection, name, timeout_msec, flags)) << "name: " << name;
+ }
+
+ void EXPECT_NAME_NOT_OWNED_EVENTUALLY(GDBusConnection* connection,
+ const gchar* name,
+ guint timeout_msec=1000,
+ GBusNameWatcherFlags flags=G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
+ {
+ EXPECT_FALSE(wait_for_name_owned(connection, name, timeout_msec, flags)) << "name: " << name;
+ }
+
+ void ASSERT_NAME_OWNED_EVENTUALLY(GDBusConnection* connection,
+ const gchar* name,
+ guint timeout_msec=1000,
+ GBusNameWatcherFlags flags=G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
+ {
+ ASSERT_TRUE(wait_for_name_owned(connection, name, timeout_msec, flags)) << "name: " << name;
+ }
+
+ void ASSERT_NAME_NOT_OWNED_EVENTUALLY(GDBusConnection* connection,
+ const gchar* name,
+ guint timeout_msec=1000,
+ GBusNameWatcherFlags flags=G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
+ {
+ ASSERT_FALSE(wait_for_name_owned(connection, name, timeout_msec, flags)) << "name: " << name;
+ }
+
+ using source_func = std::function<gboolean()>;
+
+ guint idle_add(source_func&& func)
+ {
+ return g_idle_add_full(
+ G_PRIORITY_DEFAULT_IDLE,
+ [](gpointer gf){return (*static_cast<source_func*>(gf))();},
+ new std::function<gboolean()>(func),
+ [](gpointer gf){delete static_cast<source_func*>(gf);}
+ );
+ }
+
+ guint timeout_add(source_func&& func, std::chrono::milliseconds msec)
+ {
+ return g_timeout_add_full(
+ G_PRIORITY_DEFAULT,
+ msec.count(),
+ [](gpointer gf){return (*static_cast<source_func*>(gf))();},
+ new std::function<gboolean()>(func),
+ [](gpointer gf){delete static_cast<source_func*>(gf);}
+ );
+ }
+
+ GMainLoop* loop {};
};
-#endif /* INDICATOR_DATETIME_TESTS_GLIB_FIXTURE_H */
diff --git a/tests/libdbusmock-fixture.h b/tests/libdbusmock-fixture.h
new file mode 100644
index 0000000..7301042
--- /dev/null
+++ b/tests/libdbusmock-fixture.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2014-2016 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>
+ */
+
+#pragma once
+
+#include "glib-fixture.h"
+
+#include <libdbustest/dbus-test.h>
+
+/***
+****
+***/
+
+class LibdbusmockFixture: public GlibFixture
+{
+private:
+
+ typedef GlibFixture super;
+
+protected:
+
+ GDBusConnection * system_bus {};
+ GDBusConnection * session_bus {};
+ DbusTestService * service {};
+
+ void SetUp() override
+ {
+
+ super::SetUp();
+
+ service = dbus_test_service_new(nullptr);
+ }
+
+ void startDbusMock()
+ {
+ // start 'em up.
+ // make the system bus work off the mock bus too, since that's
+ // where the upower and screen are on the system bus...
+
+ dbus_test_service_start_tasks(service);
+ g_setenv("DBUS_SYSTEM_BUS_ADDRESS", g_getenv("DBUS_SESSION_BUS_ADDRESS"), TRUE);
+
+ session_bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
+ ASSERT_NE(nullptr, session_bus);
+ g_dbus_connection_set_exit_on_close(session_bus, false);
+ g_object_add_weak_pointer(G_OBJECT(session_bus), (gpointer *)&session_bus);
+
+ system_bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr);
+ ASSERT_NE(nullptr, system_bus);
+ g_dbus_connection_set_exit_on_close(system_bus, FALSE);
+ g_object_add_weak_pointer(G_OBJECT(system_bus), (gpointer *)&system_bus);
+ }
+
+ void TearDown() override
+ {
+ g_clear_object(&service);
+ g_object_unref(session_bus);
+ g_object_unref(system_bus);
+
+ // wait a little while for the scaffolding to shut down,
+ // but don't block on it forever...
+ wait_for([this](){return system_bus==nullptr && session_bus==nullptr;}, 5000);
+
+ super::TearDown();
+ }
+
+ bool wait_for_method_call(DbusTestDbusMock* mock,
+ DbusTestDbusMockObject* obj,
+ const gchar* method,
+ GVariant* params=nullptr,
+ guint timeout_msec=100)
+ {
+ if (params != nullptr)
+ g_variant_ref_sink(params);
+
+ auto test_function = [mock, obj, method, params]() {
+ GError* error {};
+ const auto called = dbus_test_dbus_mock_object_check_method_call(mock,
+ obj,
+ method,
+ params,
+ &error);
+ if (error != nullptr) {
+ g_critical("Error looking for method call '%s': %s", method, error->message);
+ g_clear_error(&error);
+ }
+
+ return called;
+ };
+
+ const auto ret = wait_for(test_function, timeout_msec);
+ g_clear_pointer(&params, g_variant_unref);
+ return ret;
+ }
+
+ void EXPECT_METHOD_CALLED_EVENTUALLY(DbusTestDbusMock* mock,
+ DbusTestDbusMockObject* obj,
+ const gchar* method,
+ GVariant* params=nullptr,
+ guint timeout_msec=1000)
+ {
+ EXPECT_TRUE(wait_for_method_call(mock, obj, method, params, timeout_msec)) << "method: " << method;
+ }
+
+ void EXPECT_METHOD_NOT_CALLED_EVENTUALLY(DbusTestDbusMock* mock,
+ DbusTestDbusMockObject* obj,
+ const gchar* method,
+ GVariant* params=nullptr,
+ guint timeout_msec=1000)
+ {
+ EXPECT_FALSE(wait_for_method_call(mock, obj, method, params, timeout_msec)) << "method: " << method;
+ }
+
+ void ASSERT_METHOD_CALLED_EVENTUALLY(DbusTestDbusMock* mock,
+ DbusTestDbusMockObject* obj,
+ const gchar* method,
+ GVariant* params=nullptr,
+ guint timeout_msec=1000)
+ {
+ ASSERT_TRUE(wait_for_method_call(mock, obj, method, params, timeout_msec)) << "method: " << method;
+ }
+
+ void ASSERT_METHOD_NOT_CALLED_EVENTUALLY(DbusTestDbusMock* mock,
+ DbusTestDbusMockObject* obj,
+ const gchar* method,
+ GVariant* params=nullptr,
+ guint timeout_msec=1000)
+ {
+ ASSERT_FALSE(wait_for_method_call(mock, obj, method, params, timeout_msec)) << "method: " << method;
+ }
+};
+
diff --git a/tests/manual-test-snap.cpp b/tests/manual-test-snap.cpp
index a0f80f2..72fd374 100644
--- a/tests/manual-test-snap.cpp
+++ b/tests/manual-test-snap.cpp
@@ -74,12 +74,14 @@ int main(int argc, const char* argv[])
a.alarms.push_back(Alarm{"Alarm Text", "", a.begin});
auto loop = g_main_loop_new(nullptr, false);
- 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&, const Alarm&){
- g_message("You clicked 'OK'");
+ auto on_response = [loop](const Appointment& appt, const Alarm&, const Snap::Response& response){
+ const char* str {""};
+ switch(response) {
+ case Snap::Response::ShowApp: str = "show-app"; break;
+ case Snap::Response::Snooze: str = "snooze"; break;
+ case Snap::Response::None: str = "no-action"; break;
+ };
+ g_message("You clicked '%s' for appt url '%s'", str, appt.summary.c_str());
g_idle_add(quit_idle, loop);
};
@@ -92,10 +94,13 @@ int main(int argc, const char* argv[])
settings->alarm_volume.set(volume);
auto notification_engine = std::make_shared<ain::Engine>("ayatana-indicator-datetime-service");
- Snap snap (notification_engine, settings);
- snap(a, a.alarms.front(), on_snooze, on_ok);
+ auto sound_builder = std::make_shared<ain::DefaultSoundBuilder>();
+ auto system_bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr);
+ Snap snap (notification_engine, sound_builder, settings, system_bus);
+ snap(a, a.alarms.front(), on_response);
g_main_loop_run(loop);
g_main_loop_unref(loop);
+ g_clear_object(&system_bus);
return 0;
}
diff --git a/tests/test-snap.cpp b/tests/notification-fixture.h
index afee297..cbce9ff 100644
--- a/tests/test-snap.cpp
+++ b/tests/notification-fixture.h
@@ -1,8 +1,5 @@
/*
- * Copyright 2014 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
+ * Copyright 2014-2016 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
@@ -15,8 +12,15 @@
*
* 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>
*/
+#pragma once
+
+#include "libdbusmock-fixture.h"
+
#include <datetime/appointment.h>
#include <datetime/dbus-shared.h>
#include <datetime/settings.h>
@@ -27,38 +31,25 @@
#include <libdbustest/dbus-test.h>
-#include <glib.h>
-
#include <unistd.h> // getuid()
#include <sys/types.h> // getuid()
-using namespace ayatana::indicator::datetime;
-
-#include "glib-fixture.h"
-
/***
****
***/
-namespace
-{
- static constexpr char const * APP_NAME {"ayatana-indicator-datetime-service"};
-}
-
-using namespace ayatana::indicator::datetime;
-
-class SnapFixture: public GlibFixture
+class NotificationFixture: public LibdbusmockFixture
{
private:
- typedef GlibFixture super;
+ typedef LibdbusmockFixture super;
+
+protected:
static constexpr char const * NOTIFY_BUSNAME {"org.freedesktop.Notifications"};
static constexpr char const * NOTIFY_INTERFACE {"org.freedesktop.Notifications"};
static constexpr char const * NOTIFY_PATH {"/org/freedesktop/Notifications"};
-protected:
-
static constexpr char const * HAPTIC_METHOD_VIBRATE_PATTERN {"VibratePattern"};
static constexpr int SCREEN_COOKIE {8675309};
@@ -87,15 +78,13 @@ protected:
static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"};
static constexpr char const * AS_BUSNAME {"org.freedesktop.Accounts"};
- static constexpr char const * AS_INTERFACE {"com.ubuntu.touch.AccountsService.Sound"};
+ static constexpr char const * AS_INTERFACE {"com.lomiri.touch.AccountsService.Sound"};
static constexpr char const * PROP_OTHER_VIBRATIONS {"OtherVibrate"};
static constexpr char const * PROP_SILENT_MODE {"SilentMode"};
- Appointment appt;
- Appointment ualarm;
- GDBusConnection * system_bus = nullptr;
- GDBusConnection * session_bus = nullptr;
- DbusTestService * service = nullptr;
+ ayatana::indicator::datetime::Appointment appt;
+ ayatana::indicator::datetime::Appointment ualarm;
+
DbusTestDbusMock * as_mock = nullptr;
DbusTestDbusMock * notify_mock = nullptr;
DbusTestDbusMock * powerd_mock = nullptr;
@@ -118,23 +107,21 @@ protected:
appt.color = "green";
appt.summary = "Christmas";
appt.uid = "D4B57D50247291478ED31DED17FF0A9838DED402";
- appt.type = Appointment::EVENT;
- const auto christmas = DateTime::Local(2015,12,25,0,0,0);
+ appt.type = ayatana::indicator::datetime::Appointment::EVENT;
+ const auto christmas = ayatana::indicator::datetime::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{"Ho Ho Ho!", "", appt.begin});
+ appt.alarms.push_back(ayatana::indicator::datetime::Alarm{"Ho Ho Ho!", CALENDAR_DEFAULT_SOUND, appt.begin});
- // init an Ubuntu Alarm
+ // init a Lomiri Alarm
ualarm.color = "red";
ualarm.summary = "Wakeup";
ualarm.uid = "E4B57D50247291478ED31DED17FF0A9838DED403";
- ualarm.type = Appointment::UBUNTU_ALARM;
- const auto tomorrow = DateTime::NowLocal().add_days(1);
+ ualarm.type = ayatana::indicator::datetime::Appointment::UBUNTU_ALARM;
+ const auto tomorrow = ayatana::indicator::datetime::DateTime::NowLocal().add_days(1);
ualarm.begin = tomorrow;
ualarm.end = tomorrow;
- ualarm.alarms.push_back(Alarm{"It's Tomorrow!", "", appt.begin});
-
- service = dbus_test_service_new(nullptr);
+ ualarm.alarms.push_back(ayatana::indicator::datetime::Alarm{"It's Tomorrow!", "", appt.begin});
///
/// Add the AccountsService mock
@@ -311,23 +298,7 @@ protected:
g_assert_no_error (error);
dbus_test_service_add_task(service, DBUS_TEST_TASK(haptic_mock));
-
- // start 'em up.
- // make the system bus work off the mock bus too, since that's
- // where the upower and screen are on the system bus...
-
- dbus_test_service_start_tasks(service);
- g_setenv("DBUS_SYSTEM_BUS_ADDRESS", g_getenv("DBUS_SESSION_BUS_ADDRESS"), TRUE);
-
- session_bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
- ASSERT_NE(nullptr, session_bus);
- g_dbus_connection_set_exit_on_close(session_bus, false);
- g_object_add_weak_pointer(G_OBJECT(session_bus), (gpointer *)&session_bus);
-
- system_bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr);
- ASSERT_NE(nullptr, system_bus);
- g_dbus_connection_set_exit_on_close(system_bus, FALSE);
- g_object_add_weak_pointer(G_OBJECT(system_bus), (gpointer *)&system_bus);
+ startDbusMock();
}
void TearDown() override
@@ -337,20 +308,6 @@ protected:
g_clear_object(&powerd_mock);
g_clear_object(&notify_mock);
g_clear_object(&as_mock);
- g_clear_object(&service);
- g_object_unref(session_bus);
- g_object_unref(system_bus);
-
- // wait a little while for the scaffolding to shut down,
- // but don't block on it forever...
- unsigned int cleartry = 0;
- while (((system_bus != nullptr) || (session_bus != nullptr)) && (cleartry < 50))
- {
- g_usleep(100000);
- while (g_main_context_pending(nullptr))
- g_main_context_iteration(nullptr, true);
- cleartry++;
- }
super::TearDown();
}
@@ -371,213 +328,15 @@ protected:
&error);
g_assert_no_error (error);
}
-};
-/***
-****
-***/
-
-namespace
-{
- gboolean quit_idle (gpointer gloop)
+ std::shared_ptr<ayatana::indicator::datetime::Snap>
+ create_snap(const std::shared_ptr<ayatana::indicator::notifications::Engine>& ne,
+ const std::shared_ptr<ayatana::indicator::notifications::SoundBuilder>& sb,
+ const std::shared_ptr<ayatana::indicator::datetime::Settings>& settings)
{
- g_main_loop_quit(static_cast<GMainLoop*>(gloop));
- return G_SOURCE_REMOVE;
- };
-}
-
-TEST_F(SnapFixture, InteractiveDuration)
-{
- static constexpr int duration_minutes = 120;
- auto settings = std::make_shared<Settings>();
- settings->alarm_duration.set(duration_minutes);
- auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
- Snap snap (ne, settings);
-
- make_interactive();
-
- // call the Snap Decision
- 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;
- GError * error = nullptr;
- const auto calls = dbus_test_dbus_mock_object_get_method_calls (notify_mock,
- notify_obj,
- METHOD_NOTIFY,
- &len,
- &error);
- g_assert_no_error(error);
- ASSERT_EQ(1, len);
-
- // confirm that the app_name passed to Notify was APP_NAME
- const auto& params = calls[0].params;
- ASSERT_EQ(8, g_variant_n_children(params));
- const char * str = nullptr;
- g_variant_get_child (params, 0, "&s", &str);
- ASSERT_STREQ(APP_NAME, str);
-
- // confirm that the icon passed to Notify was "alarm-clock"
- g_variant_get_child (params, 2, "&s", &str);
- ASSERT_STREQ("alarm-clock", str);
-
- // confirm that the hints passed to Notify included a timeout matching duration_minutes
- int32_t i32;
- bool b;
- auto hints = g_variant_get_child_value (params, 6);
- b = g_variant_lookup (hints, HINT_TIMEOUT, "i", &i32);
- EXPECT_TRUE(b);
- const auto duration = std::chrono::minutes(duration_minutes);
- EXPECT_EQ(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(), i32);
- g_variant_unref(hints);
- ne.reset();
-}
-
-/***
-****
-***/
-
-TEST_F(SnapFixture, InhibitSleep)
-{
- auto settings = std::make_shared<Settings>();
- auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
- auto snap = new Snap (ne, settings);
-
- make_interactive();
-
- // invoke the notification
- auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
- (*snap)(appt, appt.alarms.front(), func, func);
-
- wait_msec(1000);
-
- // confirm that sleep got inhibited
- GError * error = nullptr;
- EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
- powerd_obj,
- POWERD_METHOD_REQUEST_SYS_STATE,
- g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE),
- &error));
-
- // confirm that the screen got forced on
- EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock,
- screen_obj,
- SCREEN_METHOD_KEEP_DISPLAY_ON,
- nullptr,
- &error));
-
- // force-close the snap
- wait_msec(100);
- delete snap;
- wait_msec(100);
-
- // confirm that sleep got uninhibted
- EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
- powerd_obj,
- POWERD_METHOD_CLEAR_SYS_STATE,
- g_variant_new("(s)", POWERD_COOKIE),
- &error));
-
- // confirm that the screen's no longer forced on
- EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (screen_mock,
- screen_obj,
- SCREEN_METHOD_REMOVE_DISPLAY_ON_REQUEST,
- g_variant_new("(i)", SCREEN_COOKIE),
- &error));
-
- g_assert_no_error (error);
-}
-
-/***
-****
-***/
-
-TEST_F(SnapFixture, ForceScreen)
-{
- auto settings = std::make_shared<Settings>();
- auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
- auto snap = new Snap (ne, settings);
-
- make_interactive();
-
- // invoke the notification
- auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
- (*snap)(appt, appt.alarms.front(), func, func);
-
- wait_msec(1000);
-
- // confirm that sleep got inhibited
- GError * error = nullptr;
- EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
- powerd_obj,
- POWERD_METHOD_REQUEST_SYS_STATE,
- g_variant_new("(si)", APP_NAME, POWERD_SYS_STATE_ACTIVE),
- &error));
- g_assert_no_error(error);
-
- // force-close the snap
- wait_msec(100);
- delete snap;
- wait_msec(100);
-
- // confirm that sleep got uninhibted
- EXPECT_TRUE (dbus_test_dbus_mock_object_check_method_call (powerd_mock,
- powerd_obj,
- POWERD_METHOD_CLEAR_SYS_STATE,
- g_variant_new("(s)", POWERD_COOKIE),
- &error));
- g_assert_no_error(error);
-}
-
-/***
-****
-***/
-
-TEST_F(SnapFixture,Vibrate)
-{
- auto settings = std::make_shared<Settings>();
- auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
- auto func = [this](const Appointment&, const Alarm&){g_idle_add(quit_idle, loop);};
- GError * error = nullptr;
-
- struct {
- bool other_vibrations; // the com.ubuntu.touch.AccountsService.Sound "other vibrations" setting
- const char* haptic_mode; // supported values: "none", "pulse"
- bool expected_vibrate_called; // do we expect the phone to vibrate?
- } test_cases[] = {
- { false, "none", false },
- { true, "none", false },
- { false, "pulse", false },
- { true, "pulse", true }
- };
-
- auto snap = std::make_shared<Snap>(ne, settings);
-
- for(const auto& test_case : test_cases)
- {
- // clear out any previous iterations' noise
- dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error);
-
- // set the properties to match the test case
- settings->alarm_haptic.set(test_case.haptic_mode);
- dbus_test_dbus_mock_object_update_property(as_mock,
- as_obj,
- PROP_OTHER_VIBRATIONS,
- g_variant_new_boolean(test_case.other_vibrations),
- &error);
- g_assert_no_error(error);
- wait_msec(100);
-
- // run the test
- (*snap)(appt, appt.alarms.front(), func, func);
- wait_msec(100);
- const bool vibrate_called = dbus_test_dbus_mock_object_check_method_call(haptic_mock,
- haptic_obj,
- HAPTIC_METHOD_VIBRATE_PATTERN,
- nullptr,
- &error);
- g_assert_no_error(error);
- EXPECT_EQ(test_case.expected_vibrate_called, vibrate_called);
+ auto snap = std::make_shared<ayatana::indicator::datetime::Snap>(ne, sb, settings, system_bus);
+ wait_msec(100); // wait a moment for the Snap to finish its async dbus bootstrapping
+ return snap;
}
-}
+};
+
diff --git a/tests/print-to.h b/tests/print-to.h
index 19367ac..652da52 100644
--- a/tests/print-to.h
+++ b/tests/print-to.h
@@ -21,6 +21,7 @@
#define INDICATOR_DATETIME_TESTS_PRINT_TO
#include <algorithm>
+#include <vector>
#include <datetime/appointment.h>
@@ -71,6 +72,15 @@ PrintTo(const Appointment& appointment, std::ostream* os)
*os << '}';
}
+void
+PrintTo(const std::vector<Appointment>& appointments, std::ostream* os)
+{
+ *os << '{';
+ for (const auto& appointment : appointments)
+ PrintTo(appointment, os);
+ *os << '}';
+}
+
} // namespace datetime
} // namespace indicator
} // namespace ayatana
diff --git a/tests/run-eds-ics-test.sh b/tests/run-eds-ics-test.sh
index 13c1617..b38fe77 100755
--- a/tests/run-eds-ics-test.sh
+++ b/tests/run-eds-ics-test.sh
@@ -6,6 +6,7 @@ TEST_EXEC=$2 # full executable path of test app
TEST_NAME=$3 # test name
CONFIG_DIR=$4 # config files
ICS_FILE=$5 # ical file holding test data
+ACCOUNTS_DB=$6 # online account database
echo "this script: ${SELF}"
echo "test-runner: ${TEST_RUNNER}"
@@ -55,6 +56,13 @@ if [ -e ${ICS_FILE} ]; then
cp --verbose --archive ${ICS_FILE} ${XDG_DATA_HOME}/evolution/tasks/system/tasks.ics
fi
+# prepare online accounts database
+if [ -e ${ACCOUNTS_DB} ]; then
+ echo "copying ${ACCOUNTS_DB} into $HOME"
+ mkdir -p ${XDG_CONFIG_HOME}/libaccounts-glib/
+ cp --verbose --archive ${ACCOUNTS_DB} ${XDG_CONFIG_HOME}/libaccounts-glib/accounts.db
+fi
+
# run the test
${TEST_RUNNER} --keep-env --max-wait=90 --task ${TEST_EXEC} --task-name ${TEST_NAME} --wait-until-complete
rv=$?
diff --git a/tests/test-actions.cpp b/tests/test-actions.cpp
index aa608a8..a01fb83 100644
--- a/tests/test-actions.cpp
+++ b/tests/test-actions.cpp
@@ -116,7 +116,7 @@ protected:
m_mock_state->mock_range_planner->appointments().set(appointments);
// activate the action
- auto v = g_variant_new_string(appointments[0].uid.c_str());
+ auto v = g_variant_new("(sx)", appointments[0].uid.c_str(), 0);
g_action_group_activate_action(action_group, action_name, v);
// test the results
@@ -134,7 +134,7 @@ protected:
EXPECT_TRUE(m_mock_actions->history().empty());
// activate the action
- v = g_variant_new_string("this-uid-is-not-one-that-we-have");
+ v = g_variant_new("(sx)", "this-uid-is-not-one-that-we-have", 0);
g_action_group_activate_action(action_group, action_name, v);
// test the results
@@ -176,25 +176,25 @@ TEST_F(ActionsFixture, ActionsExist)
TEST_F(ActionsFixture, DesktopOpenAlarmApp)
{
test_action_with_no_args("desktop.open-alarm-app",
- MockActions::DesktopOpenAlarmApp);
+ MockActions::OpenAlarmApp);
}
TEST_F(ActionsFixture, DesktopOpenAppointment)
{
test_action_with_appt_arg("desktop.open-appointment",
- MockActions::DesktopOpenAppt);
+ MockActions::OpenAppt);
}
TEST_F(ActionsFixture, DesktopOpenCalendarApp)
{
test_action_with_time_arg("desktop.open-calendar-app",
- MockActions::DesktopOpenCalendarApp);
+ MockActions::OpenCalendarApp);
}
TEST_F(ActionsFixture, DesktopOpenSettingsApp)
{
test_action_with_no_args("desktop.open-settings-app",
- MockActions::DesktopOpenSettingsApp);
+ MockActions::OpenSettingsApp);
}
/***
@@ -204,25 +204,25 @@ TEST_F(ActionsFixture, DesktopOpenSettingsApp)
TEST_F(ActionsFixture, PhoneOpenAlarmApp)
{
test_action_with_no_args("phone.open-alarm-app",
- MockActions::PhoneOpenAlarmApp);
+ MockActions::OpenAlarmApp);
}
TEST_F(ActionsFixture, PhoneOpenAppointment)
{
test_action_with_appt_arg("phone.open-appointment",
- MockActions::PhoneOpenAppt);
+ MockActions::OpenAppt);
}
TEST_F(ActionsFixture, PhoneOpenCalendarApp)
{
test_action_with_time_arg("phone.open-calendar-app",
- MockActions::PhoneOpenCalendarApp);
+ MockActions::OpenCalendarApp);
}
TEST_F(ActionsFixture, PhoneOpenSettingsApp)
{
test_action_with_no_args("phone.open-settings-app",
- MockActions::PhoneOpenSettingsApp);
+ MockActions::OpenSettingsApp);
}
/***
diff --git a/tests/test-eds-ics-all-day-events.cpp b/tests/test-eds-ics-all-day-events.cpp
index 68a3c95..5d7cdc6 100644
--- a/tests/test-eds-ics-all-day-events.cpp
+++ b/tests/test-eds-ics-all-day-events.cpp
@@ -24,6 +24,7 @@
#include <datetime/alarm-queue-simple.h>
#include <datetime/clock-mock.h>
#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
#include <datetime/planner-range.h>
#include <gtest/gtest.h>
@@ -43,7 +44,7 @@ using VAlarmFixture = GlibFixture;
TEST_F(VAlarmFixture, MultipleAppointments)
{
// start the EDS engine
- auto engine = std::make_shared<EdsEngine>();
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
// we need a consistent timezone for the planner and our local DateTimes
constexpr char const * zone_str {"America/Chicago"};
diff --git a/tests/test-eds-ics-missing-trigger.cpp b/tests/test-eds-ics-missing-trigger.cpp
index 0aa00c6..70bbccb 100644
--- a/tests/test-eds-ics-missing-trigger.cpp
+++ b/tests/test-eds-ics-missing-trigger.cpp
@@ -21,9 +21,10 @@
#include <algorithm>
-#include <datetime/engine-eds.h>
#include <datetime/alarm-queue-simple.h>
#include <datetime/clock-mock.h>
+#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
#include <datetime/planner-range.h>
#include <gtest/gtest.h>
@@ -43,7 +44,7 @@ using VAlarmFixture = GlibFixture;
TEST_F(VAlarmFixture, MissingTriggers)
{
// start the EDS engine
- auto engine = std::make_shared<EdsEngine>();
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
// we need a consistent timezone for the planner and our local DateTimes
constexpr char const * zone_str {"America/Chicago"};
@@ -62,7 +63,7 @@ TEST_F(VAlarmFixture, MissingTriggers)
// 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,30,23,59,59.5};
+ const DateTime range_end {gtz, 2015,7,1,23,59,59.5};
planner->range().set(std::make_pair(range_begin, range_end));
// give EDS a moment to load
diff --git a/tests/test-eds-ics-non-attending-alarms.cpp b/tests/test-eds-ics-non-attending-alarms.cpp
new file mode 100644
index 0000000..bfa3ac3
--- /dev/null
+++ b/tests/test-eds-ics-non-attending-alarms.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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/myself.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 ayatana::indicator::datetime;
+using VAlarmFixture = GlibFixture;
+
+/***
+****
+***/
+
+TEST_F(VAlarmFixture, NonAttendingEvent)
+{
+ // start the EDS engine
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
+
+ // we need a consistent timezone for the planner and our local DateTimes
+ constexpr char const * zone_str {"America/Recife"};
+ auto tz = std::make_shared<MockTimezone>(zone_str);
+
+ #if GLIB_CHECK_VERSION(2, 68, 0)
+ auto gtz = g_time_zone_new_identifier(zone_str);
+
+ if (gtz == NULL)
+ {
+ gtz = g_time_zone_new_utc();
+ }
+ #else
+ auto gtz = g_time_zone_new(zone_str);
+ #endif
+
+ // make a planner that looks at the first half of 2016 in EDS
+ auto planner = std::make_shared<SimpleRangePlanner>(engine, tz);
+ const DateTime range_begin {gtz, 2016,1, 1, 0, 0, 0.0};
+ const DateTime range_end {gtz, 2016,6,30,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();
+ EXPECT_EQ(2, appts.size());
+ EXPECT_EQ(appts[0].begin, DateTime(gtz, 2016, 4, 4, 16, 0, 0));
+ EXPECT_EQ(appts[1].begin, DateTime(gtz, 2016, 4, 6, 16, 0, 0));
+
+ // cleanup
+ g_time_zone_unref(gtz);
+}
diff --git a/tests/test-eds-ics-non-attending-alarms.ics.in b/tests/test-eds-ics-non-attending-alarms.ics.in
new file mode 100644
index 0000000..7adc8ab
--- /dev/null
+++ b/tests/test-eds-ics-non-attending-alarms.ics.in
@@ -0,0 +1,53 @@
+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
+STATUS:CONFIRMED
+DTSTAMP:20160405T152128Z
+CREATED:20160405T152128Z
+UID:ddtvl069dn2cquo8dhg3j9c360@google.com
+SEQUENCE:1
+TRANSP:OPAQUE
+SUMMARY:Every day at 4PM
+DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160404T160000
+RRULE:FREQ=DAILY;UNTIL=20160406T190000Z
+DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160404T170000
+ATTENDEE;CN=Uphablet;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;
+ CUTYPE=INDIVIDUAL:mailto:uphablet@lomiri.com
+LAST-MODIFIED:20160405T152128Z
+BEGIN:VALARM
+TRIGGER;VALUE=DURATION:-PT30M
+ACTION:EMAIL
+DESCRIPTION:This is an event reminder
+X-EVOLUTION-ALARM-UID:20160405T152128Z-2848-32011-1844-65@lomiri-phablet
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+STATUS:CONFIRMED
+DTSTAMP:20160405T152128Z
+CREATED:20160405T151054Z
+UID:ddtvl069dn2cquo8dhg3j9c360@google.com
+SEQUENCE:1
+TRANSP:OPAQUE
+SUMMARY::Every day at 4PM
+DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Fortaleza:
+ 20160405T160000
+RECURRENCE-ID;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160405T160000
+DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/America/Fortaleza:
+ 20160405T170000
+ATTENDEE;CN=Uphablet;PARTSTAT=DECLINED;ROLE=REQ-PARTICIPANT;
+ CUTYPE=INDIVIDUAL:mailto:uphablet@lomiri.com
+LAST-MODIFIED:20160405T152128Z
+BEGIN:VALARM
+TRIGGER;VALUE=DURATION:-PT30M
+ACTION:EMAIL
+DESCRIPTION:This is an event reminder
+X-EVOLUTION-ALARM-UID:20160405T152128Z-2848-32011-1844-66@lomiri-phablet
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/tests/test-eds-ics-non-selected-source.cpp b/tests/test-eds-ics-non-selected-source.cpp
new file mode 100644
index 0000000..5101b32
--- /dev/null
+++ b/tests/test-eds-ics-non-selected-source.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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:
+ * Renato Araujo Oliveira Filh <renato.filho@canonical.com>
+ */
+
+#include <algorithm>
+
+#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
+#include <datetime/planner-range.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include <gtest/gtest.h>
+
+#include "glib-fixture.h"
+#include "timezone-mock.h"
+
+using namespace ayatana::indicator::datetime;
+using VAlarmFixture = GlibFixture;
+
+/***
+****
+***/
+
+TEST_F(VAlarmFixture, NonSelectedSources)
+{
+ // start the EDS engine
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
+
+ // 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);
+ }
+
+ // appointmes are visible
+ auto appts = planner->appointments().get();
+ EXPECT_TRUE(appts.size() > 0);
+
+ // Unselect all sources
+ auto registry = e_source_registry_new_sync(NULL, NULL);
+ auto sources = e_source_registry_list_sources(registry, E_SOURCE_EXTENSION_TASK_LIST);
+ for (auto l=sources; l!=nullptr; l=l->next) {
+ auto source = static_cast<ESource*>(l->data);
+ auto extension = e_source_get_extension(source, E_SOURCE_EXTENSION_CALENDAR);
+ e_source_selectable_set_selected(E_SOURCE_SELECTABLE(extension), FALSE);
+ e_source_write_sync(source, NULL, NULL);
+ }
+
+ g_list_free_full(sources, g_object_unref);
+ g_object_unref(registry);
+
+ // give some time to planner update
+ wait_msec(5 * G_TIME_SPAN_MILLISECOND);
+
+ // the planner should be empty at this point
+ appts = planner->appointments().get();
+ EXPECT_TRUE(appts.size() == 0);
+ // cleanup
+ g_time_zone_unref(gtz);
+}
diff --git a/tests/test-eds-ics-non-selected-source.ics.in b/tests/test-eds-ics-non-selected-source.ics.in
new file mode 100644
index 0000000..19f93d7
--- /dev/null
+++ b/tests/test-eds-ics-non-selected-source.ics.in
@@ -0,0 +1,28 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Ximian//NONSGML Evolution Calendar//EN
+VERSION:2.0
+X-EVOLUTION-DATA-REVISION:2015-05-07T21:14:49.315443Z(0)
+BEGIN:VTODO
+UID:20150507T211449Z-4262-32011-1418-1@lomiri-phablet
+DTSTAMP:20150508T211449Z
+DTSTART:20150508T164000
+RRULE:FREQ=WEEKLY;BYDAY=FR
+SUMMARY:Alarm
+CATEGORIES:x-lomiri-alarm
+CREATED:20150507T211449Z
+LAST-MODIFIED:20150507T211449Z
+BEGIN:VALARM
+X-EVOLUTION-ALARM-UID:20150507T211449Z-4262-32011-1418-2@lomiri-phablet
+ACTION:AUDIO
+ATTACH:file://@ALARM_DEFAULT_SOUND@
+TRIGGER;VALUE=DURATION;RELATED=START:PT0S
+END:VALARM
+BEGIN:VALARM
+X-EVOLUTION-ALARM-UID:20150507T211449Z-4262-32011-1418-3@lomiri-phablet
+ACTION:DISPLAY
+DESCRIPTION:Alarm
+TRIGGER;VALUE=DURATION;RELATED=START:PT0S
+END:VALARM
+END:VTODO
+END:VCALENDAR
diff --git a/tests/test-eds-ics-nonrepeating-events.cpp b/tests/test-eds-ics-nonrepeating-events.cpp
index e79ab1a..8aa2b82 100644
--- a/tests/test-eds-ics-nonrepeating-events.cpp
+++ b/tests/test-eds-ics-nonrepeating-events.cpp
@@ -24,6 +24,7 @@
#include <datetime/alarm-queue-simple.h>
#include <datetime/clock-mock.h>
#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
#include <datetime/planner-range.h>
#include <gtest/gtest.h>
@@ -43,7 +44,7 @@ using VAlarmFixture = GlibFixture;
TEST_F(VAlarmFixture, MultipleAppointments)
{
// start the EDS engine
- auto engine = std::make_shared<EdsEngine>();
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
// we need a consistent timezone for the planner and our local DateTimes
constexpr char const * zone_str {"America/Chicago"};
@@ -80,7 +81,7 @@ TEST_F(VAlarmFixture, MultipleAppointments)
// what we expect to get...
Appointment expected_appt;
- expected_appt.uid = "20150520T000726Z-3878-32011-1770-81@ubuntu-phablet";
+ expected_appt.uid = "20150520T000726Z-3878-32011-1770-81@lomiri-phablet";
expected_appt.color = "#becedd";
expected_appt.summary = "Alarm";
std::array<Alarm,1> expected_alarms = {
diff --git a/tests/test-eds-ics-repeating-events-with-individual-change.cpp b/tests/test-eds-ics-repeating-events-with-individual-change.cpp
new file mode 100644
index 0000000..a4a85c0
--- /dev/null
+++ b/tests/test-eds-ics-repeating-events-with-individual-change.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016 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:
+ * Renato Araujo Oliveira Filho <renato.filho@canonical.com>
+ */
+
+#include <algorithm>
+
+#include <datetime/alarm-queue-simple.h>
+#include <datetime/clock-mock.h>
+#include <datetime/engine-eds.h>
+#include <datetime/myself.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 ayatana::indicator::datetime;
+using VAlarmFixture = GlibFixture;
+
+/***
+****
+***/
+
+TEST_F(VAlarmFixture, RepeatingEventsWithIndividualChange)
+{
+ // start the EDS engine
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
+
+ // we need a consistent timezone for the planner and our local DateTimes
+ constexpr char const * zone_str {"America/Recife"};
+ auto tz = std::make_shared<MockTimezone>(zone_str);
+ #if GLIB_CHECK_VERSION(2, 68, 0)
+ auto gtz = g_time_zone_new_identifier(zone_str);
+
+ if (gtz == NULL)
+ {
+ gtz = g_time_zone_new_utc();
+ }
+ #else
+ auto gtz = g_time_zone_new(zone_str);
+ #endif
+
+ // make a planner that looks at the year of 2016 in EDS
+ auto planner = std::make_shared<SimpleRangePlanner>(engine, tz);
+ const DateTime range_begin {gtz, 2016,1, 1, 0, 0, 0.0};
+ const DateTime range_end {gtz, 2016,12,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);
+ }
+
+ // what we expect to get...
+ Appointment expected_appt;
+ expected_appt.summary = "Alarm";
+ std::array<DateTime,10> expected_times = {
+ DateTime(gtz,2016,6, 20,10,00,0),
+ DateTime(gtz,2016,6, 21,10,00,0),
+ DateTime(gtz,2016,6, 22,10,00,0),
+ DateTime(gtz,2016,6, 23,10,00,0),
+ DateTime(gtz,2016,6, 24,20,00,0),
+ DateTime(gtz,2016,6, 25,10,00,0),
+ DateTime(gtz,2016,6, 26,10,00,0),
+ DateTime(gtz,2016,6, 27,10,00,0),
+ DateTime(gtz,2016,6, 28,10,00,0),
+ DateTime(gtz,2016,6, 29,10,00,0)
+ };
+
+ // compare it to what we actually loaded...
+ const auto appts = planner->appointments().get();
+ EXPECT_EQ(expected_times.size(), appts.size());
+ for (size_t i=0, n=expected_times.size(); i<n; i++) {
+ const auto& appt = appts[i];
+ if (i != 4)
+ EXPECT_EQ("Every day and every night", appt.summary);
+ else
+ EXPECT_EQ("At night", appt.summary);
+ EXPECT_EQ(expected_times[i], appt.begin);
+ }
+
+ // cleanup
+ g_time_zone_unref(gtz);
+}
diff --git a/tests/test-eds-ics-repeating-events-with-individual-change.ics.in b/tests/test-eds-ics-repeating-events-with-individual-change.ics.in
new file mode 100644
index 0000000..3723399
--- /dev/null
+++ b/tests/test-eds-ics-repeating-events-with-individual-change.ics.in
@@ -0,0 +1,969 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Ximian//NONSGML Evolution Calendar//EN
+VERSION:2.0
+X-EVOLUTION-DATA-REVISION:2016-06-21T21:42:08.507434Z(7)
+BEGIN:VTIMEZONE
+TZID:/freeassociation.sourceforge.net/Tzfile/America/Recife
+X-LIC-LOCATION:America/Recife
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:19680301T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:19851102T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:19860315T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:19861025T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:19870214T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:19871025T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:19880207T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:19881016T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:19890129T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:19891015T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:19900211T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:19991003T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:20000227T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:20001008T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:20001015T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:BRST
+DTSTART:20011014T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:BRT
+DTSTART:20020217T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:-0300
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VTIMEZONE
+TZID:/freeassociation.sourceforge.net/Tzfile/America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19691026T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19700426T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19701025T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19710425T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19711031T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19720430T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19721029T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19730429T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19731028T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19740106T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19741027T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19750223T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19751026T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19760425T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19761031T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19770424T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19771030T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19780430T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19781029T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19790429T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19791028T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19800427T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19801026T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19810426T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19811025T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19820425T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19821031T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19830424T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19831030T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19840429T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19841028T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19850428T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19851027T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19860427T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19861026T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19870405T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19871025T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19880403T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19881030T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19890402T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19891029T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19900401T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19901028T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19910407T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19911027T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19920405T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19921025T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19930404T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19931031T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19940403T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19941030T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19950402T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19951029T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19960407T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19961027T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19970406T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19971026T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19980405T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19981025T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:19990404T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:19991031T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20000402T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20001029T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20010401T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20011028T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20020407T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20021027T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20030406T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20031026T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20040404T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20041031T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20050403T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20051030T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20060402T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20061029T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20070311T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20071104T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20080309T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20081102T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20090308T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20091101T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20100314T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20101107T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20110313T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20111106T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20120311T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20121104T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20130310T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20131103T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20140309T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20141102T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20150308T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20151101T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20160313T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20161106T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20170312T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20171105T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20180311T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20181104T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20190310T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20191103T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20200308T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20201101T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20210314T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20211107T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20220313T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20221106T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20230312T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20231105T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20240310T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20241103T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20250309T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20251102T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20260308T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20261101T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20270314T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20271107T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20280312T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20281105T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20290311T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20291104T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20300310T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20301103T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20310309T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20311102T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20320314T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20321107T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20330313T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20331106T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20340312T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20341105T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20350311T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20351104T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20360309T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20361102T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+TZNAME:EDT
+DTSTART:20370308T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+TZNAME:EST
+DTSTART:20371101T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:20160621T214054Z-31488-1000-4151-27@rento-lomiri
+DTSTAMP:20160621T123718Z
+DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160620T100000
+DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160620T103000
+TRANSP:OPAQUE
+SEQUENCE:2
+SUMMARY:Every day and every night
+CLASS:PUBLIC
+RRULE;X-EVOLUTION-ENDDATE=20160629T130000Z:FREQ=DAILY;COUNT=10
+CREATED:20160621T214124Z
+LAST-MODIFIED:20160621T214124Z
+END:VEVENT
+BEGIN:VEVENT
+UID:20160621T214054Z-31488-1000-4151-27@rento-lomiri
+DTSTAMP:20160621T123718Z
+DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160624T200000
+DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160624T203000
+TRANSP:OPAQUE
+SEQUENCE:3
+SUMMARY:At night
+CLASS:PUBLIC
+CREATED:20160621T214124Z
+LAST-MODIFIED:20160621T214208Z
+RECURRENCE-ID;TZID=/freeassociation.sourceforge.net/Tzfile/America/Recife:
+ 20160624T100000
+END:VEVENT
+END:VCALENDAR
diff --git a/tests/test-eds-ics-repeating-events.cpp b/tests/test-eds-ics-repeating-events.cpp
index d4f0026..4125623 100644
--- a/tests/test-eds-ics-repeating-events.cpp
+++ b/tests/test-eds-ics-repeating-events.cpp
@@ -24,6 +24,7 @@
#include <datetime/alarm-queue-simple.h>
#include <datetime/clock-mock.h>
#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
#include <datetime/planner-range.h>
#include <gtest/gtest.h>
@@ -43,7 +44,7 @@ using VAlarmFixture = GlibFixture;
TEST_F(VAlarmFixture, MultipleAppointments)
{
// start the EDS engine
- auto engine = std::make_shared<EdsEngine>();
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
// we need a consistent timezone for the planner and our local DateTimes
constexpr char const * zone_str {"America/Chicago"};
@@ -80,7 +81,7 @@ TEST_F(VAlarmFixture, MultipleAppointments)
// what we expect to get...
Appointment expected_appt;
- expected_appt.uid = "20150507T211449Z-4262-32011-1418-1@ubuntu-phablet";
+ expected_appt.uid = "20150507T211449Z-4262-32011-1418-1@lomiri-phablet";
expected_appt.color = "#becedd";
expected_appt.summary = "Alarm";
std::array<Alarm,8> expected_alarms = {
diff --git a/tests/test-eds-ics-repeating-valarms.cpp b/tests/test-eds-ics-repeating-valarms.cpp
index 2132b71..1584983 100644
--- a/tests/test-eds-ics-repeating-valarms.cpp
+++ b/tests/test-eds-ics-repeating-valarms.cpp
@@ -24,6 +24,7 @@
#include <datetime/alarm-queue-simple.h>
#include <datetime/clock-mock.h>
#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
#include <datetime/planner-range.h>
#include <gtest/gtest.h>
@@ -43,7 +44,7 @@ using VAlarmFixture = GlibFixture;
TEST_F(VAlarmFixture, MultipleAppointments)
{
// start the EDS engine
- auto engine = std::make_shared<EdsEngine>();
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
// we need a consistent timezone for the planner and our local DateTimes
constexpr char const * zone_str {"America/Chicago"};
diff --git a/tests/test-eds-ics-tzids-2.cpp b/tests/test-eds-ics-tzids-2.cpp
index c8b0370..a1d2f5a 100644
--- a/tests/test-eds-ics-tzids-2.cpp
+++ b/tests/test-eds-ics-tzids-2.cpp
@@ -24,6 +24,7 @@
#include <datetime/alarm-queue-simple.h>
#include <datetime/clock-mock.h>
#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
#include <datetime/planner-range.h>
#include <gtest/gtest.h>
@@ -43,7 +44,7 @@ using VAlarmFixture = GlibFixture;
TEST_F(VAlarmFixture, MultipleAppointments)
{
// start the EDS engine
- auto engine = std::make_shared<EdsEngine>();
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
// we need a consistent timezone for the planner and our local DateTimes
constexpr char const * zone_str {"America/Los_Angeles"};
diff --git a/tests/test-eds-ics-tzids-utc.cpp b/tests/test-eds-ics-tzids-utc.cpp
new file mode 100644
index 0000000..f79bf3e
--- /dev/null
+++ b/tests/test-eds-ics-tzids-utc.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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/myself.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 ayatana::indicator::datetime;
+using VAlarmFixture = GlibFixture;
+
+/***
+****
+***/
+
+TEST_F(VAlarmFixture, UTCAppointments)
+{
+ // start the EDS engine
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
+
+ // we need a consistent timezone for the planner and our local DateTimes
+ constexpr char const * zone_str {"America/Recife"};
+ auto tz = std::make_shared<MockTimezone>(zone_str);
+
+ #if GLIB_CHECK_VERSION(2, 68, 0)
+ auto gtz = g_time_zone_new_identifier(zone_str);
+
+ if (gtz == NULL)
+ {
+ gtz = g_time_zone_new_utc();
+ }
+ #else
+ auto gtz = g_time_zone_new(zone_str);
+ #endif
+
+ // 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, 2016,1, 1, 0, 0, 0.0};
+ const DateTime range_end {gtz, 2017,1, 1, 0, 0, 0.0};
+ 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);
+ }
+
+ // what we expect to get...
+ std::array<Appointment,1> expected_appts;
+ auto appt = &expected_appts[0];
+ appt->uid = "20160322T132738Z";
+ appt->color = "#becedd";
+ appt->summary = "UTC event";
+ appt->begin = DateTime{gtz,2016,3,22,15,0,0};
+ appt->end = DateTime{gtz,2016,3,22,16,0,0};
+
+ // compare it to what we actually loaded...
+ const auto appts = planner->appointments().get();
+ EXPECT_EQ(expected_appts.size(), appts.size());
+ for (size_t i=0, n=std::min(appts.size(),expected_appts.size()); i<n; i++)
+ EXPECT_EQ(expected_appts[i], appts[i]);
+
+ // cleanup
+ g_time_zone_unref(gtz);
+}
diff --git a/tests/test-eds-ics-tzids-utc.ics.in b/tests/test-eds-ics-tzids-utc.ics.in
new file mode 100644
index 0000000..da607d6
--- /dev/null
+++ b/tests/test-eds-ics-tzids-utc.ics.in
@@ -0,0 +1,15 @@
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Ximian//NONSGML Evolution Calendar//EN
+VERSION:2.0
+X-EVOLUTION-DATA-REVISION:2016-03-22T16:13:53.714952Z(2)
+BEGIN:VEVENT
+UID:20160322T132738Z
+DTSTAMP:20160322T133534Z
+DTSTART:20160322T180000Z
+DTEND:20160322T190000Z
+SUMMARY:UTC event
+SEQUENCE:1
+LAST-MODIFIED:20160322T133534Z
+END:VEVENT
+END:VCALENDAR
diff --git a/tests/test-eds-ics-tzids.cpp b/tests/test-eds-ics-tzids.cpp
index c80feb2..11d44b7 100644
--- a/tests/test-eds-ics-tzids.cpp
+++ b/tests/test-eds-ics-tzids.cpp
@@ -24,6 +24,7 @@
#include <datetime/alarm-queue-simple.h>
#include <datetime/clock-mock.h>
#include <datetime/engine-eds.h>
+#include <datetime/myself.h>
#include <datetime/planner-range.h>
#include <gtest/gtest.h>
@@ -43,7 +44,7 @@ using VAlarmFixture = GlibFixture;
TEST_F(VAlarmFixture, MultipleAppointments)
{
// start the EDS engine
- auto engine = std::make_shared<EdsEngine>();
+ auto engine = std::make_shared<EdsEngine>(std::make_shared<Myself>());
// we need a consistent timezone for the planner and our local DateTimes
constexpr char const * zone_str {"Europe/Berlin"};
diff --git a/tests/test-formatter.cpp b/tests/test-formatter.cpp
index 855d4c5..87c6475 100644
--- a/tests/test-formatter.cpp
+++ b/tests/test-formatter.cpp
@@ -66,15 +66,14 @@ class FormatterFixture: public GlibFixture
bool SetLocale(const char* expected_locale, const char* name)
{
- setlocale(LC_TIME, expected_locale);
- const auto actual_locale = setlocale(LC_TIME, nullptr);
- if (!g_strcmp0(expected_locale, actual_locale))
+ if (setlocale(LC_TIME, expected_locale) != nullptr)
{
return true;
}
else
{
- g_message("Unable to set locale to %s, actual locale is %s; skipping %s locale tests.", expected_locale, actual_locale, name);
+ g_warning("Unable to set locale to %s; skipping %s locale tests. (Current LC_TIME: %s)",
+ expected_locale, name, setlocale(LC_TIME, nullptr));
return false;
}
}
@@ -87,7 +86,7 @@ class FormatterFixture: public GlibFixture
/**
* Test the phone header format
*/
-TEST_F(FormatterFixture, TestPhoneHeader)
+TEST_F(FormatterFixture, DISABLED_TestPhoneHeader)
{
auto now = DateTime::Local(2020, 10, 31, 18, 30, 59);
auto clock = std::make_shared<MockClock>(now);
@@ -114,7 +113,7 @@ TEST_F(FormatterFixture, TestPhoneHeader)
/**
* Test the default values of the desktop header format
*/
-TEST_F(FormatterFixture, TestDesktopHeader)
+TEST_F(FormatterFixture, DISABLED_TestDesktopHeader)
{
struct {
bool is_12h;
diff --git a/tests/test-live-actions.cpp b/tests/test-live-actions.cpp
index 9f17001..2d6ac9b 100644
--- a/tests/test-live-actions.cpp
+++ b/tests/test-live-actions.cpp
@@ -17,18 +17,72 @@
* Charles Kerr <charles.kerr@canonical.com>
*/
+#include "state-mock.h"
#include "timedated-fixture.h"
+#include <datetime/actions-live.h>
+
+using namespace ayatana::indicator::datetime;
+
+class MockLiveActions: public LiveActions
+{
+public:
+ std::string last_cmd;
+ std::string last_url;
+
+ explicit MockLiveActions(const std::shared_ptr<State>& state_in): LiveActions(state_in) {}
+ ~MockLiveActions() {}
+};
+
+class TestLiveActionsFixture: public TimedatedFixture
+{
+private:
+
+ using super = TimedatedFixture;
+
+protected:
+
+ std::shared_ptr<MockState> m_mock_state;
+ std::shared_ptr<State> m_state;
+ std::shared_ptr<MockLiveActions> m_live_actions;
+ std::shared_ptr<Actions> m_actions;
+
+ void SetUp() override
+ {
+ super::SetUp();
+
+ // create the State and Actions
+ m_mock_state.reset(new MockState);
+ m_mock_state->settings.reset(new Settings);
+ m_state = std::dynamic_pointer_cast<State>(m_mock_state);
+ m_live_actions.reset(new MockLiveActions(m_state));
+ m_actions = std::dynamic_pointer_cast<Actions>(m_live_actions);
+
+ // start the timedate1 dbusmock
+ start_timedate1("Etc/Utc");
+ }
+
+ void TearDown() override
+ {
+ m_actions.reset();
+ m_live_actions.reset();
+ m_state.reset();
+ m_mock_state.reset();
+
+ super::TearDown();
+ }
+};
+
/***
****
***/
-TEST_F(TimedateFixture, HelloWorld)
+TEST_F(TestLiveActionsFixture, HelloWorld)
{
EXPECT_TRUE(true);
}
-TEST_F(TimedateFixture, SetLocation)
+TEST_F(TestLiveActionsFixture, SetLocation)
{
const std::string tzid = "America/Chicago";
const std::string name = "Oklahoma City";
@@ -36,49 +90,50 @@ TEST_F(TimedateFixture, SetLocation)
EXPECT_NE(expected, m_state->settings->timezone_name.get());
- m_actions->set_location(tzid, name);
+ std::string new_name;
m_state->settings->timezone_name.changed().connect(
- [this](const std::string&){
- g_main_loop_quit(loop);
- });
- g_main_loop_run(loop);
- EXPECT_EQ(attempted_tzid, tzid);
- wait_msec();
+ [&new_name](const std::string& n){new_name = n;}
+ );
+
+ m_actions->set_location(tzid, name);
+ EXPECT_TRUE(wait_for([&new_name](){return !new_name.empty();}));
+ EXPECT_EQ(expected, new_name);
EXPECT_EQ(expected, m_state->settings->timezone_name.get());
+ EXPECT_EQ(tzid, get_timedate1_timezone());
}
/***
****
***/
-TEST_F(TimedateFixture, DesktopOpenAlarmApp)
+TEST_F(TestLiveActionsFixture, DesktopOpenAlarmApp)
{
- m_actions->desktop_open_alarm_app();
+ m_actions->open_alarm_app();
const std::string expected = "evolution -c calendar";
EXPECT_EQ(expected, m_live_actions->last_cmd);
}
-TEST_F(TimedateFixture, DesktopOpenAppointment)
+TEST_F(TestLiveActionsFixture, DesktopOpenAppointment)
{
Appointment a;
a.uid = "some-uid";
a.begin = DateTime::NowLocal();
- m_actions->desktop_open_appointment(a);
+ m_actions->open_appointment(a, a.begin);
const std::string expected_substr = "evolution \"calendar:///?startdate=";
EXPECT_NE(m_live_actions->last_cmd.find(expected_substr), std::string::npos);
}
-TEST_F(TimedateFixture, DesktopOpenCalendarApp)
+TEST_F(TestLiveActionsFixture, DesktopOpenCalendarApp)
{
- m_actions->desktop_open_calendar_app(DateTime::NowLocal());
+ m_actions->open_calendar_app(DateTime::NowLocal());
const std::string expected_substr = "evolution \"calendar:///?startdate=";
EXPECT_NE(m_live_actions->last_cmd.find(expected_substr), std::string::npos);
}
-TEST_F(TimedateFixture, DesktopOpenSettingsApp)
+TEST_F(TestLiveActionsFixture, DesktopOpenSettingsApp)
{
- m_actions->desktop_open_settings_app();
+ m_actions->open_settings_app();
const std::string expected_substr = "control-center";
EXPECT_NE(m_live_actions->last_cmd.find(expected_substr), std::string::npos);
}
@@ -89,42 +144,45 @@ TEST_F(TimedateFixture, DesktopOpenSettingsApp)
namespace
{
- const std::string clock_app_url = "appid://com.ubuntu.clock/clock/current-user-version";
-
- const std::string calendar_app_url = "appid://com.ubuntu.calendar/calendar/current-user-version";
+ const std::string clock_app_url = "alarm://";
}
-TEST_F(TimedateFixture, PhoneOpenAlarmApp)
+TEST_F(TestLiveActionsFixture, PhoneOpenAlarmApp)
{
- m_actions->phone_open_alarm_app();
+ m_actions->open_alarm_app();
EXPECT_EQ(clock_app_url, m_live_actions->last_url);
}
-TEST_F(TimedateFixture, PhoneOpenAppointment)
+TEST_F(TestLiveActionsFixture, PhoneOpenAppointment)
{
Appointment a;
- a.uid = "some-uid";
+ a.uid = "event-uid";
+ a.source_uid = "source-uid";
a.begin = DateTime::NowLocal();
a.type = Appointment::EVENT;
- m_actions->phone_open_appointment(a);
- EXPECT_EQ(calendar_app_url, m_live_actions->last_url);
+ auto ocurrenceDate = DateTime::Local(2014, 1, 1, 0, 0, 0);
+ m_actions->open_appointment(a, ocurrenceDate);
+ const std::string appointment_app_url = ocurrenceDate.to_timezone("UTC").format("calendar://startdate=%Y-%m-%dT%H:%M:%S+00:00");
+ EXPECT_EQ(appointment_app_url, m_live_actions->last_url);
a.type = Appointment::UBUNTU_ALARM;
- m_actions->phone_open_appointment(a);
+ m_actions->open_appointment(a, a.begin);
EXPECT_EQ(clock_app_url, m_live_actions->last_url);
}
-TEST_F(TimedateFixture, PhoneOpenCalendarApp)
+TEST_F(TestLiveActionsFixture, PhoneOpenCalendarApp)
{
- m_actions->phone_open_calendar_app(DateTime::NowLocal());
- const std::string expected = "appid://com.ubuntu.calendar/calendar/current-user-version";
+ auto now = DateTime::NowLocal();
+ m_actions->open_calendar_app(now);
+ const std::string expected = now.to_timezone("UTC").format("calendar://startdate=%Y-%m-%dT%H:%M:%S+00:00");
EXPECT_EQ(expected, m_live_actions->last_url);
}
-TEST_F(TimedateFixture, PhoneOpenSettingsApp)
+
+TEST_F(TestLiveActionsFixture, PhoneOpenSettingsApp)
{
- m_actions->phone_open_settings_app();
+ m_actions->open_settings_app();
const std::string expected = "settings:///system/time-date";
EXPECT_EQ(expected, m_live_actions->last_url);
}
@@ -133,7 +191,7 @@ TEST_F(TimedateFixture, PhoneOpenSettingsApp)
****
***/
-TEST_F(TimedateFixture, CalendarState)
+TEST_F(TestLiveActionsFixture, CalendarState)
{
// init the clock
auto now = DateTime::Local(2014, 1, 1, 0, 0, 0);
diff --git a/tests/test-menu-appointments.cpp b/tests/test-menu-appointments.cpp
new file mode 100644
index 0000000..91a4b42
--- /dev/null
+++ b/tests/test-menu-appointments.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2016 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 "glib-fixture.h"
+#include "print-to.h"
+
+#include <datetime/appointment.h>
+#include <datetime/menu.h>
+
+#include <vector>
+
+using MenuAppointmentFixture = GlibFixture;
+
+using namespace ayatana::indicator::datetime;
+
+namespace
+{
+ Appointment create_appointment(
+ const Appointment::Type& type,
+ const std::string& uid,
+ const std::string& summary,
+ const DateTime& begin,
+ const DateTime& end)
+ {
+ Appointment a;
+ a.type = type;
+ a.uid = uid;
+ a.summary = summary;
+ a.begin = begin;
+ a.end = end;
+ return a;
+ }
+}
+
+TEST_F(MenuAppointmentFixture, DisplayEvents)
+{
+ const auto airport = create_appointment(
+ Appointment::UBUNTU_ALARM,
+ "uid-airport",
+ "Pick Aunt Mabel up at the airport",
+ DateTime::Local(2016,12,24,10,0,0),
+ DateTime::Local(2016,12,24,10,0,0)
+ );
+
+ const auto christmas_eve_candle_service = create_appointment(
+ Appointment::EVENT,
+ "uid-christmas-eve-candle-service",
+ "Christmas Eve Candle Service",
+ DateTime::Local(2016,12,24,22,0,0),
+ DateTime::Local(2016,12,24,23,0,0)
+ );
+
+ const auto christmas = create_appointment(
+ Appointment::EVENT,
+ "uid-christmas",
+ "Christmas",
+ DateTime::Local(2016,12,25,0,0,0),
+ DateTime::Local(2016,12,26,0,0,0)
+ );
+
+ const auto santa = create_appointment(
+ Appointment::UBUNTU_ALARM,
+ "uid-santa",
+ "Time to set out cookies and milk for Santa",
+ DateTime::Local(2016,12,25,1,0,0),
+ DateTime::Local(2016,12,25,1,0,0)
+ );
+
+ const auto bike = create_appointment(
+ Appointment::UBUNTU_ALARM,
+ "uid-bike",
+ "Remember to put out the bike, it's in the garage",
+ DateTime::Local(2016,12,25,1,0,0),
+ DateTime::Local(2016,12,25,1,0,0)
+ );
+
+
+ const auto christmas_lunch = create_appointment(
+ Appointment::EVENT,
+ "uid-christmas-lunch",
+ "Christmas Lunch at Grandma's",
+ DateTime::Local(2016,12,25,12,0,0),
+ DateTime::Local(2016,12,25,14,0,0)
+ );
+
+ const auto boxing_day = create_appointment(
+ Appointment::EVENT,
+ "uid-boxing-day",
+ "Boxing Day",
+ DateTime::Local(2016,12,26,0,0,0),
+ DateTime::Local(2016,12,27,0,0,0)
+ );
+
+ const auto new_years_eve = create_appointment(
+ Appointment::EVENT,
+ "uid-new-years-eve",
+ "New Years' Eve",
+ DateTime::Local(2016,12,31,0,0,0),
+ DateTime::Local(2017,1,1,0,0,0)
+ );
+
+ const auto nye_party = create_appointment(
+ Appointment::EVENT,
+ "uid-new-years-party",
+ "New Year Party at Ted's",
+ DateTime::Local(2016,12,31,19,0,0),
+ DateTime::Local(2017, 1, 1, 2,0,0)
+ );
+
+ const auto new_years_day = create_appointment(
+ Appointment::EVENT,
+ "uid-new-years-day",
+ "New Years' Day",
+ DateTime::Local(2017,1,1,0,0,0),
+ DateTime::Local(2017,1,2,0,0,0)
+ );
+
+ const auto weekday_wakeup_alarm = create_appointment(
+ Appointment::UBUNTU_ALARM,
+ "wakeup-alarm",
+ "Wake Up",
+ DateTime::Local(2017,1,3,6,0,0),
+ DateTime::Local(2017,1,3,6,0,0)
+ );
+
+ const auto dentist_appointment = create_appointment(
+ Appointment::EVENT,
+ "dentist",
+ "Dentist",
+ DateTime::Local(2017,1,5,14,0,0),
+ DateTime::Local(2017,1,5,15,0,0)
+ );
+
+ const auto marcus_birthday = create_appointment(
+ Appointment::EVENT,
+ "uid-mlk",
+ "Marcus' Birthday",
+ DateTime::Local(2017,1,8,0,0,0),
+ DateTime::Local(2017,1,9,0,0,0)
+ );
+
+ const auto mlk_day = create_appointment(
+ Appointment::EVENT,
+ "uid-mlk",
+ "Martin Luther King Day",
+ DateTime::Local(2017,1,16,0,0,0),
+ DateTime::Local(2017,1,17,0,0,0)
+ );
+
+ const auto rodney_party = create_appointment(
+ Appointment::EVENT,
+ "uid-rodney",
+ "Rodney's Party",
+ DateTime::Local(2017,1,30,19,0,0),
+ DateTime::Local(2017,1,30,23,0,0)
+ );
+
+ const auto pub_with_pawel = create_appointment(
+ Appointment::UBUNTU_ALARM,
+ "uid-pawel",
+ "Meet Pawel at the Pub",
+ DateTime::Local(2017,2,4,19,0,0),
+ DateTime::Local(2017,2,4,19,0,0)
+ );
+
+ const struct
+ {
+ const char* const description;
+ DateTime start;
+ std::vector<Appointment> appointments;
+ std::vector<Appointment> expected_display_appointments;
+ int max_items;
+ }
+ tests[] =
+ {
+ {
+ "test presentation order: full-day events come before part-day events",
+ DateTime::Local(2016,12,25,6,0,0),
+ std::vector<Appointment>({christmas, christmas_lunch, boxing_day, new_years_eve}),
+ std::vector<Appointment>({christmas, christmas_lunch, boxing_day, new_years_eve}),
+ 5
+ },
+ {
+ "test presentation order: part-day events in chronological order",
+ DateTime::Local(2016,12,24,0,0,0),
+ std::vector<Appointment>({airport, christmas_eve_candle_service, christmas, santa, christmas_lunch}),
+ std::vector<Appointment>({airport, christmas_eve_candle_service, christmas, santa, christmas_lunch}),
+ 5
+ },
+ {
+ "test presentation order: multiple events with the same start+end sorted alphabetically",
+ DateTime::Local(2016,12,25,0,0,0),
+ std::vector<Appointment>({christmas, bike, santa, christmas_lunch}),
+ std::vector<Appointment>({christmas, bike, santa, christmas_lunch}),
+ 5
+ },
+ {
+ "test culling priority: today's part-day events outrank today's full-day events",
+ DateTime::Local(2016,12,25,1,0,0),
+ std::vector<Appointment>({christmas, santa, christmas_lunch}),
+ std::vector<Appointment>({santa, christmas_lunch}),
+ 2
+ },
+ {
+ "test culling priority: events later today outrank both tomorrow's full-day and part-day events",
+ DateTime::Local(2016,12,24,0,0,0),
+ std::vector<Appointment>({christmas_eve_candle_service, christmas, santa}),
+ std::vector<Appointment>({christmas_eve_candle_service}),
+ 1
+ },
+ {
+ "test edge cases: confirm <max events works ok",
+ DateTime::Local(2016,12,24,0,0,0),
+ std::vector<Appointment>({christmas, christmas_lunch}),
+ std::vector<Appointment>({christmas, christmas_lunch}),
+ 5
+ },
+ {
+ "test edge cases: confirm 0 events works ok",
+ DateTime::Local(2016,12,24,0,0,0),
+ std::vector<Appointment>({}),
+ std::vector<Appointment>({}),
+ 5
+ },
+ {
+ "test edge cases: confirm max-events of 0 doesn't crash",
+ DateTime::Local(2016,12,24,0,0,0),
+ std::vector<Appointment>({christmas, bike, santa, christmas_lunch}),
+ std::vector<Appointment>({}),
+ 0
+ }
+ };
+
+ for (const auto& test : tests)
+ {
+ g_debug("running test: %s", test.description);
+
+ // run the test...
+ ASSERT_EQ(test.expected_display_appointments, Menu::get_display_appointments(test.appointments, test.start, test.max_items));
+
+ // ...and again with a reversed vector to confirm input order doesn't matter
+ auto reversed = test.appointments;
+ std::reverse(reversed.begin(), reversed.end());
+ ASSERT_EQ(test.expected_display_appointments, Menu::get_display_appointments(reversed, test.start, test.max_items));
+ }
+}
+
diff --git a/tests/test-notification-response.cpp b/tests/test-notification-response.cpp
new file mode 100644
index 0000000..fd40ed8
--- /dev/null
+++ b/tests/test-notification-response.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2014-2016 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/appointment.h>
+#include <datetime/settings.h>
+#include <datetime/snap.h>
+
+#include "notification-fixture.h"
+
+/***
+****
+***/
+
+using namespace ayatana::indicator::datetime;
+
+namespace
+{
+ static constexpr char const * APP_NAME {"indicator-datetime-service"};
+
+ gboolean quit_idle (gpointer gloop)
+ {
+ g_main_loop_quit(static_cast<GMainLoop*>(gloop));
+ return G_SOURCE_REMOVE;
+ }
+}
+
+/***
+****
+***/
+
+TEST_F(NotificationFixture,Response)
+{
+ // create the world
+ make_interactive();
+ auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
+ auto sb = std::make_shared<ayatana::indicator::notifications::DefaultSoundBuilder>();
+ auto settings = std::make_shared<Settings>();
+ int next_notification_id {FIRST_NOTIFY_ID};
+
+ // set a response callback that remembers what response we got
+ bool on_response_called {};
+ Snap::Response response {};
+ auto on_response = [this, &on_response_called, &response]
+ (const Appointment&, const Alarm&, const Snap::Response& r){
+ on_response_called = true;
+ response = r;
+ g_idle_add(quit_idle, loop);
+ };
+
+ // our tests!
+ const struct {
+ Appointment appt;
+ std::vector<std::string> expected_actions;
+ std::string action;
+ Snap::Response expected_response;
+ } tests[] = {
+ { appt, {"show-app"}, "show-app", Snap::Response::ShowApp },
+ { ualarm, {"none", "snooze"}, "snooze", Snap::Response::Snooze },
+ { ualarm, {"none", "snooze"}, "none", Snap::Response::None }
+ };
+
+
+ settings->cal_notification_enabled.set(true);
+ settings->cal_notification_sounds.set(true);
+ settings->cal_notification_vibrations.set(true);
+ settings->cal_notification_bubbles.set(true);
+ settings->cal_notification_list.set(true);
+
+ // walk through the tests
+ for (const auto& test : tests)
+ {
+ // wait for previous iterations' bus noise to finish and reset the counters
+ GError* error {};
+ wait_msec(500);
+ dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error);
+ g_assert_no_error(error);
+ on_response_called = false;
+
+ // create a snap decision
+ auto snap = create_snap(ne, sb, settings);
+ (*snap)(test.appt, test.appt.alarms.front(), on_response);
+
+ // wait for the notification to show up
+ EXPECT_METHOD_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY);
+
+ // test that Notify was called the right number of times
+ static constexpr int expected_num_notify_calls {1};
+ guint num_notify_calls {};
+ const auto notify_calls = dbus_test_dbus_mock_object_get_method_calls(
+ notify_mock,
+ notify_obj,
+ METHOD_NOTIFY,
+ &num_notify_calls,
+ &error);
+ g_assert_no_error(error);
+ EXPECT_EQ(expected_num_notify_calls, num_notify_calls);
+
+ // test that Notify was called with the correct list of actions
+ if (num_notify_calls > 0) {
+ std::vector<std::string> actions;
+ const gchar** as {nullptr};
+ g_variant_get_child(notify_calls[0].params, 5, "^a&s", &as);
+ for (int i=0; as && as[i]; i+=2) // actions are in pairs of (name, i18n), skip the i18n
+ actions.push_back(as[i]);
+ EXPECT_EQ(test.expected_actions, actions);
+ }
+
+ // make the notification mock tell the world that the user invoked an action
+ const auto notification_id = next_notification_id++;
+ idle_add([this, notification_id, test](){
+ GError* err {};
+ dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "ActionInvoked",
+ G_VARIANT_TYPE("(us)"),
+ g_variant_new("(us)", guint(notification_id), test.action.c_str()),
+ &err);
+ dbus_test_dbus_mock_object_emit_signal(notify_mock, notify_obj, "NotificationClosed",
+ G_VARIANT_TYPE("(uu)"),
+ g_variant_new("(uu)", guint(notification_id), guint(NOTIFICATION_CLOSED_DISMISSED)),
+ &err);
+ g_assert_no_error(err);
+ return G_SOURCE_REMOVE;
+ });
+
+ // confirm that the response callback got the right response
+ EXPECT_TRUE(wait_for([&on_response_called](){return on_response_called;}));
+ EXPECT_EQ(int(test.expected_response), int(response)) << "notification_id " << notification_id;
+ }
+}
diff --git a/tests/test-notification.cpp b/tests/test-notification.cpp
new file mode 100644
index 0000000..83a021f
--- /dev/null
+++ b/tests/test-notification.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2014-2016 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/appointment.h>
+#include <datetime/settings.h>
+#include <datetime/snap.h>
+
+#include "notification-fixture.h"
+
+/***
+****
+***/
+
+using namespace ayatana::indicator::datetime;
+
+namespace
+{
+ static constexpr char const * APP_NAME {"indicator-datetime-service"};
+
+ gboolean quit_idle (gpointer gloop)
+ {
+ g_main_loop_quit(static_cast<GMainLoop*>(gloop));
+ return G_SOURCE_REMOVE;
+ }
+}
+
+/***
+****
+***/
+
+TEST_F(NotificationFixture,Notification)
+{
+ // Feed different combinations of system settings,
+ // indicator-datetime settings, and event types,
+ // then see if notifications and haptic feedback behave as expected.
+
+ auto settings = std::make_shared<Settings>();
+ auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
+ auto sb = std::make_shared<ayatana::indicator::notifications::DefaultSoundBuilder>();
+ auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);};
+
+ // combinatorial factor #1: event type
+ struct {
+ Appointment appt;
+ const char* icon_name;
+ const char* prefix;
+ bool expected_notify_called;
+ bool expected_vibrate_called;
+ } test_appts[] = {
+ { appt, "calendar-app", "Event", true, true },
+ { ualarm, "alarm-clock", "Alarm", true, true }
+ };
+
+ // combinatorial factor #2: indicator-datetime's haptic mode
+ struct {
+ const char* haptic_mode;
+ bool expected_notify_called;
+ bool expected_vibrate_called;
+ } test_haptics[] = {
+ { "none", true, false },
+ { "pulse", true, true }
+ };
+
+ // combinatorial factor #3: system settings' "other vibrations" enabled
+ struct {
+ bool other_vibrations;
+ bool expected_notify_called;
+ bool expected_vibrate_called;
+ } test_other_vibrations[] = {
+ { true, true, true },
+ { false, true, false }
+ };
+
+ // combinatorial factor #4: system settings' notifications disabled
+ struct {
+ bool cal_notification_enabled; // calendar app can trigger notifications
+ std::set<Appointment::Type> expected_notify_called; // do we expect the notification to show?
+ std::set<Appointment::Type> expected_vibrate_called; // do we expect the phone to vibrate?
+ } test_cal_disabled[] = {
+ { true, std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT },
+ std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT } },
+ { false, std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM },
+ std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM } }
+ };
+
+ for (const auto& test_appt : test_appts)
+ {
+ for (const auto& test_haptic : test_haptics)
+ {
+ for (const auto& test_vibes : test_other_vibrations)
+ {
+ for (const auto& test_disabled : test_cal_disabled)
+ {
+ const bool expected_notify_called = test_appt.expected_notify_called
+ && test_vibes.expected_notify_called
+ && (test_disabled.expected_notify_called.count(test_appt.appt.type) > 0)
+ && test_haptic.expected_notify_called;
+
+ const bool expected_vibrate_called = test_appt.expected_vibrate_called
+ && test_vibes.expected_vibrate_called
+ && (test_disabled.expected_vibrate_called.count(test_appt.appt.type) > 0)
+ && test_haptic.expected_vibrate_called;
+
+ // set test case properties: cal_notification_enabled
+ settings->cal_notification_enabled.set(test_disabled.cal_notification_enabled);
+ settings->cal_notification_sounds.set(test_disabled.cal_notification_enabled);
+ settings->cal_notification_vibrations.set(test_disabled.cal_notification_enabled);
+ settings->cal_notification_bubbles.set(test_disabled.cal_notification_enabled);
+ settings->cal_notification_list.set(test_disabled.cal_notification_enabled);
+
+ // set test case properties: haptic mode
+ settings->alarm_haptic.set(test_haptic.haptic_mode);
+
+ // set test case properties: other-vibrations flag
+ // (and wait for the PropertiesChanged signal so we know the dbusmock got it)
+ GError * error {};
+ dbus_test_dbus_mock_object_update_property(as_mock,
+ as_obj,
+ PROP_OTHER_VIBRATIONS,
+ g_variant_new_boolean(test_vibes.other_vibrations),
+ &error);
+ g_assert_no_error(error);
+
+ // wait for previous iterations' bus noise to finish and reset the counters
+ wait_msec(500);
+ dbus_test_dbus_mock_object_clear_method_calls(haptic_mock, haptic_obj, &error);
+ dbus_test_dbus_mock_object_clear_method_calls(notify_mock, notify_obj, &error);
+ g_assert_no_error(error);
+
+ // run the test
+ auto snap = create_snap(ne, sb, settings);
+ (*snap)(test_appt.appt, appt.alarms.front(), func);
+
+ // confirm that the notification was as expected
+ if (expected_notify_called) {
+ EXPECT_METHOD_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY);
+ } else {
+ EXPECT_METHOD_NOT_CALLED_EVENTUALLY(notify_mock, notify_obj, METHOD_NOTIFY);
+ }
+
+ // confirm that the vibration was as expected
+ if (expected_vibrate_called) {
+ EXPECT_METHOD_CALLED_EVENTUALLY(haptic_mock, haptic_obj, HAPTIC_METHOD_VIBRATE_PATTERN);
+ } else {
+ EXPECT_METHOD_NOT_CALLED_EVENTUALLY(haptic_mock, haptic_obj, HAPTIC_METHOD_VIBRATE_PATTERN);
+ }
+
+ // confirm that the notification was as expected
+ guint num_notify_calls = 0;
+ const auto notify_calls = dbus_test_dbus_mock_object_get_method_calls(notify_mock,
+ notify_obj,
+ METHOD_NOTIFY,
+ &num_notify_calls,
+ &error);
+ g_assert_no_error(error);
+ if (num_notify_calls > 0)
+ {
+ // test that Notify was called with the app_name
+ const gchar* app_name {nullptr};
+ g_variant_get_child(notify_calls[0].params, 0, "&s", &app_name);
+ ASSERT_STREQ(APP_NAME, app_name);
+
+ // test that Notify was called with the type-appropriate icon
+ const gchar* icon_name {nullptr};
+ g_variant_get_child(notify_calls[0].params, 2, "&s", &icon_name);
+ ASSERT_STREQ(test_appt.icon_name, icon_name);
+
+ // test that the Notification title has the correct prefix
+ const gchar* title {nullptr};
+ g_variant_get_child(notify_calls[0].params, 3, "&s", &title);
+ ASSERT_TRUE(g_str_has_prefix(title, test_appt.prefix));
+
+ // test that Notify was called with the appointment's body
+ const gchar* body {nullptr};
+ g_variant_get_child(notify_calls[0].params, 4, "&s", &body);
+ ASSERT_STREQ(test_appt.appt.summary.c_str(), body);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/test-settings.cpp b/tests/test-settings.cpp
index 3af9eab..b9658f4 100644
--- a/tests/test-settings.cpp
+++ b/tests/test-settings.cpp
@@ -22,6 +22,11 @@
#include <datetime/settings-live.h>
#include <datetime/settings-shared.h>
+extern "C"
+{
+ #include <ayatana/common/utils.h>
+}
+
using namespace ayatana::indicator::datetime;
/***
@@ -37,19 +42,23 @@ protected:
std::shared_ptr<LiveSettings> m_live;
std::shared_ptr<Settings> m_settings;
- GSettings * m_gsettings;
+ GSettings * m_gsettings {};
+ GSettings * m_gsettings_cal_notification {};
void SetUp() override
{
super::SetUp();
m_gsettings = g_settings_new(SETTINGS_INTERFACE);
+ m_gsettings_cal_notification = g_settings_new_with_path(SETTINGS_NOTIFY_SCHEMA_ID, SETTINGS_NOTIFY_CALENDAR_PATH);
+
m_live.reset(new LiveSettings);
m_settings = std::dynamic_pointer_cast<Settings>(m_live);
}
void TearDown() override
{
+ g_clear_object(&m_gsettings_cal_notification);
g_clear_object(&m_gsettings);
m_settings.reset();
m_live.reset();
@@ -57,62 +66,62 @@ protected:
super::TearDown();
}
- void TestBoolProperty(core::Property<bool>& property, const gchar* key)
+ void TestBoolProperty(GSettings* gsettings, core::Property<bool>& property, const gchar* key)
{
- EXPECT_EQ(g_settings_get_boolean(m_gsettings, key), property.get());
- g_settings_set_boolean(m_gsettings, key, false);
+ EXPECT_EQ(g_settings_get_boolean(gsettings, key), property.get());
+ g_settings_set_boolean(gsettings, key, false);
EXPECT_FALSE(property.get());
- g_settings_set_boolean(m_gsettings, key, true);
+ g_settings_set_boolean(gsettings, key, true);
EXPECT_TRUE(property.get());
property.set(false);
- EXPECT_FALSE(g_settings_get_boolean(m_gsettings, key));
+ EXPECT_FALSE(g_settings_get_boolean(gsettings, key));
property.set(true);
- EXPECT_TRUE(g_settings_get_boolean(m_gsettings, key));
+ EXPECT_TRUE(g_settings_get_boolean(gsettings, key));
}
- void TestStringProperty(core::Property<std::string>& property, const gchar* key)
+ void TestStringProperty(GSettings* gsettings, core::Property<std::string>& property, const gchar* key)
{
gchar* tmp;
std::string str;
- tmp = g_settings_get_string(m_gsettings, key);
+ tmp = g_settings_get_string(gsettings, key);
EXPECT_EQ(tmp, property.get());
g_clear_pointer(&tmp, g_free);
str = "a";
- g_settings_set_string(m_gsettings, key, str.c_str());
+ g_settings_set_string(gsettings, key, str.c_str());
EXPECT_EQ(str, property.get());
str = "b";
- g_settings_set_string(m_gsettings, key, str.c_str());
+ g_settings_set_string(gsettings, key, str.c_str());
EXPECT_EQ(str, property.get());
str = "a";
property.set(str);
- tmp = g_settings_get_string(m_gsettings, key);
+ tmp = g_settings_get_string(gsettings, key);
EXPECT_EQ(str, tmp);
g_clear_pointer(&tmp, g_free);
str = "b";
property.set(str);
- tmp = g_settings_get_string(m_gsettings, key);
+ tmp = g_settings_get_string(gsettings, key);
EXPECT_EQ(str, tmp);
g_clear_pointer(&tmp, g_free);
}
- void TestUIntProperty(core::Property<unsigned int>& property, const gchar* key)
+ void TestUIntProperty(GSettings* gsettings, core::Property<unsigned int>& property, const gchar* key)
{
- EXPECT_EQ(g_settings_get_uint(m_gsettings, key), property.get());
+ EXPECT_EQ(g_settings_get_uint(gsettings, key), property.get());
unsigned int expected_values[] = { 1, 2, 3 };
// modify GSettings and confirm that the new value is propagated
for(const auto& expected_value : expected_values)
{
- g_settings_set_uint(m_gsettings, key, expected_value);
+ g_settings_set_uint(gsettings, key, expected_value);
EXPECT_EQ(expected_value, property.get());
- EXPECT_EQ(expected_value, g_settings_get_uint(m_gsettings, key));
+ EXPECT_EQ(expected_value, g_settings_get_uint(gsettings, key));
}
// modify the property and confirm that the new value is propagated
@@ -120,7 +129,7 @@ protected:
{
property.set(expected_value);
EXPECT_EQ(expected_value, property.get());
- EXPECT_EQ(expected_value, g_settings_get_uint(m_gsettings, key));
+ EXPECT_EQ(expected_value, g_settings_get_uint(gsettings, key));
}
}
};
@@ -136,31 +145,31 @@ TEST_F(SettingsFixture, HelloWorld)
TEST_F(SettingsFixture, BoolProperties)
{
- TestBoolProperty(m_settings->show_seconds, SETTINGS_SHOW_SECONDS_S);
- TestBoolProperty(m_settings->show_calendar, SETTINGS_SHOW_CALENDAR_S);
- TestBoolProperty(m_settings->show_date, SETTINGS_SHOW_DATE_S);
- TestBoolProperty(m_settings->show_day, SETTINGS_SHOW_DAY_S);
- TestBoolProperty(m_settings->show_detected_location, SETTINGS_SHOW_DETECTED_S);
- TestBoolProperty(m_settings->show_events, SETTINGS_SHOW_EVENTS_S);
- TestBoolProperty(m_settings->show_locations, SETTINGS_SHOW_LOCATIONS_S);
- TestBoolProperty(m_settings->show_week_numbers, SETTINGS_SHOW_WEEK_NUMBERS_S);
- TestBoolProperty(m_settings->show_year, SETTINGS_SHOW_YEAR_S);
+ TestBoolProperty(m_gsettings, m_settings->show_seconds, SETTINGS_SHOW_SECONDS_S);
+ TestBoolProperty(m_gsettings, m_settings->show_calendar, SETTINGS_SHOW_CALENDAR_S);
+ TestBoolProperty(m_gsettings, m_settings->show_date, SETTINGS_SHOW_DATE_S);
+ TestBoolProperty(m_gsettings, m_settings->show_day, SETTINGS_SHOW_DAY_S);
+ TestBoolProperty(m_gsettings, m_settings->show_detected_location, SETTINGS_SHOW_DETECTED_S);
+ TestBoolProperty(m_gsettings, m_settings->show_events, SETTINGS_SHOW_EVENTS_S);
+ TestBoolProperty(m_gsettings, m_settings->show_locations, SETTINGS_SHOW_LOCATIONS_S);
+ TestBoolProperty(m_gsettings, m_settings->show_week_numbers, SETTINGS_SHOW_WEEK_NUMBERS_S);
+ TestBoolProperty(m_gsettings, m_settings->show_year, SETTINGS_SHOW_YEAR_S);
}
TEST_F(SettingsFixture, UIntProperties)
{
- TestUIntProperty(m_settings->alarm_duration, SETTINGS_ALARM_DURATION_S);
- TestUIntProperty(m_settings->alarm_volume, SETTINGS_ALARM_VOLUME_S);
- TestUIntProperty(m_settings->snooze_duration, SETTINGS_SNOOZE_DURATION_S);
+ TestUIntProperty(m_gsettings, m_settings->alarm_duration, SETTINGS_ALARM_DURATION_S);
+ TestUIntProperty(m_gsettings, m_settings->alarm_volume, SETTINGS_ALARM_VOLUME_S);
+ TestUIntProperty(m_gsettings, m_settings->snooze_duration, SETTINGS_SNOOZE_DURATION_S);
}
TEST_F(SettingsFixture, StringProperties)
{
- TestStringProperty(m_settings->custom_time_format, SETTINGS_CUSTOM_TIME_FORMAT_S);
- TestStringProperty(m_settings->timezone_name, SETTINGS_TIMEZONE_NAME_S);
- TestStringProperty(m_settings->alarm_sound, SETTINGS_ALARM_SOUND_S);
- TestStringProperty(m_settings->calendar_sound, SETTINGS_CALENDAR_SOUND_S);
- TestStringProperty(m_settings->alarm_haptic, SETTINGS_ALARM_HAPTIC_S);
+ TestStringProperty(m_gsettings, m_settings->custom_time_format, SETTINGS_CUSTOM_TIME_FORMAT_S);
+ TestStringProperty(m_gsettings, m_settings->timezone_name, SETTINGS_TIMEZONE_NAME_S);
+ TestStringProperty(m_gsettings, m_settings->alarm_sound, SETTINGS_ALARM_SOUND_S);
+ TestStringProperty(m_gsettings, m_settings->calendar_sound, SETTINGS_CALENDAR_SOUND_S);
+ TestStringProperty(m_gsettings, m_settings->alarm_haptic, SETTINGS_ALARM_HAPTIC_S);
}
TEST_F(SettingsFixture, TimeFormatMode)
@@ -221,3 +230,16 @@ TEST_F(SettingsFixture, Locations)
g_strfreev(tmp);
EXPECT_EQ(bv, vtmp);
}
+
+TEST_F(SettingsFixture, MutedApps)
+{
+ if (!m_gsettings_cal_notification) {
+ return;
+ }
+
+ TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_enabled, SETTINGS_NOTIFY_ENABLED_KEY);
+ TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_sounds, SETTINGS_NOTIFY_SOUNDS_KEY);
+ TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_vibrations, SETTINGS_NOTIFY_VIBRATIONS_KEY);
+ TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_bubbles, SETTINGS_NOTIFY_BUBBLES_KEY);
+ TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_list, SETTINGS_NOTIFY_LIST_KEY);
+}
diff --git a/tests/test-sound.cpp b/tests/test-sound.cpp
new file mode 100644
index 0000000..f808db6
--- /dev/null
+++ b/tests/test-sound.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2014-2016 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/appointment.h>
+#include <datetime/settings.h>
+#include <datetime/snap.h>
+
+#include "notification-fixture.h"
+
+using namespace ayatana::indicator::datetime;
+
+namespace uin = ayatana::indicator::notifications;
+
+/***
+****
+***/
+
+namespace
+{
+ static constexpr char const * APP_NAME {"indicator-datetime-service"};
+}
+
+
+namespace
+{
+ gboolean quit_idle (gpointer gloop)
+ {
+ g_main_loop_quit(static_cast<GMainLoop*>(gloop));
+ return G_SOURCE_REMOVE;
+ };
+}
+
+/***
+****
+***/
+
+TEST_F(NotificationFixture, InteractiveDuration)
+{
+ static constexpr int duration_minutes = 120;
+ auto settings = std::make_shared<Settings>();
+ settings->alarm_duration.set(duration_minutes);
+ auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
+ auto sb = std::make_shared<ayatana::indicator::notifications::DefaultSoundBuilder>();
+ auto snap = create_snap(ne, sb, settings);
+
+ settings->cal_notification_enabled.set(true);
+ settings->cal_notification_sounds.set(true);
+ settings->cal_notification_vibrations.set(true);
+ settings->cal_notification_bubbles.set(true);
+ settings->cal_notification_list.set(true);
+
+ make_interactive();
+
+ // call the Snap Decision
+ auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);};
+ (*snap)(appt, appt.alarms.front(), func);
+
+ // confirm that Notify got called once
+ guint len = 0;
+ GError * error = nullptr;
+ const auto calls = dbus_test_dbus_mock_object_get_method_calls (notify_mock,
+ notify_obj,
+ METHOD_NOTIFY,
+ &len,
+ &error);
+ g_assert_no_error(error);
+ ASSERT_EQ(1, len);
+
+ // confirm that the app_name passed to Notify was APP_NAME
+ const auto& params = calls[0].params;
+ ASSERT_EQ(8, g_variant_n_children(params));
+ const char * str = nullptr;
+ g_variant_get_child (params, 0, "&s", &str);
+ ASSERT_STREQ(APP_NAME, str);
+
+ // confirm that the icon passed to Notify was "alarm-clock"
+ g_variant_get_child (params, 2, "&s", &str);
+ ASSERT_STREQ("calendar-app", str);
+
+ // confirm that the hints passed to Notify included a timeout matching duration_minutes
+ int32_t i32;
+ bool b;
+ auto hints = g_variant_get_child_value (params, 6);
+ b = g_variant_lookup (hints, HINT_TIMEOUT, "i", &i32);
+ EXPECT_TRUE(b);
+ const auto duration = std::chrono::minutes(duration_minutes);
+ EXPECT_EQ(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(), i32);
+ g_variant_unref(hints);
+ ne.reset();
+}
+
+/***
+****
+***/
+
+/**
+ * A DefaultSoundBuilder wrapper which remembers the parameters of the last sound created.
+ */
+class TestSoundBuilder: public uin::SoundBuilder
+{
+public:
+ TestSoundBuilder() =default;
+ ~TestSoundBuilder() =default;
+
+ virtual std::shared_ptr<uin::Sound> create(const std::string& role, const std::string& uri, unsigned int volume, bool loop) override {
+ m_role = role;
+ m_uri = uri;
+ m_volume = volume;
+ m_loop = loop;
+ return m_impl.create(role, uri, volume, loop);
+ }
+
+ const std::string& role() { return m_role; }
+ const std::string& uri() { return m_uri; }
+ unsigned int volume() { return m_volume; }
+ bool loop() { return m_loop; }
+
+private:
+ std::string m_role;
+ std::string m_uri;
+ unsigned int m_volume;
+ bool m_loop;
+ uin::DefaultSoundBuilder m_impl;
+};
+
+std::string path_to_uri(const std::string& path)
+{
+ auto file = g_file_new_for_path(path.c_str());
+ auto uri_cstr = g_file_get_uri(file);
+ std::string uri = uri_cstr;
+ g_free(uri_cstr);
+ g_clear_pointer(&file, g_object_unref);
+ return uri;
+}
+
+TEST_F(NotificationFixture,DefaultSounds)
+{
+ auto settings = std::make_shared<Settings>();
+ auto ne = std::make_shared<ayatana::indicator::notifications::Engine>(APP_NAME);
+ auto sb = std::make_shared<TestSoundBuilder>();
+ auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);};
+
+ settings->cal_notification_enabled.set(true);
+ settings->cal_notification_sounds.set(true);
+ settings->cal_notification_vibrations.set(true);
+ settings->cal_notification_bubbles.set(true);
+ settings->cal_notification_list.set(true);
+
+ const struct {
+ Appointment appointment;
+ std::string expected_role;
+ std::string expected_uri;
+ } test_cases[] = {
+ { ualarm, "alarm", path_to_uri(ALARM_DEFAULT_SOUND) }
+ // No sound for appointments
+ // { appt, "alert", path_to_uri(CALENDAR_DEFAULT_SOUND) }
+ };
+
+ auto snap = create_snap(ne, sb, settings);
+ for(const auto& test_case : test_cases)
+ {
+ (*snap)(test_case.appointment, test_case.appointment.alarms.front(), func);
+ EXPECT_EQ(test_case.expected_uri, sb->uri());
+ EXPECT_EQ(test_case.expected_role, sb->role());
+ }
+}
diff --git a/tests/test-timezone-timedated.cpp b/tests/test-timezone-timedated.cpp
index 2fdec12..c686c39 100644
--- a/tests/test-timezone-timedated.cpp
+++ b/tests/test-timezone-timedated.cpp
@@ -1,9 +1,5 @@
-
/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
+ * Copyright © 2014-2016 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
@@ -16,127 +12,76 @@
*
* 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>
+ * Ted Gould <ted.gould@canonical.com>
*/
#include "timedated-fixture.h"
#include <datetime/timezone-timedated.h>
-using ayatana::indicator::datetime::TimedatedTimezone;
+using namespace ayatana::indicator::datetime;
+
+using TestTimedatedFixture = TimedatedFixture;
/***
****
***/
-#define TIMEZONE_FILE (SANDBOX"/timezone")
-
-class TimezoneFixture: public TimedateFixture
+TEST_F(TestTimedatedFixture, HelloWorld)
{
- private:
-
- typedef TimedateFixture super;
-
- protected:
-
- void SetUp() override
- {
- super::SetUp();
- }
-
- void TearDown() override
- {
- super::TearDown();
- }
-
- public:
-
- /* convenience func to set the timezone file */
- void set_file(const std::string& text)
- {
- g_debug("set_file %s %s", TIMEZONE_FILE, text.c_str());
- auto fp = fopen(TIMEZONE_FILE, "w+");
- fprintf(fp, "%s\n", text.c_str());
- fclose(fp);
- sync();
- }
-};
+}
/**
- * Test that timezone-timedated warns, but doesn't crash, if the timezone file doesn't exist
+ * Test that the tzid is right if timedated isn't available
*/
-TEST_F(TimezoneFixture, NoFile)
+TEST_F(TestTimedatedFixture, DefaultTimezone)
{
- remove(TIMEZONE_FILE);
- ASSERT_FALSE(g_file_test(TIMEZONE_FILE, G_FILE_TEST_EXISTS));
+ const std::string expected_tzid{"Etc/Utc"};
- expectLogMessage(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "*No such file or directory*");
- TimedatedTimezone tz(TIMEZONE_FILE);
+ TimedatedTimezone tmp {m_bus};
+ EXPECT_TZID(expected_tzid, tmp);
}
/**
- * Test that timezone-timedated gives a default of UTC if the file doesn't exist
+ * Test that the tzid is right if timedated shows BEFORE we start
*/
-TEST_F(TimezoneFixture, DefaultValueNoFile)
+TEST_F(TestTimedatedFixture, Timedate1First)
{
- const std::string expected_timezone = "Etc/Utc";
- remove(TIMEZONE_FILE);
- ASSERT_FALSE(g_file_test(TIMEZONE_FILE, G_FILE_TEST_EXISTS));
+ const std::string expected_tzid{"America/Chicago"};
- expectLogMessage(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "*No such file or directory*");
- TimedatedTimezone tz(TIMEZONE_FILE);
- ASSERT_EQ(expected_timezone, tz.timezone.get());
+ start_timedate1(expected_tzid);
+ TimedatedTimezone tmp {m_bus};
+ EXPECT_TZID(expected_tzid, tmp);
}
/**
- * Test that timezone-timedated picks up the initial value
+ * Test that the tzid is right if timedated shows AFTER we start
*/
-TEST_F(TimezoneFixture, InitialValue)
+TEST_F(TestTimedatedFixture, Timedate1Last)
{
- const std::string expected_timezone = "America/Chicago";
- set_file(expected_timezone);
- TimedatedTimezone tz(TIMEZONE_FILE);
+ const std::string expected_tzid("America/Los_Angeles");
+
+ TimedatedTimezone tmp {m_bus};
+ start_timedate1(expected_tzid);
+ EXPECT_TZID(expected_tzid, tmp);
}
/**
- * Test that changing the tz after we are running works.
+ * Test that the tzid is right if timedated's property changes
*/
-TEST_F(TimezoneFixture, ChangedValue)
+TEST_F(TestTimedatedFixture, TimezoneChange)
{
- const std::string initial_timezone = "America/Chicago";
- const std::string changed_timezone = "America/New_York";
-
- set_file(initial_timezone);
-
- TimedatedTimezone tz(TIMEZONE_FILE);
- ASSERT_EQ(initial_timezone, tz.timezone.get());
-
- bool changed = false;
- tz.timezone.changed().connect(
- [&changed, this](const std::string& s){
- g_message("timezone changed to %s", s.c_str());
- changed = true;
- g_main_loop_quit(loop);
- });
+ const std::vector<std::string> expected_tzids{"America/Los_Angeles", "America/Chicago", "Etc/Utc"};
- g_idle_add([](gpointer gself){
- static_cast<TimedateFixture*>(gself)->set_timezone("America/New_York");
- return G_SOURCE_REMOVE;
- }, this);
+ TimedatedTimezone tmp {m_bus};
+ start_timedate1("America/New_York");
- g_main_loop_run(loop);
-
- ASSERT_TRUE(changed);
- ASSERT_EQ(changed_timezone, tz.timezone.get());
-}
-
-/**
- * Test that timezone-timedated picks up the initial value
- */
-TEST_F(TimezoneFixture, IgnoreComments)
-{
- const std::string comment = "# Created by cloud-init v. 0.7.5 on Thu, 24 Apr 2014 14:03:29 +0000";
- const std::string expected_timezone = "Europe/Berlin";
- set_file(comment + "\n" + expected_timezone);
- TimedatedTimezone tz(TIMEZONE_FILE);
- ASSERT_EQ(expected_timezone, tz.timezone.get());
+ for(const auto& expected_tzid : expected_tzids)
+ {
+ set_timedate1_timezone(expected_tzid);
+ EXPECT_TZID(expected_tzid, tmp);
+ }
}
diff --git a/tests/timedated-fixture.h b/tests/timedated-fixture.h
index 00269e0..3aff986 100644
--- a/tests/timedated-fixture.h
+++ b/tests/timedated-fixture.h
@@ -17,285 +17,132 @@
* Charles Kerr <charles.kerr@canonical.com>
*/
-#ifndef INDICATOR_DATETIME_TESTS_TIMEDATED_FIXTURE_H
-#define INDICATOR_DATETIME_TESTS_TIMEDATED_FIXTURE_H
+#pragma once
#include <datetime/actions-live.h>
-#include "state-mock.h"
#include "glib-fixture.h"
-using namespace ayatana::indicator::datetime;
-
-class MockLiveActions: public LiveActions
-{
-public:
- std::string last_cmd;
- std::string last_url;
- explicit MockLiveActions(const std::shared_ptr<State>& state_in): LiveActions(state_in) {}
- ~MockLiveActions() {}
-
-protected:
- void dispatch_url(const std::string& url) override { last_url = url; }
- void execute_command(const std::string& cmd) override { last_cmd = cmd; }
-};
+#include <datetime/dbus-shared.h>
+#include <datetime/timezone.h>
/***
****
***/
-using namespace ayatana::indicator::datetime;
-
-class TimedateFixture: public GlibFixture
+struct TimedatedFixture: public GlibFixture
{
private:
- typedef GlibFixture super;
-
- static GVariant * timedate1_get_properties (GDBusConnection * /*connection*/ ,
- const gchar * /*sender*/,
- const gchar * /*object_path*/,
- const gchar * /*interface_name*/,
- const gchar *property_name,
- GError ** /*error*/,
- gpointer gself)
+ using super = GlibFixture;
- {
- auto self = static_cast<TimedateFixture*>(gself);
- g_debug("get_properties called");
- if (g_strcmp0(property_name, "Timezone") == 0)
- {
- g_debug("timezone requested, giving '%s'",
- self->attempted_tzid.c_str());
- return g_variant_new_string(self->attempted_tzid.c_str());
- }
- return nullptr;
- }
+protected:
+ GDBusConnection* m_bus {};
+ GTestDBus* m_test_bus {};
- static void on_bus_acquired(GDBusConnection* conn,
- const gchar* name,
- gpointer gself)
+ virtual void SetUp() override
{
- auto self = static_cast<TimedateFixture*>(gself);
- g_debug("bus acquired: %s, connection is %p", name, conn);
-
- /* Set up a fake timedated which handles setting and getting the
- ** timezone
- */
- static const GDBusInterfaceVTable vtable = {
- timedate1_handle_method_call,
- timedate1_get_properties, /* GetProperty */
- nullptr, /* SetProperty */
- };
+ super::SetUp();
- self->connection = G_DBUS_CONNECTION(g_object_ref(G_OBJECT(conn)));
+ // use a fake bus
+ m_test_bus = g_test_dbus_new(G_TEST_DBUS_NONE);
+ g_test_dbus_up(m_test_bus);
+ const char * address = g_test_dbus_get_bus_address(m_test_bus);
+ g_setenv("DBUS_SYSTEM_BUS_ADDRESS", address, true);
+ g_setenv("DBUS_SESSION_BUS_ADDRESS", address, true);
+ g_debug("test_dbus's address is %s", address);
- GError* error = nullptr;
- self->object_register_id = g_dbus_connection_register_object(
- conn,
- "/org/freedesktop/timedate1",
- self->node_info->interfaces[0],
- &vtable,
- self,
- nullptr,
- &error);
- g_assert_no_error(error);
+ // get the bus
+ m_bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
+ g_dbus_connection_set_exit_on_close(m_bus, FALSE);
+ g_object_add_weak_pointer(G_OBJECT(m_bus), (gpointer*)&m_bus);
}
- static void on_name_acquired(GDBusConnection* conn,
- const gchar* name,
- gpointer gself)
+ virtual void TearDown() override
{
- g_debug("on_name_acquired");
- auto self = static_cast<TimedateFixture*>(gself);
- self->name_acquired = true;
- self->proxy = g_dbus_proxy_new_sync(conn,
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
- nullptr,
- name,
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- nullptr,
- nullptr);
- g_main_loop_quit(self->loop);
- }
+ g_clear_object(&m_bus);
+ g_clear_object(&m_test_bus);
- static void on_name_lost(GDBusConnection* /*conn*/,
- const gchar* /*name*/,
- gpointer gself)
- {
- g_debug("on_name_lost");
- auto self = static_cast<TimedateFixture*>(gself);
- self->name_acquired = false;
+ super::TearDown();
}
- static void on_bus_closed(GObject* /*object*/,
- GAsyncResult* res,
- gpointer gself)
+ void start_timedate1(const std::string& tzid)
{
- g_debug("on_bus_closed");
- auto self = static_cast<TimedateFixture*>(gself);
- GError* err = nullptr;
- g_dbus_connection_close_finish(self->connection, res, &err);
- g_assert_no_error(err);
- g_main_loop_quit(self->loop);
+ // start dbusmock with the timedated template
+ auto json_parameters = g_strdup_printf("{\"Timezone\": \"%s\"}", tzid.c_str());
+ const gchar* child_argv[] = {
+ "python3", "-m", "dbusmock",
+ "--template", "timedated",
+ "--parameters", json_parameters,
+ nullptr
+ };
+ GError* error = nullptr;
+ g_spawn_async(nullptr, (gchar**)child_argv, nullptr, G_SPAWN_SEARCH_PATH, nullptr, nullptr, nullptr, &error);
+ g_assert_no_error(error);
+ g_free(json_parameters);
+
+ // wait for it to appear on the bus
+ wait_for_name_owned(m_bus, Bus::Timedate1::BUSNAME);
}
- static void
- timedate1_handle_method_call(GDBusConnection * connection,
- const gchar * /*sender*/,
- const gchar * object_path,
- const gchar * interface_name,
- const gchar * method_name,
- GVariant * parameters,
- GDBusMethodInvocation * invocation,
- gpointer gself)
+ bool wait_for_tzid(const std::string& tzid, ayatana::indicator::datetime::Timezone& tz)
{
- g_assert(!g_strcmp0(method_name, "SetTimezone"));
- g_assert(g_variant_is_of_type(parameters, G_VARIANT_TYPE_TUPLE));
- g_assert(2 == g_variant_n_children(parameters));
-
- auto child = g_variant_get_child_value(parameters, 0);
- g_assert(g_variant_is_of_type(child, G_VARIANT_TYPE_STRING));
- auto self = static_cast<TimedateFixture*>(gself);
- self->attempted_tzid = g_variant_get_string(child, nullptr);
- g_debug("set tz (dbus side): '%s'", self->attempted_tzid.c_str());
- g_dbus_method_invocation_return_value(invocation, nullptr);
-
- /* Send PropertiesChanged */
- GError * local_error = nullptr;
- auto builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
- g_variant_builder_add (builder,
- "{sv}",
- "Timezone",
- g_variant_new_string(
- self->attempted_tzid.c_str()));
- g_dbus_connection_emit_signal (connection,
- NULL,
- object_path,
- "org.freedesktop.DBus.Properties",
- "PropertiesChanged",
- g_variant_new ("(sa{sv}as)",
- interface_name,
- builder,
- NULL),
- &local_error);
- g_assert_no_error (local_error);
- g_variant_unref(child);
+ return wait_for([&tzid, &tz](){return tzid == tz.timezone.get();});
}
-protected:
-
- std::shared_ptr<MockState> m_mock_state;
- std::shared_ptr<State> m_state;
- std::shared_ptr<MockLiveActions> m_live_actions;
- std::shared_ptr<Actions> m_actions;
-
- bool name_acquired;
- std::string attempted_tzid;
-
- GTestDBus* bus;
- guint own_name;
- GDBusConnection* connection;
- GDBusNodeInfo* node_info;
- int object_register_id;
- GDBusProxy *proxy;
-
- void SetUp()
+ void set_timedate1_timezone(const std::string& tzid)
{
- super::SetUp();
- g_debug("SetUp");
-
- name_acquired = false;
- attempted_tzid.clear();
- connection = nullptr;
- node_info = nullptr;
- object_register_id = 0;
- own_name = 0;
- proxy = nullptr;
-
- // bring up the test bus
- bus = g_test_dbus_new(G_TEST_DBUS_NONE);
- g_test_dbus_up(bus);
- const auto address = g_test_dbus_get_bus_address(bus);
- g_setenv("DBUS_SYSTEM_BUS_ADDRESS", address, true);
- g_setenv("DBUS_SESSION_BUS_ADDRESS", address, true);
- g_debug("test_dbus's address is %s", address);
-
- // parse the org.freedesktop.timedate1 interface
- const gchar introspection_xml[] =
- "<node>"
- " <interface name='org.freedesktop.timedate1'>"
- " <property name='Timezone' type='s' access='read' />"
- " <method name='SetTimezone'>"
- " <arg name='timezone' type='s' direction='in'/>"
- " <arg name='user_interaction' type='b' direction='in'/>"
- " </method>"
- " </interface>"
- "</node>";
- node_info = g_dbus_node_info_new_for_xml(introspection_xml, nullptr);
- ASSERT_TRUE(node_info != nullptr);
- ASSERT_TRUE(node_info->interfaces != nullptr);
- ASSERT_TRUE(node_info->interfaces[0] != nullptr);
- ASSERT_TRUE(node_info->interfaces[1] == nullptr);
- ASSERT_STREQ("org.freedesktop.timedate1", node_info->interfaces[0]->name);
-
- // own the bus
- own_name = g_bus_own_name(G_BUS_TYPE_SYSTEM,
- "org.freedesktop.timedate1",
- G_BUS_NAME_OWNER_FLAGS_NONE,
- on_bus_acquired, on_name_acquired, on_name_lost,
- this, nullptr);
- ASSERT_TRUE(object_register_id == 0);
- ASSERT_FALSE(name_acquired);
- ASSERT_TRUE(connection == nullptr);
- g_main_loop_run(loop);
- ASSERT_TRUE(object_register_id != 0);
- ASSERT_TRUE(name_acquired);
- ASSERT_TRUE(G_IS_DBUS_CONNECTION(connection));
+ GError* error {};
+ auto v = g_dbus_connection_call_sync(
+ m_bus,
+ Bus::Timedate1::BUSNAME,
+ Bus::Timedate1::ADDR,
+ Bus::Timedate1::IFACE,
+ Bus::Timedate1::Methods::SET_TIMEZONE,
+ g_variant_new("(sb)", tzid.c_str(), FALSE),
+ nullptr,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ nullptr,
+ &error);
+ g_assert_no_error(error);
- // create the State and Actions
- m_mock_state.reset(new MockState);
- m_mock_state->settings.reset(new Settings);
- m_state = std::dynamic_pointer_cast<State>(m_mock_state);
- m_live_actions.reset(new MockLiveActions(m_state));
- m_actions = std::dynamic_pointer_cast<Actions>(m_live_actions);
+ g_clear_pointer(&v, g_variant_unref);
}
- void TearDown()
+ std::string get_timedate1_timezone()
{
- g_debug("TearDown");
- m_actions.reset();
- m_live_actions.reset();
- m_state.reset();
- m_mock_state.reset();
- g_dbus_connection_unregister_object(connection, object_register_id);
- g_object_unref(proxy);
- g_dbus_node_info_unref(node_info);
- g_bus_unown_name(own_name);
- g_dbus_connection_close(connection, nullptr, on_bus_closed, this);
- g_main_loop_run(loop);
- g_clear_object(&connection);
- g_test_dbus_down(bus);
- g_clear_object(&bus);
+ GError* error {};
+ auto v = g_dbus_connection_call_sync(
+ m_bus,
+ Bus::Timedate1::BUSNAME,
+ Bus::Timedate1::ADDR,
+ Bus::Properties::IFACE,
+ Bus::Properties::Methods::GET,
+ g_variant_new("(ss)", Bus::Timedate1::IFACE, Bus::Timedate1::Properties::TIMEZONE),
+ G_VARIANT_TYPE("(v)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ nullptr,
+ &error);
+ g_assert_no_error(error);
- super::TearDown();
- }
-public:
- void set_timezone(std::string tz)
- {
- g_debug("set_timezone: '%s'", tz.c_str());
- g_dbus_proxy_call_sync(proxy,
- "SetTimezone",
- g_variant_new("(sb)",
- tz.c_str(),
- FALSE),
- G_DBUS_CALL_FLAGS_NONE,
- 500,
- nullptr,
- nullptr);
+ GVariant* tzv {};
+ g_variant_get(v, "(v)", &tzv);
+ std::string tzid;
+ const char* tz = g_variant_get_string(tzv, nullptr);
+ if (tz != nullptr)
+ tzid = tz;
+
+ g_clear_pointer(&tzv, g_variant_unref);
+ g_clear_pointer(&v, g_variant_unref);
+ return tzid;
}
};
-#endif
+#define EXPECT_TZID(expected_tzid, tmp) \
+ EXPECT_TRUE(wait_for_tzid(expected_tzid, tmp)) \
+ << "expected " << expected_tzid \
+ << " got " << tmp.timezone.get();
+