diff --git a/src/Lisp.cpp b/src/Lisp.cpp new file mode 100644 index 000000000..11f2b1a7b --- /dev/null +++ b/src/Lisp.cpp @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 "Lisp.h" + +//////////////////////////////////////////////////////////////////////////////// +Lisp::Lisp () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Lisp::~Lisp () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Tree* Lisp::parse (const std::string& input) +{ + Tree* root = new Tree ("root"); + if (root) + { + Nibbler n (input); + parseNode (root, n); + } + + return root; +} + +//////////////////////////////////////////////////////////////////////////////// +// Grammar +// node ::= '(' list ')' +// list ::= item [[space item] ...] +// item ::= word | node +void Lisp::parseNode (Tree* parent, Nibbler& n) +{ + // Work on a stack-based copy, to allow backtracking. + Nibbler attempt (n); + + if (attempt.skip ('(')) + { + Tree* b = new Tree (""); + parent->addBranch (b); + + parseList (b, attempt); + if (attempt.skip (')')) + { + n = attempt; + return; + } + } + + throw std::string ("Error: malformed node"); +} + +//////////////////////////////////////////////////////////////////////////////// +void Lisp::parseList (Tree* parent, Nibbler& n) +{ + // Work on a stack-based copy, to allow backtracking. + Nibbler attempt (n); + + parseItem (parent, attempt); + + while (attempt.skip (' ')) + parseItem (parent, attempt); + + n = attempt; +} + +//////////////////////////////////////////////////////////////////////////////// +void Lisp::parseItem (Tree* parent, Nibbler& n) +{ + // Work on a stack-based copy, to allow backtracking. + Nibbler attempt (n); + + if (attempt.next () == '(') + parseNode (parent, attempt); + else + parseWord (parent, attempt); + + n = attempt; + return; +} + +//////////////////////////////////////////////////////////////////////////////// +// A word is any group of non-whitespace followed by a space or ')'. +void Lisp::parseWord (Tree* parent, Nibbler& n) +{ + // Work on a stack-based copy, to allow backtracking. + Nibbler attempt (n); + + std::string word; + if (attempt.getUntilOneOf (" )", word)) + { + parent->tag (word); + n = attempt; + return; + } + + throw std::string ("Error: failed to parse word"); +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Lisp.h b/src/Lisp.h new file mode 100644 index 000000000..d86c428b4 --- /dev/null +++ b/src/Lisp.h @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_LISP +#define INCLUDED_LISP + +#include +#include "Tree.h" +#include "Nibbler.h" + +class Lisp +{ +public: + Lisp (); + Lisp (const Lisp&); + Lisp& operator= (const Lisp&); + ~Lisp (); + + Tree* parse (const std::string&); + +private: + void parseNode (Tree*, Nibbler&); + void parseList (Tree*, Nibbler&); + void parseItem (Tree*, Nibbler&); + void parseWord (Tree*, Nibbler&); +}; + +#endif + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/Makefile.am b/src/Makefile.am index 9b59824d7..fbd5fb679 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,17 +1,20 @@ bin_PROGRAMS = task task_SHORTNAME = t -task_SOURCES = API.cpp Att.cpp Cmd.cpp Color.cpp Config.cpp Context.cpp \ - Date.cpp Directory.cpp Duration.cpp File.cpp Filter.cpp \ - Grid.cpp Hooks.cpp Keymap.cpp Location.cpp Nibbler.cpp \ - Path.cpp Permission.cpp Record.cpp Sequence.cpp \ - StringTable.cpp Subst.cpp TDB.cpp Table.cpp Task.cpp \ - Taskmod.cpp Transport.cpp TransportSSH.cpp Timer.cpp \ - command.cpp custom.cpp dependency.cpp \ - edit.cpp export.cpp import.cpp interactive.cpp main.cpp \ - recur.cpp report.cpp rules.cpp rx.cpp text.cpp util.cpp \ - API.h Att.h Cmd.h Color.h Config.h Context.h Date.h \ - Directory.h Duration.h File.h Filter.h Grid.h Hooks.h Keymap.h \ - Location.h Nibbler.h Path.h Permission.h Record.h Sequence.h \ - StringTable.h Subst.h TDB.h Table.h Task.h Taskmod.h Timer.h \ Transport.h TransportSSH.h i18n.h main.h text.h util.h rx.h +task_SOURCES = API.cpp API.h Att.cpp Att.h Cmd.cpp Cmd.h Color.cpp Color.h \ + Config.cpp Config.h Context.cpp Context.h Date.cpp Date.h \ + Directory.cpp Directory.h Duration.cpp Duration.h File.cpp \ + File.h Filter.cpp Filter.h Grid.cpp Grid.h Hooks.cpp Hooks.h \ + Keymap.cpp Keymap.h Lisp.cpp Lisp.h Location.cpp Location.h \ + Nibbler.cpp Nibbler.h Path.cpp Path.h Permission.cpp \ + Permission.h Record.cpp Record.h Rectangle.cpp Rectangle.h \ + Sensor.cpp Sensor.h Sequence.cpp Sequence.h StringTable.cpp \ + StringTable.h Subst.cpp Subst.h TDB.cpp TDB.h Table.cpp Table.h \ + Task.cpp Task.h Taskmod.cpp Taskmod.h Thread.cpp Thread.h \ + Timer.cpp Timer.h Transport.cpp Transport.h TransportSSH.cpp \ + TransportSSH.h Tree.cpp Tree.h command.cpp custom.cpp \ + dependency.cpp edit.cpp export.cpp i18n.h import.cpp \ + interactive.cpp main.cpp main.h recur.cpp report.cpp rules.cpp \ + rx.cpp rx.h text.cpp text.h util.cpp util.h task_CPPFLAGS=$(LUA_CFLAGS) task_LDFLAGS=$(LUA_LFLAGS) + diff --git a/src/Rectangle.cpp b/src/Rectangle.cpp new file mode 100644 index 000000000..72509af0b --- /dev/null +++ b/src/Rectangle.cpp @@ -0,0 +1,126 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 "Rectangle.h" + +//////////////////////////////////////////////////////////////////////////////// +Rectangle::Rectangle () +: left (0) +, top (0) +, width (0) +, height (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Rectangle::Rectangle (int l, int t, int w, int h) +{ + left = l; + top = t; + width = w; + height = h; +} + +//////////////////////////////////////////////////////////////////////////////// +Rectangle::Rectangle (const Rectangle& other) +{ + *this = other; +} + +//////////////////////////////////////////////////////////////////////////////// +Rectangle& Rectangle::operator= (const Rectangle& other) +{ + if (this != &other) + { + left = other.left; + top = other.top; + width = other.width; + height = other.height; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Rectangle::operator== (const Rectangle& other) const +{ + if (left == other.left && + top == other.top && + width == other.width && + height == other.height) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Rectangle::operator!= (const Rectangle& other) const +{ + return !(*this == other); +} + +//////////////////////////////////////////////////////////////////////////////// +// Algorithm: +// Find the conditions at which the rectangles do not intersect and then +// negate the result. +bool Rectangle::intersects (const Rectangle& other) const +{ + return ! (other.left > left + width - 1 || + other.left + other.width - 1 < left || + other.top > top + height - 1 || + other.top + other.height - 1 < top); +} + +/////////////////////////////////////////////////////////////////////////////// +bool Rectangle::contains (const Rectangle& other) const +{ + if (other.left >= left && + other.left + other.width <= left + width && + other.top >= top && + other.top + other.height <= top + height) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// Adjacent rectangles must not intersect, but must have at top/bottom, +// bottom/top, left/right or right/left adjacency. +bool Rectangle::adjacentTo (const Rectangle& other) const +{ + if (! this->intersects (other)) + if (top + height == other.top || + top == other.top + other.height || + left + width == other.left || + left == other.left + other.width) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/Rectangle.h b/src/Rectangle.h new file mode 100644 index 000000000..f04510b43 --- /dev/null +++ b/src/Rectangle.h @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_RECTANGLE +#define INCLUDED_RECTANGLE + +class Rectangle +{ +public: + Rectangle (); + Rectangle (int, int, int, int); + Rectangle (const Rectangle&); + Rectangle& operator= (const Rectangle&); + + bool operator== (const Rectangle&) const; + bool operator!= (const Rectangle&) const; + bool intersects (const Rectangle&) const; + bool contains (const Rectangle&) const; + bool adjacentTo (const Rectangle&) const; + +public: + int left; + int top; + int width; + int height; +}; + +#endif + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/Sensor.cpp b/src/Sensor.cpp new file mode 100644 index 000000000..8a616bb20 --- /dev/null +++ b/src/Sensor.cpp @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2010, Paul Beckingham, Federico Hernandez. +// 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 "Sensor.h" + +//////////////////////////////////////////////////////////////////////////////// +Sensor::Sensor () +: _changed (false) +, _file ("") +, _was (0) +, _is (0) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Sensor::~Sensor () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +bool Sensor::changed () +{ + _is = getModification (); + if (_is != _was) + _changed = true; + + return _changed; +} + +//////////////////////////////////////////////////////////////////////////////// +void Sensor::reset () +{ + _changed = false; + _was = _is; +} + +//////////////////////////////////////////////////////////////////////////////// +/* +void Sensor::fileCreation (const std::string&) +{ +} +*/ + +//////////////////////////////////////////////////////////////////////////////// +void Sensor::fileModification (const std::string& file) +{ + _file = file; + _was = getModification (); +} + +//////////////////////////////////////////////////////////////////////////////// +/* +void Sensor::fileDeletion (const std::string&) +{ +} +*/ + +//////////////////////////////////////////////////////////////////////////////// +time_t Sensor::getModification () +{ + struct stat s = {0}; + if (0 == stat (_file.c_str (), &s)) + return s.st_mtime; + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Sensor.h b/src/Sensor.h new file mode 100644 index 000000000..836aa4632 --- /dev/null +++ b/src/Sensor.h @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2010, Paul Beckingham, Federico Hernandez. +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_SENSOR +#define INCLUDED_SENSOR + +#include + +class Sensor +{ +public: + Sensor (); + ~Sensor (); + Sensor (const Sensor&); + Sensor& operator= (const Sensor&); + + bool changed (); + void reset (); + +// void fileCreation (const std::string&); + void fileModification (const std::string&); +// void fileDeletion (const std::string&); + +private: + time_t getModification (); + +private: + bool _changed; + std::string _file; + time_t _was; + time_t _is; +}; + +#endif + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Thread.cpp b/src/Thread.cpp new file mode 100644 index 000000000..f2dd7bfae --- /dev/null +++ b/src/Thread.cpp @@ -0,0 +1,79 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 + +//////////////////////////////////////////////////////////////////////////////// +Thread::Thread () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Thread::~Thread () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +int Thread::start (void* inArg) +{ + mArg = inArg; + return pthread_create (&mTID, NULL, (void*(*)(void*)) Thread::entryPoint, (void*) this); +} + +//////////////////////////////////////////////////////////////////////////////// +void Thread::wait () +{ + pthread_join (mTID, NULL); +} + +//////////////////////////////////////////////////////////////////////////////// +void Thread::cancel () +{ + pthread_cancel (mTID); +} + +//////////////////////////////////////////////////////////////////////////////// +void Thread::detach () +{ + pthread_detach (mTID); +} + +//////////////////////////////////////////////////////////////////////////////// +void* Thread::entryPoint (void* inThis) +{ + Thread* p = (Thread*) inThis; + p->execute (p->arg ()); + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +void* Thread::arg () +{ + return mArg; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Thread.h b/src/Thread.h new file mode 100644 index 000000000..8e5e3e483 --- /dev/null +++ b/src/Thread.h @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_THREAD +#define INCLUDED_THREAD + +#include + +class Thread +{ +public: + Thread (); + virtual ~Thread (); + int start (void* arg); + void wait (); + void cancel (); + void detach (); + void* arg (); + +protected: + static void* entryPoint (void*); + virtual void execute (void*) = 0; + +private: + pthread_t mTID; + void* mArg; +}; + +#endif + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Tree.cpp b/src/Tree.cpp new file mode 100644 index 000000000..d4bfeefed --- /dev/null +++ b/src/Tree.cpp @@ -0,0 +1,332 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2010, Paul Beckingham, Federico Hernandez. +// 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 "text.h" +#include "Tree.h" + +//////////////////////////////////////////////////////////////////////////////// +// - Tree, Branch and Node are synonymous. +// - A Tree may contain any number of branches. +// - A Branch may contain any number of name/value pairs, unique by name. +// - The destructor will delete all branches recursively. +// - Tree::enumerate is a snapshot, and is invalidated by modification. +// - Branch sequence is preserved. +Tree::Tree (const std::string& name) +: _trunk (NULL) +, _name (name) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Tree::~Tree () +{ + for (std::vector ::iterator i = _branches.begin (); + i != _branches.end (); + ++i) + delete *i; +} + +//////////////////////////////////////////////////////////////////////////////// +Tree::Tree (const Tree& other) +{ + throw "Unimplemented Tree::Tree (Tree&)"; +} + +//////////////////////////////////////////////////////////////////////////////// +Tree& Tree::operator= (const Tree& other) +{ + throw "Unimplemented Tree::operator= ()"; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Tree* Tree::operator[] (const int branch) +{ + if (branch < 0 || + branch > (int) _branches.size () - 1) + throw "Tree::operator[] out of range"; + + return _branches[branch]; +} + +//////////////////////////////////////////////////////////////////////////////// +void Tree::addBranch (Tree* branch) +{ + branch->_trunk = this; + _branches.push_back (branch); +} + +//////////////////////////////////////////////////////////////////////////////// +void Tree::removeBranch (Tree* branch) +{ + for (std::vector ::iterator i = _branches.begin (); + i != _branches.end (); + ++i) + { + if (*i == branch) + { + _branches.erase (i); + return; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +void Tree::replaceBranch (Tree* from, Tree* to) +{ + for (unsigned int i = 0; i < _branches.size (); ++i) + { + if (_branches[i] == from) + { + to->_trunk = this; + _branches[i] = to; + return; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +int Tree::branches () +{ + return _branches.size (); +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Tree::name () const +{ + return _name; +} + +//////////////////////////////////////////////////////////////////////////////// +// Accessor for attributes. +void Tree::attribute (const std::string& name, const std::string& value) +{ + _attributes[name] = value; +} + +//////////////////////////////////////////////////////////////////////////////// +// Accessor for attributes. +void Tree::attribute (const std::string& name, const int value) +{ + std::stringstream s; + s << value; + _attributes[name] = s.str (); +} + +//////////////////////////////////////////////////////////////////////////////// +// Accessor for attributes. +std::string Tree::attribute (const std::string& name) +{ + // Prevent autovivification. + std::map::iterator i = _attributes.find (name); + if (i != _attributes.end ()) + return i->second; + + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +void Tree::removeAttribute (const std::string& name) +{ + _attributes.erase (name); +} + +//////////////////////////////////////////////////////////////////////////////// +int Tree::attributes () const +{ + return _attributes.size (); +} + +//////////////////////////////////////////////////////////////////////////////// +std::vector Tree::allAttributes () const +{ + std::vector names; + std::map ::const_iterator it; + for (it = _attributes.begin (); it != _attributes.end (); ++it) + names.push_back (it->first); + + return names; +} + +//////////////////////////////////////////////////////////////////////////////// +// Recursively completes a list of Tree* objects, left to right, depth first. +// The reason for the depth-first enumeration is that a client may wish to +// traverse the tree and delete nodes. With a depth-first iteration, this is a +// safe mechanism, and a node pointer will never be dereferenced after it has +// been deleted. +void Tree::enumerate (std::vector & all) const +{ + for (std::vector ::const_iterator i = _branches.begin (); + i != _branches.end (); + ++i) + { + (*i)->enumerate (all); + all.push_back (*i); + } +} + +//////////////////////////////////////////////////////////////////////////////// +Tree* Tree::parent () const +{ + return _trunk; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Tree::hasTag (const std::string& tag) const +{ + if (std::find (_tags.begin (), _tags.end (), tag) != _tags.end ()) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +void Tree::tag (const std::string& tag) +{ + if (! hasTag (tag)) + _tags.push_back (tag); +} + +//////////////////////////////////////////////////////////////////////////////// +int Tree::tags () const +{ + return _tags.size (); +} + +//////////////////////////////////////////////////////////////////////////////// +std::vector Tree::allTags () const +{ + return _tags; +} + +//////////////////////////////////////////////////////////////////////////////// +int Tree::count () const +{ + int total = 1; // this one. + + for (std::vector ::const_iterator i = _branches.begin (); + i != _branches.end (); + ++i) + { + // Recurse and count the branches. + total += (*i)->count (); + } + + return total; +} + +//////////////////////////////////////////////////////////////////////////////// +Tree* Tree::find (const std::string& path) +{ + std::vector elements; + split (elements, path, '/'); + + // Must start at the trunk. + Tree* cursor = this; + std::vector ::iterator it = elements.begin (); + if (cursor->name () != *it) + return NULL; + + // Perhaps the trunk is what is needed? + if (elements.size () == 1) + return this; + + // Now look for the next branch. + for (++it; it != elements.end (); ++it) + { + bool found = false; + + // If the cursor has a branch that matches *it, proceed. + for (int i = 0; i < cursor->branches (); ++i) + { + if ((*cursor)[i]->name () == *it) + { + cursor = (*cursor)[i]; + found = true; + break; + } + } + + if (!found) + return NULL; + } + + return cursor; +} + +//////////////////////////////////////////////////////////////////////////////// +void Tree::dumpNode (Tree* t, int depth) +{ + // Dump node + for (int i = 0; i < depth; ++i) + std::cout << " "; + + std::cout << t << " \033[1m" << t->name () << "\033[0m"; + + // Dump attributes. + std::string atts; + std::vector attributes = t->allAttributes (); + std::vector ::iterator it; + for (it = attributes.begin (); it != attributes.end (); ++it) + { + if (it != attributes.begin ()) + atts += " "; + + atts += *it + "='\033[33m" + t->attribute (*it) + "\033[0m'"; + } + + if (atts.length ()) + std::cout << " " << atts; + + // Dump tags. + std::string tags; + std::vector allTags = t->allTags (); + for (it = allTags.begin (); it != allTags.end (); ++it) + tags += (tags.length () ? " " : "") + *it; + + if (tags.length ()) + std::cout << " \033[32m" << tags << "\033[0m"; + + std::cout << std::endl; + + // Recurse for branches. + for (int i = 0; i < t->branches (); ++i) + dumpNode ((*t)[i], depth + 1); +} + +//////////////////////////////////////////////////////////////////////////////// +void Tree::dump () +{ + std::cout << "Tree (" << count () << " nodes)" << std::endl; + dumpNode (this, 1); +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/Tree.h b/src/Tree.h new file mode 100644 index 000000000..236e1e809 --- /dev/null +++ b/src/Tree.h @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2010, Paul Beckingham, Federico Hernandez. +// 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 +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_TREE +#define INCLUDED_TREE + +#include +#include +#include + +class Tree; + +class Tree +{ +public: + Tree (const std::string&); + ~Tree (); + Tree (const Tree&); + Tree& operator= (const Tree&); + Tree* operator[] (const int); + + void addBranch (Tree*); + void removeBranch (Tree*); + void replaceBranch (Tree*, Tree*); + int branches (); + + std::string name () const; + void attribute (const std::string&, const std::string&); + void attribute (const std::string&, const int); + std::string attribute (const std::string&); + void removeAttribute (const std::string&); + int attributes () const; + std::vector allAttributes () const; + + bool hasTag (const std::string&) const; + void tag (const std::string&); + int tags () const; + std::vector allTags () const; + + void enumerate (std::vector & all) const; + Tree* parent () const; + + int count () const; + + Tree* find (const std::string&); + + void dump (); + +private: + void dumpNode (Tree*, int); + +private: + Tree* _trunk; // Parent. + std::string _name; // Name. + std::vector _branches; // Children. + std::map _attributes; // Attributes (name->value). + std::vector _tags; // Tags (tag, tag ...). +}; + +#endif + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/tests/.gitignore b/src/tests/.gitignore index 6f45bc593..55bf6d54b 100644 --- a/src/tests/.gitignore +++ b/src/tests/.gitignore @@ -1,26 +1,31 @@ -t.t -t.benchmark.t -tdb.t -date.t -duration.t -text.t -autocomplete.t -seq.t -att.t -record.t -stringtable.t -nibbler.t -subst.t -filt.t -cmd.t -config.t -util.t -color.t -list.t -path.t -file.t -directory.t -grid.t -rx.t -taskmod.t *.log +att.t +autocomplete.t +cmd.t +color.t +config.t +date.t +directory.t +duration.t +file.t +filt.t +grid.t +lisp.t +list.t +nibbler.t +path.t +record.t +rectangle.t +rx.t +sensor.t +seq.t +stringtable.t +subst.t +t.benchmark.t +t.t +taskmod.t +tdb.t +text.t +tree.t +tree2.t +util.t diff --git a/src/tests/Makefile b/src/tests/Makefile index 3e215f126..3d18bf960 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,6 +1,7 @@ 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 taskmod.t + cmd.t util.t color.t list.t path.t file.t directory.t grid.t rx.t \ + taskmod.t sensor.t rectangle.t tree.t tree2.t lisp.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 \ @@ -12,7 +13,8 @@ OBJECTS = ../t-TDB.o ../t-Task.o ../t-text.o ../t-Date.o ../t-Table.o \ ../t-export.o ../t-import.o ../t-edit.o ../t-Timer.o \ ../t-Permission.o ../t-Path.o ../t-File.o ../t-Directory.o \ ../t-Hooks.o ../t-API.o ../t-rx.o ../t-Taskmod.o ../t-dependency.o \ - ../t-Transport.o ../t-TransportSSH.o + ../t-Transport.o ../t-TransportSSH.o ../t-Sensor.o ../t-Thread.o \ + ../t-Lisp.o ../t-Rectangle.o ../t-Tree.o all: $(PROJECT) @@ -103,3 +105,18 @@ rx.t: rx.t.o $(OBJECTS) test.o taskmod.t: taskmod.t.o $(OBJECTS) test.o g++ taskmod.t.o $(OBJECTS) test.o $(LFLAGS) -o taskmod.t +lisp.t: lisp.t.o $(OBJECTS) test.o + g++ lisp.t.o $(OBJECTS) test.o $(LFLAGS) -o lisp.t + +rectangle.t: rectangle.t.o $(OBJECTS) test.o + g++ rectangle.t.o $(OBJECTS) test.o $(LFLAGS) -o rectangle.t + +sensor.t: sensor.t.o $(OBJECTS) test.o + g++ sensor.t.o $(OBJECTS) test.o $(LFLAGS) -o sensor.t + +tree.t: tree.t.o $(OBJECTS) test.o + g++ tree.t.o $(OBJECTS) test.o $(LFLAGS) -o tree.t + +tree2.t: tree2.t.o $(OBJECTS) test.o + g++ tree2.t.o $(OBJECTS) test.o $(LFLAGS) -o tree2.t + diff --git a/src/tests/lisp.t.cpp b/src/tests/lisp.t.cpp new file mode 100644 index 000000000..a5f6fc7ca --- /dev/null +++ b/src/tests/lisp.t.cpp @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 "main.h" +#include "test.h" +#include "Context.h" +#include "Lisp.h" + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest test (6); + + // (one) + // t -> "one" (no tags) + // -> no child nodes + Lisp l; + Tree* t = l.parse ("(one)"); + // TODO When tegelsten/Tree is merged in, uncomment this. + t->dump (); + test.is (t->branches (), 1, "(one) -> 1 node under root"); + test.is ((*t)[0]->tags (), 0, "(one) -> 0 tags"); + test.is ((*t)[0]->branches (), 0, "(one) -> 0 child nodes"); + delete t; + + // (one two) + // t -> "one" (tag: "two") + // -> no child nodes + t = l.parse ("(one two)"); + // TODO When tegelsten/Tree is merged in, uncomment this. + t->dump (); + test.is (t->branches (), 1, "(one two) -> 1 node under root"); + test.is ((*t)[0]->tags (), 1, "(one) -> 1 tag"); + test.is ((*t)[0]->branches (), 0, "(one two) -> 0 child nodes"); + delete t; + + return 0; +} + diff --git a/src/tests/rectangle.t.cpp b/src/tests/rectangle.t.cpp new file mode 100644 index 000000000..da007aad5 --- /dev/null +++ b/src/tests/rectangle.t.cpp @@ -0,0 +1,162 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 "Context.h" +#include "Rectangle.h" +#include "text.h" +#include "test.h" + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest t (34); + + // . . . . . . + // . 0 0 0 . . + // . 0 0 0 . . + // . . . . . . + // . . . . . . + // . . . . . . + Rectangle r0 (1, 1, 3, 2); + + // . . . . . . + // . . . . . . + // . . . 1 1 . + // . . . 1 1 . + // . . . . . . + // . . . . . . + Rectangle r1 (3, 2, 2, 2); + + // . . 2 . . . + // . . 2 . . . + // . . 2 . . . + // . . 2 . . . + // . . 2 . . . + // . . 2 . . . + Rectangle r2 (2, 0, 1, 6); + + // . . . . . . + // . 3 . . . . + // . . . . . . + // . . . . . . + // . . . . . . + // . . . . . . + Rectangle r3 (1, 1, 1, 1); + + // . . . . . . + // . 4 4 4 . . + // . 4 4 4 . . + // . . . . . . + // . . . . . . + // . . . . . . + Rectangle r4 (1, 1, 3, 2); + + // 5 5 5 5 5 5 + // 5 5 5 5 5 5 + // 5 5 5 5 5 5 + // 5 5 5 5 5 5 + // 5 5 5 5 5 5 + // 5 5 5 5 5 5 + Rectangle r5 (0, 0, 6, 6); + + // . . . . . . + // . . . . . . + // . . . . . . + // 6 6 . . . . + // . . . . . . + // . . . . . . + Rectangle r6 (0, 3, 2, 1); + + // . . . . . . + // . . . . . . + // . . . . . . + // . . . . . . + // . . . . 7 7 + // . . . . 7 7 + Rectangle r7 (4, 4, 2, 2); + + // . . . . . . + // . . . . . . + // 8 8 . . . . + // 8 8 . . . . + // . . . . . . + // . . . . . . + Rectangle r8 (0, 2, 2, 2); + + t.ok (r0.intersects (r1), "r0.intersects (r1)"); + t.ok (r0.intersects (r2), "r0.intersects (r2)"); + t.ok (r0.intersects (r3), "r0.intersects (r3)"); + t.ok (r0.intersects (r4), "r0.intersects (r4)"); + t.ok (r0.intersects (r5), "r0.intersects (r5)"); + t.ok (!r0.intersects (r6), "!r0.intersects (r6)"); + t.ok (!r0.intersects (r7), "!r0.intersects (r7)"); + t.ok (r0.intersects (r8), "r0.intersects (r8)"); + + t.ok (r1.intersects (r0), "r1.intersects (r0)"); + t.ok (r2.intersects (r0), "r2.intersects (r0)"); + t.ok (r3.intersects (r0), "r3.intersects (r0)"); + t.ok (r4.intersects (r0), "r4.intersects (r0)"); + t.ok (r5.intersects (r0), "r5.intersects (r0)"); + t.ok (!r6.intersects (r0), "!r6.intersects (r0)"); + t.ok (!r7.intersects (r0), "!r8.intersects (r0)"); + t.ok (r8.intersects (r0), "r8.intersects (r0)"); + + // 2:0,0,4,12 does not overlap 1:0,10,12,4 + Rectangle rBug1 (0, 0, 4, 12); + Rectangle rBug2 (0, 10, 12, 4); + t.ok (rBug1.intersects (rBug2), "rBug1.intersects (rBug2)"); + t.ok (rBug2.intersects (rBug1), "rBug2.intersects (rBug1)"); + + t.ok (r5.contains (r0), "r5.contains (r0)"); + t.ok (r5.contains (r1), "r5.contains (r1)"); + t.ok (r5.contains (r2), "r5.contains (r2)"); + t.ok (r5.contains (r3), "r5.contains (r3)"); + t.ok (r5.contains (r4), "r5.contains (r4)"); + t.ok (r5.contains (r6), "r5.contains (r6)"); + t.ok (r5.contains (r7), "r5.contains (r7)"); + t.ok (r5.contains (r8), "r5.contains (r8)"); + t.ok (r0.contains (r3), "r0.contains (r3)"); + t.ok (!r0.contains (r5), "!r0.contains (r5)"); + + t.ok (r0 == r4, "r0 == r4"); + t.ok (r0 != r1, "r0 != r1"); + + Rectangle rX = r0; + t.ok (rX == r0, "rX == r0"); + + Rectangle rY (r0); + t.ok (rY == r0, "rY == r0"); + + t.notok (r0.adjacentTo (r1), "r0 not adjacent to r1"); + t.ok (r1.adjacentTo (r2), "r1 is adjacent to r2"); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/tests/sensor.t.cpp b/src/tests/sensor.t.cpp new file mode 100644 index 000000000..4a0cac280 --- /dev/null +++ b/src/tests/sensor.t.cpp @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2010, Paul Beckingham, Federico Hernandez, Federico Hernandez. +// 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 "Context.h" +#include "Sensor.h" +#include "test.h" + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest ut (7); + + // Make sure there is no file. + unlink ("./sensor.foo"); + + // Create sensor for missing file. + Sensor s; + s.fileModification ("./sensor.foo"); + ut.ok (!s.changed (), "file not yet changed"); + + // Create the file. + std::ofstream one ("./sensor.foo", std::ios_base::out | std::ios_base::app); + if (one.good ()) + { + one << "touch" << std::endl; + one.close (); + } + + // Should register the change, so reset. + ut.ok (s.changed (), "file changed"); + s.reset (); + ut.ok (!s.changed (), "file not yet changed"); + + // Wait a little, then modify the file. + ut.diag ("sleep 2"); + sleep (2); + std::ofstream two ("./sensor.foo", std::ios_base::out | std::ios_base::app); + if (two.good ()) + { + two << "touch" << std::endl; + two.close (); + } + + ut.ok (s.changed (), "file changed"); + ut.ok (s.changed (), "file still changed"); + s.reset (); + ut.ok (!s.changed (), "file not changed again"); + + unlink ("./sensor.foo"); + ut.ok (s.changed (), "file changed"); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/tests/tree.t.cpp b/src/tests/tree.t.cpp new file mode 100644 index 000000000..3686c6133 --- /dev/null +++ b/src/tests/tree.t.cpp @@ -0,0 +1,82 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 "Context.h" +#include "Tree.h" +#include "test.h" + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest ut (8); + + // Construct tree as shown above. + Tree t (""); + + Tree* b = new Tree (""); + b->attribute ("name", "c1"); + b->tag ("tag"); + t.addBranch (b); + + b = new Tree (""); + b->attribute ("name", "c2"); + t.addBranch (b); + + b = new Tree (""); + b->attribute ("name", "c3"); + t.addBranch (b); + + Tree* l = new Tree (""); + l->attribute ("name", "c4"); + + b->addBranch (l); + + // Iterate over tree. + std::vector all; + t.enumerate (all); + ut.is (all[0]->attribute ("name"), "c1", "c1"); + ut.is (all[1]->attribute ("name"), "c2", "c2"); + ut.is (all[2]->attribute ("name"), "c4", "c4"); + ut.is (all[3]->attribute ("name"), "c3", "c3"); + + all[3]->tag ("one"); + all[3]->tag ("two"); + ut.ok (all[3]->hasTag ("one"), "hasTag +"); + ut.notok (all[3]->hasTag ("three"), "hasTag -"); + + ut.is (t.count (), 5, "t.count"); + + all.clear (); + b->enumerate (all); + ut.is (all[0]->attribute ("name"), "c4", "t -> c3 -> c4"); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/tests/tree2.t.cpp b/src/tests/tree2.t.cpp new file mode 100644 index 000000000..c70a274a6 --- /dev/null +++ b/src/tests/tree2.t.cpp @@ -0,0 +1,156 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez. +// 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 "Context.h" +#include "Tree.h" +#include "test.h" + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest ut (30); + + // Create the following tree: + // t + // | + // +---+---+-+-+---+---+ + // | | | | | | + // a b c d e f + + // Create a tree. + Tree t (""); + + // Create six branches. + Tree* a = new Tree (""); a->attribute ("name", "a"); + Tree* b = new Tree (""); b->attribute ("name", "b"); + Tree* c = new Tree (""); c->attribute ("name", "c"); + Tree* d = new Tree (""); d->attribute ("name", "d"); + Tree* e = new Tree (""); e->attribute ("name", "e"); + Tree* f = new Tree (""); f->attribute ("name", "f"); + + // Create two branches. + Tree* x = new Tree (""); x->attribute ("name", "x"); + Tree* y = new Tree (""); y->attribute ("name", "y"); + + // Add the six. + t.addBranch (a); + t.addBranch (b); + t.addBranch (c); + t.addBranch (d); + t.addBranch (e); + t.addBranch (f); + + // Verify tree structure. + ut.ok (a->parent () == &t, "a -> t"); + ut.ok (b->parent () == &t, "b -> t"); + ut.ok (c->parent () == &t, "c -> t"); + ut.ok (d->parent () == &t, "d -> t"); + ut.ok (e->parent () == &t, "e -> t"); + ut.ok (f->parent () == &t, "f -> t"); + ut.ok (x->parent () == NULL, "x -> NULL"); + ut.ok (y->parent () == NULL, "y -> NULL"); + + ut.ok (t.branches () == 6, "t[6]"); + + ut.diag ("---------------------------------------------------------"); + + // Modify the tree to become: + // t + // | + // +---+-+-+---+ + // | | | | + // a b x f + // | + // +---+---+ + // | | | + // c d e + + // Make x the parent of c, d and e. + x->addBranch (c); + x->addBranch (d); + x->addBranch (e); + + // Make x replace c as one of t's branches. + t.replaceBranch (c, x); + t.removeBranch (d); + t.removeBranch (e); + + // Verify structure. + ut.ok (a->parent () == &t, "a -> t"); + ut.ok (b->parent () == &t, "b -> t"); + ut.ok (c->parent () == x, "c -> x"); + ut.ok (d->parent () == x, "d -> x"); + ut.ok (e->parent () == x, "e -> x"); + ut.ok (f->parent () == &t, "f -> t"); + ut.ok (x->parent () == &t, "x -> t"); + ut.ok (y->parent () == NULL, "y -> NULL"); + + ut.ok (t.branches () == 4, "t[4]"); + ut.ok (x->branches () == 3, "x[3]"); + + ut.diag ("---------------------------------------------------------"); + + // Modify the tree to become: + // t + // | + // +---+---+ + // | | | + // a y f + // | + // +-+-+ + // | | + // b x + // | + // +---+---+ + // | | | + // c d e + + // Now insert y to be parent of b, x. + y->addBranch (b); + y->addBranch (x); + t.replaceBranch (x, y); + t.removeBranch (b); + + ut.ok (a->parent () == &t, "a -> t"); + ut.ok (b->parent () == y, "b -> y"); + ut.ok (c->parent () == x, "c -> x"); + ut.ok (d->parent () == x, "d -> x"); + ut.ok (e->parent () == x, "e -> x"); + ut.ok (f->parent () == &t, "f -> t"); + ut.ok (x->parent () == y, "x -> y"); + ut.ok (y->parent () == &t, "y -> t"); + + ut.ok (t.branches () == 3, "t[3]"); + ut.ok (x->branches () == 3, "x[3]"); + ut.ok (y->branches () == 2, "y[2]"); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +