3 commits - c++/compiled c++/lib c++/tests

Christian Mollekopf mollekopf at kolabsys.com
Wed Feb 29 23:18:14 CET 2012


 c++/compiled/XMLParserWrapper.cpp |   14 
 c++/compiled/XMLParserWrapper.h   |    9 
 c++/lib/CMakeLists.txt            |   13 
 c++/lib/calendaring.cpp           |   54 +++
 c++/lib/calendaring.h             |   35 ++
 c++/lib/kolabkcalconversion.cpp   |  188 +++++++++++
 c++/lib/kolabkcalconversion.h     |    3 
 c++/tests/bindingstest.cpp        |   14 
 c++/tests/kcalconversiontest.cpp  |  609 +++++++++++++++++++-------------------
 c++/tests/kcalconversiontest.h    |   16 
 c++/tests/serializers.h           |    2 
 c++/tests/testfiles/icalEvent.xml |    8 
 12 files changed, 633 insertions(+), 332 deletions(-)

New commits:
commit 003399e48e233fc1014db9c833b9047f30e2b0b6
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Wed Feb 29 23:17:46 2012 +0100

    First Proof-Of-Concept for advanced calendaring features, read timezone info from system using ktimezoned, use only existing timezones
    
    The ktimezoned runtime dependency could be a problem on some platforms....
    Bindings for the module are still missing.

diff --git a/c++/lib/CMakeLists.txt b/c++/lib/CMakeLists.txt
index 12c2133..189639f 100644
--- a/c++/lib/CMakeLists.txt
+++ b/c++/lib/CMakeLists.txt
@@ -45,12 +45,17 @@ if(KDECORE_FOUND AND KCALCORE_FOUND)
     message("Building KCalCore dependend libraries.")
 
     #Library with converters to/from kcalcore and code to provide advanced functionality (such as expanding recurrences) from kcalcore.
-    add_library(kolabkcal SHARED kolabkcalconversion.cpp)
+    add_library(kolabkcal SHARED kolabkcalconversion.cpp calendaring.cpp)
     target_link_libraries(kolabkcal kolabxml ${KCALCORE} ${KDECORE})
 
-    #Library with serialization/deserialization code for KCalCore containers (deprecated)
-#     add_library(kolabxmlkcal SHARED kcalkolabformat.cpp ../compiled/XMLParserWrapper.cpp ../compiled/grammar-input-stream.cxx ${SCHEMA_SOURCEFILES})
-#     target_link_libraries(kolabxmlkcal xerces-c ${KCALCORE} ${KDECORE})
+    set_target_properties(kolabkcal PROPERTIES VERSION 0.1.0 SOVERSION 0)
+    install(TARGETS kolabkcal LIBRARY DESTINATION lib)
+
+    install( FILES
+    kolabkcalconversion.h
+    calendaring.h
+    DESTINATION include/kolab COMPONENT Devel)
+
 else()
     message(WARNING "Could not build KCalCore/KDElibs dependend libraries, because kdepimlibs/kdelibs is missing.")
 endif()
diff --git a/c++/lib/calendaring.cpp b/c++/lib/calendaring.cpp
new file mode 100644
index 0000000..60e4355
--- /dev/null
+++ b/c++/lib/calendaring.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "calendaring.h"
+
+#include <kcalcore/event.h>
+#include <KDE/KCalCore/Todo>
+#include <Qt/qdebug.h>
+
+#include "kolabkcalconversion.h"
+
+namespace Kolab {
+
+    namespace Calendaring {
+
+        bool conflicts(const Kolab::Event &e1, const Kolab::Event &e2)
+        {
+            KCalCore::Event::Ptr k1 = KCalConversion::toKCalCore(e1);
+            KCalCore::Event::Ptr k2 = KCalConversion::toKCalCore(e2);
+            if (k2->dtEnd().compare(k1->dtStart()) == KDateTime::Before) {
+                return false;
+            } else if (k1->dtEnd().compare(k2->dtStart()) == KDateTime::Before) {
+                return false;
+            }
+            return true;
+        }
+
+        std::vector<Kolab::DateTime> timeInInterval(const Kolab::Event &e, const Kolab::DateTime &start, const Kolab::DateTime &end)
+        {
+            KCalCore::Event::Ptr k = KCalConversion::toKCalCore(e);
+            KCalCore::DateTimeList list = k->recurrence()->timesInInterval(KCalConversion::toDate(start), KCalConversion::toDate(end));
+            std::vector<Kolab::DateTime> dtList;
+            foreach(const KDateTime &dt, list) {
+                dtList.push_back(KCalConversion::fromDate(dt));
+            }
+            return dtList;
+        }
+
+    } //Namespace
+} //Namespace
\ No newline at end of file
diff --git a/c++/lib/calendaring.h b/c++/lib/calendaring.h
new file mode 100644
index 0000000..7ee946c
--- /dev/null
+++ b/c++/lib/calendaring.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KOLABCALENDARING_H
+#define KOLABCALENDARING_H
+
+#include "kolabevent.h"
+#include <kcalcore/event.h>
+
+namespace Kolab {
+    namespace Calendaring {
+        /**
+         * Returns true if the events conflict (overlap)
+         */
+        bool conflicts(const Kolab::Event &, const Kolab::Event &);
+
+        std::vector<Kolab::DateTime> timeInInterval(const Kolab::Event &, const Kolab::DateTime &start, const Kolab::DateTime &end);
+    };
+};
+
+#endif
\ No newline at end of file
diff --git a/c++/lib/kolabkcalconversion.cpp b/c++/lib/kolabkcalconversion.cpp
index 1c24bbe..cc46ee2 100644
--- a/c++/lib/kolabkcalconversion.cpp
+++ b/c++/lib/kolabkcalconversion.cpp
@@ -22,6 +22,7 @@
 #include <QtCore/QVector>
 #include <QtCore/QDebug>
 #include <vector>
+#include <KDE/KSystemTimeZones>
 
 namespace Kolab {
 namespace KCalConversion {
@@ -38,7 +39,14 @@ KDateTime toDate(const Kolab::DateTime &dt)
         if (dt.isUTC()) { //UTC
             date.setTimeSpec(KDateTime::Spec(KDateTime::UTC));
         } else if (!dt.timezone().empty()) { //Timezone
-            date.setTimeSpec(KDateTime::Spec(KTimeZone(QString::fromStdString(dt.timezone()))));
+            const KTimeZone &tz = KSystemTimeZones::zone(QString::fromStdString(dt.timezone())); //Needs ktimezoned (timezone daemon running) http://api.kde.org/4.x-api/kdelibs-apidocs/kdecore/html/classKSystemTimeZones.html
+            if (!tz.isValid()) {
+                qWarning() << "timezone not found" << QString::fromStdString(dt.timezone());
+                if (!KSystemTimeZones::isTimeZoneDaemonAvailable()) {
+                    qWarning() << "ktimezoned is not available and required for timezone interpretation";
+                }
+            }
+            date.setTimeSpec(KDateTime::Spec(tz));
         } //Floating
     }
     return date;
diff --git a/c++/lib/kolabkcalconversion.h b/c++/lib/kolabkcalconversion.h
index 60c5e3f..45cbc7b 100644
--- a/c++/lib/kolabkcalconversion.h
+++ b/c++/lib/kolabkcalconversion.h
@@ -30,6 +30,9 @@ namespace Kolab {
         
         //TODO converters in both directions for all containers
         
+        KDateTime toDate(const Kolab::DateTime &dt);
+        DateTime fromDate(const KDateTime &dt);
+        
     };
 };
 
diff --git a/c++/tests/bindingstest.cpp b/c++/tests/bindingstest.cpp
index 69422f3..0a34988 100644
--- a/c++/tests/bindingstest.cpp
+++ b/c++/tests/bindingstest.cpp
@@ -32,7 +32,7 @@ void setIncidence(T &ev)
     ev.setSequence(1);
     ev.setClassification(Kolab::Confidential);
     ev.addCategory("Category");
-    ev.setStart(Kolab::DateTime("US/Eastern", 2006,1,6,12,0,0));
+    ev.setStart(Kolab::DateTime("Europe/Zurich", 2006,1,6,12,0,0));
     
     Kolab::RecurrenceRule rule;
     rule.setFrequency(Kolab::RecurrenceRule::Daily);
@@ -54,9 +54,9 @@ void setIncidence(T &ev)
     rule.setBymonth(list);
     
     ev.setRecurrenceRule(rule);
-    ev.addRecurrenceDate(Kolab::DateTime("US/Eastern", 2006,1,6,12,0,0));
-    ev.addExceptionDate(Kolab::DateTime("US/Eastern", 2006,1,6,12,0,0));
-    ev.setRecurrenceID(Kolab::DateTime("US/Eastern", 2006,1,6,12,0,0), true);
+    ev.addRecurrenceDate(Kolab::DateTime("Europe/Zurich", 2006,1,6,12,0,0));
+    ev.addExceptionDate(Kolab::DateTime("Europe/Zurich", 2006,1,6,12,0,0));
+    ev.setRecurrenceID(Kolab::DateTime("Europe/Zurich", 2006,1,6,12,0,0), true);
     ev.setSummary("summary");
     ev.setDescription("description");
     ev.setPriority(3);
@@ -181,7 +181,7 @@ void BindingsTest::eventCompletness()
 {
     Kolab::Event ev;
     setIncidence(ev);
-    ev.setEnd(Kolab::DateTime("US/Eastern", 2006,1,8,12,0,0));
+    ev.setEnd(Kolab::DateTime("Europe/Zurich", 2006,1,8,12,0,0));
     ev.setTransparency(true);
     
     std::string result = Kolab::writeEvent(ev);
@@ -213,7 +213,7 @@ void BindingsTest::todoCompletness()
 {
     Kolab::Todo ev;
     setIncidence(ev);
-    ev.setDue(Kolab::DateTime("US/Eastern", 2006,1,8,12,0,0));
+    ev.setDue(Kolab::DateTime("Europe/Zurich", 2006,1,8,12,0,0));
     ev.addRelatedTo("rel1");
     ev.addRelatedTo("rel2");
     ev.setPercentComplete(50);
@@ -239,7 +239,7 @@ void BindingsTest::journalCompletness()
     ev.setSequence(1);
     ev.setClassification(Kolab::Confidential);
     ev.addCategory("Category");
-    ev.setStart(Kolab::DateTime("US/Eastern", 2006,1,6,12,0,0));
+    ev.setStart(Kolab::DateTime("Europe/Zurich", 2006,1,6,12,0,0));
     Kolab::Attendee attendee("email");
     attendee.setName("name");
     attendee.setPartStat(Kolab::PartDelegated);
diff --git a/c++/tests/kcalconversiontest.cpp b/c++/tests/kcalconversiontest.cpp
index b8b9fdd..d15e927 100644
--- a/c++/tests/kcalconversiontest.cpp
+++ b/c++/tests/kcalconversiontest.cpp
@@ -2,10 +2,12 @@
 
 #include <QtCore/QObject>
 #include <QtTest/QtTest>
+#include <KDE/KSystemTimeZones>
 #include <kcalcore/recurrence.h>
 
 #include <lib/kolabkcalconversion.h>
 #include <lib/kolabkcalconversion.cpp>
+#include <lib/calendaring.h>
 
 #include "serializers.h"
 
@@ -14,6 +16,7 @@ using namespace Kolab::KCalConversion;
 Q_DECLARE_METATYPE(Kolab::Duration);
 Q_DECLARE_METATYPE(Kolab::DateTime);
 Q_DECLARE_METATYPE(Kolab::Event);
+Q_DECLARE_METATYPE(std::vector<Kolab::DateTime>);
 Q_DECLARE_METATYPE(KCalCore::Event);
 
 namespace QTest {
@@ -104,7 +107,7 @@ void KCalConversionTest::testDate_data()
     QTest::addColumn<Kolab::DateTime>( "input" );
     QTest::addColumn<KDateTime>( "result" );
 
-    QTest::newRow( "datetime with tz" ) << Kolab::DateTime("US/Eastern",2006,1,8,12,0,0) << KDateTime(KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KTimeZone(QString::fromLatin1("US/Eastern"))));
+    QTest::newRow( "datetime with tz" ) << Kolab::DateTime("Europe/Zurich",2006,1,8,12,0,0) << KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KSystemTimeZones::zone("Europe/Zurich"));
     QTest::newRow( "floating datetime" ) << Kolab::DateTime(2006,1,8,12,0,0, false) << KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KDateTime::Spec(KDateTime::ClockTime));
     QTest::newRow( "utc datetime" ) << Kolab::DateTime(2006,1,8,12,0,0, true) << KDateTime(KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KDateTime::UTC));
     QTest::newRow( "date only" ) << Kolab::DateTime(2006,1,8) << KDateTime(QDate(2006, 1, 8));
@@ -124,6 +127,30 @@ void KCalConversionTest::testDate()
 }
 
 
+void KCalConversionTest::testDateTZ_data()
+{
+    QTest::addColumn<Kolab::DateTime>( "input" );
+    QTest::addColumn<KDateTime>( "result" );
+    QTest::addColumn<int>( "offset" );
+       
+    QTest::newRow( "berlin" ) << Kolab::DateTime("Europe/Berlin",2006,1,8,12,0,0) << KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KSystemTimeZones::zone("Europe/Berlin")) << 3600;
+}
+
+void KCalConversionTest::testDateTZ()
+{
+    QFETCH(Kolab::DateTime, input);
+    QFETCH(KDateTime, result);
+    QFETCH(int, offset);
+    
+    const KDateTime &r = Kolab::KCalConversion::toDate(input);
+    QCOMPARE(result.timeZone().name(), QString::fromStdString(input.timezone()));
+    QCOMPARE(r.timeZone().currentOffset(), offset);
+    
+    const Kolab::DateTime &r2 = Kolab::KCalConversion::fromDate(result);
+    QCOMPARE(QString::fromStdString(r2.timezone()), result.timeZone().name());
+}
+
+
 void KCalConversionTest::testConversion_data()
 {
     QTest::addColumn<KCalCore::Event>( "kcal" );
@@ -279,144 +306,147 @@ void KCalConversionTest::testConversion()
     
 //     QCOMPARE(e->alarms(), kcal.alarms()); //TODO
 //TODO custom properties
+
+    QBENCHMARK {
+        toKCalCore(kolab);
+    }
     
     const Kolab::Event &b = fromKCalCore(kcal);
     QCOMPARE(b.uid(), kolab.uid());
 }
 
-/*
-void KCalConversionTest::BenchmarkRoundtripKCAL()
-{
-    std::ifstream ifs;
-//     ifs.exceptions (std::ifstream::badbit | std::ifstream::failbit);
-    ifs.open ("../../tests/testfiles/icalEvent.xml");
-    std::string result;
-    
-    std::istream_iterator<std::string> DataBegin( ifs );
-    std::istream_iterator<std::string> DataEnd;
 
-    while( DataBegin != DataEnd ) {
-        result += *DataBegin;
-        result += "\n";
-        DataBegin++;
+void KCalConversionTest::testEventConflict_data()
+{
+    QTest::addColumn<Kolab::Event>( "e1" );
+    QTest::addColumn<Kolab::Event>( "e2" );
+    QTest::addColumn<bool>( "result" );
+    {
+        Kolab::Event e1;
+        e1.setStart(Kolab::DateTime(2011,10,10,12,1,1));
+        e1.setEnd(Kolab::DateTime(2011,10,11,12,1,1));
+        
+        Kolab::Event e2;
+        e2.setStart(Kolab::DateTime(2011,11,10,12,1,1));
+        e2.setEnd(Kolab::DateTime(2011,11,11,12,1,1));
+        
+        QTest::newRow( "after" ) << e1 << e2 << false;
     }
     
-    
-//     std::string a;
-//     while (!ifs.eof()) {
-//         ifs >> a;
-//         result.append(a);
-//     }
-    std::cout << result << std::endl;
-    QBENCHMARK {
-        Kolab::KCal::readEvent(result, false);
+    {
+        Kolab::Event e1;
+        e1.setStart(Kolab::DateTime(2011,10,10,12,1,1));
+        e1.setEnd(Kolab::DateTime(2011,10,11,12,1,1));
+        
+        Kolab::Event e2;
+        e2.setStart(Kolab::DateTime(2011,9,10,12,1,1));
+        e2.setEnd(Kolab::DateTime(2011,9,11,12,1,1));
+        
+        QTest::newRow( "before" ) << e1 << e2 << false;
     }
-}
-
-void KCalConversionTest::readEvent()
-{
     
-    KCalCore::Event::Ptr event = Kolab::KCal::readEvent("testfiles/icalEvent.xml");
-    QVERIFY(event);
-    
-    //Check basics
-    QCOMPARE(event->created(), KDateTime(QDate(2006, 2, 6), QTime(00, 11, 21), KDateTime::Spec(KDateTime::UTC)));
-    QCOMPARE(event->created().timeSpec().type(), KDateTime::UTC);
-    QCOMPARE(event->dtStart(), KDateTime(QDate(2006, 1, 2), QTime(12, 0, 0), KTimeZone(QString::fromLatin1("US/Eastern"))));
-    QCOMPARE(event->dtStart().timeZone().name(), KTimeZone(QString::fromLatin1("US/Eastern")).name());
-
-    //Check recurrence
-    //TODO do some "heavy" testing for recurrences, including possible edge cases.
-
-    //Check recurrence rule
-    foreach (const KCalCore::RecurrenceRule *rule, event->recurrence()->rRules()) {
-        QCOMPARE(rule->startDt(), event->recurrence()->startDateTime());
-    }
-    QCOMPARE(event->recurrence()->rRules().size(), 1);
-    KCalCore::RecurrenceRule *rule = event->recurrence()->rRules().first();
-    QCOMPARE(rule->recurrenceType(), KCalCore::RecurrenceRule::rDaily);
-    QCOMPARE(rule->duration(), 5);
-    KDateTime start(event->dtStart());
-    KDateTime end(QDate(2006, 12, 14), QTime(12, 0, 0));
-    QCOMPARE(rule->timesInInterval(start, end).size(), 5); //count/duration limit
-    QCOMPARE(rule->timesInInterval(start, KDateTime(QDate(2006, 1, 4))).size(), 3); //end date limit
-    const KCalCore::DateTimeList &ruleList = rule->timesInInterval(start, end);
-    foreach (const KDateTime &d, ruleList) {
-        QCOMPARE(d.timeZone().name(), event->dtStart().timeZone().name());
-//         kDebug() << d << d.timeZone().name();
+    {
+        Kolab::Event e1;
+        e1.setStart(Kolab::DateTime(2011,10,10,12,1,1));
+        e1.setEnd(Kolab::DateTime(2011,10,11,12,1,1));
+        
+        Kolab::Event e2;
+        e2.setStart(Kolab::DateTime(2011,10,10,12,1,1));
+        e2.setEnd(Kolab::DateTime(2011,10,11,12,1,1));
+        
+        QTest::newRow( "conflict" ) << e1 << e2 << true;
     }
-    QCOMPARE(ruleList.first(), event->dtStart());
-    QCOMPARE(ruleList.last(), KDateTime(QDate(2006, 1, 6), QTime(12, 0, 0), KTimeZone(QString::fromLatin1("US/Eastern"))));
-
-    //Check complete recurrence
-    const KCalCore::DateTimeList &list = event->recurrence()->timesInInterval(start, end);  
-    foreach (const KDateTime &d, list) {
-        QCOMPARE(d.timeZone().name(), event->dtStart().timeZone().name());
-//         kDebug() << d << d.timeZone().name();
+    
+    {
+        Kolab::Event e1;
+        e1.setStart(Kolab::DateTime("Europe/Zurich", 2011,10,10,6,1,1));
+        e1.setEnd(Kolab::DateTime("Europe/Zurich", 2011,10,10,6,1,2));
+        
+        Kolab::Event e2;
+        e2.setStart(Kolab::DateTime("Asia/Dubai",2011,10,10,6,1,1));
+        e2.setEnd(Kolab::DateTime("Asia/Dubai",2011,10,10,6,1,2));
+        
+        QTest::newRow( "tz non-conflict" ) << e1 << e2 << false;
     }
     
-    QCOMPARE(event->summary(), QString::fromLatin1("Event #2"));
-    kDebug() << event->summary();
-//     QCOMPARE(event->summary(), QString::fromUtf8("Test.&#x0a;Test.Test.")); //FIXME fix control character &#x0a; (linefeed)
-    kDebug() << event->description();
+    {
+        Kolab::Event e1;
+        e1.setStart(Kolab::DateTime("Europe/Berlin", 2011,10,10,6,1,1));
+        e1.setEnd(Kolab::DateTime("Europe/Berlin", 2011,10,10,6,1,2));
+        
+        Kolab::Event e2;
+        e2.setStart(Kolab::DateTime("Europe/Zurich",2011,10,10,6,1,1));
+        e2.setEnd(Kolab::DateTime("Europe/Zurich",2011,10,10,6,1,2));
+        
+        QTest::newRow( "tz conflict" ) << e1 << e2 << true;
+    }
 }
 
-void KCalConversionTest::writeEvent()
+void KCalConversionTest::testEventConflict()
 {
-
-    KCalCore::Event::Ptr event(new KCalCore::Event);
-    event->setDtStart(KDateTime(QDate(2006, 1, 6), QTime(12, 0, 0), KTimeZone(QString::fromLatin1("US/Eastern"))));
-    event->setDtEnd(KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KTimeZone(QString::fromLatin1("US/Eastern"))));
-    
-    KCalCore::Recurrence *recurrence = event->recurrence();
-    KCalCore::RecurrenceRule *rule = new KCalCore::RecurrenceRule();
-    rule->setRecurrenceType(KCalCore::RecurrenceRule::rDaily);
-    rule->setFrequency(3);
-    rule->setDuration(5);
-    recurrence->addRRule(rule);
-    
-    kDebug() << "-------------------";
-    kDebug() << QString::fromStdString(Kolab::KCal::writeEvent(event));
-    kDebug() << "-------------------";
+    QFETCH(Kolab::Event, e1);
+    QFETCH(Kolab::Event, e2);
+    QFETCH(bool, result);
+    QCOMPARE(Kolab::Calendaring::conflicts(e1,e2), result);
 }
 
-void KCalConversionTest::roundtripReverseEvent()
+
+
+void KCalConversionTest::testTimesInInterval_data()
 {
-    KCalCore::Event::Ptr event = Kolab::KCal::readEvent("testfiles/icalEvent.xml");
-    kDebug() << "-------------------";
-    kDebug() << QString::fromStdString(Kolab::KCal::writeEvent(event));
-    kDebug() << "-------------------";
+    QTest::addColumn<Kolab::Event>( "event" );
+    QTest::addColumn<Kolab::DateTime>( "start" );
+    QTest::addColumn<Kolab::DateTime>( "end" );
+    QTest::addColumn< std::vector<Kolab::DateTime> >( "result" );
+    {
+        {
+            Kolab::Event event;
+            event.setStart(Kolab::DateTime(2011,1,1,1,1,1));
+            event.setEnd(Kolab::DateTime(2011,1,1,2,1,1));
+            Kolab::RecurrenceRule rrule;
+            rrule.setFrequency(Kolab::RecurrenceRule::Daily);
+            rrule.setInterval(1);
+            rrule.setCount(5);
+            event.setRecurrenceRule(rrule);
+            
+            std::vector<Kolab::DateTime> result;
+            result.push_back(Kolab::DateTime(2011,1,1,1,1,1)); 
+            result.push_back(Kolab::DateTime(2011,1,2,1,1,1));
+            result.push_back(Kolab::DateTime(2011,1,3,1,1,1)); 
+            result.push_back(Kolab::DateTime(2011,1,4,1,1,1));
+            result.push_back(Kolab::DateTime(2011,1,5,1,1,1)); 
+            QTest::newRow( "simple" ) << event << Kolab::DateTime(2011,1,1,1,1,1) << Kolab::DateTime(2011,1,5,1,1,1) << result;
+        }
+    }
 }
 
-void KCalConversionTest::roundtripEvent()
+void KCalConversionTest::testTimesInInterval()
 {
-    KCalCore::Event::Ptr event(new KCalCore::Event);
-    event->setDtStart(KDateTime(QDate(2006, 1, 6), QTime(12, 0, 0), KTimeZone(QString::fromLatin1("US/Eastern"))));
-    event->setDtEnd(KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KTimeZone(QString::fromLatin1("US/Eastern"))));
-    
-    KCalCore::Recurrence *recurrence = event->recurrence();
-    KCalCore::RecurrenceRule *rule = new KCalCore::RecurrenceRule();
-    rule->setRecurrenceType(KCalCore::RecurrenceRule::rDaily);
-    rule->setFrequency(3);
-    rule->setDuration(5);
-    recurrence->addRRule(rule);
-    
-    QString result = QString::fromStdString(Kolab::KCal::writeEvent(event));
-    kDebug() << result;
-    KCalCore::Event::Ptr resEvent = Kolab::KCal::readEvent(result.toStdString(), false);
-    QVERIFY(resEvent);
-    QCOMPARE(event->dtStart(), resEvent->dtStart());
+    QFETCH(Kolab::Event, event);
+    QFETCH(Kolab::DateTime, start);
+    QFETCH(Kolab::DateTime, end);
+    QFETCH(std::vector<Kolab::DateTime>, result);
+    QCOMPARE(Kolab::Calendaring::timeInInterval(event,start, end), result);
 }
 
-void KCalConversionTest::BenchmarkRoundtrip()
+void KCalConversionTest::testTimesInIntervalBenchmark()
 {
-    KCalCore::Event::Ptr event = Kolab::KCal::readEvent("testfiles/icalEvent.xml");
-    std::string result;
+    Kolab::Event event;
+    event.setStart(Kolab::DateTime(2011,1,1,1,1,1));
+    event.setEnd(Kolab::DateTime(2011,1,1,2,1,1));
+    Kolab::RecurrenceRule rrule;
+    rrule.setFrequency(Kolab::RecurrenceRule::Daily);
+    rrule.setInterval(1);
+    rrule.setCount(500);
+    event.setRecurrenceRule(rrule);
+    
     QBENCHMARK {
-        result = Kolab::KCal::writeEvent(event);
-        Kolab::KCal::readEvent(result, false);
+        Kolab::Calendaring::timeInInterval(event, Kolab::DateTime(2011,1,1,1,1,1), Kolab::DateTime(2013,1,1,1,1,1));
     }
-}*/
+    const std::vector<Kolab::DateTime> &result = Kolab::Calendaring::timeInInterval(event, Kolab::DateTime(2011,1,1,1,1,1), Kolab::DateTime(2013,1,1,1,1,1));
+    QVERIFY(result.size() == 500);
+//     qDebug() << QTest::toString(result);    
+}
 
 
 
diff --git a/c++/tests/kcalconversiontest.h b/c++/tests/kcalconversiontest.h
index d029e11..5ef6be6 100644
--- a/c++/tests/kcalconversiontest.h
+++ b/c++/tests/kcalconversiontest.h
@@ -17,12 +17,16 @@ class KCalConversionTest : public QObject
 
     void testDate_data();
     void testDate();
-/*    
-    void readEvent();
-    void writeEvent();
-    void roundtripEvent();
-    void roundtripReverseEvent();
-    void BenchmarkRoundtrip();*/
+    
+    void testDateTZ_data();
+    void testDateTZ();
+
+    void testEventConflict_data();
+    void testEventConflict();
+    
+    void testTimesInInterval_data();
+    void testTimesInInterval();
+    void testTimesInIntervalBenchmark();
 };
 
 #endif
\ No newline at end of file
diff --git a/c++/tests/serializers.h b/c++/tests/serializers.h
index c7f67d7..f6bcae6 100644
--- a/c++/tests/serializers.h
+++ b/c++/tests/serializers.h
@@ -22,7 +22,7 @@ namespace QTest {
     {
         QByteArray ba = "vector<Kolab::DateTime>(";
         for (int i = 0; i < v.size(); i++) {
-            ba += QByteArray(toString(v.at(i)))+ ", ";
+            ba += QByteArray(toString(v.at(i)))+ "\n";
         }
         ba += ")";
         return qstrdup(ba.data());
diff --git a/c++/tests/testfiles/icalEvent.xml b/c++/tests/testfiles/icalEvent.xml
index f18773e..89f99a5 100644
--- a/c++/tests/testfiles/icalEvent.xml
+++ b/c++/tests/testfiles/icalEvent.xml
@@ -27,7 +27,7 @@
              </dtstamp>
              <dtstart>
                <parameters>
-                 <tzid><text>/kolab.org/US/Eastern</text></tzid>
+                 <tzid><text>/kolab.org/Europe/Zurich</text></tzid>
                </parameters>
                <date-time>2006-01-02T12:00:00</date-time>
              </dtstart>
@@ -42,7 +42,7 @@
              </rrule>
              <rdate>
                <parameters>
-                 <tzid><text>/kolab.org/US/Eastern</text></tzid>
+                 <tzid><text>/kolab.org/Europe/Zurich</text></tzid>
                </parameters>
                <date-time>2007-02-06T00:11:21</date-time>
        <!--        <period>
@@ -67,7 +67,7 @@ Test.</text>
              </dtstamp>
              <dtstart>
                <parameters>
-                 <tzid><text>US/Eastern</text></tzid>
+                 <tzid><text>Europe/Zurich</text></tzid>
                </parameters>
                <date-time>2006-01-04T14:00:00</date-time>
              </dtstart>
@@ -76,7 +76,7 @@ Test.</text>
              </duration>
              <recurrence-id>
                <parameters>
-                 <tzid><text>US/Eastern</text></tzid>
+                 <tzid><text>Europe/Zurich</text></tzid>
                </parameters>
                <date-time>2006-01-04T12:00:00</date-time>
              </recurrence-id>


commit bc9dc0eafce9bea7c2302907033e18e632ebf325
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Wed Feb 29 17:59:44 2012 +0100

    Almost complete Kolab::Event to KCalCore conversion

diff --git a/c++/lib/kolabkcalconversion.cpp b/c++/lib/kolabkcalconversion.cpp
index 4a54c62..1c24bbe 100644
--- a/c++/lib/kolabkcalconversion.cpp
+++ b/c++/lib/kolabkcalconversion.cpp
@@ -134,6 +134,44 @@ QStringList toStringList(const std::vector<std::string> &l)
     return list;
 }
 
+KCalCore::Attendee::PartStat toPartStat(Kolab::PartStatus p)
+{
+    switch (p) {
+        case PartNeedsAction:
+            return KCalCore::Attendee::NeedsAction;
+        case PartAccepted:
+            return KCalCore::Attendee::Accepted;
+        case PartDeclined:
+            return KCalCore::Attendee::Declined;
+        case PartTentative:
+            return KCalCore::Attendee::Tentative;
+        case PartDelegated:
+            return KCalCore::Attendee::Delegated;
+        default:
+            qWarning() << "unhandled";
+            Q_ASSERT(0);
+    }
+    return KCalCore::Attendee::NeedsAction;
+}
+
+KCalCore::Attendee::Role toRole(Kolab::Role r)
+{
+    switch (r) {
+        case Required:
+            return KCalCore::Attendee::ReqParticipant;
+        case Chair:
+            return KCalCore::Attendee::Chair;
+        case Optional:
+            return KCalCore::Attendee::OptParticipant;
+        case NonParticipant:
+            return KCalCore::Attendee::NonParticipant;
+        default:
+            qWarning() << "unhandled";
+            Q_ASSERT(0);
+    }
+    return KCalCore::Attendee::ReqParticipant;
+}
+
 void setIncidence(KCalCore::Incidence &i, const Kolab::Event &e)
 {
     if (!e.uid().empty()) {
@@ -152,17 +190,34 @@ void setIncidence(KCalCore::Incidence &i, const Kolab::Event &e)
     if (e.duration().isValid()) {
         i.setDuration(toDuration(e.duration()));
     }
-    
     i.setSummary(QString::fromStdString(e.summary())); //TODO detect richtext
     i.setDescription(QString::fromStdString(e.description())); //TODO detect richtext
     i.setPriority(toPriority(e.priority()));
     i.setStatus(toStatus(e.status()));
     i.setLocation(QString::fromStdString(e.location())); //TODO detect richtext
-//     i.setOrganizer();
-//     i.addAttendee();
-//     i.addAttachment();
-//     i.addAlarm();
-//     i.setCustomProperties();
+    i.setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person(QString::fromStdString(e.organizerName()), QString::fromStdString(e.organizerEmail()))));
+    foreach (const Kolab::Attendee a, e.attendees()) {
+        i.addAttendee(KCalCore::Attendee::Ptr(new KCalCore::Attendee(QString::fromStdString(a.name()), 
+                                                                     QString::fromStdString(a.email()), 
+                                                                     a.rsvp(),
+                                                                     toPartStat(a.partStat()),
+                                                                     toRole(a.role()),
+                                                                     QString::fromStdString(a.uid()) )));
+    }
+    foreach (const Kolab::Attachment a, e.attachments()) {
+        KCalCore::Attachment::Ptr ptr;
+        if (!a.uri().empty()) {
+            ptr = KCalCore::Attachment::Ptr(new KCalCore::Attachment(QString::fromStdString(a.uri()), QString::fromStdString(a.mimetype())));
+        } else {
+            ptr = KCalCore::Attachment::Ptr(new KCalCore::Attachment(QByteArray::fromRawData(a.data().c_str(), a.data().size()), QString::fromStdString(a.mimetype())));
+        }
+        if (!a.label().empty()) {
+            ptr->setLabel(QString::fromStdString(a.label()));
+        }
+        i.addAttachment(ptr);
+    }
+//     i.addAlarm(); //TODO
+//     i.setCustomProperties(); //TODO
 }
 
 void getIncidence(Event &i, const KCalCore::Event &e)
@@ -171,7 +226,61 @@ void getIncidence(Event &i, const KCalCore::Event &e)
 //     i.setCreated(fromDate(e.created()));
 }
 
+int toWeekDay(Kolab::Weekday wday)
+{
+    switch (wday) {
+        case Kolab::Monday:
+            return  1;
+        case Kolab::Tuesday:
+            return 2;
+        case Kolab::Wednesday:
+            return 3;
+        case Kolab::Thursday:
+            return 4;
+        case Kolab::Friday:
+            return 5;
+        case Kolab::Saturday:
+            return 6;
+        case Kolab::Sunday:
+            return 7;
+        default:
+            qWarning() << "unhandled";
+            Q_ASSERT(0);
+    }
+    return 1;
+}
+
+KCalCore::RecurrenceRule::PeriodType toRecurrenceType(Kolab::RecurrenceRule::Frequency freq)
+{
+    switch(freq) {
+        case Kolab::RecurrenceRule::None:
+            qWarning() << "no recurrence?";
+            break;
+        case Kolab::RecurrenceRule::Yearly:
+            return KCalCore::RecurrenceRule::rYearly;
+        case Kolab::RecurrenceRule::Monthly:
+            return KCalCore::RecurrenceRule::rMonthly;
+        case Kolab::RecurrenceRule::Weekly:
+            return KCalCore::RecurrenceRule::rWeekly;
+        case Kolab::RecurrenceRule::Daily:
+            return KCalCore::RecurrenceRule::rDaily;
+        case Kolab::RecurrenceRule::Hourly:
+            return KCalCore::RecurrenceRule::rHourly;
+        case Kolab::RecurrenceRule::Minutely:
+            return KCalCore::RecurrenceRule::rMinutely;
+        case Kolab::RecurrenceRule::Secondly:
+            return KCalCore::RecurrenceRule::rSecondly;
+        default:
+            qWarning() << "unhandled";
+            Q_ASSERT(0);
+    }
+    return KCalCore::RecurrenceRule::rNone;
+}
 
+KCalCore::RecurrenceRule::WDayPos toWeekDayPos(const Kolab::DayPos &dp)
+{
+    return KCalCore::RecurrenceRule::WDayPos(dp.occurence(), toWeekDay(dp.weekday())-1); //Yes, we have a different day-int mapping here...
+}
 
 KCalCore::Event::Ptr toKCalCore(const Kolab::Event &event)
 {
@@ -185,8 +294,63 @@ KCalCore::Event::Ptr toKCalCore(const Kolab::Event &event)
     } else {
         e->setTransparency(KCalCore::Event::Opaque);
     }
-//     e->recurrence();
 
+    const Kolab::RecurrenceRule &rrule = event.recurrenceRule();
+    if (rrule.isValid()) {
+        KCalCore::Recurrence *rec = e->recurrence();
+
+        KCalCore::RecurrenceRule *defaultRR = rec->defaultRRule(true);
+        Q_ASSERT(defaultRR);
+
+        defaultRR->setWeekStart(toWeekDay(rrule.weekStart()));
+        defaultRR->setRecurrenceType(toRecurrenceType(rrule.frequency()));
+        defaultRR->setFrequency(rrule.interval());
+
+        if (rrule.end().isValid()) {
+            rec->setEndDateTime(toDate(rrule.end())); //TODO date/datetime
+        } else {
+            rec->setDuration(rrule.count());
+        }
+        
+        if (!rrule.bysecond().empty()) {
+            defaultRR->setBySeconds(QVector<int>::fromStdVector(rrule.bysecond()).toList());
+        }
+        if (!rrule.byminute().empty()) {
+            defaultRR->setByMinutes(QVector<int>::fromStdVector(rrule.byminute()).toList());
+        }
+        if (!rrule.byhour().empty()) {
+            defaultRR->setByHours(QVector<int>::fromStdVector(rrule.byhour()).toList());
+        }
+        if (!rrule.byday().empty()) {
+            QList<KCalCore::RecurrenceRule::WDayPos> daypos;
+            foreach(const Kolab::DayPos &dp, rrule.byday()) {
+                daypos.append(toWeekDayPos(dp));
+            }
+            defaultRR->setByDays(daypos);
+        }
+        if (!rrule.bymonthday().empty()) {
+            defaultRR->setByMonthDays(QVector<int>::fromStdVector(rrule.bymonthday()).toList());
+        }
+        if (!rrule.byyearday().empty()) {
+            defaultRR->setByYearDays(QVector<int>::fromStdVector(rrule.byyearday()).toList());
+        }
+        if (!rrule.byweekno().empty()) {
+            defaultRR->setByWeekNumbers(QVector<int>::fromStdVector(rrule.byweekno()).toList());
+        }
+        if (!rrule.bymonth().empty()) {
+            defaultRR->setByMonths(QVector<int>::fromStdVector(rrule.bymonth()).toList());
+        }
+    }
+    foreach (const Kolab::DateTime &dt, event.recurrenceDates()) {
+        e->recurrence()->addRDateTime(toDate(dt));//TODO date/datetime
+    }
+    foreach (const Kolab::DateTime &dt, event.exceptionDates()) {
+        e->recurrence()->addExDateTime(toDate(dt));//TODO date/datetime
+    }
+    if (event.recurrenceID().isValid()) {
+        e->setRecurrenceId(toDate(event.recurrenceID()));
+    }
+        
     return e;
 }
 
diff --git a/c++/tests/kcalconversiontest.cpp b/c++/tests/kcalconversiontest.cpp
index 80adff7..b8b9fdd 100644
--- a/c++/tests/kcalconversiontest.cpp
+++ b/c++/tests/kcalconversiontest.cpp
@@ -27,6 +27,76 @@ namespace QTest {
         ba += ")";
         return qstrdup(ba.data());
     }
+    
+    template<>
+    char *toString(const KCalCore::Attendee &at)
+    {
+        QByteArray ba = "Attendee(";
+        ba += at.name().toAscii() + ", ";
+        ba += at.email().toAscii() + ", ";
+        ba += QString::number(at.role()) + ", ";
+        ba += QString::number(at.status()) + ", ";
+        ba += QString::number(at.RSVP()) + ", ";
+        ba += at.delegate().toAscii() + ", ";
+        ba += at.delegator().toAscii() + ", ";
+        ba += at.uid().toAscii() + ", ";
+        ba += ")";
+        return qstrdup(ba.data());
+    }
+    
+    
+    template<>
+    char *toString(const QList<int> &l)
+    {
+        QByteArray ba = "QList<int>(";
+        foreach(int i, l) {
+            ba += QString::number(i) + ", ";
+        }
+        ba += ")";
+        return qstrdup(ba.data());
+    }
+    
+    template<>
+    char *toString(const QList<KCalCore::RecurrenceRule::WDayPos> &l)
+    {
+        QByteArray ba = "QList<int>(";
+        foreach(const KCalCore::RecurrenceRule::WDayPos &i, l) {
+            ba += QString::number(i.pos()) + " ";
+            ba += QString::number(i.day()) + ", ";
+        }
+        ba += ")";
+        return qstrdup(ba.data());
+    }
+    
+    template<>
+    char *toString(const KCalCore::Recurrence &at)
+    {
+        at.dump();
+        KCalCore::RecurrenceRule *r = at.defaultRRule();
+        QByteArray ba;
+        if (!r) {
+            ba += "Recurrence( )";
+        } else {
+            Q_ASSERT(r);
+            Q_ASSERT(at.rRules().size() == 1);
+            
+            ba += "Recurrence(";
+            ba += QString::number(r->recurrenceType()) + ", ";
+            ba += QString::number(r->frequency()) + ", ";
+            ba += QString::number(r->duration()) + ", ";
+            ba += QByteArray(toString(r->startDt())) + ", ";
+            ba += QByteArray(toString(r->endDt())) + ", ";
+            ba += QByteArray(toString(r->bySeconds())) + ", ";
+            ba += QByteArray(toString(r->byMinutes())) + ", ";
+            ba += QByteArray(toString(r->byHours())) + ", ";
+            ba += QByteArray(toString(r->byDays())) + ", ";
+            ba += QByteArray(toString(r->byMonthDays())) + ", ";
+            ba += QByteArray(toString(r->byYearDays())) + ", ";
+            ba += QByteArray(toString(r->byMonths())) + ", ";
+            ba += ")";
+        }
+        return qstrdup(ba.data());
+    }
 }
 
 void KCalConversionTest::testDate_data()
@@ -60,6 +130,16 @@ void KCalConversionTest::testConversion_data()
     QTest::addColumn<Kolab::Event>( "kolab" );
     
     Kolab::DateTime date(2011,2,2,12,11,10);
+    Kolab::DateTime date2(2011,2,2,12,12,10);
+    Kolab::DateTime date3(2012,2,2,12,12,10);
+    std::vector<int> intVector;
+    intVector.push_back(1);
+    intVector.push_back(-3);
+    intVector.push_back(2);
+    std::vector<std::string> stringVector;
+    stringVector.push_back("cat1");
+    stringVector.push_back("cat2");
+    stringVector.push_back("parent/child");
     
     KCalCore::Event kcal;
     kcal.setUid("uid");
@@ -67,7 +147,45 @@ void KCalConversionTest::testConversion_data()
     kcal.setLastModified(toDate(date));
     kcal.setRevision(3);
     kcal.setSecrecy(KCalCore::Incidence::SecrecyConfidential);
+    kcal.setCategories(toStringList(stringVector));
     kcal.setDtStart(toDate(date));
+    kcal.setDtEnd(toDate(date2));
+    kcal.setTransparency(KCalCore::Event::Transparent);
+    
+    kcal.setRecurrenceId(toDate(date2)); //TODO THISANDFUTURE
+    kcal.recurrence()->setDaily(3);
+    kcal.recurrence()->setDuration(5);
+//     kcal.recurrence()->setEndDateTime(); //TODO
+    kcal.recurrence()->addRDateTime(toDate(date2));
+    kcal.recurrence()->addExDateTime(toDate(date3));
+    
+    KCalCore::RecurrenceRule *rr = kcal.recurrence()->defaultRRule(true);
+    QList<int> intList = QVector<int>::fromStdVector(intVector).toList();
+    rr->setBySeconds(intList);
+    rr->setByMinutes(intList);
+    rr->setByHours(intList);
+    rr->setByDays(QList<KCalCore::RecurrenceRule::WDayPos>() << KCalCore::RecurrenceRule::WDayPos(3,0) << KCalCore::RecurrenceRule::WDayPos(5,3));
+    rr->setByMonthDays(intList);
+    rr->setByYearDays(intList);
+    rr->setByMonths(intList);
+    rr->setByWeekNumbers(intList);
+    
+    kcal.setSummary("summary");
+    kcal.setDescription("description");
+    kcal.setPriority(3);
+    kcal.setStatus(KCalCore::Incidence::StatusConfirmed);
+    kcal.setLocation("location");
+    kcal.setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person("organizer", "organizer at email")));
+    kcal.addAttendee(KCalCore::Attendee::Ptr(new KCalCore::Attendee("attendee", "attendee at email", false, KCalCore::Attendee::NeedsAction, KCalCore::Attendee::ReqParticipant, "uid")));
+    //TODO KCalCore Delegate/Delegator
+    kcal.addAttachment(KCalCore::Attachment::Ptr(new KCalCore::Attachment(QString("uri"), "mimetype/mime")));
+    KCalCore::Alarm::Ptr alarm = KCalCore::Alarm::Ptr(new KCalCore::Alarm(&kcal));    
+    KCalCore::Person::List addressees;
+    addressees.append(KCalCore::Person::Ptr(new KCalCore::Person("name", "email at email")));
+    alarm->setEmailAlarm("subject", "text", addressees, QStringList()); //No support for attachments
+    kcal.addAlarm(alarm);
+    //TODO alarms
+    //TODO custom properties
     
     Kolab::Event kolab;
     kolab.setUid("uid");
@@ -75,8 +193,50 @@ void KCalConversionTest::testConversion_data()
     kolab.setLastModified(date);
     kolab.setSequence(3);
     kolab.setClassification(Kolab::Confidential);
+    kolab.setCategories(stringVector);
     kolab.setStart(date);
+    kolab.setEnd(date2);
+    kolab.setTransparency(true);
+    
+    Kolab::RecurrenceRule rrule;
+    rrule.setInterval(3);
+    rrule.setFrequency(Kolab::RecurrenceRule::Daily);
+    rrule.setCount(5);
+    rrule.setBysecond(intVector);
+    rrule.setByminute(intVector);
+    rrule.setByhour(intVector);
+    rrule.setByday(std::vector<Kolab::DayPos>() << Kolab::DayPos(3, Kolab::Monday) << Kolab::DayPos(5, Kolab::Thursday));
+    rrule.setBymonthday(intVector);
+    rrule.setByyearday(intVector);
+    rrule.setByweekno(intVector);
+    rrule.setBymonth(intVector);
+    
+    kolab.setRecurrenceRule(rrule);
+    kolab.setRecurrenceID(date2, true);
+    kolab.setRecurrenceDates(std::vector<Kolab::DateTime>() << date2);
+    kolab.setExceptionDates(std::vector<Kolab::DateTime>() << date3);
     
+    kolab.setSummary("summary");
+    kolab.setDescription("description");
+    kolab.setPriority(3);
+    kolab.setStatus(Kolab::Confirmed);
+    kolab.setLocation("location");
+    kolab.setOrganizer("organizer at email", "organizer");
+    
+    Kolab::Attendee a("attendee at email");
+    a.setName("attendee");
+    a.setUid("uid");
+    kolab.setAttendees(std::vector<Kolab::Attendee>() << a);
+    
+    Kolab::Attachment attach;
+    attach.setUri("uri", "mimetype/mime");
+    kolab.setAttachments(std::vector<Kolab::Attachment>() << attach);
+    
+//     std::vector<std::string> receipents;
+//     receipents.push_back("email at email");
+//     Kolab::Alarm alarm2("summary", "description", receipents);
+//     kolab.setAlarms(std::vector<Kolab::Alarm>() << alarm2);
+
     QTest::newRow( "test1" ) << kcal << kolab;
     
 }
@@ -98,7 +258,7 @@ void KCalConversionTest::testConversion()
     QCOMPARE(e->dtEnd(), kcal.dtEnd());
     QCOMPARE(e->duration(), kcal.duration());
     QCOMPARE(e->transparency(), kcal.transparency());
-    QCOMPARE(e->recurrence(), kcal.recurrence());
+    QCOMPARE(*e->recurrence(), *kcal.recurrence());
     QCOMPARE(e->recurrenceId(), kcal.recurrenceId());
     QCOMPARE(e->recurrenceType(), kcal.recurrenceType());
     QCOMPARE(e->summary(), kcal.summary());
@@ -106,10 +266,22 @@ void KCalConversionTest::testConversion()
     QCOMPARE(e->priority(), kcal.priority());
     QCOMPARE(e->status(), kcal.status());
     QCOMPARE(e->location(), kcal.location());
-    QCOMPARE(e->organizer(), kcal.organizer());
-    QCOMPARE(e->attendees(), kcal.attendees());
-    QCOMPARE(e->attachments(), kcal.attachments());
-    QCOMPARE(e->alarms(), kcal.alarms());
+    QCOMPARE(e->organizer()->name(), kcal.organizer()->name());
+    QCOMPARE(e->organizer()->email(), kcal.organizer()->email());
+    QCOMPARE(e->attendees().size(), 1);
+    for (int i = 0 ; i < e->attendees().size(); i++) {
+        QCOMPARE(*e->attendees().at(i), *kcal.attendees().at(i));
+    }
+    QCOMPARE(e->attachments().size(), 1);
+    for (int i = 0 ; i < e->attachments().size(); i++) {
+        QCOMPARE(*e->attachments().at(i), *kcal.attachments().at(i));
+    }
+    
+//     QCOMPARE(e->alarms(), kcal.alarms()); //TODO
+//TODO custom properties
+    
+    const Kolab::Event &b = fromKCalCore(kcal);
+    QCOMPARE(b.uid(), kolab.uid());
 }
 
 /*
@@ -248,195 +420,6 @@ void KCalConversionTest::BenchmarkRoundtrip()
 
 
 
-#if 0
-class KCalConversionTest : public QObject
-{
-  Q_OBJECT
-  private slots:
-      
-    void testConversion_data()
-    {
-        QTest::addColumn<QString>( "kcalrecurrence" );
-        QTest::addColumn<QString>( "result" );
-        
-        QTest::newRow( "test1" );
-    }
-    
-    void testConversion()
-    {
-        
-    }
-      
-/*
-    void testContacts_data()
-    {
-      createContactsTestSet();
-    }
-
-    void testContacts()
-    {
-      QFETCH( QString, vcardFileName );
-      QFETCH( QString, mimeFileName );
-
-      KolabHandler *handler = KolabHandler::createHandler( "contact", Collection() );
-      QVERIFY( handler );
-
-      // mime -> vcard conversion
-      const Item kolabItem = readMimeFile( mimeFileName );
-      QVERIFY( kolabItem.hasPayload() );
-
-      Item::List vcardItems = handler->translateItems( Akonadi::Item::List() << kolabItem );
-      QCOMPARE( vcardItems.size(), 1 );
-      QVERIFY( vcardItems.first().hasPayload<KABC::Addressee>() );
-      KABC::Addressee convertedAddressee = vcardItems.first().payload<KABC::Addressee>();
-
-      QFile vcardFile( vcardFileName );
-      QVERIFY( vcardFile.open( QFile::ReadOnly ) );
-      KABC::VCardConverter converter;
-      const KABC::Addressee realAddressee = converter.parseVCard( vcardFile.readAll() );
-
-      // fix up the converted addressee for comparisson
-      convertedAddressee.setName( realAddressee.name() ); // name() apparently is something strange
-      QVERIFY( !convertedAddressee.custom( "KOLAB", "CreationDate" ).isEmpty() );
-      convertedAddressee.removeCustom( "KOLAB", "CreationDate" ); // that's conversion time !?
-      QVERIFY( normalizePhoneNumbers( convertedAddressee, realAddressee ) ); // phone number ids are random
-      QVERIFY( normalizeAddresses( convertedAddressee, realAddressee ) ); // same here
-
-//       qDebug() << convertedAddressee.toString();
-//       qDebug() << realAddressee.toString();
-      QCOMPARE( realAddressee, convertedAddressee );
-
-
-      // and now the other way around
-      Item convertedKolabItem;
-      Item vcardItem( "text/directory" );
-      vcardItem.setPayload( realAddressee );
-      handler->toKolabFormat( vcardItem, convertedKolabItem );
-      QVERIFY( convertedKolabItem.hasPayload<KMime::Message::Ptr>() );
-
-      const KMime::Message::Ptr convertedMime = convertedKolabItem.payload<KMime::Message::Ptr>();
-      const KMime::Message::Ptr realMime = kolabItem.payload<KMime::Message::Ptr>();
-
-//       qDebug() << convertedMime->encodedContent();
-//       qDebug() << realMime->encodedContent();
-      QVERIFY( compareMimeMessage( convertedMime, realMime ) );
-
-      delete handler;
-    }
-
-    void testIncidences_data()
-    {
-      createIndidenceTestSet();
-    }
-
-    void testIncidences()
-    {
-      QFETCH( QString, type );
-      QFETCH( QString, icalFileName );
-      QFETCH( QString, mimeFileName );
-
-      KolabHandler *handler = KolabHandler::createHandler( type.toLatin1(), Collection() );
-      QVERIFY( handler );
-
-      // mime -> vcard conversion
-      const Item kolabItem = readMimeFile( mimeFileName );
-      QVERIFY( kolabItem.hasPayload() );
-
-      Item::List icalItems = handler->translateItems( Akonadi::Item::List() << kolabItem );
-      QCOMPARE( icalItems.size(), 1 );
-      QVERIFY( icalItems.first().hasPayload<KCalCore::Incidence::Ptr>() );
-      KCalCore::Incidence::Ptr convertedIncidence = icalItems.first().payload<KCalCore::Incidence::Ptr>();
-
-      QFile icalFile( icalFileName );
-      QVERIFY( icalFile.open( QFile::ReadOnly ) );
-      KCalCore::ICalFormat format;
-      const KCalCore::Incidence::Ptr realIncidence( format.fromString( QString::fromUtf8( icalFile.readAll() ) ) );
-
-      // fix up the converted incidence for comparisson
-      foreach ( KCalCore::Attendee::Ptr a, convertedIncidence->attendees() )
-        a->setUid( QString() ); // contains random values
-      foreach ( KCalCore::Attendee::Ptr a, realIncidence->attendees() )
-        a->setUid( QString() ); // contains random values
-      if ( type == "task" ) {
-        QVERIFY( icalItems.first().hasPayload<KCalCore::Todo::Ptr>() );
-        KCalCore::Todo::Ptr todo = icalItems.first().payload<KCalCore::Todo::Ptr>();
-        if ( !todo->hasDueDate() && !todo->hasStartDate() )
-          convertedIncidence->setAllDay( realIncidence->allDay() ); // all day has no meaning if there are no start and due dates but may differ nevertheless
-      }
-      // recurrence objects are created on demand, but KCalCore::Incidence::operator==() doesn't take that into account
-      // so make sure both incidences have one
-      realIncidence->recurrence();
-      convertedIncidence->recurrence();
-
-      if ( *(realIncidence.data()) != *(convertedIncidence.data()) ) {
-        qDebug() << "REAL: " << format.toString( realIncidence );
-        qDebug() << "CONVERTED: " << format.toString( convertedIncidence );
-      }
-      QVERIFY( *(realIncidence.data()) ==  *(convertedIncidence.data()) );
-
-
-      // and now the other way around
-      Item convertedKolabItem;
-      Item icalItem;
-      switch ( realIncidence->type() ) {
-        case KCalCore::IncidenceBase::TypeEvent: icalItem.setMimeType( KCalCore::Event::eventMimeType() ); return;
-        case KCalCore::IncidenceBase::TypeTodo: icalItem.setMimeType( KCalCore::Todo::todoMimeType() ); return;
-        case KCalCore::IncidenceBase::TypeJournal: icalItem.setMimeType( KCalCore::Journal::journalMimeType() ); return;
-        default: QFAIL( "incidence type not supported" );
-      }
-      icalItem.setPayload( realIncidence );
-      handler->toKolabFormat( icalItem, convertedKolabItem );
-      QVERIFY( convertedKolabItem.hasPayload<KMime::Message::Ptr>() );
-
-      const KMime::Message::Ptr convertedMime = convertedKolabItem.payload<KMime::Message::Ptr>();
-      const KMime::Message::Ptr realMime = kolabItem.payload<KMime::Message::Ptr>();
-
-//       qDebug() << convertedMime->encodedContent();
-//       qDebug() << realMime->encodedContent();
-      QVERIFY( compareMimeMessage( convertedMime, realMime ) );
-
-      delete handler;
-    }
-
-    void benchmarkContactsLoading_data()
-    {
-      createContactsTestSet();
-    }
-
-    void benchmarkContactsLoading()
-    {
-      QFETCH( QString, vcardFileName );
-      QFETCH( QString, mimeFileName );
-
-      QBENCHMARK {
-        KolabHandler *handler = KolabHandler::createHandler( "contact", Collection() );
-        const Item kolabItem = readMimeFile( mimeFileName );
-        const Item::List vcardItems = handler->translateItems( Akonadi::Item::List() << kolabItem );
-        delete handler;
-      }
-    }
-
-    void benchmarkIncidenceLoading_data()
-    {
-      createIndidenceTestSet();
-    }
-
-    void benchmarkIncidenceLoading()
-    {
-      QFETCH( QString, type );
-      QFETCH( QString, mimeFileName );
-
-      QBENCHMARK {
-        KolabHandler *handler = KolabHandler::createHandler( type.toLatin1(), Collection() );
-        const Item kolabItem = readMimeFile( mimeFileName );
-        const Item::List icalItems = handler->translateItems( Akonadi::Item::List() << kolabItem );
-        delete handler;
-      }
-    }*/
-};
-#endif
-
-
 QTEST_MAIN( KCalConversionTest )
 
 #include "kcalconversiontest.moc"


commit 80e4ac5442f989c869861319cb5192ce753d26d5
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Wed Feb 29 13:51:58 2012 +0100

    make XMLParserWrapper threadsafe.
    
    Creates one xerces instance per thread, so memory usage is probably not ideal.

diff --git a/c++/compiled/XMLParserWrapper.cpp b/c++/compiled/XMLParserWrapper.cpp
index ce38d2c..169599a 100644
--- a/c++/compiled/XMLParserWrapper.cpp
+++ b/c++/compiled/XMLParserWrapper.cpp
@@ -40,6 +40,8 @@
 
 #include <xsd/cxx/tree/error-handler.hxx>
 
+#include <boost/thread.hpp>
+
 #include "kolabformat-xcal-schema.hxx"
 #include "grammar-input-stream.hxx"
 
@@ -64,6 +66,18 @@ XMLParserWrapper::~XMLParserWrapper()
 
 }
 
+boost::thread_specific_ptr<XMLParserWrapper> ptr;
+
+XMLParserWrapper& XMLParserWrapper::inst()
+{
+    XMLParserWrapper *t = ptr.get();
+    if (!t) {
+        t = new XMLParserWrapper();
+        ptr.reset(t);
+    }
+    return *t;
+}
+
 
 void XMLParserWrapper::init()
 {
diff --git a/c++/compiled/XMLParserWrapper.h b/c++/compiled/XMLParserWrapper.h
index 1c8b7ee..03640cd 100644
--- a/c++/compiled/XMLParserWrapper.h
+++ b/c++/compiled/XMLParserWrapper.h
@@ -57,10 +57,11 @@ public:
     XMLParserWrapper();
     ~XMLParserWrapper();
     
-    static XMLParserWrapper &inst(){
-        static XMLParserWrapper instance;
-        return instance;
-    };
+    /**
+     * Threadsafe singleton. One Xerces instance is created per thread (threadlocal).
+     * Access via singleton to reuse parser.
+     */
+    static XMLParserWrapper &inst();
     
     xml_schema::dom::auto_ptr<xercesc::DOMDocument> parseFile(const std::string &url);
     xml_schema::dom::auto_ptr<xercesc::DOMDocument> parseString(const std::string &s);





More information about the commits mailing list