From c640e050490a45ad4299af4577d3e0054972ec4e Mon Sep 17 00:00:00 2001 From: Johannes Schlatow Date: Wed, 4 Aug 2010 19:00:42 +0200 Subject: [PATCH] Unit tests - Added tests for class Taskmod - Added tests for _merge command --- src/tests/.gitignore | 1 + src/tests/Makefile | 5 +- src/tests/merge.t | 261 ++++++++++++++++++++++++++++++++++++++++ src/tests/taskmod.t.cpp | 137 +++++++++++++++++++++ 4 files changed, 403 insertions(+), 1 deletion(-) create mode 100755 src/tests/merge.t create mode 100644 src/tests/taskmod.t.cpp diff --git a/src/tests/.gitignore b/src/tests/.gitignore index 95b8b0660..6f45bc593 100644 --- a/src/tests/.gitignore +++ b/src/tests/.gitignore @@ -22,4 +22,5 @@ file.t directory.t grid.t rx.t +taskmod.t *.log diff --git a/src/tests/Makefile b/src/tests/Makefile index f3e8bcab3..e8d947295 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,6 +1,6 @@ PROJECT = t.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \ config.t seq.t att.t stringtable.t record.t nibbler.t subst.t filt.t \ - cmd.t util.t color.t list.t path.t file.t directory.t grid.t rx.t + cmd.t util.t color.t list.t path.t file.t directory.t grid.t rx.t taskmod.t CFLAGS = -I. -I.. -I../.. -Wall -pedantic -ggdb3 -fno-rtti LFLAGS = -L/usr/local/lib -lncurses -llua OBJECTS = ../t-TDB.o ../t-Task.o ../t-text.o ../t-Date.o ../t-Table.o \ @@ -99,3 +99,6 @@ grid.t: grid.t.o $(OBJECTS) test.o rx.t: rx.t.o $(OBJECTS) test.o g++ rx.t.o $(OBJECTS) test.o $(LFLAGS) -o rx.t +taskmod.t: taskmod.t.o $(OBJECTS) test.o + g++ taskmod.t.o $(OBJECTS) test.o $(LFLAGS) -o taskmod.t + diff --git a/src/tests/merge.t b/src/tests/merge.t new file mode 100755 index 000000000..42e1a3096 --- /dev/null +++ b/src/tests/merge.t @@ -0,0 +1,261 @@ +#! /usr/bin/perl +################################################################################ +## task - a command line task list manager. +## +## Copyright 2006 - 2010, Paul Beckingham. +## All rights reserved. +## +## This program is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free Software +## Foundation; either version 2 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 General Public License for more +## details. +## +## You should have received a copy of the GNU General Public License along with +## this program; if not, write to the +## +## Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, +## Boston, MA +## 02110-1301 +## USA +## +################################################################################ + +use strict; +use warnings; +use Test::More tests => 40; +use File::Copy; + +use constant false => 0; +use constant true => 1; + +# Create data locations +mkdir("local", 0755); +ok(-e 'local', "Created directory local"); +mkdir("remote", 0755); +ok(-e 'remote', "Created directory remote"); + +# Create the rc files. +if (open my $fh, '>', 'local.rc') +{ + print $fh "data.location=./local\n", + "confirmation=no\n", + "report.list.description=DESC\n", + "report.list.columns=id,project,active,priority,description,tags\n", + "report.list.labels=id,pro,a,pri,d,t\n", + "report.list.sort=id+\n", + "report.list.filter=status:pending\n"; + close $fh; + ok (-r 'local.rc', 'Created local.rc'); +} + +if (open my $fh, '>', 'remote.rc') +{ + print $fh "data.location=./remote\n", + "confirmation=no\n", + "report.list.description=DESC\n", + "report.list.columns=id,project,active,priority,description,tags\n", + "report.list.labels=id,pro,a,pri,d,t\n", + "report.list.sort=id+\n", + "report.list.filter=status:pending\n"; + close $fh; + ok (-r 'remote.rc', 'Created remote.rc'); +} + +# Create some basic tasks on both sides +qx{../task rc:local.rc add left_modified}; +sleep(1); +qx{../task rc:local.rc add right_modified}; +sleep(1); +qx{../task rc:local.rc add left_newer}; +sleep(1); +qx{../task rc:local.rc add right_newer}; +sleep(1); +qx{../task rc:local.rc add left_deleted}; +sleep(1); +qx{../task rc:local.rc add right_deleted}; +sleep(1); +qx{../task rc:local.rc add left_completed}; +sleep(1); +qx{../task rc:local.rc add right_completed}; +sleep(1); + +copy("local/undo.data", "remote/undo.data") or fail("copy local/undo.data to remote/undo.data"); +copy("local/pending.data", "remote/pending.data") or fail("copy local/undo.data to remote/undo.data"); +copy("local/completed.data", "remote/completed.data") or fail("copy local/undo.data to remote/undo.data"); + +# make local modifications +qx{../task rc:local.rc add left_added}; #left_added +sleep(1); +qx{../task rc:local.rc 1 prio:H}; #left_modified +sleep(1); +qx{../task rc:local.rc 3 +stay}; #left_newer +sleep(1); +qx{../task rc:local.rc 4 project:test}; #right_newer +sleep(1); +qx{../task rc:local.rc 6 +delete}; #right_deleted +sleep(1); + +# make remote modifications +qx{../task rc:remote.rc add right_added}; #right_added +sleep(1); +qx{../task rc:remote.rc 2 prio:L}; #right_modified +sleep(1); +qx{../task rc:remote.rc 2 wait:tomorrow}; #right_modified +sleep(1); +qx{../task rc:remote.rc 4 proj:realProject}; #right_newer +sleep(1); +qx{../task rc:remote.rc 5 project:deletion}; #left_deleted +sleep(1); +qx{../task rc:remote.rc done 8}; #right_completed +sleep(1); +qx{../task rc:remote.rc del 6}; #right_deleted +sleep(1); +qx{../task rc:remote.rc done 3}; #left_newer +sleep(1); + +# make new local modifications +qx{../task rc:local.rc start 3}; #left_newer +sleep(1); +qx{../task rc:local.rc 4 +car}; #right_newer +sleep(1); +qx{../task rc:local.rc done 7}; #left_completed +sleep(1); +qx{../task rc:local.rc del 5}; #left_deleted +sleep(1); + +# make new remote modifications +qx{../task rc:remote.rc 4 +gym}; # right_newer + +# invoke gc +qx{../task rc:local.rc}; +qx{../task rc:remote.rc}; + +# merge remote into local +my $output_l = qx{../task rc:local.rc _merge remote/undo.data}; + +#check output +unlike ($output_l, qr/Missing/, "local-merge: no missing entry"); +unlike ($output_l, qr/Not adding duplicate/, "local-merge: no duplicates"); + +# merge local into remote +my $output_r = qx{../task rc:remote.rc _merge local/undo.data}; + +# check output +unlike ($output_r, qr/Missing/, "remote-merge: no missing entry"); +unlike ($output_r, qr/Not adding duplicate/, "remote-merge: no duplicates"); + +# check reports +my $report_l = qx{../task rc:local.rc}; +my $report_r = qx{../task rc:remote.rc}; + +# local-merge +like ($report_l, qr/left_added/, "local-merge: left_added is present"); +like ($report_l, qr/right_added/, "local-merge: right_added is present"); +like ($report_l, qr/H.*left_modified/, "local-merge: left_modified ok"); +like ($report_l, qr/\*.*left_newer.*stay/, "local-merge: left_newer ok"); +like ($report_l, qr/realProject.*right_newer.*gym/, "local-merge: right_newer ok"); + +$report_l = qx{../task rc:local.rc export.csv}; +like ($report_l, qr/deleted.*left_deleted/, "local-merge: left_deleted ok"); +like ($report_l, qr/deleted.*right_deleted/, "local-merge: right_deleted ok"); +like ($report_l, qr/completed.*left_completed/, "local-merge: left_completed ok"); +like ($report_l, qr/completed.*right_completed/, "local-merge: right_completed ok"); + +$report_l = qx(../task rc:local.rc waiting); +like ($report_l, qr/L.*right_modified/, "local-merge: right_modified ok"); + +# remote-merge +like ($report_r, qr/left_added/, "remote-merge: left_added is present"); +like ($report_r, qr/right_added/, "remote-merge: right_added is present"); +like ($report_r, qr/H.*left_modified/, "remote-merge: left_modified ok"); +like ($report_r, qr/\*.*left_newer.*stay/, "remote-merge: left_newer ok"); +like ($report_r, qr/realProject.*right_newer.*gym/, "remote-merge: right_newer ok"); + +$report_r = qx{../task rc:remote.rc export.csv}; +like ($report_r, qr/deleted.*left_deleted/, "remote-merge: left_deleted ok"); +like ($report_r, qr/deleted.*right_deleted/, "remote-merge: right_deleted ok"); +like ($report_r, qr/completed.*left_completed/, "remote-merge: left_completed ok"); +like ($report_r, qr/completed.*right_completed/, "remote-merge: right_completed ok"); + +$report_r = qx(../task rc:remote.rc waiting); +like ($report_r, qr/L.*right_modified/, "remote-merge: right_modified ok"); + +# check timestamps in undo.data +my $good = true; +if (open my $fh, 'local/undo.data') { + my $lasttime = 0; + while (!eof($fh)) { + if (defined ($_ = <$fh>)) { + if ($_ =~ m/^time (\d+)/) { + my $time = $1 + 0; + if ($time <= $lasttime) { + fail ("timestamps in local/undo.data are not monotonically ordered"); + $good = false; + } + $lasttime = $time; + } + } + } +} else { + fail ("could not open local/undo.data"); +} +ok ($good, "local-merge: timestamps ok"); + +$good = true; +if (open my $fh, 'remote/undo.data') { + my $lasttime = 0; + while (!eof($fh)) { + if (defined ($_ = <$fh>)) { + if ($_ =~ m/^time (\d+)/) { + my $time = $1 + 0; + if ($time <= $lasttime) { + fail ("timestamps in remote/undo.data are not monotonically ordered"); + $good = false; + } + $lasttime = $time; + } + } + } +} else { + fail ("could not open remote/undo.data"); +} +ok ($good, "remote-merge: timestamps ok"); + +# Cleanup. +unlink 'local/pending.data'; +ok (!-r 'local/pending.data', 'Removed local/pending.data'); + +unlink 'local/completed.data'; +ok (!-r 'local/completed.data', 'Removed local/completed.data'); + +unlink 'local/undo.data'; +ok (!-r 'local/undo.data', 'Removed local/undo.data'); + +unlink 'local.rc'; +ok (!-r 'local.rc', 'Removed local.rc'); + +unlink 'remote/pending.data'; +ok (!-r 'remote/pending.data', 'Removed remote/pending.data'); + +unlink 'remote/completed.data'; +ok (!-r 'remote/completed.data', 'Removed remote/completed.data'); + +unlink 'remote/undo.data'; +ok (!-r 'remote/undo.data', 'Removed remote/undo.data'); + +unlink 'remote.rc'; +ok (!-r 'remote.rc', 'Removed remote.rc'); + +rmdir("remote"); +ok (!-e "remote", "Removed dir remote"); +rmdir("local"); +ok (!-e "local", "Removed dir local"); + +exit 0; + diff --git a/src/tests/taskmod.t.cpp b/src/tests/taskmod.t.cpp new file mode 100644 index 000000000..fd4238a8f --- /dev/null +++ b/src/tests/taskmod.t.cpp @@ -0,0 +1,137 @@ +//////////////////////////////////////////////////////////////////////////////// +// task - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham. +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 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 General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the +// +// Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA +// 02110-1301 +// USA +// +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +//#include +#include +#include +#include +#include + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest t (16); + + bool good = true; + + // base timestamp + unsigned long timestamp = (unsigned long)time(NULL); + timestamp -= timestamp % 100; + + // create some tasks + Task tasks[3]; + + // base task + tasks[0] = Task("[description:\"Desc1\" uuid:\"df95dac3-5f2b-af88-5416-03a3163d00fd\"]"); + // first modification + tasks[1] = tasks[0]; + tasks[1].addTag("tag1"); + // second modification + tasks[2] = tasks[1]; + tasks[2].setStatus(Task::completed); + + // create taskmods + Taskmod mods[4]; + mods[0] = Taskmod(); + mods[0].setTimestamp(timestamp); + mods[0].setBefore(tasks[0]); + mods[0].setAfter(tasks[1]); + + mods[1] = Taskmod(); + mods[1].setTimestamp(timestamp + 2); + mods[1].setBefore(tasks[1]); + mods[1].setAfter(tasks[2]); + + // getUuid() not + Taskmod empty = Taskmod(); + good = true; + try { + empty.getUuid(); + } catch (std::string& e) { t.diag(e); good = false; } + t.notok (good, "Taskmod::getUuid() not"); + + // issetAfter() not + Taskmod newMod = Taskmod(); + t.notok(newMod.issetAfter(), "Taskmod::issetAfter() not"); + + // getUuid() + newMod.setAfter(tasks[1]); + try { + std::string uuid = newMod.getUuid(); + t.is(uuid, "df95dac3-5f2b-af88-5416-03a3163d00fd", "Taskmod::getUuid()"); + } catch (std::string& e) { + t.diag(e); + t.fail("Taskmod::getUuid()"); + } + + // isValid() not + t.notok(newMod.isValid(), "Taskmod::isValid() not") ; + + // issetBefore() not + t.notok(newMod.issetBefore(), "Taskmod::issetBefore() not"); + + // isValid() + newMod.setTimestamp(timestamp+1); + t.ok(newMod.isValid(), "Taskmod::isValid()"); + + // isNew() + t.ok(newMod.isNew(), "Taskmod::isNew()"); + + // issetBefore() + newMod.setBefore(tasks[0]); + t.ok(newMod.issetBefore(), "Taskmod::issetBefore()"); + + // isNew() not + t.notok(newMod.isNew(), "Taskmod::isNew() not"); + + // < + t.ok(mods[0] < newMod, "Taskmod::operator<"); + t.notok(newMod < mods[0], "Taskmod::operator< not"); + + // > + t.ok(mods[1] > mods[0], "Taskmod::operator>"); + t.notok(mods[0] > mods[1], "Taskmod::operator> not"); + + // != + t.ok(mods[0] != mods[1], "Taskmod::operator!=" ); + + // copy constructor + Taskmod clone1 = Taskmod(mods[0]); + t.ok(mods[0] == clone1, "Taskmod::Taskmod(const Taskmod&)"); + + // = + Taskmod clone2 = mods[0]; + t.ok(mods[0] == clone2, "Taskmod::operator="); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////////