summaryrefslogtreecommitdiffstats
path: root/karm/test
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /karm/test
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'karm/test')
-rw-r--r--karm/test/Makefile.am18
-rw-r--r--karm/test/README80
-rw-r--r--karm/test/__httpd.py39
-rwxr-xr-xkarm/test/__korg.sh134
-rw-r--r--karm/test/__lib.sh79
-rwxr-xr-xkarm/test/__webdav.pl57
-rwxr-xr-xkarm/test/booktime-baddate.sh22
-rwxr-xr-xkarm/test/booktime-badduration.sh22
-rwxr-xr-xkarm/test/booktime-badtime.sh22
-rwxr-xr-xkarm/test/booktime-baduid.sh22
-rwxr-xr-xkarm/test/booktime-works.sh30
-rwxr-xr-xkarm/test/bug94447.sh30
-rwxr-xr-xkarm/test/delete.sh33
-rw-r--r--karm/test/example.ics173
-rw-r--r--karm/test/lifetest.php221
-rw-r--r--karm/test/lockerthread.cpp44
-rw-r--r--karm/test/lockerthread.h21
-rw-r--r--karm/test/locking.cpp151
-rwxr-xr-xkarm/test/refresh_on_change.sh57
-rwxr-xr-xkarm/test/remote_storage.sh58
-rw-r--r--karm/test/runscripts.cpp130
-rw-r--r--karm/test/script.cpp115
-rw-r--r--karm/test/script.h52
-rwxr-xr-xkarm/test/version.sh24
-rwxr-xr-xkarm/test/webdav.sh58
25 files changed, 1692 insertions, 0 deletions
diff --git a/karm/test/Makefile.am b/karm/test/Makefile.am
new file mode 100644
index 000000000..7205a5995
--- /dev/null
+++ b/karm/test/Makefile.am
@@ -0,0 +1,18 @@
+METASOURCES = AUTO
+
+check_PROGRAMS = runscripts locking
+
+runscripts_SOURCES = script.cpp runscripts.cpp
+runscripts_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+runscripts_LDADD = $(LIB_QT) $(LIB_KDECORE)
+
+locking_SOURCES = locking.cpp lockerthread.cpp
+locking_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+locking_LDADD = $(LIB_QT) $(top_builddir)/libkcal/libkcal.la
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+INCLUDES = -I$(srcdir) -I$(top_srcdir) -I$(top_srcdir)/libkcal $(all_includes)
+
+#TESTS = runscripts locking
+TESTS = locking
diff --git a/karm/test/README b/karm/test/README
new file mode 100644
index 000000000..31dbc8d24
--- /dev/null
+++ b/karm/test/README
@@ -0,0 +1,80 @@
+This directory holds automated tests for karm.
+
+It's in very rough shape.
+
+
+How you start:
+
+ (1) get and install kdepim including karm
+
+ (2) get and install xautomation from http://hoopajoo.net/projects/xautomation.html
+
+ (3) get and install Net::DAV::Server with CPAN
+
+ (4) get and install Net::Virtual::Plain with CPAN
+
+ (5) get and install File::Find::Rule::Filesys::Virtual with CPAN
+
+ (6) start the automated tests with the command make check
+
+
+Here are some of the issues:
+
+ (1) The tests require KDE to be running in English.
+
+ The automated XTests use shortcut keys to drive the app. These key
+ combinations are language specific.
+
+ (2) The tests require that you "make install" first.
+
+ The XAutomation tests and tests that use DCOP run karm from the bash
+ prompt.
+
+ (3) The tests are destructive.
+
+ If you have an already running instance of karm, the tests will kill
+ that instance. So you cannot, for example, record time spent running
+ karm automated tests.
+
+ The tests are smart enough to use test iCalendar files. But they will
+ alter the karm storage settings for the ics file name.
+
+ (4) The runscripts program does not kill scripts that never return.
+
+ You have to monitor the progress and press Control-C if you think a
+ script is hung.
+
+ (5) No attempt is made to check for installed script interpreters.
+
+ In addition to required interpreters (Python 2.2, for example), the bash
+ scripts use xte, which on Debian is in the xautomation package.
+
+ If a required library is not found, runscripts will consider this a
+ script failure and stop.
+
+ (6) I have only tested this with Bash on GNU/Linux.
+
+ (7) When a test fails, it is really hard to figure out why. There is too
+ much stuff mixed together on the console output, and the tests
+ themselves do not give much info when they fail.
+
+That having been said, I find it so useful that I will keep working on this so
+it should get better shortly.
+
+
+Some notes on runscripts.cpp:
+
+ Parses this directory for script files (Python, PHP, Perl and Bash). It
+ identifies a script file by the extension.
+
+ It runs any script files it finds. Within each script type, it runs the
+ scripts in alphabetical order. Scripts that start with a double underscore
+ are skipped.
+
+ When a script fails runscripts stops.
+
+ Script files should return a non-zero exit code to indicate a failure.
+
+--
+Mark Bucciarelli <mark@hubcapconsulting.com>
+December 6, 2004
diff --git a/karm/test/__httpd.py b/karm/test/__httpd.py
new file mode 100644
index 000000000..ba87113be
--- /dev/null
+++ b/karm/test/__httpd.py
@@ -0,0 +1,39 @@
+'''Runs an HTTP server on port 8000 (or the first command line argument).'''
+
+import BaseHTTPServer
+import SimpleHTTPServer
+import sys
+import os.path
+
+class MyHandler( SimpleHTTPServer.SimpleHTTPRequestHandler ):
+
+ def do_PUT( self ):
+ '''Just enough to work with karm.'''
+ path = self.translate_path(self.path)
+
+ rval = 200
+ if not os.path.exists( path ): rval = 201
+
+ f = file( path, "w" )
+ lines = []
+ while 1:
+ line = self.rfile.readline()
+ lines.append( line )
+ if line == '\r\n' or line == '\n' or line == '':
+ break
+ f.writelines( lines )
+ self.send_response( rval )
+
+
+DEFAULT_PORT = 8000
+
+if sys.argv[1:]: port = int(sys.argv[1])
+else: port = DEFAULT_PORT
+server_address = ('', port)
+
+SimpleHTTPServer.SimpleHTTPRequestHandler.protocol_version = "HTTP/1.0"
+httpd = BaseHTTPServer.HTTPServer(server_address, MyHandler )
+
+sa = httpd.socket.getsockname()
+print "Serving HTTP on", sa[0], "port", sa[1], "..."
+httpd.serve_forever()
diff --git a/karm/test/__korg.sh b/karm/test/__korg.sh
new file mode 100755
index 000000000..e7fa9629f
--- /dev/null
+++ b/karm/test/__korg.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+
+# Example of how to use xautomation.
+#
+# Notes:
+#
+# - This test fails for korg, as it opens a modal dialog box, even
+# after changes are saved (ref bug #94537).
+#
+# - The xte str command is broken (it types to fast). To be safe,
+# put in characters one-by-one using the key command. Writing a
+# bash function that does this for a given string would be helpful.
+#
+# - This script uses hardcoded English short cut keys. To make generic:
+#
+# 1. Get two char language code from OS (or KDE?)
+#
+# 2. Source bash script for language (e.g. source __shortcuts.en)
+#
+# 3. Call functions from that script (e.g. open_file $FILENAME)
+#
+# - Using killall isn't great. karm has a quit() dcop function for clean
+# shutdown. Need to check if korgac or korganizer provide this interface.
+
+
+# kill any running processes
+killall korganizer
+killall korgac
+
+# start korganizer
+korganizer&
+
+# make sure it's done opening
+sleep 10
+
+# open file in korganizer.
+# Note: this opens a second korg instance
+xte 'keydown Alt_L'
+xte 'key F'
+xte 'keyup Alt_L'
+xte 'key O'
+
+# wait for open file dialog to come up
+sleep 1
+
+# put focus on file name control
+xte 'keydown Alt_L'
+xte 'key L'
+xte 'keyup Alt_L'
+xte 'key ~'
+xte 'key /'
+xte 'key t'
+xte 'key e'
+xte 'key s'
+xte 'key t'
+xte 'key .'
+xte 'key i'
+xte 'key c'
+xte 'key s'
+
+# save new storage file
+xte 'keydown Alt_L'
+xte 'key O'
+xte 'keyup Alt_L'
+
+sleep 1
+
+# open new to-do dialog
+xte 'keydown Alt_L'
+xte 'key A'
+xte 'keup Alt_L'
+xte 'key v'
+
+sleep 1
+
+# set focus to title
+xte 'keydown Alt_L'
+xte 'key I'
+xte 'keyup Alt_L'
+
+# type in test task name (you have to type slowly for xte)
+xte 'key T'
+xte 'key e'
+xte 'key s'
+xte 'key t'
+xte 'key -'
+xte 'key t'
+xte 'key a'
+xte 'key s'
+xte 'key k'
+xte 'key -'
+xte 'key 1'
+
+sleep 1
+
+# save new todo
+xte 'keydown Alt_L'
+xte 'key O'
+xte 'keyup Alt_L'
+
+sleep 1
+
+# save changes to file
+xte 'keydown Alt_L'
+xte 'key F'
+xte 'keyup Alt_L'
+xte 'key S'
+
+sleep 1
+
+# Quit below fails.
+#
+# korg pops up a dialog that says:
+#
+# The calendar contains unsaved changes.
+# Do you want to save them before exiting?
+
+# quit korganizer
+xte 'keydown Control_L'
+xte 'key q'
+xte 'keyup Control_L'
+
+# quit first korganizer view
+xte 'keydown Control_L'
+xte 'key q'
+xte 'keyup Control_L'
+
+sleep 1
+
+killall korgac
+
+# 1. cleanup
+rm "~/test.ics"
+
diff --git a/karm/test/__lib.sh b/karm/test/__lib.sh
new file mode 100644
index 000000000..06fd9df62
--- /dev/null
+++ b/karm/test/__lib.sh
@@ -0,0 +1,79 @@
+
+# Expects karm test file in $TESTFILE
+# Returns dcop id in $DCOP_ID
+function set_up()
+{
+ DCOPID=`dcop 2>/dev/null | grep karm`
+
+ if [ -n "$DCOPID" ]; then dcop $DCOPID KarmDCOPIface quit; fi;
+
+ if [ "x$SKIP_TESTFILE_DELETE" != "xtrue" ]; then
+ if [ -e "$TESTFILE" ]; then rm $TESTFILE; fi
+ fi
+
+ #echo "__lib.sh - starting karm with $TESTFILE"
+ karm "$TESTFILE" &
+
+ # Make sure karm is up and running
+ limit=10
+ idx=0
+ DCOPID=""
+ while [ "$idx" -lt "$limit" ]
+ do
+ #echo "__lib.sh: dcop 2>/dev/null | grep karm"
+ DCOPID=`dcop 2>/dev/null | grep karm`
+ if [ -n "$DCOPID" ]
+ then
+ break
+ else
+ let "idx += 1"
+ fi
+ sleep 1
+ done
+
+ # It's not enough to get the dcop id, as this is available almost
+ # immediately. We need to make sure karm (and fam) is done loading data.
+ limit=20
+ idx=0
+ KARM_VERSION=""
+ while [ "$idx" -lt "$limit" ]
+ do
+ #echo "__lib.sh: dcop $DCOPID KarmDCOPIface version 2>/dev/null"
+ KARM_VERSION=`dcop $DCOPID KarmDCOPIface version 2>/dev/null`
+ if [ -n "$KARM_VERSION" ]
+ then
+ break
+ else
+ let "idx += 1"
+ fi
+ sleep 1
+ done
+
+ if [ "x$DCOPID" = x ]
+ then
+ echo "__lib.sh set_up error: could not start karm--no dcop id."
+ exit 1
+ else
+ echo "__lib.sh: DCOPID = $DCOPID, KARM_VERSION = $KARM_VERSION"
+ fi
+
+ if [ "x$KARM_VERSION" = x ]
+ then
+ echo "__lib.sh set_up error: karm did not return a version string."
+ exit 1
+ fi
+}
+
+function test_func()
+{
+ echo "Yep, that works."
+}
+
+function tear_down()
+{
+ if [ -n "$DCOPID" ]; then dcop "$DCOPID" KarmDCOPIface quit; fi;
+
+ if [ "x$SKIP_TESTFILE_DELETE" != "xtrue" ]; then
+ if [ -e "$TESTFILE" ]; then rm "$TESTFILE"; fi
+ fi
+}
diff --git a/karm/test/__webdav.pl b/karm/test/__webdav.pl
new file mode 100755
index 000000000..b09875755
--- /dev/null
+++ b/karm/test/__webdav.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl -w
+
+# This script requires the following Perl modules:
+#
+# $ perl -MCPAN -e 'shell'
+# cpan> install Net::DAV::Server
+# cpan> install Filesys::Virtual::Plain
+# cpan> install File::Find::Rule::Filesys::Virtual
+# cpan> install XML::LibXML
+#
+# The last Perl module needs the libxml2 development libraries installed
+# (the libxml2-dev package on Debian).
+
+use Net::DAV::Server;
+use Filesys::Virtual::Plain;
+use HTTP::Daemon;
+
+# If 1, output request and response headers
+my $DEBUG=0;
+
+my $filesys = Filesys::Virtual::Plain->new();
+$filesys->root_path('/tmp');
+$filesys->cwd('/tmp');
+#print foreach ($filesys->list('/'));
+
+my $webdav = Net::DAV::Server->new();
+$webdav->filesys($filesys);
+
+my $d = new HTTP::Daemon
+ LocalAddr => 'localhost',
+ LocalPort => 4242,
+ ReuseAddr => 1 || die;
+print "Please contact me at: ", $d->url, "\n";
+while (my $c = $d->accept) {
+ while (my $request = $c->get_request) {
+ if ( $DEBUG ) {
+ print qq|------------------------------------------------------------
+REQUEST
+------------------------------------------------------------\n|;
+ while ( ($k,$v) = each %{$request} ) {
+ print " $k => $v\n";
+ }
+ }
+ my $response = $webdav->run($request);
+ if ( $DEBUG ) {
+ print qq|------------------------------------------------------------
+RESPONSE
+------------------------------------------------------------\n|;
+ while ( ($k,$v) = each %{$response} ) {
+ print " $k => $v\n";
+ }
+ }
+ $c->send_response ($response);
+ }
+ $c->close;
+ undef($c);
+}
diff --git a/karm/test/booktime-baddate.sh b/karm/test/booktime-baddate.sh
new file mode 100755
index 000000000..d89e54cb1
--- /dev/null
+++ b/karm/test/booktime-baddate.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+TESTFILE="/tmp/testkarm1.ics"
+
+source __lib.sh
+
+set_up
+
+dcop $DCOPID KarmDCOPIface addTask Task1 2>/dev/null
+TASKID=`dcop $DCOPID KarmDCOPIface taskIdFromName Task1 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface bookTime $TASKID notadate 360 2>/dev/null`
+
+tear_down
+
+EXPECTED=5
+if [ "$RVAL" == "$EXPECTED" ]; then
+ echo "PASS $0"
+ exit 0;
+else
+ echo "FAIL $0: got /$RVAL/, expected /$EXPECTED/"
+ exit 1;
+fi
diff --git a/karm/test/booktime-badduration.sh b/karm/test/booktime-badduration.sh
new file mode 100755
index 000000000..2b1e8c96b
--- /dev/null
+++ b/karm/test/booktime-badduration.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+TESTFILE="/tmp/testkarm1.ics"
+
+source __lib.sh
+
+set_up
+
+dcop $DCOPID KarmDCOPIface addTask Task1 2>/dev/null
+TASKID=`dcop $DCOPID KarmDCOPIface taskIdFromName Task1 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface bookTime $TASKID 20050619 notanumber 2>/dev/null`
+
+tear_down
+
+EXPECTED=7
+if [ "$RVAL" == "$EXPECTED" ]; then
+ echo "PASS $0"
+ exit 0;
+else
+ echo "FAIL $0: got /$RVAL/, expected /$EXPECTED/"
+ exit 1;
+fi
diff --git a/karm/test/booktime-badtime.sh b/karm/test/booktime-badtime.sh
new file mode 100755
index 000000000..1bbaa3d53
--- /dev/null
+++ b/karm/test/booktime-badtime.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+TESTFILE="/tmp/testkarm1.ics"
+
+source __lib.sh
+
+set_up
+
+dcop $DCOPID KarmDCOPIface addTask Task1 2>/dev/null
+TASKID=`dcop $DCOPID KarmDCOPIface taskIdFromName Task1 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface bookTime $TASKID 20050619Tabc 360 2>/dev/null`
+
+tear_down
+
+EXPECTED=5
+if [ "$RVAL" == "$EXPECTED" ]; then
+ echo "PASS $0"
+ exit 0;
+else
+ echo "FAIL $0: got /$RVAL/, expected /$EXPECTED/"
+ exit 1;
+fi
diff --git a/karm/test/booktime-baduid.sh b/karm/test/booktime-baduid.sh
new file mode 100755
index 000000000..8cb064244
--- /dev/null
+++ b/karm/test/booktime-baduid.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# First test, just check version.
+
+TESTFILE="/tmp/testkarm1.ics"
+
+source __lib.sh
+
+set_up
+
+RVAL=`dcop $DCOPID KarmDCOPIface bookTime bad-uid 20050619 360 2>/dev/null`
+
+tear_down
+
+EXPECTED=4
+if [ "$RVAL" == "$EXPECTED" ]; then
+ echo "PASS $0"
+ exit 0;
+else
+ echo "FAIL $0: got /$RVAL/, expected /$EXPECTED/"
+ exit 1;
+fi
diff --git a/karm/test/booktime-works.sh b/karm/test/booktime-works.sh
new file mode 100755
index 000000000..280e1231b
--- /dev/null
+++ b/karm/test/booktime-works.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+TESTFILE="/tmp/testkarm1.ics"
+
+source __lib.sh
+
+set_up
+
+DURATION=12
+dcop $DCOPID KarmDCOPIface addTask Task1 2>/dev/null
+TASKID=`dcop $DCOPID KarmDCOPIface taskIdFromName Task1 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface bookTime $TASKID 2005-06-19 $DURATION 2>/dev/null`
+
+if [ "x$RVAL" != "x0" ]; then
+ echo "FAIL $0: got /$RVAL/, expected /$EXPECTED/"
+ exit 1;
+fi
+
+RVAL=`dcop $DCOPID KarmDCOPIface totalMinutesForTaskId $TASKID 2>/dev/null`
+
+SKIP_TESTFILE_DELETE=true
+tear_down
+
+if [ "x$RVAL" == "x$DURATION" ]; then
+ echo "PASS $0"
+ exit 0;
+else
+ echo "FAIL $0: got /$RVAL/, expected /$DURATION/"
+ exit 1;
+fi
diff --git a/karm/test/bug94447.sh b/karm/test/bug94447.sh
new file mode 100755
index 000000000..fa163735b
--- /dev/null
+++ b/karm/test/bug94447.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# Create files relative to current directory if no "/" prefix
+# in file name given on command line
+
+exec >>check.log 2>&1
+
+TESTFILE="testkarm.ics"
+TESTTODO="testtodo"
+
+source __lib.sh
+
+set_up
+
+# make karm create the file.
+dcop $DCOPID KarmDCOPIface addtodo "$TESTTODO"
+
+RVAL=1
+if [ -e $TESTFILE ]; then RVAL=0; fi
+
+tear_down
+
+if [ $RVAL -eq 0 ]
+then
+ echo "PASS $0"
+ exit 0
+else
+ echo "FAIL $0"
+ exit 1
+fi
diff --git a/karm/test/delete.sh b/karm/test/delete.sh
new file mode 100755
index 000000000..78f04a7de
--- /dev/null
+++ b/karm/test/delete.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# check if deleting a task works
+
+exec >> check.log 2>&1
+
+TESTFILE="/tmp/testkarm1.ics"
+rm $TESTFILE
+
+source __lib.sh
+
+set_up
+
+# do not prompt on deleting a task
+GPOD=`dcop $DCOPID KarmDCOPIface getpromptdelete 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface setpromptdelete 0 2>/dev/null`
+
+RVAL=`dcop $DCOPID KarmDCOPIface addTask todo1 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface addTask todo2 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface deletetodo 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface deletetodo 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface setpromptdelete $GPOD 2>/dev/null`
+RVAL=`dcop $DCOPID KarmDCOPIface version 2>/dev/null`
+
+tear_down
+
+if [ "$RVAL" == "" ]; then
+ echo "FAIL $0: got no version."
+ exit 1;
+else
+ echo "PASS $0"
+ exit 0;
+fi
diff --git a/karm/test/example.ics b/karm/test/example.ics
new file mode 100644
index 000000000..8cfe93525
--- /dev/null
+++ b/karm/test/example.ics
@@ -0,0 +1,173 @@
+BEGIN:VCALENDAR
+PRODID:-//K Desktop Environment//NONSGML libkcal 3.5//EN
+VERSION:2.0
+BEGIN:VTODO
+DTSTAMP:20061125T204432Z
+ORGANIZER;CN=root:MAILTO:
+X-KDE-karm-totalSessionTime:0
+X-KDE-karm-totalTaskTime:0
+CREATED:20061118T183926Z
+UID:libkcal-1156600660.458
+SEQUENCE:0
+LAST-MODIFIED:20061125T204432Z
+SUMMARY:customer BÄR
+CLASS:PUBLIC
+PRIORITY:3
+PERCENT-COMPLETE:0
+END:VTODO
+
+BEGIN:VTODO
+DTSTAMP:20061125T204432Z
+ORGANIZER;CN=root:MAILTO:
+X-KDE-karm-totalSessionTime:0
+X-KDE-karm-totalTaskTime:0
+CREATED:20061118T183934Z
+UID:libkcal-1923273586.967
+SEQUENCE:0
+LAST-MODIFIED:20061125T204432Z
+SUMMARY:documenting
+CLASS:PUBLIC
+PRIORITY:3
+RELATED-TO:libkcal-1156600660.458
+PERCENT-COMPLETE:0
+END:VTODO
+
+BEGIN:VTODO
+DTSTAMP:20061125T204432Z
+ORGANIZER;CN=root:MAILTO:
+X-KDE-karm-totalSessionTime:90
+X-KDE-karm-totalTaskTime:90
+CREATED:20061118T184032Z
+UID:libkcal-61950406.193
+SEQUENCE:0
+LAST-MODIFIED:20061125T204432Z
+SUMMARY:analysis
+CLASS:PUBLIC
+PRIORITY:3
+RELATED-TO:libkcal-1156600660.458
+PERCENT-COMPLETE:0
+END:VTODO
+
+BEGIN:VTODO
+DTSTAMP:20061125T204432Z
+ORGANIZER;CN=root:MAILTO:
+X-KDE-karm-totalSessionTime:184
+X-KDE-karm-totalTaskTime:184
+CREATED:20061118T184044Z
+UID:libkcal-1755408865.833
+SEQUENCE:0
+LAST-MODIFIED:20061125T204432Z
+SUMMARY:programming
+CLASS:PUBLIC
+PRIORITY:3
+RELATED-TO:libkcal-1156600660.458
+PERCENT-COMPLETE:0
+END:VTODO
+
+BEGIN:VTODO
+DTSTAMP:20061125T204432Z
+ORGANIZER;CN=root:MAILTO:
+X-KDE-karm-totalSessionTime:156
+X-KDE-karm-totalTaskTime:156
+CREATED:20061118T184054Z
+UID:libkcal-1177224330.526
+SEQUENCE:0
+LAST-MODIFIED:20061125T204432Z
+SUMMARY:phone with mother
+CLASS:PUBLIC
+PRIORITY:3
+PERCENT-COMPLETE:0
+END:VTODO
+
+BEGIN:VEVENT
+DTSTAMP:20061125T204432Z
+ORGANIZER:MAILTO:
+X-KDE-karm-duration:9360
+CREATED:20061118T184102Z
+UID:libkcal-733807033.405
+SEQUENCE:0
+LAST-MODIFIED:20061118T184102Z
+SUMMARY:phone with mother
+CLASS:PUBLIC
+PRIORITY:3
+CATEGORIES:KArm
+RELATED-TO:libkcal-1177224330.526
+DTSTART:20061118T184054Z
+DTEND:20061118T211654Z
+TRANSP:OPAQUE
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTAMP:20061125T204432Z
+ORGANIZER:MAILTO:
+X-KDE-karm-duration:5400
+CREATED:20061118T184114Z
+UID:libkcal-552065854.752
+SEQUENCE:0
+LAST-MODIFIED:20061118T184114Z
+SUMMARY:analysis
+CLASS:PUBLIC
+PRIORITY:3
+CATEGORIES:KArm
+RELATED-TO:libkcal-61950406.193
+DTSTART:20061118T184032Z
+DTEND:20061118T201032Z
+TRANSP:OPAQUE
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTAMP:20061125T204432Z
+ORGANIZER:MAILTO:
+X-KDE-karm-duration:10920
+CREATED:20061118T184125Z
+UID:libkcal-691043213.294
+SEQUENCE:0
+LAST-MODIFIED:20061118T184125Z
+SUMMARY:programming
+CLASS:PUBLIC
+PRIORITY:3
+CATEGORIES:KArm
+RELATED-TO:libkcal-1755408865.833
+DTSTART:20061118T184044Z
+DTEND:20061118T214244Z
+TRANSP:OPAQUE
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTAMP:20061125T204432Z
+ORGANIZER:MAILTO:
+X-KDE-karm-duration:2
+CREATED:20061118T183930Z
+UID:libkcal-251324967.864
+SEQUENCE:0
+LAST-MODIFIED:20061118T183930Z
+SUMMARY:cr
+CLASS:PUBLIC
+PRIORITY:3
+CATEGORIES:KArm
+RELATED-TO:libkcal-1156600660.458
+DTSTART:20061118T183928Z
+DTEND:20061118T183930Z
+TRANSP:OPAQUE
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTAMP:20061125T204432Z
+ORGANIZER:MAILTO:
+X-KDE-karm-duration:95
+CREATED:20061118T184306Z
+UID:libkcal-729762004.89
+SEQUENCE:0
+LAST-MODIFIED:20061118T184306Z
+SUMMARY:programming
+CLASS:PUBLIC
+PRIORITY:3
+CATEGORIES:KArm
+RELATED-TO:libkcal-1755408865.833
+DTSTART:20061118T184130Z
+DTEND:20061118T184305Z
+TRANSP:OPAQUE
+END:VEVENT
+
+END:VCALENDAR
+
diff --git a/karm/test/lifetest.php b/karm/test/lifetest.php
new file mode 100644
index 000000000..7a24bd3d7
--- /dev/null
+++ b/karm/test/lifetest.php
@@ -0,0 +1,221 @@
+#!/usr/bin/php
+<?
+
+// Description:
+// This program starts karm and simulates keypresses to do a real life-test of karm.
+// This program returns zero if all tests went ok, else an error code.
+// You need a US or DE keyboard to run this.
+
+// for those who do not know php:
+// for a tutorial about php, check out www.usegroup.de
+// for a reference about php, surf to www.php.net
+
+// TODO
+// prepare Windows-port
+
+function createplannerexample()
+{
+$handle=fopen("/tmp/example.planner","w");
+fwrite($handle,
+'<?xml version="1.0"?>
+<project name="" company="" manager="" phase="" project-start="20041101T000000Z" mrproject-version="2" calendar="1">
+ <properties>
+ <property name="cost" type="cost" owner="resource" label="Cost" description="standard cost for a resource"/>
+ </properties>
+ <phases/>
+ <calendars>
+ <day-types>
+ <day-type id="0" name="Working" description="Ein Vorgabe-Arbeitstag"/>
+ <day-type id="1" name="Nonworking" description="Ein Vorgabetag, an dem nicht gearbeitet wird"/>
+ <day-type id="2" name="Basis verwenden" description="Use day from base calendar"/>
+ </day-types>
+ <calendar id="1" name="Vorgabe">
+ <default-week mon="0" tue="0" wed="0" thu="0" fri="0" sat="1" sun="1"/>
+ <overridden-day-types>
+ <overridden-day-type id="0">
+ <interval start="0800" end="1200"/>
+ <interval start="1300" end="1700"/>
+ </overridden-day-type>
+ </overridden-day-types>
+ <days/>
+ </calendar>
+ </calendars>
+ <tasks>
+ <task id="1" name="task 1" note="" work="28800" start="20041101T000000Z" end="20041101T170000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
+ <task id="2" name="task 2" note="" work="28800" start="20041101T000000Z" end="20041101T170000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
+ <task id="3" name="subtask 1-1" note="" work="28800" start="20041101T000000Z" end="20041101T170000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
+ <task id="4" name="subtask 1-2" note="" work="28800" start="20041101T000000Z" end="20041101T170000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
+ </task>
+ </tasks>
+ <resource-groups/>
+ <resources/>
+ <allocations/>
+</project>
+');
+fclose($handle);
+};
+
+function simkey($s)
+// This function simulates keypresses that form the string $s, e.g. for $s==hallo, it simulates the keypress of h, then a, then l and so on.
+// find a useful list of keycodes under /usr/include/X11/keysymdef.h
+{
+ for ($i=0; $i<strlen($s); $i++)
+ {
+ usleep(10000); # this is just for the user to see what happens
+ if ($s[$i]=="/") system("xte 'key KP_Divide'");
+ else system("xte 'key ".$s[$i]."'");
+ usleep(10000);
+ }
+}
+
+function keysim($s)
+// remove everything that makes you have to think twice!!
+{
+ simkey($s);
+}
+
+function funkeysim($s, $count=1)
+// same as keysim, but interprets $s as function key name to be used by xte and expects a $count to indicate how often key is to be pressed
+{
+ for ($i=1; $i<=$count; $i++)
+ {
+ usleep(10000);
+ $rc=exec("xte 'key $s'");
+ usleep(10000);
+ }
+ return $rc;
+}
+
+// int main()
+if ($argv[1]!="--batch")
+{
+ echo "\nThis is lifetest.php, a program to test karm by starting it and simulating keypresses.\n";
+ echo "It is intended for developers who do changes to karm's sourcecode.\n";
+ echo "Before publishing these changes, they should\n";
+ echo "(a) resolve all conflicts with the latest karm sourcecode (cvs up)\n";
+ echo "(b) make sure the code still builds (make)\n";
+ echo "(c) run automated test routines like this (make check)\n\n";
+
+ echo "This program simulates keypresses, so please leave the keyboard alone during the test. Please use a us or de keyboardlayout (setxkbmap us). This must be run in X environment.\n
+ You must have XAutomation installed to run this.";
+ system("xte -h 2&>/dev/null",$rc);
+ if ($rc==0) echo " You have.\n";
+ if ($rc==127) echo " You do not have, please get it from http://hoopajoo.net/projects/xautomation.html .\n";
+ echo "This program will test karm by issueing karm, so, make sure, this calls the version you want to test (make install).\n\n";
+
+ echo "This program will now stop unless you give the parameter --batch (confirming that you do not touch the keyboard)\n";
+
+ $err="";
+ $exit=0;
+}
+else
+{
+ if ( system( "which xte 2> /dev/null" ) == "" ) {
+ echo "xte not found\n";
+ exit(0);
+ }
+ switch (funkeysim("Alt_L"))
+ {
+ case 1:
+ $err.="this must be run in an X environment\n";
+ break;
+ case 127:
+ $err.="you do not have XAutomation installed, get it from http://hoopajoo.net/projects/xautomation.html\n";
+ break;
+ }
+ // the following is the same as 'if file_exist(...) unlink(...)', but atomic
+ @unlink ("/tmp/karmtest.ics");
+ @unlink ("/tmp/example.planner");
+ if ($err=="")
+ {
+ // start and wait till mainwindow is up
+ // the mouse can be in the way, so, move it out. This here even works with "focus strictly under mouse".
+ system("xte 'mousemove 1 1'");
+ echo "\nStarting karm";
+ $process=popen("karm --geometry 200x100+0+0 /tmp/karmtest.ics >/dev/null 2>&1", 'w');
+ $rc=1;
+ while ($rc==1) system("dcop `dcop 2>/dev/null | grep karm` KarmDCOPIface version",$rc);
+ echo "mainwindow is ready";
+ sleep (1);
+
+ funkeysim("Alt_L");
+
+ funkeysim("Right",3);
+ funkeysim("Down",2);
+ funkeysim("Return");
+ sleep (1);
+ funkeysim("Down",2);
+ funkeysim("Tab",5);
+ simkey("/tmp/karmtest.ics");
+ sleep (1);
+ funkeysim("Return");
+ sleep (1);
+ funkeysim("Return");
+ sleep (1);
+
+ # add a new task
+ funkeysim("Alt_L");
+ funkeysim("Right",2);
+ funkeysim("Down");
+ sleep (1);
+ funkeysim("Return");
+ sleep (1);
+ simkey("example 1");
+ funkeysim("Return");
+ sleep (1);
+
+ echo "\nCreating a planner project file...";
+ createplannerexample();
+
+ # import planner project file
+ funkeysim("Alt_L");
+ funkeysim("Down",5);
+ funkeysim("Right");
+ funkeysim("Down");
+ funkeysim("Return");
+ sleep (2);
+ keysim("/tmp/example.planner");
+ sleep (1);
+ funkeysim("Return");
+ sleep (1);
+
+ # export to CSV file
+ funkeysim("Alt_L");
+ funkeysim("Down",5);
+ funkeysim("Right");
+ funkeysim("Down",2);
+ funkeysim("Return");
+ sleep(2);
+ keysim("/tmp/exporttest.csv");
+ sleep(1);
+ funkeysim("Tab",6);
+ system ("xte 'keydown Alt_L'");
+ system ("xte 'key m'");
+ system ("xte 'keyup Alt_L'");
+ sleep(1);
+ funkeysim("Return");
+
+ # send CTRL_Q
+ sleep (2);
+ echo "\nsending CTRL_Q...\n";
+ system ("xte 'keydown Control_L'");
+ system ("xte 'key Q'");
+ system ("xte 'keyup Control_L'");
+
+ $content=file_get_contents("/tmp/karmtest.ics");
+ $lines=explode("\n",$content);
+ if (!preg_match("/DTSTAMP:[0-9]{1,8}T[0-9]{1,6}Z/", $lines[4])) $err.="iCal file: wrong dtstamp";
+ if ($lines[12]<>"SUMMARY:example 1") $err.="iCal file: wrong task, should be example 1, but is $lines[12]";
+ if ($lines[16]<>"END:VTODO") $err.="iCal file: wrong end of vtodo";
+ $content=file_get_contents("/tmp/exporttest.csv");
+ $lines=explode("\n",$content);
+ if (!preg_match("/\"example 1\",,0[,|.]00,0[,|.]00,0[,|.]00,0[,|.]00/", $lines[0])) $err.="csv export is wrong";
+ pclose($process);
+ if ($err == "") @unlink ("/tmp/karmtest.ics");
+ @unlink ("/tmp/example.planner");
+ if ($err == "") @unlink ("/tmp/exporttest.csv");
+ }
+}
+ echo $err;
+ if ($err!="") exit(1);
+?> \ No newline at end of file
diff --git a/karm/test/lockerthread.cpp b/karm/test/lockerthread.cpp
new file mode 100644
index 000000000..6ec6e7ba2
--- /dev/null
+++ b/karm/test/lockerthread.cpp
@@ -0,0 +1,44 @@
+#include <qthread.h>
+#include <qstring.h>
+
+#include <resourcecalendar.h>
+#include <resourcelocal.h>
+#include <calendarresources.h>
+
+#include "lockerthread.h"
+
+LockerThread::LockerThread( const QString &icsfile )
+{
+ m_gotlock = false;
+ m_icsfile = icsfile;
+}
+
+/*
+void LockerThread::setIcsFile( const QString &filename )
+{
+ m_icsfile = filename;
+}
+*/
+
+void LockerThread::run()
+{
+ KCal::CalendarResources *calendars = 0;
+ KCal::ResourceCalendar *calendar = 0;
+ KCal::CalendarResources::Ticket *lock = 0;
+
+ calendars = new KCal::CalendarResources( QString::fromLatin1( "UTC" ) );
+ calendar = new KCal::ResourceLocal( m_icsfile );
+ lock = calendars->requestSaveTicket( calendar );
+ if ( lock )
+ {
+ m_gotlock = true;
+ calendars->releaseSaveTicket( lock );
+ }
+ else
+ {
+ m_gotlock = false;
+ }
+
+ delete calendar;
+ delete calendars;
+}
diff --git a/karm/test/lockerthread.h b/karm/test/lockerthread.h
new file mode 100644
index 000000000..d40f234ad
--- /dev/null
+++ b/karm/test/lockerthread.h
@@ -0,0 +1,21 @@
+#include <qthread.h>
+
+class QString;
+
+/**
+ * Attempt to open and lock a calendar resource in a seperate thread.
+ *
+ * Result of attempt returned by gotlock().
+ */
+class LockerThread : public QThread
+{
+ public:
+ LockerThread( const QString &filename );
+ //void setIcsFile( const QString &filename );
+ void run();
+ bool gotlock() const { return m_gotlock; };
+
+ private:
+ QString m_icsfile;
+ bool m_gotlock;
+};
diff --git a/karm/test/locking.cpp b/karm/test/locking.cpp
new file mode 100644
index 000000000..49c7637d3
--- /dev/null
+++ b/karm/test/locking.cpp
@@ -0,0 +1,151 @@
+#include <assert.h>
+
+#include <qstring.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <kcmdlineargs.h>
+#include <kapplication.h>
+
+#include <resourcecalendar.h>
+#include <resourcelocal.h>
+#include <calendarresources.h>
+
+#include "lockerthread.h"
+
+const QString icalfilename = "karmtest.ics";
+
+// If one thread has the file is locked, the other cannot get the lock.
+short test1()
+{
+ short rval = 0;
+
+ KCal::CalendarResources *calendars = 0;
+ KCal::ResourceCalendar *calendar = 0;
+ KCal::CalendarResources::Ticket *lock = 0;
+
+ calendars = new KCal::CalendarResources( QString::fromLatin1( "UTC" ) );
+ calendar = new KCal::ResourceLocal( icalfilename );
+ lock = calendars->requestSaveTicket( calendar );
+
+ if ( !lock )
+ {
+ kdDebug( 5970 ) << "test1(): failed to lock " << icalfilename << endl;
+ rval = 1;
+ }
+
+ if ( !rval )
+ {
+ LockerThread thread( icalfilename );
+ thread.run();
+ if ( thread.gotlock() )
+ {
+ kdDebug( 5970 ) << "test1(): second thread was able to lock " << icalfilename << endl;
+ rval = 1;
+ }
+ }
+
+ // This frees the lock memory.
+ calendars->releaseSaveTicket( lock );
+
+ delete calendar;
+ delete calendars;
+
+ return rval;
+}
+
+// First thread opens but doesn't lock, second should get lock.
+short test2()
+{
+ short rval = 0;
+
+ KCal::CalendarResources *calendars = 0;
+ KCal::ResourceCalendar *calendar = 0;
+ KCal::CalendarResources::Ticket *lock = 0;
+
+ calendars = new KCal::CalendarResources( QString::fromLatin1( "UTC" ) );
+ calendar = new KCal::ResourceLocal( icalfilename );
+
+ LockerThread thread( icalfilename );
+ thread.run();
+ if ( !thread.gotlock() )
+ {
+ kdDebug(5970) << "test2(): second thread was not able to lock " << icalfilename << endl;
+ rval = 1;
+ }
+
+ delete calendar;
+ delete calendars;
+
+ return rval;
+}
+
+// First thread locks, then unlocks--second should get lock.
+short test3()
+{
+ short rval = 0;
+
+ KCal::CalendarResources *calendars = 0;
+ KCal::ResourceCalendar *calendar = 0;
+ KCal::CalendarResources::Ticket *lock = 0;
+
+ calendars = new KCal::CalendarResources( QString::fromLatin1( "UTC" ) );
+ calendar = new KCal::ResourceLocal( icalfilename );
+
+ // lock then unlock
+ lock = calendars->requestSaveTicket( calendar );
+ if ( !lock )
+ {
+ kdDebug( 5970 ) << "test1(): failed to lock " << icalfilename << endl;
+ rval = 1;
+ }
+ calendars->releaseSaveTicket( lock );
+
+ // second thread should get lock
+ if ( !rval )
+ {
+ LockerThread thread( icalfilename );
+ thread.run();
+ if ( !thread.gotlock() )
+ {
+ kdDebug( 5970 ) << "test1(): second thread was not able to lock " << icalfilename << endl;
+ rval = 1;
+ }
+ }
+
+
+ delete calendar;
+ delete calendars;
+
+ return rval;
+}
+
+// TODO:
+// If one thread changes the file, the other is notified.
+// What happens if we lock one incident and try to change another?
+
+int main( int argc, char *argv[] )
+{
+ short rval = 0;
+
+ // Use another directory than the real one, just to keep things clean
+ // KDEHOME needs to be writable though, for a ksycoca database
+ // FIXME: Delete this directory when done with test.
+ setenv( "KDEHOME", QFile::encodeName( QDir::homeDirPath() + "/.kde-testresource" ), true );
+
+ // Copied from Till's test in libkcal. Not sure what this is for.
+ setenv( "KDE_FORK_SLAVES", "yes", true ); // simpler, for the final cleanup
+
+ // Copied from Till's test in libkcal. Not sure what this is for.
+ KApplication::disableAutoDcopRegistration();
+
+ KCmdLineArgs::init(argc,argv,"testresourcelocking", 0, 0, 0, 0);
+
+ KApplication app( false, false );
+
+ // basic libkcal locking stuff
+ if ( !rval ) rval = test1();
+ if ( !rval ) rval = test2();
+ if ( !rval ) rval = test3();
+
+ return rval;
+}
diff --git a/karm/test/refresh_on_change.sh b/karm/test/refresh_on_change.sh
new file mode 100755
index 000000000..6253c63b6
--- /dev/null
+++ b/karm/test/refresh_on_change.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# I cannot get this test to work reliably!
+# I suspect the culprit is FAM.
+# -- Mark
+
+exec >>check.log 2>&1
+
+source __lib.sh
+
+TESTFILE="/tmp/testkarm.ics"
+
+set_up
+
+TODO_NAME=$0
+TODO_UID=abc-123
+TODO_TIME=`date +%Y%m%dT%H%M%SZ`
+
+sleep 1 # make sure kdirstat can recognize the change in last change date
+
+cat >> $TESTFILE << endl
+BEGIN:VCALENDAR
+PRODID:-//K Desktop Environment//NONSGML KArm Test Scripts//EN
+VERSION:2.0
+
+BEGIN:VTODO
+DTSTAMP:$TODO_TIME
+ORGANIZER;CN=Anonymous:MAILTO:nobody@nowhere
+CREATED:$TODO_TIME
+UID:$TODO_UID
+SEQUENCE:0
+LAST-MODIFIED:$TODO_TIME
+SUMMARY:$TODO_NAME
+CLASS:PUBLIC
+PRIORITY:5
+PERCENT-COMPLETE:0
+END:VTODO
+
+END:VCALENDAR
+endl
+
+# wait so FAM and KDirWatcher tell karm and karm refreshes view
+sleep 2
+
+RVAL=`dcop $DCOPID KarmDCOPIface taskIdFromName $TODO_NAME`
+#echo "RVAL = $RVAL"
+
+tear_down
+
+# check that todo was found
+if [ "$RVAL" == "$TODO_UID" ]; then
+ echo "PASS $0"
+ exit 0;
+else
+ echo "FAIL $0: got /$RVAL/, expected /$TODO_UID/"
+ exit 1;
+fi
diff --git a/karm/test/remote_storage.sh b/karm/test/remote_storage.sh
new file mode 100755
index 000000000..a4335b6c1
--- /dev/null
+++ b/karm/test/remote_storage.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# Karm can read and write to an FTP server for storage file.
+
+exec >>check.log 2>&1
+
+PORT=8000
+TESTFILE="http://localhost:$PORT/testkarm.ics"
+TESTFILE_LOCAL="testkarm.ics"
+TESTTODO="testtodo"
+
+# Start with clean environment
+# If runscripts sees output on stderr, it thinks script failed.
+DCOPID=`dcop | grep karm 2>/dev/null`
+if [ -n $DCOPID ]; then dcop $DCOPID KarmDCOPIface quit; fi;
+if [ -e $TESTFILE_LOCAL ]; then rm $TESTFILE_LOCAL; fi
+
+# if the file does not exist, kresources pops up a modal dialog box
+# telling us that a file does not exist.
+
+touch $TESTFILE_LOCAL
+
+python __httpd.py $PORT &
+
+sleep 2
+
+HTTPD_PID=`ps -C "python __httpd.py" -o pid=`
+
+karm $TESTFILE &
+
+sleep 2
+
+DCOPID=`dcop | grep karm`
+
+# karm does not write file until data is saved.
+
+echo "DEBUG: dcop $DCOPID KarmDCOPIface addtodo \"$TESTTODO\""
+dcop $DCOPID KarmDCOPIface addtodo "$TESTTODO"
+
+sleep 1
+
+RVAL=1
+if [ -e $TESTFILE_LOCAL ]; then RVAL=0; fi
+
+# clean up
+if [ -n $DCOPID ]; then dcop $DCOPID KarmDCOPIface quit; fi;
+if [ -e $TESTFILE_LOCAL ]; then rm $TESTFILE_LOCAL; fi
+if [ -n $HTTPD_PID ]; then kill $HTTPD_PID; fi
+
+# return 0 on success, 1 on failure
+if [ $RVAL -eq 0 ]
+then
+ echo "PASS $0"
+ exit 0
+else
+ echo "FAIL $0"
+ exit 1
+fi
diff --git a/karm/test/runscripts.cpp b/karm/test/runscripts.cpp
new file mode 100644
index 000000000..aa5449541
--- /dev/null
+++ b/karm/test/runscripts.cpp
@@ -0,0 +1,130 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Mark Bucciarelli <mark@hubcapconsulting.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+#include "script.h"
+
+static QString srcdir();
+static int runscripts
+( const QString &interpreter, const QString &extension, const QString &path );
+
+const QString dots = "..................................................";
+const QString not_a_test_filename_prefix = "__";
+
+// Read srcdir from Makefile (for builddir != srcdir).
+QString srcdir()
+{
+ bool found = false;
+ QString dir;
+
+ QFile file( "Makefile" );
+ if ( !file.open( IO_ReadOnly | IO_Translate ) ) return "";
+
+ QTextStream in( &file );
+ QString line;
+ while ( !found && !in.atEnd() )
+ {
+ line = in.readLine();
+ if ( line.startsWith( "srcdir = " ) )
+ {
+ dir = line.mid( 9 );
+ found = true;
+ }
+ }
+
+ if ( !found ) dir = "";
+
+ return dir;
+}
+
+int runscripts
+( const QString &interpreter, const QString &extension, const QString &path )
+{
+ int rval = 0;
+ int oneBadApple = 0;
+ QStringList files;
+
+ QDir dir( path );
+
+ Script* s = new Script( dir );
+
+ dir.setNameFilter( extension );
+ dir.setFilter( QDir::Files );
+ dir.setSorting( QDir::Name | QDir::IgnoreCase );
+ const QFileInfoList *list = dir.entryInfoList();
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+ while ( !rval && ( fi = it.current() ) != 0 )
+ {
+ // Don't run scripts that are shared routines.
+ if ( ! fi->fileName().startsWith( not_a_test_filename_prefix ) )
+ {
+ s->addArgument( interpreter );
+ s->addArgument( path + QDir::separator() + fi->fileName().latin1() );
+
+ // Thorsten's xautomation tests run with user interaction by default.
+ if ( interpreter == "sh" ) s->addArgument( "--batch" );
+ if ( interpreter == "php" ) s->addArgument( "--batch" );
+
+ rval = s->run();
+
+ kdDebug() << "runscripts: " << fi->fileName()
+ << " " << dots.left( dots.length() - fi->fileName().length() )
+ << " " << ( ! rval ? "PASS" : "FAIL" ) << endl;
+
+ // Don't abort if one test files--run them all
+ if ( rval )
+ {
+ oneBadApple = 1;
+ rval = 0;
+ }
+
+ delete s;
+ s = new Script( dir );
+ }
+ ++it;
+ }
+ delete s;
+ s = 0;
+
+ return oneBadApple;
+}
+
+int main( int, char** )
+{
+ int rval = 0;
+
+ QString path = srcdir();
+
+ if ( !rval ) rval = runscripts( "python", "*.py *.Py *.PY *.pY", path );
+
+ if ( !rval ) rval = runscripts( "sh", "*.sh *.Sh *.SH *.sH", path );
+
+ if ( !rval ) rval = runscripts( "perl", "*.pl *.Pl *.PL *.pL", path );
+
+ if ( !rval ) rval = runscripts( "php", "*.php *.php3 *.php4 *.php5", path );
+
+ return rval;
+}
diff --git a/karm/test/script.cpp b/karm/test/script.cpp
new file mode 100644
index 000000000..37fe058d3
--- /dev/null
+++ b/karm/test/script.cpp
@@ -0,0 +1,115 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Anders Lund <anders@alweb.dk>
+ Copyright (C) 2004 Mark Bucciarelli <mark@hubcapconsulting.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include <qdir.h>
+#include <qprocess.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+
+#include "script.h"
+
+/*
+ n.b. Do not use kdDebug statements in this file.
+
+ With qt-copy 3_3_BRANCH, they cause a Valgrind error.
+ Ref: KDE bug #95237.
+*/
+
+// Wait for terminate() attempt to return before using kill()
+// kill() doesn't let script interpreter try to clean up.
+const int NICE_KILL_TIMEOUT_IN_SECS = 5;
+
+Script::Script( const QDir& workingDirectory )
+{
+ m_status = 0;
+ m_stderr = false;
+ m_timeoutInSeconds = 5;
+
+ m_proc = new QProcess( this );
+ m_proc->setWorkingDirectory( workingDirectory );
+
+ connect ( m_proc, SIGNAL( readyReadStdout() ),
+ this , SLOT ( stdout() )
+ );
+ connect ( m_proc, SIGNAL( readyReadStderr() ),
+ this , SLOT ( stderr() )
+ );
+ connect ( m_proc, SIGNAL( processExited() ),
+ this , SLOT ( exit() )
+ );
+}
+
+Script::~Script()
+{
+ delete m_proc;
+ m_proc = 0;
+}
+
+void Script::addArgument( const QString &arg )
+{
+ m_proc->addArgument( arg );
+}
+
+void Script::setTimeout( int seconds )
+{
+ if ( seconds <= 0 ) return;
+ m_timeoutInSeconds = seconds;
+}
+
+int Script::run()
+{
+ m_proc->start();
+ // This didn't work. But Ctrl-C does. :P
+ //QTimer::singleShot( m_timeoutInSeconds * 1000, m_proc, SLOT( kill() ) );
+ //while ( ! m_proc->normalExit() );
+ while ( m_proc->isRunning() );
+ return m_status;
+}
+
+void Script::terminate()
+{
+ // These both trigger processExited, so exit() will run.
+ m_proc->tryTerminate();
+ QTimer::singleShot( NICE_KILL_TIMEOUT_IN_SECS*1000, m_proc, SLOT( kill() ) );
+}
+
+void Script::exit()
+{
+ m_status = m_proc->exitStatus();
+ delete m_proc;
+ m_proc = 0;
+}
+
+void Script::stderr()
+{
+ // Treat any output to std err as a script failure
+ m_status = 1;
+ QString data = QString( m_proc->readStderr() );
+ m_stderr= true;
+}
+
+void Script::stdout()
+{
+ QString data = QString( m_proc->readStdout() );
+}
+
+#include "script.moc"
diff --git a/karm/test/script.h b/karm/test/script.h
new file mode 100644
index 000000000..f5ae1e227
--- /dev/null
+++ b/karm/test/script.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Mark Bucciarelli <mark@hubcapconsulting.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _script_h_
+#define _script_h_
+
+//#include <qvariant.h>
+#include <qobject.h>
+
+class QDir;
+class QProcess;
+class QString;
+class QStringList;
+
+class Script : public QObject
+{
+ Q_OBJECT
+public:
+ Script( const QDir& workingDirectory );
+ virtual ~Script();
+ void addArgument( const QString &arg );
+ void setTimeout( int seconds );
+ int run();
+private slots:
+ void exit();
+ void stderr();
+ void stdout();
+ void terminate();
+private:
+ QProcess *m_proc;
+ int m_status;
+ bool m_stderr;
+ int m_timeoutInSeconds;
+};
+
+#endif // _script_h_
diff --git a/karm/test/version.sh b/karm/test/version.sh
new file mode 100755
index 000000000..64fbc8fb0
--- /dev/null
+++ b/karm/test/version.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# First test, just check version.
+
+exec >>check.log 2>&1
+
+TESTFILE="/tmp/testkarm1.ics"
+VERSION="1.6.0"
+
+source __lib.sh
+
+set_up
+
+RVAL=`dcop $DCOPID KarmDCOPIface version 2>/dev/null`
+
+tear_down
+
+if [ "$RVAL" == "$VERSION" ]; then
+ echo "PASS $0"
+ exit 0;
+else
+ echo "FAIL $0: got /$RVAL/, expected /$VERSION/"
+ exit 1;
+fi
diff --git a/karm/test/webdav.sh b/karm/test/webdav.sh
new file mode 100755
index 000000000..8d51db92c
--- /dev/null
+++ b/karm/test/webdav.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+# Add a todo to an iCal file stored on a webdav server.
+
+exec >>check.log 2>&1
+
+source __lib.sh
+
+# check for required perl stuff
+perl -e "use Net::DAV::Server;" > /dev/null 2>&1
+if ! [ $? = 0 ]; then
+ echo "PASS"
+ exit 0
+fi
+
+# Start webdav server
+perl __webdav.pl &
+sleep 2
+WEBDAV_PID=`ps -C "perl __webdav.pl" -o pid=`
+
+# Start karm
+TESTFILE="http://localhost:4242/testkarm.ics"
+TESTFILE_LOCAL="/tmp/testkarm.ics"
+TESTTODO="testtodo"
+SKIP_TESTFILE_DELETE=true
+# Need this or karm complains there is no file
+rm -f $TESTFILE_LOCAL
+touch $TESTFILE_LOCAL
+set_up
+#wait till download is ready
+sleep 3
+
+# add a todo
+dcop $DCOPID KarmDCOPIface addTask "$TESTTODO"
+sleep 1
+dcop $DCOPID KarmDCOPIface save
+
+sleep 1
+
+if grep $TESTTODO $TESTFILE_LOCAL
+ then RVAL=0
+ else RVAL=1
+fi
+
+# clean up
+tear_down
+#if [ -e $TESTFILE_LOCAL ]; then rm $TESTFILE_LOCAL; fi
+if [ -n $WEBDAV_PID ]; then kill $WEBDAV_PID; fi
+
+# return 0 on success, 1 on failure
+if [ $RVAL -eq 0 ]
+then
+ echo "PASS $0"
+ exit 0
+else
+ echo "FAIL $0"
+ exit 1
+fi