Integration - TDB write operations
- TDB::gc rewritten. - TDB::commit fixed. - Corrected usage of handleRecurringTasks wrt TDB. - Unit tests for TDB.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,7 +5,7 @@ config.h.in
|
|||||||
config.status
|
config.status
|
||||||
src/.deps
|
src/.deps
|
||||||
src/Makefile
|
src/Makefile
|
||||||
*/task
|
*/*task
|
||||||
stamp-h1
|
stamp-h1
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
|||||||
@@ -57,16 +57,17 @@ Record::~Record ()
|
|||||||
//
|
//
|
||||||
// [ Att::composeF4 ... ] \n
|
// [ Att::composeF4 ... ] \n
|
||||||
//
|
//
|
||||||
std::string Record::composeF4 ()
|
std::string Record::composeF4 () const
|
||||||
{
|
{
|
||||||
std::string ff4 = "[";
|
std::string ff4 = "[";
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
foreach (att, (*this))
|
std::map <std::string, Att>::const_iterator it;
|
||||||
|
for (it = this->begin (); it != this->end (); ++it)
|
||||||
{
|
{
|
||||||
if (att->second.value () != "")
|
if (it->second.value () != "")
|
||||||
{
|
{
|
||||||
ff4 += (first ? "" : " ") + att->second.composeF4 ();
|
ff4 += (first ? "" : " ") + it->second.composeF4 ();
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ public:
|
|||||||
Record (const std::string&); // Copy constructor
|
Record (const std::string&); // Copy constructor
|
||||||
virtual ~Record (); // Destructor
|
virtual ~Record (); // Destructor
|
||||||
|
|
||||||
std::string composeF4 ();
|
std::string composeF4 () const;
|
||||||
std::string composeCSV ();
|
std::string composeCSV () const;
|
||||||
void parse (const std::string&);
|
void parse (const std::string&);
|
||||||
|
|
||||||
bool has (const std::string&) const;
|
bool has (const std::string&) const;
|
||||||
|
|||||||
94
src/TDB.cpp
94
src/TDB.cpp
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
@@ -53,7 +54,7 @@
|
|||||||
// | | |
|
// | | |
|
||||||
// | | +- TDB::add (T)
|
// | | +- TDB::add (T)
|
||||||
// | | |
|
// | | |
|
||||||
// | | +- TDB::update (T, T')
|
// | | +- TDB::update (T)
|
||||||
// | | |
|
// | | |
|
||||||
// | | +- TDB::commit
|
// | | +- TDB::commit
|
||||||
// | | write all
|
// | | write all
|
||||||
@@ -133,8 +134,11 @@ void TDB::unlock ()
|
|||||||
|
|
||||||
foreach (location, mLocations)
|
foreach (location, mLocations)
|
||||||
{
|
{
|
||||||
|
fflush (location->pending);
|
||||||
fclose (location->pending);
|
fclose (location->pending);
|
||||||
location->pending = NULL;
|
location->pending = NULL;
|
||||||
|
|
||||||
|
fflush (location->completed);
|
||||||
fclose (location->completed);
|
fclose (location->completed);
|
||||||
location->completed = NULL;
|
location->completed = NULL;
|
||||||
}
|
}
|
||||||
@@ -257,16 +261,16 @@ int TDB::loadCompleted (std::vector <Task>& tasks, Filter& filter)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// TODO Write to transaction log.
|
// TODO Write to transaction log.
|
||||||
// Note: mLocations[0] is where all tasks are written.
|
// Note: mLocations[0] is where all tasks are written.
|
||||||
void TDB::add (Task& task)
|
void TDB::add (const Task& task)
|
||||||
{
|
{
|
||||||
mNew.push_back (task);
|
mNew.push_back (task);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// TODO Write to transaction log.
|
// TODO Write to transaction log.
|
||||||
void TDB::update (Task& before, Task& after)
|
void TDB::update (const Task& task)
|
||||||
{
|
{
|
||||||
mModified.push_back (after);
|
mModified.push_back (task);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -308,11 +312,9 @@ int TDB::commit ()
|
|||||||
mNew.clear ();
|
mNew.clear ();
|
||||||
|
|
||||||
// Write out all pending.
|
// Write out all pending.
|
||||||
fseek (mLocations[0].pending, 0, SEEK_SET);
|
if (fseek (mLocations[0].pending, 0, SEEK_SET) == 0)
|
||||||
// TODO Do I need to truncate the file? Does file I/O even work that way
|
foreach (task, mPending)
|
||||||
// any more? I forget.
|
fputs (task->composeF4 ().c_str (), mLocations[0].pending);
|
||||||
foreach (task, mPending)
|
|
||||||
fputs (task->composeF4 ().c_str (), mLocations[0].pending);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return quantity;
|
return quantity;
|
||||||
@@ -337,50 +339,70 @@ void TDB::upgrade ()
|
|||||||
int TDB::gc ()
|
int TDB::gc ()
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
/*
|
|
||||||
// Read everything from the pending file.
|
|
||||||
std::vector <T> all;
|
|
||||||
allPendingT (all);
|
|
||||||
|
|
||||||
// A list of the truly pending tasks.
|
// Set up a second TDB.
|
||||||
std::vector <T> pending;
|
Filter filter;
|
||||||
|
TDB tdb;
|
||||||
|
tdb.location (mLocations[0].path);
|
||||||
|
tdb.lock ();
|
||||||
|
|
||||||
std::vector<T>::iterator it;
|
std::vector <Task> pending;
|
||||||
for (it = all.begin (); it != all.end (); ++it)
|
tdb.loadPending (pending, filter);
|
||||||
|
|
||||||
|
std::vector <Task> completed;
|
||||||
|
tdb.loadCompleted (completed, filter);
|
||||||
|
|
||||||
|
// Now move completed and deleted tasks from the pending list to the
|
||||||
|
// completed list. Isn't garbage collection easy?
|
||||||
|
foreach (task, pending)
|
||||||
{
|
{
|
||||||
// Some tasks stay in the pending file.
|
if (task->getStatus () == Task::completed ||
|
||||||
if (it->getStatus () == T::pending ||
|
task->getStatus () == Task::deleted)
|
||||||
it->getStatus () == T::recurring)
|
|
||||||
{
|
{
|
||||||
pending.push_back (*it);
|
completed.push_back (*task);
|
||||||
}
|
pending.erase (task);
|
||||||
|
|
||||||
// Others are transferred to the completed file.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
writeCompleted (*it);
|
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump all clean tasks into pending. But don't bother unless at least one
|
// No commit - all updates performed manually.
|
||||||
// task was transferred.
|
if (count > 0)
|
||||||
if (count)
|
{
|
||||||
overwritePending (pending);
|
if (fseek (tdb.mLocations[0].pending, 0, SEEK_SET) == 0)
|
||||||
*/
|
{
|
||||||
|
ftruncate (fileno (tdb.mLocations[0].pending), 0);
|
||||||
|
foreach (task, pending)
|
||||||
|
fputs (task->composeF4 ().c_str (), tdb.mLocations[0].pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek (tdb.mLocations[0].completed, 0, SEEK_SET) == 0)
|
||||||
|
{
|
||||||
|
ftruncate (fileno (tdb.mLocations[0].completed), 0);
|
||||||
|
foreach (task, completed)
|
||||||
|
fputs (task->composeF4 ().c_str (), tdb.mLocations[0].completed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close files.
|
||||||
|
tdb.unlock ();
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
FILE* TDB::openAndLock (const std::string& file)
|
FILE* TDB::openAndLock (const std::string& file)
|
||||||
{
|
{
|
||||||
|
// TODO Need provision here for read-only locations.
|
||||||
|
|
||||||
// Check for access.
|
// Check for access.
|
||||||
if (access (file.c_str (), F_OK | R_OK | W_OK))
|
bool exists = access (file.c_str (), F_OK) ? false : true;
|
||||||
throw std::string ("Task does not have the correct permissions for '") +
|
if (exists)
|
||||||
file + "'.";
|
if (access (file.c_str (), R_OK | W_OK))
|
||||||
|
throw std::string ("Task does not have the correct permissions for '") +
|
||||||
|
file + "'.";
|
||||||
|
|
||||||
// Open the file.
|
// Open the file.
|
||||||
FILE* in = fopen (file.c_str (), "r+");
|
FILE* in = fopen (file.c_str (), (exists ? "r+" : "w+"));
|
||||||
if (!in)
|
if (!in)
|
||||||
throw std::string ("Could not open '") + file + "'.";
|
throw std::string ("Could not open '") + file + "'.";
|
||||||
|
|
||||||
|
|||||||
10
src/TDB.h
10
src/TDB.h
@@ -53,11 +53,11 @@ public:
|
|||||||
int loadPending (std::vector <Task>&, Filter&);
|
int loadPending (std::vector <Task>&, Filter&);
|
||||||
int loadCompleted (std::vector <Task>&, Filter&);
|
int loadCompleted (std::vector <Task>&, Filter&);
|
||||||
|
|
||||||
void add (Task&); // Single task add to pending
|
void add (const Task&); // Single task add to pending
|
||||||
void update (Task&, Task&); // Single task update to pending
|
void update (const Task&); // Single task update to pending
|
||||||
int commit (); // Write out all tasks
|
int commit (); // Write out all tasks
|
||||||
void upgrade (); // Convert both files to FF4
|
void upgrade (); // Convert both files to FF4
|
||||||
int gc (); // Clean up pending
|
int gc (); // Clean up pending
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FILE* openAndLock (const std::string&);
|
FILE* openAndLock (const std::string&);
|
||||||
|
|||||||
23
src/Task.cpp
23
src/Task.cpp
@@ -40,6 +40,25 @@ Task::Task ()
|
|||||||
set ("uuid", uuid ());
|
set ("uuid", uuid ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Task::Task (const Task& other)
|
||||||
|
: Record (other)
|
||||||
|
, id (other.id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Task& Task::operator= (const Task& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
Record::operator= (other);
|
||||||
|
id = other.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Attempt an FF4 parse first, using Record::parse, and in the event of an error
|
// Attempt an FF4 parse first, using Record::parse, and in the event of an error
|
||||||
// try a legacy parse (F3, FF2). Note that FF1 is no longer supported.
|
// try a legacy parse (F3, FF2). Note that FF1 is no longer supported.
|
||||||
@@ -296,7 +315,7 @@ void Task::legacyParse (const std::string& line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
std::string Task::composeCSV ()
|
std::string Task::composeCSV () const
|
||||||
{
|
{
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
|
|
||||||
@@ -421,7 +440,7 @@ void Task::addTags (const std::vector <std::string>& tags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void Task::getTags (std::vector<std::string>& tags)
|
void Task::getTags (std::vector<std::string>& tags) const
|
||||||
{
|
{
|
||||||
split (tags, get ("tags"), ',');
|
split (tags, get ("tags"), ',');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,11 +36,13 @@ class Task : public Record
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Task (); // Default constructor
|
Task (); // Default constructor
|
||||||
|
Task (const Task&); // Copy constructor
|
||||||
|
Task& operator= (const Task&); // Assignment operator
|
||||||
Task (const std::string&); // Parse
|
Task (const std::string&); // Parse
|
||||||
~Task (); // Destructor
|
~Task (); // Destructor
|
||||||
|
|
||||||
void parse (const std::string&);
|
void parse (const std::string&);
|
||||||
std::string composeCSV ();
|
std::string composeCSV () const;
|
||||||
|
|
||||||
// Status values.
|
// Status values.
|
||||||
enum status {pending, completed, deleted, recurring /* , retired, deferred */};
|
enum status {pending, completed, deleted, recurring /* , retired, deferred */};
|
||||||
@@ -61,7 +63,7 @@ public:
|
|||||||
bool hasTag (const std::string&);
|
bool hasTag (const std::string&);
|
||||||
void addTag (const std::string&);
|
void addTag (const std::string&);
|
||||||
void addTags (const std::vector <std::string>&);
|
void addTags (const std::vector <std::string>&);
|
||||||
void getTags (std::vector<std::string>&);
|
void getTags (std::vector<std::string>&) const;
|
||||||
void removeTag (const std::string&);
|
void removeTag (const std::string&);
|
||||||
|
|
||||||
void getAnnotations (std::vector <Att>&) const;
|
void getAnnotations (std::vector <Att>&) const;
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ std::string handleAdd ()
|
|||||||
|
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.add (context.task);
|
context.tdb.add (context.task);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
|
|
||||||
return out.str ();
|
return out.str ();
|
||||||
@@ -97,6 +98,8 @@ std::string handleProjects ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
int quantity = context.tdb.loadPending (tasks, context.filter);
|
int quantity = context.tdb.loadPending (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
|
|
||||||
// Scan all the tasks for their project name, building a map using project
|
// Scan all the tasks for their project name, building a map using project
|
||||||
@@ -154,6 +157,8 @@ std::string handleTags ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
int quantity = context.tdb.loadPending (tasks, context.filter);
|
int quantity = context.tdb.loadPending (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
|
|
||||||
// Scan all the tasks for their project name, building a map using project
|
// Scan all the tasks for their project name, building a map using project
|
||||||
@@ -663,8 +668,9 @@ std::string handleExport ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.loadPending (tasks, context.filter);
|
context.tdb.loadPending (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
foreach (task, tasks)
|
foreach (task, tasks)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -86,9 +86,12 @@ std::string handleCustomReport (const std::string& report)
|
|||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
// TODO Include filter from custom report.
|
// TODO Include filter from custom report.
|
||||||
context.tdb.load (tasks, context.filter);
|
context.tdb.load (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
|
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
// Filter sequence.
|
||||||
|
context.filter.applySequence (tasks, context.sequence);
|
||||||
|
|
||||||
// Initialize colorization for subsequent auto colorization.
|
// Initialize colorization for subsequent auto colorization.
|
||||||
initializeColorRules ();
|
initializeColorRules ();
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ void gatherNextTasks (std::vector <Task>&, std::vector <int>&);
|
|||||||
void onChangeCallback ();
|
void onChangeCallback ();
|
||||||
|
|
||||||
// recur.cpp
|
// recur.cpp
|
||||||
void handleRecurrence ();
|
void handleRecurrence (std::vector <Task>&);
|
||||||
Date getNextRecurrence (Date&, std::string&);
|
Date getNextRecurrence (Date&, std::string&);
|
||||||
bool generateDueDates (Task&, std::vector <Date>&);
|
bool generateDueDates (Task&, std::vector <Date>&);
|
||||||
void updateRecurrenceMask (/*TDB&,*/ std::vector <Task>&, Task&);
|
void updateRecurrenceMask (/*TDB&,*/ std::vector <Task>&, Task&);
|
||||||
|
|||||||
@@ -271,8 +271,9 @@ std::string handleInfo ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.loadPending (tasks, context.filter);
|
context.tdb.loadPending (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
// Filter sequence.
|
// Filter sequence.
|
||||||
context.filter.applySequence (tasks, context.sequence);
|
context.filter.applySequence (tasks, context.sequence);
|
||||||
@@ -487,8 +488,9 @@ std::string handleReportSummary ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.load (tasks, context.filter);
|
context.tdb.load (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
// Generate unique list of project names from all pending tasks.
|
// Generate unique list of project names from all pending tasks.
|
||||||
std::map <std::string, bool> allProjects;
|
std::map <std::string, bool> allProjects;
|
||||||
@@ -651,8 +653,9 @@ std::string handleReportNext ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.loadPending (tasks, context.filter);
|
context.tdb.loadPending (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
// Restrict to matching subset.
|
// Restrict to matching subset.
|
||||||
std::vector <int> matching;
|
std::vector <int> matching;
|
||||||
@@ -814,8 +817,9 @@ std::string handleReportHistory ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.load (tasks, context.filter);
|
context.tdb.load (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
foreach (task, tasks)
|
foreach (task, tasks)
|
||||||
{
|
{
|
||||||
@@ -967,8 +971,9 @@ std::string handleReportGHistory ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.load (tasks, context.filter);
|
context.tdb.load (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
foreach (task, tasks)
|
foreach (task, tasks)
|
||||||
{
|
{
|
||||||
@@ -1157,8 +1162,9 @@ std::string handleReportTimesheet ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.load (tasks, context.filter);
|
context.tdb.load (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
// Just do this once.
|
// Just do this once.
|
||||||
int width = context.getWidth ();
|
int width = context.getWidth ();
|
||||||
@@ -1487,8 +1493,9 @@ std::string handleReportCalendar ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.loadPending (tasks, context.filter);
|
context.tdb.loadPending (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
// Find the oldest pending due date.
|
// Find the oldest pending due date.
|
||||||
Date oldest;
|
Date oldest;
|
||||||
@@ -1594,8 +1601,9 @@ std::string handleReportStats ()
|
|||||||
std::vector <Task> tasks;
|
std::vector <Task> tasks;
|
||||||
context.tdb.lock (context.config.get ("locking", true));
|
context.tdb.lock (context.config.get ("locking", true));
|
||||||
context.tdb.load (tasks, context.filter);
|
context.tdb.load (tasks, context.filter);
|
||||||
|
handleRecurrence (tasks);
|
||||||
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
// TODO handleRecurrence (tdb, tasks);
|
|
||||||
|
|
||||||
Date now;
|
Date now;
|
||||||
time_t earliest = time (NULL);
|
time_t earliest = time (NULL);
|
||||||
|
|||||||
@@ -32,88 +32,111 @@
|
|||||||
|
|
||||||
Context context;
|
Context context;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void get (std::vector <Task>& pending, std::vector <Task>& completed)
|
||||||
|
{
|
||||||
|
TDB tdb;
|
||||||
|
tdb.location (".");
|
||||||
|
tdb.lock ();
|
||||||
|
tdb.loadPending (pending, context.filter);
|
||||||
|
tdb.loadCompleted (completed, context.filter);
|
||||||
|
tdb.unlock ();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest t (38);
|
UnitTest t (22);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
// Remove any residual test file.
|
// Remove any residual test file.
|
||||||
unlink ("./pending.data");
|
unlink ("./pending.data");
|
||||||
unlink ("./completed.data");
|
unlink ("./completed.data");
|
||||||
|
|
||||||
// Try reading an empty database.
|
// Try reading an empty database.
|
||||||
|
Filter filter;
|
||||||
|
std::vector <Task> all;
|
||||||
|
std::vector <Task> pending;
|
||||||
|
std::vector <Task> completed;
|
||||||
|
get (pending, completed);
|
||||||
|
t.ok (pending.size () == 0, "TDB Read empty pending");
|
||||||
|
t.ok (completed.size () == 0, "TDB Read empty completed");
|
||||||
|
|
||||||
|
// Add without commit.
|
||||||
TDB tdb;
|
TDB tdb;
|
||||||
tdb.dataDirectory (".");
|
tdb.location (".");
|
||||||
std::vector <T> all;
|
tdb.lock ();
|
||||||
t.ok (!tdb.pendingT (all), "TDB::pendingT read empty db");
|
Task task ("[name:\"value\"]");
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
tdb.add (task);
|
||||||
t.ok (!tdb.allPendingT (all), "TDB::allPendingT read empty db");
|
tdb.unlock ();
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
|
||||||
t.ok (!tdb.completedT (all), "TDB::completedT read empty db");
|
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
|
||||||
t.ok (!tdb.allCompletedT (all), "TDB::allCompletedT read empty db");
|
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
|
||||||
|
|
||||||
// Add a new task.
|
pending.clear ();
|
||||||
T t1;
|
completed.clear ();
|
||||||
t1.setId (1);
|
get (pending, completed);
|
||||||
t1.setStatus (T::pending);
|
t.ok (pending.size () == 0, "TDB add -> no commit -> empty");
|
||||||
t1.setAttribute ("project", "p1");
|
t.ok (completed.size () == 0, "TDB add -> no commit -> empty");
|
||||||
t1.setDescription ("task 1");
|
|
||||||
t.diag (t1.compose ());
|
|
||||||
t.ok (tdb.addT (t1), "TDB::addT t1");
|
|
||||||
|
|
||||||
// Verify as above.
|
// Add with commit.
|
||||||
t.ok (tdb.pendingT (all), "TDB::pendingT read db");
|
tdb.lock ();
|
||||||
t.is ((int) all.size (), 1, "empty db");
|
tdb.add (task);
|
||||||
t.ok (tdb.allPendingT (all), "TDB::allPendingT read db");
|
tdb.commit ();
|
||||||
t.is ((int) all.size (), 1, "empty db");
|
tdb.unlock ();
|
||||||
t.ok (!tdb.completedT (all), "TDB::completedT read empty db");
|
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
|
||||||
t.ok (!tdb.allCompletedT (all), "TDB::allCompletedT read empty db");
|
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
|
||||||
|
|
||||||
// TODO Modify task.
|
get (pending, completed);
|
||||||
|
t.ok (pending.size () == 1, "TDB add -> commit -> saved");
|
||||||
|
t.is (pending[0].get ("name"), "value", "TDB load name=value");
|
||||||
|
t.is (pending[0].id, 1, "TDB load verification id=1");
|
||||||
|
t.ok (completed.size () == 0, "TDB add -> commit -> saved");
|
||||||
|
|
||||||
// Complete task.
|
// Update with commit.
|
||||||
t1.setStatus (T::completed);
|
tdb.lock ();
|
||||||
t.ok (tdb.modifyT (t1), "TDB::modifyT (completed) t1");;
|
pending.clear ();
|
||||||
t.ok (tdb.pendingT (all), "TDB::pendingT read db");
|
completed.clear ();
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
tdb.load (all, context.filter);
|
||||||
t.ok (tdb.allPendingT (all), "TDB::allPendingT read db");
|
all[0].set ("name", "value2");
|
||||||
t.is ((int) all.size (), 1, "empty db");
|
tdb.update (all[0]);
|
||||||
t.ok (!tdb.completedT (all), "TDB::completedT read empty db");
|
tdb.commit ();
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
tdb.unlock ();
|
||||||
t.ok (!tdb.allCompletedT (all), "TDB::allCompletedT read empty db");
|
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
|
||||||
|
|
||||||
t.is (tdb.gc (), 1, "TDB::gc");
|
pending.clear ();
|
||||||
t.ok (tdb.pendingT (all), "TDB::pendingT read empty db");
|
completed.clear ();
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
get (pending, completed);
|
||||||
t.ok (tdb.allPendingT (all), "TDB::allPendingT read empty db");
|
t.ok (all.size () == 1, "TDB update -> commit -> saved");
|
||||||
t.is ((int) all.size (), 0, "empty db");
|
t.is (all[0].get ("name"), "value2", "TDB load name=value2");
|
||||||
t.ok (tdb.completedT (all), "TDB::completedT read db");
|
t.is (all[0].id, 1, "TDB load verification id=1");
|
||||||
t.is ((int) all.size (), 1, "empty db");
|
|
||||||
t.ok (tdb.allCompletedT (all), "TDB::allCompletedT read db");
|
|
||||||
t.is ((int) all.size (), 1, "empty db");
|
|
||||||
|
|
||||||
// Add a new task.
|
// GC.
|
||||||
T t2;
|
tdb.lock ();
|
||||||
t2.setId (1);
|
all.clear ();
|
||||||
t2.setAttribute ("project", "p2");
|
tdb.loadPending (all, context.filter);
|
||||||
t2.setDescription ("task 2");
|
all[0].setStatus (Task::completed);
|
||||||
t.ok (tdb.addT (t2), "TDB::addT t2");
|
tdb.update (all[0]);
|
||||||
|
Task t2 ("[foo:\"bar\" status:\"pending\"]");
|
||||||
|
tdb.add (t2);
|
||||||
|
tdb.commit ();
|
||||||
|
tdb.unlock ();
|
||||||
|
|
||||||
// Delete task.
|
pending.clear ();
|
||||||
t2.setStatus (T::deleted);
|
completed.clear ();
|
||||||
t.ok (tdb.modifyT (t2), "TDB::modifyT (deleted) t2");
|
get (pending, completed);
|
||||||
|
t.is (pending.size (), (size_t)2, "TDB before gc pending #2");
|
||||||
|
t.is (pending[0].id, 1, "TDB before gc pending id 1");
|
||||||
|
t.is (pending[0].getStatus (), Task::completed, "TDB before gc pending status completed");
|
||||||
|
t.is (pending[1].id, 2, "TDB before gc pending id 2");
|
||||||
|
t.is (pending[1].getStatus (), Task::pending, "TDB before gc pending status pending");
|
||||||
|
t.is (completed.size (), (size_t)0, "TDB before gc completed 0");
|
||||||
|
|
||||||
// GC the files.
|
tdb.gc ();
|
||||||
t.is (tdb.gc (), 1, "1 <- TDB::gc");
|
|
||||||
*/
|
pending.clear ();
|
||||||
|
completed.clear ();
|
||||||
|
get (pending, completed);
|
||||||
|
t.is (pending.size (), (size_t)1, "TDB after gc pending #1");
|
||||||
|
t.is (pending[0].id, 1, "TDB after gc pending id 2");
|
||||||
|
t.is (pending[0].getStatus (), Task::pending, "TDB after gc pending status pending");
|
||||||
|
t.is (completed.size (), (size_t)1, "TDB after gc completed #1");
|
||||||
|
t.is (completed[0].getStatus (), Task::completed, "TDB after gc completed status completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (std::string& error)
|
catch (std::string& error)
|
||||||
@@ -128,8 +151,10 @@ int main (int argc, char** argv)
|
|||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
unlink ("./pending.data");
|
unlink ("./pending.data");
|
||||||
unlink ("./completed.data");
|
unlink ("./completed.data");
|
||||||
|
*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user