mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Enhancements - task diff
- Implemented util.cpp/taskDiff to generate a proxy description of the difference between two tasks. - Implemented unit tests for taskDiff.
This commit is contained in:
parent
c5d7b41d98
commit
a56eeb9ec2
6 changed files with 186 additions and 7 deletions
28
ChangeLog
28
ChangeLog
|
@ -24,6 +24,32 @@
|
||||||
(thanks to Federico Hernandez).
|
(thanks to Federico Hernandez).
|
||||||
+ Removed obsolete DEVELOPERS file. The online support forums at
|
+ Removed obsolete DEVELOPERS file. The online support forums at
|
||||||
http://taskwarrior.org will provide better information.
|
http://taskwarrior.org will provide better information.
|
||||||
|
+ Fixed bug that kept some deleted tasks showing up on the calendar report
|
||||||
|
(thanks to Federico Hernandez).
|
||||||
|
+ Now asks the user to confirm large changes if configuration variable
|
||||||
|
'confirmation' is set to 'yes'. A large change is one that completely
|
||||||
|
replaces a task description, or operates on a large number of tasks,
|
||||||
|
which defaults to 4 but is configurable via the 'bulk' configuration
|
||||||
|
variable (thanks to John Florian).
|
||||||
|
+ Now echoes back the new task ID on 'add' (thanks to Bruce Dillahunty).
|
||||||
|
+ The new "shell" command provides an interactive shell for task. All
|
||||||
|
commands are supported (thanks to Bruce Dillahunty, Federico Hernandez,
|
||||||
|
and John Florian).
|
||||||
|
+ New "recurring" report to list all recurring tasks.
|
||||||
|
+ New, more flexible, more consistent, grep-able file format.
|
||||||
|
|
||||||
|
Add:
|
||||||
|
att mods
|
||||||
|
new custom reports
|
||||||
|
new custom report fields
|
||||||
|
aliases
|
||||||
|
limit:
|
||||||
|
wait:
|
||||||
|
report.waiting
|
||||||
|
report.all
|
||||||
|
debug mode
|
||||||
|
new colorization support
|
||||||
|
many, many new unit tests
|
||||||
|
|
||||||
------ old releases ------------------------------
|
------ old releases ------------------------------
|
||||||
|
|
||||||
|
@ -358,7 +384,7 @@
|
||||||
+ Rules-based colorization.
|
+ Rules-based colorization.
|
||||||
|
|
||||||
0.8.1 (1/28/2008) - 0.8.16 (3/13/2008)
|
0.8.1 (1/28/2008) - 0.8.16 (3/13/2008)
|
||||||
+ autoconf conversion (many builds).
|
+ autoconf conversion
|
||||||
|
|
||||||
0.8.0 Polish (1/25/2008)
|
0.8.0 Polish (1/25/2008)
|
||||||
+ Code cleanup, reorganization.
|
+ Code cleanup, reorganization.
|
||||||
|
|
1
src/tests/.gitignore
vendored
1
src/tests/.gitignore
vendored
|
@ -15,4 +15,5 @@ subst.t
|
||||||
filt.t
|
filt.t
|
||||||
cmd.t
|
cmd.t
|
||||||
config.t
|
config.t
|
||||||
|
util.t
|
||||||
*.log
|
*.log
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
PROJECT = t.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \
|
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 \
|
config.t seq.t att.t stringtable.t record.t nibbler.t subst.t filt.t \
|
||||||
cmd.t
|
cmd.t util.t
|
||||||
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
|
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
|
||||||
LFLAGS = -L/usr/local/lib -lncurses
|
LFLAGS = -L/usr/local/lib -lncurses
|
||||||
OBJECTS = ../TDB.o ../Task.o ../valid.o ../text.o ../Date.o ../Table.o \
|
OBJECTS = ../TDB.o ../Task.o ../valid.o ../text.o ../Date.o ../Table.o \
|
||||||
|
@ -72,3 +72,6 @@ cmd.t: cmd.t.o $(OBJECTS) test.o
|
||||||
config.t: config.t.o $(OBJECTS) test.o
|
config.t: config.t.o $(OBJECTS) test.o
|
||||||
g++ config.t.o $(OBJECTS) test.o $(LFLAGS) -o config.t
|
g++ config.t.o $(OBJECTS) test.o $(LFLAGS) -o config.t
|
||||||
|
|
||||||
|
util.t: util.t.o $(OBJECTS) test.o
|
||||||
|
g++ util.t.o $(OBJECTS) test.o $(LFLAGS) -o util.t
|
||||||
|
|
||||||
|
|
96
src/tests/util.t.cpp
Normal file
96
src/tests/util.t.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// task - a command line task list manager.
|
||||||
|
//
|
||||||
|
// Copyright 2006 - 2009, 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 <iostream>
|
||||||
|
#include "main.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int main (int argc, char** argv)
|
||||||
|
{
|
||||||
|
UnitTest t (17);
|
||||||
|
|
||||||
|
// TODO bool confirm (const std::string&);
|
||||||
|
// TODO int confirm3 (const std::string&);
|
||||||
|
// TODO void delay (float);
|
||||||
|
// TODO std::string formatSeconds (time_t);
|
||||||
|
// TODO std::string formatSecondsCompact (time_t);
|
||||||
|
|
||||||
|
// std::string formatBytes (size_t);
|
||||||
|
t.is (formatBytes (0), "0 B", "0 -> 0 B");
|
||||||
|
|
||||||
|
t.is (formatBytes (999), "999 B", "999 -> 999 B");
|
||||||
|
t.is (formatBytes (1000), "1.0 KiB", "1000 -> 1.0 KiB");
|
||||||
|
t.is (formatBytes (1001), "1.0 KiB", "1001 -> 1.0 KiB");
|
||||||
|
|
||||||
|
t.is (formatBytes (999999), "1.0 MiB", "999999 -> 1.0 MiB");
|
||||||
|
t.is (formatBytes (1000000), "1.0 MiB", "1000000 -> 1.0 MiB");
|
||||||
|
t.is (formatBytes (1000001), "1.0 MiB", "1000001 -> 1.0 MiB");
|
||||||
|
|
||||||
|
t.is (formatBytes (999999999), "1.0 GiB", "999999999 -> 1.0 GiB");
|
||||||
|
t.is (formatBytes (1000000000), "1.0 GiB", "1000000000 -> 1.0 GiB");
|
||||||
|
t.is (formatBytes (1000000001), "1.0 GiB", "1000000001 -> 1.0 GiB");
|
||||||
|
|
||||||
|
// TODO const std::string uuid ();
|
||||||
|
|
||||||
|
// std::string expandPath (const std::string&);
|
||||||
|
t.ok (expandPath ("foo") == "foo", "expandPath nop");
|
||||||
|
t.ok (expandPath ("~/") != "~/", "expandPath ~/");
|
||||||
|
|
||||||
|
// TODO bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
|
||||||
|
// TODO bool slurp (const std::string&, std::string&, bool trimLines = false);
|
||||||
|
// TODO void spit (const std::string&, const std::string&);
|
||||||
|
|
||||||
|
// std::string taskDiff (const Task&, const Task&);
|
||||||
|
Task left;
|
||||||
|
left.set ("zero", "0");
|
||||||
|
left.set ("one", 1);
|
||||||
|
left.set ("two", 2);
|
||||||
|
|
||||||
|
Task right;
|
||||||
|
right.set ("zero", "00");
|
||||||
|
right.set ("two", 2);
|
||||||
|
right.set ("three", 3);
|
||||||
|
|
||||||
|
Task rightAgain (right);
|
||||||
|
|
||||||
|
std::string output = taskDiff (left, right);
|
||||||
|
t.ok (output.find ("zero was changed from '0' to '00'.\n") != std::string::npos, "Detected change zero:0 -> zero:00");
|
||||||
|
t.ok (output.find ("one was deleted.\n") != std::string::npos, "Detected deletion one:1 ->");
|
||||||
|
t.ok (output.find ("two") == std::string::npos, "Detected no change two:2 -> two:2");
|
||||||
|
t.ok (output.find ("three was set to '3'.\n") != std::string::npos, "Detected addition -> three:3");
|
||||||
|
|
||||||
|
output = taskDiff (right, rightAgain);
|
||||||
|
t.ok (output.find ("No changes were made.\n") != std::string::npos, "No changes detected");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
60
src/util.cpp
60
src/util.cpp
|
@ -26,6 +26,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -183,10 +184,10 @@ std::string formatBytes (size_t bytes)
|
||||||
{
|
{
|
||||||
char formatted[24];
|
char formatted[24];
|
||||||
|
|
||||||
if (bytes > 1000000000) sprintf (formatted, "%.1f GiB", (bytes / 1000000000.0));
|
if (bytes >= 1000000000) sprintf (formatted, "%.1f GiB", (bytes / 1000000000.0));
|
||||||
else if (bytes > 1000000) sprintf (formatted, "%.1f MiB", (bytes / 1000000.0));
|
else if (bytes >= 1000000) sprintf (formatted, "%.1f MiB", (bytes / 1000000.0));
|
||||||
else if (bytes > 1000) sprintf (formatted, "%.1f KiB", (bytes / 1000.0));
|
else if (bytes >= 1000) sprintf (formatted, "%.1f KiB", (bytes / 1000.0));
|
||||||
else sprintf (formatted, "%d B", (int)bytes );
|
else sprintf (formatted, "%d B", (int)bytes );
|
||||||
|
|
||||||
return commify (formatted);
|
return commify (formatted);
|
||||||
}
|
}
|
||||||
|
@ -426,3 +427,54 @@ void spit (const std::string& file, const std::string& contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
std::string taskDiff (const Task& before, const Task& after)
|
||||||
|
{
|
||||||
|
// Attributes are all there is, so figure the different attribute names
|
||||||
|
// between before and after.
|
||||||
|
std::vector <std::string> beforeAtts;
|
||||||
|
foreach (att, before)
|
||||||
|
beforeAtts.push_back (att->first);
|
||||||
|
|
||||||
|
std::vector <std::string> afterAtts;
|
||||||
|
foreach (att, after)
|
||||||
|
afterAtts.push_back (att->first);
|
||||||
|
|
||||||
|
std::vector <std::string> beforeOnly;
|
||||||
|
std::vector <std::string> afterOnly;
|
||||||
|
listDiff (beforeAtts, afterAtts, beforeOnly, afterOnly);
|
||||||
|
|
||||||
|
// Now start generating a description of the differences.
|
||||||
|
std::stringstream out;
|
||||||
|
foreach (name, beforeOnly)
|
||||||
|
out << *name
|
||||||
|
<< " was deleted."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
foreach (name, afterOnly)
|
||||||
|
out << *name
|
||||||
|
<< " was set to '"
|
||||||
|
<< after.get (*name)
|
||||||
|
<< "'."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
foreach (name, beforeAtts)
|
||||||
|
if (*name != "uuid" &&
|
||||||
|
after.get (*name) != "" &&
|
||||||
|
before.get (*name) != after.get (*name))
|
||||||
|
out << *name
|
||||||
|
<< " was changed from '"
|
||||||
|
<< before.get (*name)
|
||||||
|
<< "' to '"
|
||||||
|
<< after.get (*name)
|
||||||
|
<< "'."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
// Can't just say nothing.
|
||||||
|
if (out.str ().length () == 0)
|
||||||
|
out << "No changes were made."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include "Task.h"
|
||||||
#include "../auto.h"
|
#include "../auto.h"
|
||||||
|
|
||||||
#ifndef min
|
#ifndef min
|
||||||
|
@ -58,7 +59,6 @@ std::string formatSecondsCompact (time_t);
|
||||||
std::string formatBytes (size_t);
|
std::string formatBytes (size_t);
|
||||||
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
|
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
|
||||||
const std::string uuid ();
|
const std::string uuid ();
|
||||||
int convertDuration (const std::string&);
|
|
||||||
std::string expandPath (const std::string&);
|
std::string expandPath (const std::string&);
|
||||||
|
|
||||||
#ifdef SOLARIS
|
#ifdef SOLARIS
|
||||||
|
@ -73,6 +73,7 @@ std::string expandPath (const std::string&);
|
||||||
bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
|
bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
|
||||||
bool slurp (const std::string&, std::string&, bool trimLines = false);
|
bool slurp (const std::string&, std::string&, bool trimLines = false);
|
||||||
void spit (const std::string&, const std::string&);
|
void spit (const std::string&, const std::string&);
|
||||||
|
std::string taskDiff (const Task&, const Task&);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue