mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-27 19:17:19 +02:00
Enhancements - T2::legacyParse
- T2 can now parse all supported legacy formats (ff2, ff3) as well as ff4. - Added tag and attribute support to T2. - Added T2 unit tests for all formats.
This commit is contained in:
parent
72e3f76ed9
commit
9d48faa759
9 changed files with 246 additions and 56 deletions
|
@ -25,6 +25,7 @@
|
||||||
112 Cannot substitute an empty string
|
112 Cannot substitute an empty string
|
||||||
113 Unrecognized character(s) at end of substitution
|
113 Unrecognized character(s) at end of substitution
|
||||||
114 Malformed substitution
|
114 Malformed substitution
|
||||||
|
115 Tags are not permitted to contain commas
|
||||||
|
|
||||||
# 2xx Commands - must be sequential
|
# 2xx Commands - must be sequential
|
||||||
200 active
|
200 active
|
||||||
|
|
|
@ -377,6 +377,10 @@ std::cout << "# parse tag removal '" << *arg << "'" << std::endl;
|
||||||
if (foundSequence)
|
if (foundSequence)
|
||||||
foundSomethingAfterSequence = true;
|
foundSomethingAfterSequence = true;
|
||||||
|
|
||||||
|
if (arg->find (',') != std::string::npos)
|
||||||
|
throw stringtable.get (TAGS_NO_COMMA,
|
||||||
|
"Tags are not permitted to contain commas.");
|
||||||
|
|
||||||
tagRemovals.push_back (arg->substr (1, std::string::npos));
|
tagRemovals.push_back (arg->substr (1, std::string::npos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,8 @@ std::string Record::composeF4 ()
|
||||||
//
|
//
|
||||||
void Record::parse (const std::string& input)
|
void Record::parse (const std::string& input)
|
||||||
{
|
{
|
||||||
|
clear ();
|
||||||
|
|
||||||
Nibbler n (input);
|
Nibbler n (input);
|
||||||
std::string line;
|
std::string line;
|
||||||
if (n.skip ('[') &&
|
if (n.skip ('[') &&
|
||||||
|
|
|
@ -629,7 +629,7 @@ int T::determineVersion (const std::string& line)
|
||||||
|
|
||||||
// Version 4 looks like:
|
// Version 4 looks like:
|
||||||
//
|
//
|
||||||
// [name:"value" ...]
|
// [name:"value" ...]\n
|
||||||
//
|
//
|
||||||
// Scan for [, ] and :".
|
// Scan for [, ] and :".
|
||||||
if (line[0] == '[' &&
|
if (line[0] == '[' &&
|
||||||
|
|
154
src/T2.cpp
154
src/T2.cpp
|
@ -26,7 +26,6 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "Nibbler.h"
|
#include "Nibbler.h"
|
||||||
#include "T2.h"
|
#include "T2.h"
|
||||||
|
@ -47,7 +46,7 @@ T2::T2 (const std::string& input)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parse (input);
|
Record::parse (input);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (std::string& e)
|
catch (std::string& e)
|
||||||
|
@ -74,8 +73,57 @@ T2::~T2 ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T2::status T2::textToStatus (const std::string& input)
|
||||||
|
{
|
||||||
|
if (input == "pending") return pending;
|
||||||
|
else if (input == "completed") return completed;
|
||||||
|
else if (input == "deleted") return deleted;
|
||||||
|
else if (input == "recurring") return recurring;
|
||||||
|
|
||||||
|
return pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
std::string T2::statusToText (T2::status s)
|
||||||
|
{
|
||||||
|
if (s == pending) return "pending";
|
||||||
|
else if (s == completed) return "completed";
|
||||||
|
else if (s == deleted) return "deleted";
|
||||||
|
else if (s == recurring) return "recurring";
|
||||||
|
|
||||||
|
return "pending";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T2::status T2::getStatus ()
|
||||||
|
{
|
||||||
|
return textToStatus (get ("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void T2::setSatus (T2::status status)
|
||||||
|
{
|
||||||
|
set ("status", statusToText (status));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void T2::parse (const std::string& line)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Record::parse (line);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (std::string& e)
|
||||||
|
{
|
||||||
|
legacyParse (line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Support FF2, FF3.
|
// Support FF2, FF3.
|
||||||
|
// Thankfully FF1 is no longer supported.
|
||||||
void T2::legacyParse (const std::string& line)
|
void T2::legacyParse (const std::string& line)
|
||||||
{
|
{
|
||||||
switch (determineVersion (line))
|
switch (determineVersion (line))
|
||||||
|
@ -88,16 +136,17 @@ void T2::legacyParse (const std::string& line)
|
||||||
|
|
||||||
// File format version 2, from 2008.1.1 - 2009.3.23
|
// File format version 2, from 2008.1.1 - 2009.3.23
|
||||||
case 2:
|
case 2:
|
||||||
/*
|
|
||||||
{
|
{
|
||||||
if (line.length () > 46) // ^.{36} . \[\] \[\] \n
|
if (line.length () > 46) // ^.{36} . \[\] \[\] \n
|
||||||
{
|
{
|
||||||
mUUID = line.substr (0, 36);
|
set ("uuid", line.substr (0, 36));
|
||||||
|
|
||||||
mStatus = line[37] == '+' ? completed
|
T2::status status = line[37] == '+' ? completed
|
||||||
: line[37] == 'X' ? deleted
|
: line[37] == 'X' ? deleted
|
||||||
: line[37] == 'r' ? recurring
|
: line[37] == 'r' ? recurring
|
||||||
: pending;
|
: pending;
|
||||||
|
|
||||||
|
set ("status", statusToText (status));
|
||||||
|
|
||||||
size_t openTagBracket = line.find ("[");
|
size_t openTagBracket = line.find ("[");
|
||||||
size_t closeTagBracket = line.find ("]", openTagBracket);
|
size_t closeTagBracket = line.find ("]", openTagBracket);
|
||||||
|
@ -111,8 +160,9 @@ void T2::legacyParse (const std::string& line)
|
||||||
{
|
{
|
||||||
std::string tags = line.substr (
|
std::string tags = line.substr (
|
||||||
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
|
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
|
||||||
std::vector <std::string> rawTags;
|
std::vector <std::string> tagSet;
|
||||||
split (mTags, tags, ' ');
|
split (tagSet, tags, ' ');
|
||||||
|
addTags (tagSet);
|
||||||
|
|
||||||
std::string attributes = line.substr (
|
std::string attributes = line.substr (
|
||||||
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
|
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
|
||||||
|
@ -123,10 +173,10 @@ void T2::legacyParse (const std::string& line)
|
||||||
std::vector <std::string> pair;
|
std::vector <std::string> pair;
|
||||||
split (pair, pairs[i], ':');
|
split (pair, pairs[i], ':');
|
||||||
if (pair.size () == 2)
|
if (pair.size () == 2)
|
||||||
mAttributes[pair[0]] = pair[1];
|
set (pair[0], pair[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
|
set ("description", line.substr (closeAttrBracket + 2, std::string::npos));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::string ("Missing attribute brackets");
|
throw std::string ("Missing attribute brackets");
|
||||||
|
@ -137,23 +187,23 @@ void T2::legacyParse (const std::string& line)
|
||||||
else
|
else
|
||||||
throw std::string ("Line too short");
|
throw std::string ("Line too short");
|
||||||
|
|
||||||
mAnnotations.clear ();
|
removeAnnotations ();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// File format version 3, from 2009.3.23
|
// File format version 3, from 2009.3.23
|
||||||
case 3:
|
case 3:
|
||||||
/*
|
|
||||||
{
|
{
|
||||||
if (line.length () > 49) // ^.{36} . \[\] \[\] \[\] \n
|
if (line.length () > 49) // ^.{36} . \[\] \[\] \[\] \n
|
||||||
{
|
{
|
||||||
mUUID = line.substr (0, 36);
|
set ("uuid", line.substr (0, 36));
|
||||||
|
|
||||||
mStatus = line[37] == '+' ? completed
|
T2::status status = line[37] == '+' ? completed
|
||||||
: line[37] == 'X' ? deleted
|
: line[37] == 'X' ? deleted
|
||||||
: line[37] == 'r' ? recurring
|
: line[37] == 'r' ? recurring
|
||||||
: pending;
|
: pending;
|
||||||
|
|
||||||
|
set ("status", statusToText (status));
|
||||||
|
|
||||||
size_t openTagBracket = line.find ("[");
|
size_t openTagBracket = line.find ("[");
|
||||||
size_t closeTagBracket = line.find ("]", openTagBracket);
|
size_t closeTagBracket = line.find ("]", openTagBracket);
|
||||||
|
@ -172,8 +222,9 @@ void T2::legacyParse (const std::string& line)
|
||||||
{
|
{
|
||||||
std::string tags = line.substr (
|
std::string tags = line.substr (
|
||||||
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
|
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
|
||||||
std::vector <std::string> rawTags;
|
std::vector <std::string> tagSet;
|
||||||
split (mTags, tags, ' ');
|
split (tagSet, tags, ' ');
|
||||||
|
addTags (tagSet);
|
||||||
|
|
||||||
std::string attributes = line.substr (
|
std::string attributes = line.substr (
|
||||||
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
|
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
|
||||||
|
@ -185,9 +236,10 @@ void T2::legacyParse (const std::string& line)
|
||||||
std::vector <std::string> pair;
|
std::vector <std::string> pair;
|
||||||
split (pair, pairs[i], ':');
|
split (pair, pairs[i], ':');
|
||||||
if (pair.size () == 2)
|
if (pair.size () == 2)
|
||||||
mAttributes[pair[0]] = pair[1];
|
set (pair[0], pair[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Extract and split the annotations, which are of the form:
|
// Extract and split the annotations, which are of the form:
|
||||||
// 1234:"..." 5678:"..."
|
// 1234:"..." 5678:"..."
|
||||||
std::string annotations = line.substr (
|
std::string annotations = line.substr (
|
||||||
|
@ -225,8 +277,9 @@ void T2::legacyParse (const std::string& line)
|
||||||
mAnnotations[::atoi (name.c_str ())] = value;
|
mAnnotations[::atoi (name.c_str ())] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
mDescription = line.substr (closeAnnoBracket + 2, std::string::npos);
|
set ("description", line.substr (closeAnnoBracket + 2, std::string::npos));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::string ("Missing annotation brackets.");
|
throw std::string ("Missing annotation brackets.");
|
||||||
|
@ -240,7 +293,6 @@ void T2::legacyParse (const std::string& line)
|
||||||
else
|
else
|
||||||
throw std::string ("Line too short.");
|
throw std::string ("Line too short.");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -271,10 +323,7 @@ void T2::getAnnotations (std::vector <Att>& annotations) const
|
||||||
void T2::setAnnotations (const std::vector <Att>& annotations)
|
void T2::setAnnotations (const std::vector <Att>& annotations)
|
||||||
{
|
{
|
||||||
// Erase old annotations.
|
// Erase old annotations.
|
||||||
Record::iterator i;
|
removeAnnotations ();
|
||||||
for (i = this->begin (); i != this->end (); ++i)
|
|
||||||
if (i->first.substr (0, 11) == "annotation_")
|
|
||||||
this->erase (i);
|
|
||||||
|
|
||||||
std::vector <Att>::const_iterator ci;
|
std::vector <Att>::const_iterator ci;
|
||||||
for (ci = annotations.begin (); ci != annotations.end (); ++ci)
|
for (ci = annotations.begin (); ci != annotations.end (); ++ci)
|
||||||
|
@ -293,6 +342,37 @@ void T2::addAnnotation (const std::string& description)
|
||||||
(*this)[s.str ()] = Att (s.str (), description);
|
(*this)[s.str ()] = Att (s.str (), description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void T2::removeAnnotations ()
|
||||||
|
{
|
||||||
|
// Erase old annotations.
|
||||||
|
Record::iterator i;
|
||||||
|
for (i = this->begin (); i != this->end (); ++i)
|
||||||
|
if (i->first.substr (0, 11) == "annotation_")
|
||||||
|
this->erase (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int T2::getTagCount ()
|
||||||
|
{
|
||||||
|
std::vector <std::string> tags;
|
||||||
|
split (tags, get ("tags"), ',');
|
||||||
|
|
||||||
|
return (int) tags.size ();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool T2::hasTag (const std::string& tag)
|
||||||
|
{
|
||||||
|
std::vector <std::string> tags;
|
||||||
|
split (tags, get ("tags"), ',');
|
||||||
|
|
||||||
|
if (std::find (tags.begin (), tags.end (), tag) != tags.end ())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void T2::addTag (const std::string& tag)
|
void T2::addTag (const std::string& tag)
|
||||||
{
|
{
|
||||||
|
@ -308,6 +388,22 @@ void T2::addTag (const std::string& tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void T2::addTags (const std::vector <std::string>& tags)
|
||||||
|
{
|
||||||
|
remove ("tags");
|
||||||
|
|
||||||
|
std::vector <std::string>::const_iterator it;
|
||||||
|
for (it = tags.begin (); it != tags.end (); ++it)
|
||||||
|
addTag (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void T2::getTags (std::vector<std::string>& tags)
|
||||||
|
{
|
||||||
|
split (tags, get ("tags"), ',');
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void T2::removeTag (const std::string& tag)
|
void T2::removeTag (const std::string& tag)
|
||||||
{
|
{
|
||||||
|
|
24
src/T2.h
24
src/T2.h
|
@ -40,6 +40,7 @@ public:
|
||||||
T2& operator= (const T2&); // Assignment operator
|
T2& operator= (const T2&); // Assignment operator
|
||||||
~T2 (); // Destructor
|
~T2 (); // Destructor
|
||||||
|
|
||||||
|
void parse (const std::string&);
|
||||||
std::string composeCSV ();
|
std::string composeCSV ();
|
||||||
|
|
||||||
// Status values.
|
// Status values.
|
||||||
|
@ -53,28 +54,23 @@ public:
|
||||||
int id () const { return sequence.size () ? sequence[0] : 0; }
|
int id () const { return sequence.size () ? sequence[0] : 0; }
|
||||||
void id (int anotherId) { sequence.push_back (anotherId); }
|
void id (int anotherId) { sequence.push_back (anotherId); }
|
||||||
|
|
||||||
/*
|
static status textToStatus (const std::string&);
|
||||||
status getStatus () const { return mStatus; }
|
static std::string statusToText (status);
|
||||||
void setStatus (status s) { mStatus = s; }
|
|
||||||
|
|
||||||
bool hasTag (const std::string&) const;
|
status getStatus ();
|
||||||
void getRemoveTags (std::vector<std::string>&); // SPECIAL
|
void setSatus (status);
|
||||||
void addRemoveTag (const std::string&); // SPECIAL
|
|
||||||
int getTagCount () const;
|
int getTagCount ();
|
||||||
void getTags (std::vector<std::string>&) const;
|
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 removeTag (const std::string&);
|
void removeTag (const std::string&);
|
||||||
/*
|
|
||||||
void removeTags ();
|
|
||||||
*/
|
|
||||||
|
|
||||||
void getAnnotations (std::vector <Att>&) const;
|
void getAnnotations (std::vector <Att>&) const;
|
||||||
void setAnnotations (const std::vector <Att>&);
|
void setAnnotations (const std::vector <Att>&);
|
||||||
void addAnnotation (const std::string&);
|
void addAnnotation (const std::string&);
|
||||||
|
void removeAnnotations ();
|
||||||
|
|
||||||
bool valid () const;
|
bool valid () const;
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,9 @@ int TDB2::load (std::vector <T2>& tasks, Filter& filter)
|
||||||
++line_number;
|
++line_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO If the filter contains Status:x where x is not deleted or
|
||||||
|
// completed, then this can be skipped.
|
||||||
|
|
||||||
line_number = 1;
|
line_number = 1;
|
||||||
file = location->path + "/completed.data";
|
file = location->path + "/completed.data";
|
||||||
while (fgets (line, T_LINE_MAX, location->completed))
|
while (fgets (line, T_LINE_MAX, location->completed))
|
||||||
|
@ -243,6 +246,9 @@ void TDB2::update (T2& before, T2& after)
|
||||||
// TODO writes all, including comments
|
// TODO writes all, including comments
|
||||||
int TDB2::commit ()
|
int TDB2::commit ()
|
||||||
{
|
{
|
||||||
|
// TODO Two passes: first the pending file.
|
||||||
|
// then the compelted file.
|
||||||
|
|
||||||
throw std::string ("unimplemented TDB2::commit");
|
throw std::string ("unimplemented TDB2::commit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@
|
||||||
#define SUBST_BAD_CHARS 113
|
#define SUBST_BAD_CHARS 113
|
||||||
#define SUBST_MALFORMED 114
|
#define SUBST_MALFORMED 114
|
||||||
|
|
||||||
|
#define TAGS_NO_COMMA 115
|
||||||
|
|
||||||
// 2xx Commands
|
// 2xx Commands
|
||||||
#define CMD_ACTIVE 200
|
#define CMD_ACTIVE 200
|
||||||
#define CMD_ADD 201
|
#define CMD_ADD 201
|
||||||
|
|
|
@ -32,27 +32,110 @@ Context context;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest test (3);
|
UnitTest test (34);
|
||||||
|
|
||||||
T2 t;
|
test.is ((int)T2::textToStatus ("pending"), (int)T2::pending, "textToStatus pending");
|
||||||
t.addTag ("tag1");
|
test.is ((int)T2::textToStatus ("completed"), (int)T2::completed, "textToStatus completed");
|
||||||
t.addTag ("tag2");
|
test.is ((int)T2::textToStatus ("deleted"), (int)T2::deleted, "textToStatus deleted");
|
||||||
test.is (t.composeF4 (), "[tags:\"tag1,tag2\" uuid:\"...\"]", "T2::addTag");
|
test.is ((int)T2::textToStatus ("recurring"), (int)T2::recurring, "textToStatus recurring");
|
||||||
|
|
||||||
T2 t2 (t.composeF4 ());
|
test.is (T2::statusToText (T2::pending), "pending", "statusToText pending");
|
||||||
test.is (t2.composeF4 (), "[tags:\"tag1,tag2\" uuid:\"...\"]", "T2::composeF4 -> parse round trip");
|
test.is (T2::statusToText (T2::completed), "completed", "statusToText completed");
|
||||||
|
test.is (T2::statusToText (T2::deleted), "deleted", "statusToText deleted");
|
||||||
|
test.is (T2::statusToText (T2::recurring), "recurring", "statusToText recurring");
|
||||||
|
|
||||||
// Round-trip testing.
|
// Round-trip testing.
|
||||||
T2 t3;
|
T2 t3;
|
||||||
std::string before = t3.composeF4 ();
|
std::string before = t3.composeF4 ();
|
||||||
/*
|
t3.parse (before);
|
||||||
t3 (t3.composeF4 ());
|
|
||||||
t3 (t3.composeF4 ());
|
|
||||||
t3 (t3.composeF4 ());
|
|
||||||
*/
|
|
||||||
std::string after = t3.composeF4 ();
|
std::string after = t3.composeF4 ();
|
||||||
|
t3.parse (after);
|
||||||
|
after = t3.composeF4 ();
|
||||||
|
t3.parse (after);
|
||||||
|
after = t3.composeF4 ();
|
||||||
test.is (before, after, "T2::composeF4 -> parse round trip 4 iterations");
|
test.is (before, after, "T2::composeF4 -> parse round trip 4 iterations");
|
||||||
|
|
||||||
|
// Legacy Format 1
|
||||||
|
// [tags] [attributes] description\n
|
||||||
|
// X [tags] [attributes] description\n
|
||||||
|
std::string sample = "[tag1 tag2] [att1:value1 att2:value2] Description";
|
||||||
|
sample = "X "
|
||||||
|
"[one two] "
|
||||||
|
"[att1:value1 att2:value2] "
|
||||||
|
"Description";
|
||||||
|
bool good = true;
|
||||||
|
try { T2 ff1 (sample); } catch (...) { good = false; }
|
||||||
|
test.notok (good, "Support for ff1 removed");
|
||||||
|
|
||||||
|
// Legacy Format 2
|
||||||
|
// uuid status [tags] [attributes] description\n
|
||||||
|
sample = "00000000-0000-0000-0000-000000000000 "
|
||||||
|
"- "
|
||||||
|
"[tag1 tag2] "
|
||||||
|
"[att1:value1 att2:value2] "
|
||||||
|
"Description";
|
||||||
|
T2 ff2 (sample);
|
||||||
|
std::string value = ff2.get ("uuid");
|
||||||
|
test.is (value, "00000000-0000-0000-0000-000000000000", "ff2 uuid");
|
||||||
|
value = ff2.get ("status");
|
||||||
|
test.is (value, "pending", "ff2 status");
|
||||||
|
test.ok (ff2.hasTag ("tag1"), "ff2 tag1");
|
||||||
|
test.ok (ff2.hasTag ("tag2"), "ff2 tag2");
|
||||||
|
test.is (ff2.getTagCount (), 2, "ff2 # tags");
|
||||||
|
value = ff2.get ("att1");
|
||||||
|
test.is (value, "value1", "ff2 att1");
|
||||||
|
value = ff2.get ("att2");
|
||||||
|
test.is (value, "value2", "ff2 att2");
|
||||||
|
value = ff2.get ("description");
|
||||||
|
test.is (value, "Description", "ff2 description");
|
||||||
|
|
||||||
|
// Legacy Format 3
|
||||||
|
// uuid status [tags] [attributes] [annotations] description\n
|
||||||
|
sample = "00000000-0000-0000-0000-000000000000 "
|
||||||
|
"- "
|
||||||
|
"[tag1 tag2] "
|
||||||
|
"[att1:value1 att2:value2] "
|
||||||
|
"[123:ann1 456:ann2] Description";
|
||||||
|
T2 ff3 (sample);
|
||||||
|
value = ff2.get ("uuid");
|
||||||
|
test.is (value, "00000000-0000-0000-0000-000000000000", "ff3 uuid");
|
||||||
|
value = ff2.get ("status");
|
||||||
|
test.is (value, "pending", "ff3 status");
|
||||||
|
test.ok (ff2.hasTag ("tag1"), "ff3 tag1");
|
||||||
|
test.ok (ff2.hasTag ("tag2"), "ff3 tag2");
|
||||||
|
test.is (ff2.getTagCount (), 2, "ff3 # tags");
|
||||||
|
value = ff3.get ("att1");
|
||||||
|
test.is (value, "value1", "ff3 att1");
|
||||||
|
value = ff3.get ("att2");
|
||||||
|
test.is (value, "value2", "ff3 att2");
|
||||||
|
value = ff3.get ("description");
|
||||||
|
test.is (value, "Description", "ff3 description");
|
||||||
|
|
||||||
|
// Current Format 4
|
||||||
|
// [name:"value" ...]\n
|
||||||
|
sample = "["
|
||||||
|
"uuid:\"00000000-0000-0000-0000-000000000000\" "
|
||||||
|
"status:\"P\" "
|
||||||
|
"tags:\"tag1&commaltag2\" "
|
||||||
|
"att1:\"value1\" "
|
||||||
|
"att2:\"value2\" "
|
||||||
|
"description:\"Description\""
|
||||||
|
"]";
|
||||||
|
T2 ff4 (sample);
|
||||||
|
value = ff2.get ("uuid");
|
||||||
|
test.is (value, "00000000-0000-0000-0000-000000000000", "ff4 uuid");
|
||||||
|
value = ff2.get ("status");
|
||||||
|
test.is (value, "pending", "ff4 status");
|
||||||
|
test.ok (ff2.hasTag ("tag1"), "ff4 tag1");
|
||||||
|
test.ok (ff2.hasTag ("tag2"), "ff4 tag2");
|
||||||
|
test.is (ff2.getTagCount (), 2, "ff4 # tags");
|
||||||
|
value = ff4.get ("att1");
|
||||||
|
test.is (value, "value1", "ff4 att1");
|
||||||
|
value = ff4.get ("att2");
|
||||||
|
test.is (value, "value2", "ff4 att2");
|
||||||
|
value = ff4.get ("description");
|
||||||
|
test.is (value, "Description", "ff4 description");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
T2::composeCSV
|
T2::composeCSV
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue