[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1106357: unblock: qtorganizer-mkcal/0.1.0~git20250424.45906b1-2



Package: release.debian.org
Severity: normal
X-Debbugs-Cc: qtorganizer-mkcal@packages.debian.org
Control: affects -1 + src:qtorganizer-mkcal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package qtorganizer-mkcal

The changeset is rather big, unfortunately, because the problem had
FTBFS / unit test failure issues after the latest upstream Git snapshot
was provided in Debian unstable.

[ Reason ]

Basically, this unblock request tackles various topics:

  * unit test testbed fix for i386 arch
  * skip flaky unit test
  * introduce unit test at build time
  * fix changing the default calendar

+qtorganizer-mkcal (0.1.0~git20250424.45906b1-2) unstable; urgency=medium
+
+  * debian/rules:
+    + Independent from build/host architecture, always use build/ sub-directory
+      for out-of-source-tree builds. This fixes mismatch between
+      DEB_BUILD+HOST_MULTIARCH vs DEB_BUILD+HOST_GNU_TYPE on i386.

-> addresses the mentioned testbed for i386 (patchnames differ on i386:
architecture DEB_HOST_MULTIARCH is i386-linux-gnu whereas the builddir
was i686-linux-gnu. To avoid more name mismatching I simply set a fixed 
builddir via d/rules.

+  * debian/patches:
+    + Add 2002_skip-flaky-testSimpleRangeRead.patch. Skip flaky unit test.
+      (Closes: #1104706).

-> self-explanatory

+ -- Mike Gabriel <sunweaver@debian.org>  Tue, 06 May 2025 13:54:57 +0200
+
+qtorganizer-mkcal (0.1.0~git20250424.45906b1-1) unstable; urgency=medium
+
+  [ Lionel Duboeuf ]
+  * Update to new upstream Git snapshot 0.1.0~git20250424.45906b1.

-> This Git snapshot adds a fix for changing the default calendar in
lomiri-calendar-app. It goes together with a fix in that app, as well.

See: https://github.com/dcaliste/qtorganizer-mkcal/commit/857565cb70d66bc006f482d69896e2c700716c27

Also, upstream made unit tests optional and stopped installing unit test
binaries to /opt.

+  [ Mike Gabriel ]
+  * debian/patches:
+    + Rebase 2000_lomiri_disabled_alarms_tag.patch.
+    + Add 2001_support-running-tests-at-build-time.patch. Support running unit
+      tests directly after build.

Furthermore, I added support for setting up a testbed that allows
running unit tests at build time.

+  * debian/control:
+    + Add to B-D: xvfb, xauth (for running unit tests).

Required for running unit tests.

+  * debian/rules:
+    + Prepare testbed and run unit tests at build time.

More testbed preps.

+ -- Mike Gabriel <sunweaver@debian.org>  Fri, 02 May 2025 16:16:42 +0200
+
+qtorganizer-mkcal (0.1.0~git20250219.312412d-1) unstable; urgency=medium
+
+  * Update to new upstream Git snapshot 0.1.0~git20250219.312412d.

This upstream Git snapshot adds a fix for storing alarm trigger offset in the mkCal db backend of qtorganizer-mkcal.

See: https://github.com/dcaliste/qtorganizer-mkcal/commit/38343d30dfd01a0629a305e65c1588fff8cec2ae

+  * debian/patches:
+    + Rebase 2000_lomiri_disabled_alarms_tag.patch.

-> manual rebase of the patch by me.


[ Impact ]
lomiri-calendar-app will be kicked out of Debian 13. This would be unfortunate for Lomiri Operating Environment users.

[ Tests ]
Tests by upstream author on Debian testing / Ubuntu Touch
24.04.x / Ubuntu 24.04 + Lomiri PPA (rebuild of all Lomiri packages from
Debian unstable against Ubuntu 24.04).

Thorough code review by me.

[ Risks ]
Minimal, only for lomiri-calendar-app users.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
None

unblock qtorganizer-mkcal/0.1.0~git20250424.45906b1-2
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/CMakeLists.txt qtorganizer-mkcal-0.1.0~git20250424.45906b1/CMakeLists.txt
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/CMakeLists.txt	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/CMakeLists.txt	2025-04-24 12:45:54.000000000 +0200
@@ -12,6 +12,7 @@
 find_package(ECM REQUIRED NO_MODULE)
 set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
 
+include(CTest)
 include(FeatureSummary)
 include(GNUInstallDirs)
 
@@ -23,6 +24,8 @@
 pkg_check_modules(MKCAL libmkcal-qt5 IMPORTED_TARGET REQUIRED)
 
 add_subdirectory(src)
-add_subdirectory(tests)
+if(BUILD_TESTING)
+	add_subdirectory(tests)
+endif()
 
 feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/changelog qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/changelog
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/changelog	2025-02-12 10:06:41.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/changelog	2025-05-06 13:54:57.000000000 +0200
@@ -1,3 +1,40 @@
+qtorganizer-mkcal (0.1.0~git20250424.45906b1-2) unstable; urgency=medium
+
+  * debian/rules:
+    + Independent from build/host architecture, always use build/ sub-directory
+      for out-of-source-tree builds. This fixes mismatch between
+      DEB_BUILD+HOST_MULTIARCH vs DEB_BUILD+HOST_GNU_TYPE on i386.
+  * debian/patches:
+    + Add 2002_skip-flaky-testSimpleRangeRead.patch. Skip flaky unit test.
+      (Closes: #1104706).
+
+ -- Mike Gabriel <sunweaver@debian.org>  Tue, 06 May 2025 13:54:57 +0200
+
+qtorganizer-mkcal (0.1.0~git20250424.45906b1-1) unstable; urgency=medium
+
+  [ Lionel Duboeuf ]
+  * Update to new upstream Git snapshot 0.1.0~git20250424.45906b1.
+
+  [ Mike Gabriel ]
+  * debian/patches:
+    + Rebase 2000_lomiri_disabled_alarms_tag.patch.
+    + Add 2001_support-running-tests-at-build-time.patch. Support running unit
+      tests directly after build.
+  * debian/control:
+    + Add to B-D: xvfb, xauth (for running unit tests).
+  * debian/rules:
+    + Prepare testbed and run unit tests at build time.
+
+ -- Mike Gabriel <sunweaver@debian.org>  Fri, 02 May 2025 16:16:42 +0200
+
+qtorganizer-mkcal (0.1.0~git20250219.312412d-1) unstable; urgency=medium
+
+  * Update to new upstream Git snapshot 0.1.0~git20250219.312412d.
+  * debian/patches:
+    + Rebase 2000_lomiri_disabled_alarms_tag.patch.
+
+ -- Mike Gabriel <sunweaver@debian.org>  Wed, 19 Feb 2025 15:05:53 +0100
+
 qtorganizer-mkcal (0.1.0~git20250211.88829da-1) unstable; urgency=medium
 
   [ Mike Gabriel ]
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/control qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/control
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/control	2024-12-19 14:28:53.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/control	2025-03-06 19:31:01.000000000 +0100
@@ -10,7 +10,9 @@
                qtbase5-dev,
                qtpim5-dev (>= 5.0~git20171109~0bd985b),
                libkf5calendarcore-dev,
-               libmkcal-qt5-dev
+               libmkcal-qt5-dev,
+               xvfb,
+               xauth,
 Standards-Version: 4.7.0
 Rules-Requires-Root: no
 Homepage: https://github.com/dcaliste/qtorganizer-mkcal/
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/2000_lomiri_disabled_alarms_tag.patch qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/2000_lomiri_disabled_alarms_tag.patch
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/2000_lomiri_disabled_alarms_tag.patch	2025-02-12 10:06:41.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/2000_lomiri_disabled_alarms_tag.patch	2025-05-02 14:57:57.000000000 +0200
@@ -2,7 +2,7 @@
 ---
 --- a/src/itemcalendars.cpp
 +++ b/src/itemcalendars.cpp
-@@ -59,15 +59,18 @@
+@@ -59,15 +59,19 @@
  #include <KCalendarCore/Journal>
  #include <KCalendarCore/OccurrenceIterator>
  
@@ -12,17 +12,18 @@
  
  static KCalendarCore::Alarm::Ptr toAlarm(KCalendarCore::Incidence::Ptr incidence,
 -                                         const QOrganizerItemReminder &reminder)
-+                                         const QOrganizerItemReminder &reminder, bool enabled)
++                                         const QOrganizerItemReminder &reminder,
++                                         bool enabled)
  {
      KCalendarCore::Alarm::Ptr alarm = incidence->newAlarm();
-     alarm->setStartOffset(KCalendarCore::Duration(reminder.secondsBeforeStart()));
+     alarm->setStartOffset(KCalendarCore::Duration(-reminder.secondsBeforeStart()));
      alarm->setRepeatCount(reminder.repetitionCount());
      alarm->setSnoozeTime(KCalendarCore::Duration(reminder.repetitionDelay()));
 +    alarm->setEnabled(enabled);
  
      return alarm;
  }
-@@ -157,7 +160,8 @@
+@@ -157,7 +161,8 @@
          }
      }
      incidence->clearAlarms();
@@ -32,7 +33,7 @@
      for (const QOrganizerItemDetail &detail : item.details()) {
          switch (detail.type()) {
          case QOrganizerItemDetail::TypeClassification:
-@@ -212,7 +216,7 @@
+@@ -212,7 +217,7 @@
              if (detailMask.isEmpty()
                  || detailMask.contains(detail.type())) {
                  QOrganizerItemAudibleReminder reminder(detail);
@@ -41,7 +42,7 @@
                  alarm->setAudioAlarm(reminder.dataUrl().toString());
              }
              break;
-@@ -220,7 +224,7 @@
+@@ -220,7 +225,7 @@
              if (detailMask.isEmpty()
                  || detailMask.contains(detail.type())) {
                  QOrganizerItemEmailReminder reminder(detail);
@@ -50,7 +51,7 @@
                  KCalendarCore::Person::List recipients;
                  for (const QString &recipient : reminder.recipients()) {
                      recipients.append(KCalendarCore::Person::fromFullName(recipient));
-@@ -232,7 +236,7 @@
+@@ -232,7 +237,7 @@
              if (detailMask.isEmpty()
                  || detailMask.contains(detail.type())) {
                  QOrganizerItemVisualReminder reminder(detail);
@@ -59,7 +60,7 @@
                  alarm->setDisplayAlarm(reminder.message());
              }
              break;
-@@ -535,7 +539,12 @@
+@@ -535,7 +540,12 @@
      }
      if (details.isEmpty()
          || details.contains(QOrganizerItemDetail::TypeReminder)) {
@@ -72,7 +73,7 @@
              switch (alarm->type()) {
              case KCalendarCore::Alarm::Audio: {
                  QOrganizerItemAudibleReminder audio;
-@@ -567,6 +576,10 @@
+@@ -567,6 +577,10 @@
                  break;
              }
          }
@@ -85,7 +86,7 @@
          QOrganizerItemRecurrence recurrence;
 --- a/tests/tst_engine.cpp
 +++ b/tests/tst_engine.cpp
-@@ -86,6 +86,7 @@
+@@ -87,6 +87,7 @@
      void testItemAudibleReminder();
      void testItemEmailReminder();
      void testItemVisualReminder();
@@ -93,7 +94,7 @@
      void testItemAttendees();
      void testItemAttendeeStatus_data();
      void testItemAttendeeStatus();
-@@ -581,6 +582,7 @@
+@@ -622,6 +623,7 @@
      QVERIFY(!alarm->hasEndOffset());
      QCOMPARE(alarm->snoozeTime().asSeconds(), detail.repetitionDelay());
      QCOMPARE(alarm->repeatCount(), detail.repetitionCount());
@@ -101,7 +102,7 @@
  
      // Verify that updates don't change the alarm
      item.setDisplayLabel(QStringLiteral("Test item audible reminder updated"));
-@@ -630,6 +632,7 @@
+@@ -671,6 +673,7 @@
      QCOMPARE(alarm->type(), KCalendarCore::Alarm::Email);
      QCOMPARE(alarm->mailSubject(), detail.subject());
      QCOMPARE(alarm->mailText(), detail.body());
@@ -109,7 +110,7 @@
      // mKCal doesn't support multiple addresses.
      //for (const KCalendarCore::Person &person : alarm->mailAddresses()) {
      //    QVERIFY(detail.recipients().contains(person.fullName()));
-@@ -668,6 +671,7 @@
+@@ -709,6 +712,7 @@
      KCalendarCore::Alarm::Ptr alarm = incidence->alarms().first();
      QCOMPARE(alarm->type(), KCalendarCore::Alarm::Display);
      QCOMPARE(alarm->text(), detail.message());
@@ -117,7 +118,7 @@
  
      QOrganizerManager manager(QString::fromLatin1("mkcal"),
                                mManager->managerParameters());
-@@ -680,6 +684,36 @@
+@@ -721,6 +725,36 @@
      QCOMPARE(value.message(), detail.message());
  }
  
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/2001_support-running-tests-at-build-time.patch qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/2001_support-running-tests-at-build-time.patch
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/2001_support-running-tests-at-build-time.patch	1970-01-01 01:00:00.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/2001_support-running-tests-at-build-time.patch	2025-05-02 16:05:10.000000000 +0200
@@ -0,0 +1,9 @@
+--- a/tests/CMakeLists.txt
++++ b/tests/CMakeLists.txt
+@@ -7,3 +7,6 @@
+         KF5::CalendarCore)
+ 
+ add_test(tst_engine tst_engine)
++
++set_tests_properties(tst_engine
++                     PROPERTIES ENVIRONMENT "QT_PLUGIN_PATH=${CMAKE_BINARY_DIR}/")
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/2002_skip-flaky-testSimpleRangeRead.patch qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/2002_skip-flaky-testSimpleRangeRead.patch
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/2002_skip-flaky-testSimpleRangeRead.patch	1970-01-01 01:00:00.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/2002_skip-flaky-testSimpleRangeRead.patch	2025-05-06 13:54:57.000000000 +0200
@@ -0,0 +1,14 @@
+Description: Skip flaky tst_enging::testSimpleRangeRead.
+Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+
+--- a/tests/tst_engine.cpp
++++ b/tests/tst_engine.cpp
+@@ -1156,6 +1156,8 @@
+ 
+ void tst_engine::testSimpleRangeRead()
+ {
++    QSKIP("Test is flaky, see: https://github.com/dcaliste/qtorganizer-mkcal/issues/9";);
++
+     QSignalSpy dataChanged(mManager, &QOrganizerManager::dataChanged);
+ 
+     QOrganizerManager manager(QString::fromLatin1("mkcal"),
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/series qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/series
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/patches/series	2025-02-12 10:06:41.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/patches/series	2025-05-06 13:54:57.000000000 +0200
@@ -1 +1,3 @@
 2000_lomiri_disabled_alarms_tag.patch
+2001_support-running-tests-at-build-time.patch
+2002_skip-flaky-testSimpleRangeRead.patch
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/rules qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/rules
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/debian/rules	2024-12-16 14:17:53.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/debian/rules	2025-05-06 13:53:37.000000000 +0200
@@ -1,8 +1,6 @@
 #!/usr/bin/make -f
 # -*- makefile -*-
 
-DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
-
 export DPKG_GENSYMBOLS_CHECK_LEVEL=1
 
 export QT_SELECT := qt5
@@ -11,16 +9,26 @@
 include /usr/share/dpkg/buildflags.mk
 
 %:
-	dh $@
+	dh $@ --builddirectory=build
 
 override_dh_missing:
 	dh_missing --fail-missing
 
 override_dh_auto_install:
-	dh_auto_install --destdir=debian/tmp
+	dh_auto_install --builddirectory=build --destdir=debian/tmp
 
 override_dh_auto_test:
-	dh_auto_test --no-parallel
+	mkdir debian/home/
+	ln -sf src build/organizer
+	export HOME=debian/home && xvfb-run -a dh_auto_test --builddirectory=build --no-parallel
+
+override_dh_auto_clean:
+	rm -fv $(builddir)/organizer
+	dh_auto_clean --builddirectory=build
+
+override_dh_clean:
+	dh_clean
+	rm -Rfv debian/home/
 
 get-orig-source:
 	uscan --noconf --force-download --rename --download-current-version --destdir=..
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/rpm/qtorganizer-mkcal.spec qtorganizer-mkcal-0.1.0~git20250424.45906b1/rpm/qtorganizer-mkcal.spec
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/rpm/qtorganizer-mkcal.spec	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/rpm/qtorganizer-mkcal.spec	2025-04-24 12:45:54.000000000 +0200
@@ -33,6 +33,7 @@
 
 %install
 make DESTDIR=%{buildroot} install
+install -m 644 -p -D tests/tst_engine %{buildroot}/opt/tests/qtorganizer-mkcal
 
 %files
 %defattr(-,root,root,-)
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/src/helper.cpp qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/helper.cpp
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/src/helper.cpp	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/helper.cpp	2025-04-24 12:45:54.000000000 +0200
@@ -32,7 +32,7 @@
 #include "helper.h"
 
 QtOrganizer::QOrganizerCollection toCollection(const QString &managerUri,
-                                               const mKCal::Notebook::Ptr &nb)
+                                               const mKCal::Notebook::Ptr &nb, bool isDefault)
 {
     QtOrganizer::QOrganizerCollection collection;
     collection.setId(QtOrganizer::QOrganizerCollectionId(managerUri, nb->uid().toUtf8()));
@@ -42,6 +42,8 @@
                            nb->description());
     collection.setMetaData(QtOrganizer::QOrganizerCollection::KeyColor,
                            nb->color());
+    collection.setExtendedMetaData(QStringLiteral("default"),
+                                       isDefault);
     collection.setExtendedMetaData(QStringLiteral("shared"),
                                    nb->isShared());
     collection.setExtendedMetaData(QStringLiteral("master"),
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/src/helper.h qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/helper.h
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/src/helper.h	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/helper.h	2025-04-24 12:45:54.000000000 +0200
@@ -37,7 +37,7 @@
 #include <notebook.h>
 
 QtOrganizer::QOrganizerCollection toCollection(const QString &managerUri,
-                                               const mKCal::Notebook::Ptr &nb);
+                                               const mKCal::Notebook::Ptr &nb, bool isDefault);
 
 void updateNotebook(mKCal::Notebook::Ptr nb,
                     const QtOrganizer::QOrganizerCollection &collection);
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/src/itemcalendars.cpp qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/itemcalendars.cpp
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/src/itemcalendars.cpp	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/itemcalendars.cpp	2025-04-24 12:45:54.000000000 +0200
@@ -65,7 +65,7 @@
                                          const QOrganizerItemReminder &reminder)
 {
     KCalendarCore::Alarm::Ptr alarm = incidence->newAlarm();
-    alarm->setStartOffset(KCalendarCore::Duration(reminder.secondsBeforeStart()));
+    alarm->setStartOffset(KCalendarCore::Duration(-reminder.secondsBeforeStart()));
     alarm->setRepeatCount(reminder.repetitionCount());
     alarm->setSnoozeTime(KCalendarCore::Duration(reminder.repetitionDelay()));
 
@@ -405,7 +405,7 @@
 static void toItemReminder(QOrganizerItemReminder *reminder,
                            const KCalendarCore::Alarm::Ptr &alarm)
 {
-    reminder->setSecondsBeforeStart(alarm->startOffset().asSeconds());
+    reminder->setSecondsBeforeStart(-alarm->startOffset().asSeconds());
     reminder->setRepetition(alarm->repeatCount(), alarm->snoozeTime().asSeconds());
 }
 
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/src/mkcalworker.cpp qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/mkcalworker.cpp
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/src/mkcalworker.cpp	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/src/mkcalworker.cpp	2025-04-24 12:45:54.000000000 +0200
@@ -546,7 +546,7 @@
     *error = QOrganizerManager::NoError;
     if (mOpened) {
         for (const mKCal::Notebook::Ptr &nb : mStorage->notebooks()) {
-            ret.append(toCollection(managerUri(), nb));
+            ret.append(toCollection(managerUri(), nb, mDefaultNotebookUid == nb->uid()));
         }
     } else {
         *error = QOrganizerManager::PermissionsError;
@@ -568,10 +568,13 @@
         int index = 0;
         for (QList<QOrganizerCollection>::Iterator it = collections->begin();
              it != collections->end(); ++it, ++index) {
+            mKCal::Notebook::Ptr nb;
+            bool isDefault = it->extendedMetaData("default").toBool();
             if (it->id().isNull()) {
-                mKCal::Notebook::Ptr nb(new mKCal::Notebook);
+                nb = mKCal::Notebook::Ptr(new mKCal::Notebook);
                 updateNotebook(nb, *it);
-                if (!mStorage->addNotebook(nb)) {
+
+                if (!(isDefault ? mStorage->setDefaultNotebook(nb) : mStorage->addNotebook(nb))) {
                     errors->insert(index, QOrganizerManager::PermissionsError);
                 } else {
                     it->setId(collectionId(nb->uid().toUtf8()));
@@ -579,10 +582,10 @@
                     added.prepend(it->id());
                 }
             } else {
-                mKCal::Notebook::Ptr nb = mStorage->notebook(it->id().localId());
+                nb = mStorage->notebook(it->id().localId());
                 if (nb) {
                     updateNotebook(nb, *it);
-                    if (!mStorage->updateNotebook(nb)) {
+                    if (!(isDefault ? mStorage->setDefaultNotebook(nb) : mStorage->updateNotebook(nb))) {
                         errors->insert(index, QOrganizerManager::PermissionsError);
                     } else {
                         modifiedIds.prepend(nb->uid());
@@ -592,6 +595,11 @@
                     errors->insert(index, QOrganizerManager::DoesNotExistError);
                 }
             }
+
+            if (isDefault && (mDefaultNotebookUid != nb->uid())) {
+                mDefaultNotebookUid = nb->uid();
+                emit defaultCollectionIdChanged(mDefaultNotebookUid);
+            }
         }
         if (!addedIds.isEmpty() || !modifiedIds.isEmpty()) {
             emit collectionsUpdated(addedIds, modifiedIds, QStringList());
@@ -600,7 +608,7 @@
             emit collectionsAdded(added);
         }
         if (!changed.isEmpty()) {
-            emit collectionsChanged(changed);            
+            emit collectionsChanged(changed);
         }
         QList<QPair<QOrganizerCollectionId, QOrganizerManager::Operation>> mods;
         for (const QOrganizerCollectionId &id : changed) {
@@ -642,16 +650,23 @@
         QStringList ids;
         QList<QOrganizerCollectionId> removedIds;
         QList<QPair<QOrganizerCollectionId, QOrganizerManager::Operation>> mods;
+        mKCal::Notebook::Ptr defaultNb = mStorage->defaultNotebook();
         int index = 0;
         for (const QOrganizerCollectionId &collectionId : collectionIds) {
             mKCal::Notebook::Ptr nb = mStorage->notebook(collectionId.localId());
             if (nb) {
-                if (!mStorage->deleteNotebook(nb)) {
+                // don't allow to remove a default collection
+                if (defaultNb && (defaultNb->uid() == nb->uid())) {
                     errors->insert(index, QOrganizerManager::PermissionsError);
+                    *error = QOrganizerManager::PermissionsError;
                 } else {
-                    ids.prepend(nb->uid());
-                    removedIds.prepend(collectionId);
-                    mods.prepend(QPair<QOrganizerCollectionId, QOrganizerManager::Operation>(collectionId, QOrganizerManager::Remove));
+                    if (!mStorage->deleteNotebook(nb)) {
+                        errors->insert(index, QOrganizerManager::PermissionsError);
+                    } else {
+                        ids.prepend(nb->uid());
+                        removedIds.prepend(collectionId);
+                        mods.prepend(QPair<QOrganizerCollectionId, QOrganizerManager::Operation>(collectionId, QOrganizerManager::Remove));
+                    }
                 }
             } else {
                 errors->insert(index, QOrganizerManager::DoesNotExistError);
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/tests/CMakeLists.txt qtorganizer-mkcal-0.1.0~git20250424.45906b1/tests/CMakeLists.txt
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/tests/CMakeLists.txt	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/tests/CMakeLists.txt	2025-04-24 12:45:54.000000000 +0200
@@ -7,5 +7,3 @@
         KF5::CalendarCore)
 
 add_test(tst_engine tst_engine)
-
-install(TARGETS tst_engine DESTINATION /opt/tests/qtorganizer-mkcal)
diff -Nru qtorganizer-mkcal-0.1.0~git20250211.88829da/tests/tst_engine.cpp qtorganizer-mkcal-0.1.0~git20250424.45906b1/tests/tst_engine.cpp
--- qtorganizer-mkcal-0.1.0~git20250211.88829da/tests/tst_engine.cpp	2025-02-11 15:23:17.000000000 +0100
+++ qtorganizer-mkcal-0.1.0~git20250424.45906b1/tests/tst_engine.cpp	2025-04-24 12:45:54.000000000 +0200
@@ -71,6 +71,7 @@
     void initTestCase();
     void cleanupTestCase();
 
+    void testDefaultCollection();
     void testCollections();
     void testCollectionIO();
     void testCollectionExternal();
@@ -160,6 +161,7 @@
 
 void tst_engine::cleanupTestCase()
 {
+    QFile::remove(QStringLiteral("db"));
     delete mManager;
 }
 
@@ -183,6 +185,42 @@
 }
 
 Q_DECLARE_METATYPE(QList<QOrganizerCollectionId>)
+void tst_engine::testDefaultCollection()
+{
+    QOrganizerCollection existingCollection = mManager->collections().first();
+    QCOMPARE(existingCollection.id(), mManager->defaultCollectionId());
+    qRegisterMetaType<QList<QOrganizerCollectionId>>();
+    QSignalSpy added(mManager, &QOrganizerManager::collectionsAdded);
+    QSignalSpy deleted(mManager, &QOrganizerManager::collectionsRemoved);
+    QSignalSpy modified(mManager, &QOrganizerManager::collectionsChanged);
+
+    QOrganizerCollection collection;
+    collection.setMetaData(QOrganizerCollection::KeyName,
+                           QStringLiteral("Test default collection"));
+    collection.setExtendedMetaData(QStringLiteral("default"), true);
+    QVERIFY(mManager->saveCollection(&collection));
+    QCOMPARE(mManager->error(), QOrganizerManager::NoError);
+    QTRY_COMPARE(added.count(), 1);
+    collection = mManager->collection(collection.id());
+    QCOMPARE(mManager->defaultCollectionId(), collection.id());
+
+    // default collection can't be deleted
+    mManager->removeCollection(collection.id());
+    QTRY_VERIFY(deleted.isEmpty());
+    QCOMPARE(mManager->error(), QOrganizerManager::PermissionsError);
+    QCOMPARE(mManager->collections().count(), 2);
+
+    // now set default to previous one so that we can delete it
+    existingCollection.setExtendedMetaData(QStringLiteral("default"), true);
+    QVERIFY(mManager->saveCollection(&existingCollection));
+    QTRY_COMPARE(modified.count(), 1);
+    QCOMPARE(mManager->defaultCollectionId(), existingCollection.id());
+
+    deleted.clear();
+    mManager->removeCollection(collection.id());
+    QTRY_COMPARE(deleted.count(), 1);
+}
+
 void tst_engine::testCollectionIO()
 {
     QOrganizerCollection collection;
@@ -197,6 +235,7 @@
     collection.setMetaData(QOrganizerCollection::KeyImage,
                            QStringLiteral("theme://notebook.png"));
     collection.setExtendedMetaData(QStringLiteral("visible"), true);
+    collection.setExtendedMetaData(QStringLiteral("default"), false);
 
     qRegisterMetaType<QList<QOrganizerCollectionId>>();
     QSignalSpy added(mManager, &QOrganizerManager::collectionsAdded);
@@ -227,6 +266,8 @@
              collection.metaData(QOrganizerCollection::KeyImage));
     QCOMPARE(read.extendedMetaData(QStringLiteral("visible")),
              collection.extendedMetaData(QStringLiteral("visible")));
+    QCOMPARE(read.extendedMetaData(QStringLiteral("default")),
+                 collection.extendedMetaData(QStringLiteral("default")));
 
     collection.setMetaData(QOrganizerCollection::KeyDescription,
                            QStringLiteral("Updated description."));
@@ -577,7 +618,7 @@
     KCalendarCore::Alarm::Ptr alarm = incidence->alarms().first();
     QCOMPARE(alarm->type(), KCalendarCore::Alarm::Audio);
     QCOMPARE(alarm->audioFile(), detail.dataUrl().toString());
-    QCOMPARE(alarm->startOffset().asSeconds(), detail.secondsBeforeStart());
+    QCOMPARE(alarm->startOffset().asSeconds(), -detail.secondsBeforeStart());
     QVERIFY(!alarm->hasEndOffset());
     QCOMPARE(alarm->snoozeTime().asSeconds(), detail.repetitionDelay());
     QCOMPARE(alarm->repeatCount(), detail.repetitionCount());

Reply to: