- Implemented RegX class to maintain a separate compile, and match
  method, thereby allowing efficient re-use of the regex.  This is
  critical to Expression::eval, where an identical regex might be
  applied to every task.
- Obsoleted rx.{h,cpp}, which combined the compile and match steps
  into a single call, and is therefore not efficient when used in
  the context of filtering.
- Fixed some unit tests that weren't building.  Now they do.  They
  don't work of course (don't be silly) but that's a problem for
  another day.
- Modified all code that relies on rx.h to use RegX.h.
This commit is contained in:
Paul Beckingham 2011-06-21 01:43:57 -04:00
parent aa8d872466
commit b49523c06d
14 changed files with 249 additions and 490 deletions

View file

@ -30,7 +30,7 @@
#include <stdlib.h>
#include <string.h>
#include <text.h>
#include <rx.h>
#include <RegX.h>
#include <Color.h>
#include <util.h>
#include <Date.h>
@ -634,7 +634,8 @@ bool Att::match (const Att& other) const
if (regex)
{
std::string pattern = "^" + mValue + "$";
if (!regexMatch (other.mValue, pattern, case_sensitive))
RegX r (pattern, case_sensitive);
if (!r.match (other.mValue))
return false;
}
else if (!compare (mValue, other.mValue, (bool) case_sensitive))
@ -652,7 +653,8 @@ bool Att::match (const Att& other) const
#ifdef FEATURE_REGEX
if (regex)
{
if (!regexMatch (other.mValue, mValue, case_sensitive))
RegX r (mValue, case_sensitive);
if (!r.match (other.mValue))
return false;
}
else if (find (other.mValue, mValue, (bool) case_sensitive) == std::string::npos)
@ -670,7 +672,8 @@ bool Att::match (const Att& other) const
if (regex)
{
std::string pattern = "^" + mValue + "$";
if (!regexMatch (other.mValue, pattern, case_sensitive))
RegX r (pattern, case_sensitive);
if (!r.match (other.mValue))
return false;
}
else if (!compare (mValue, other.mValue, (bool) case_sensitive))
@ -688,7 +691,8 @@ bool Att::match (const Att& other) const
if (regex)
{
std::string pattern = "^" + mValue + "$";
if (regexMatch (other.mValue, pattern, case_sensitive))
RegX r (pattern, case_sensitive);
if (r.match (other.mValue))
return false;
}
else if (compare (mValue, other.mValue, (bool) case_sensitive))
@ -720,7 +724,8 @@ bool Att::match (const Att& other) const
if (regex)
{
std::string pattern = "^" + mValue;
if (!regexMatch (other.mValue, pattern, case_sensitive))
RegX r (pattern, case_sensitive);
if (!r.match (other.mValue))
return false;
}
else
@ -743,7 +748,8 @@ bool Att::match (const Att& other) const
if (regex)
{
std::string pattern = mValue + "$";
if (!regexMatch (other.mValue, pattern, case_sensitive))
RegX r (pattern, case_sensitive);
if (!r.match (other.mValue))
return false;
}
else
@ -767,7 +773,8 @@ bool Att::match (const Att& other) const
#ifdef FEATURE_REGEX
if (regex)
{
if (regexMatch (other.mValue, mValue, case_sensitive))
RegX r (mValue, case_sensitive);
if (r.match (other.mValue))
return false;
}
else if (find (other.mValue, mValue, (bool) case_sensitive) != std::string::npos)
@ -862,7 +869,8 @@ bool Att::match (const Att& other) const
{
std::vector <int> start;
std::vector <int> end;
if (!regexMatch (start, end, other.mValue, mValue, case_sensitive))
RegX r (mValue, case_sensitive);
if (!r.match (start, end, other.mValue))
return false;
if (!isWordStart (other.mValue, start[0]))
@ -898,7 +906,8 @@ bool Att::match (const Att& other) const
{
std::vector <int> start;
std::vector <int> end;
if (regexMatch (start, end, other.mValue, mValue, case_sensitive) &&
RegX r (mValue, case_sensitive);
if (r.match (start, end, other.mValue) &&
isWordStart (other.mValue, start[0]) &&
isWordEnd (other.mValue, end[0]))
return false;

View file

@ -25,6 +25,7 @@ set (task_SRCS API.cpp API.h
Path.cpp Path.h
Permission.cpp Permission.h
Record.cpp Record.h
RegX.cpp RegX.h
TDB.cpp TDB.h
TDB2.cpp TDB2.h
Task.cpp Task.h
@ -45,7 +46,6 @@ set (task_SRCS API.cpp API.h
interactive.cpp
recur.cpp
rules.cpp
rx.cpp rx.h
sort.cpp
text.cpp text.h
utf8.cpp utf8.h

View file

@ -33,7 +33,7 @@
#include <inttypes.h>
#include <Nibbler.h>
#include <Date.h>
#include <rx.h>
#include <RegX.h>
const char* c_digits = "0123456789";
@ -146,9 +146,10 @@ bool Nibbler::getUntilRx (const std::string& regex, std::string& result)
else
modified_regex = regex;
RegX r (modified_regex, true);
std::vector <int> start;
std::vector <int> end;
if (regexMatch (start, end, mInput.substr (mCursor), modified_regex, true))
if (r.match (start, end, mInput.substr (mCursor)))
{
result = mInput.substr (mCursor, start[0]);
mCursor += start[0];
@ -450,8 +451,9 @@ bool Nibbler::getRx (const std::string& regex, std::string& result)
else
modified_regex = regex;
RegX r (modified_regex, true);
std::vector <std::string> results;
if (regexMatch (results, mInput.substr (mCursor), modified_regex, true))
if (r.match (results, mInput.substr (mCursor)))
{
result = results[0];
mCursor += result.length ();
@ -1010,8 +1012,9 @@ bool Nibbler::skipRx (const std::string& regex)
else
modified_regex = regex;
RegX r (modified_regex, true);
std::vector <std::string> results;
if (regexMatch (results, mInput.substr (mCursor), modified_regex, true))
if (r.match (results, mInput.substr (mCursor)))
{
mCursor += results[0].length ();
return true;

157
src/RegX.cpp Normal file
View file

@ -0,0 +1,157 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2010 - 2011, 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 <stdlib.h>
#include <string.h>
#include <RegX.h>
#define L10N // Localization complete.
//#define _POSIX_C_SOURCE 1
#define MAX_MATCHES 64
////////////////////////////////////////////////////////////////////////////////
RegX::RegX (
const std::string& pattern,
bool case_sensitive /* = true */)
: _compiled (false)
, _pattern (pattern)
, _case_sensitive (case_sensitive)
{
compile ();
}
////////////////////////////////////////////////////////////////////////////////
RegX::RegX (const RegX& other)
: _compiled (false)
, _pattern (other._pattern)
, _case_sensitive (other._case_sensitive)
{
}
////////////////////////////////////////////////////////////////////////////////
RegX& RegX::operator= (const RegX& other)
{
if (this != &other)
{
_compiled = false;
_pattern = other._pattern;
_case_sensitive = other._case_sensitive;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
bool RegX::operator== (const RegX& other) const
{
return _pattern == other._pattern &&
_case_sensitive == other._case_sensitive;
}
////////////////////////////////////////////////////////////////////////////////
RegX::~RegX ()
{
if (_compiled)
regfree (&_regex);
}
////////////////////////////////////////////////////////////////////////////////
void RegX::compile ()
{
if (!_compiled)
{
memset (&_regex, 0, sizeof (regex_t));
int result;
if ((result = regcomp (&_regex, _pattern.c_str (),
REG_EXTENDED | /*REG_NOSUB |*/ REG_NEWLINE |
(_case_sensitive ? 0 : REG_ICASE))) != 0)
{
char message[256];
regerror (result, &_regex, message, 256);
throw std::string (message);
}
_compiled = true;
}
}
////////////////////////////////////////////////////////////////////////////////
bool RegX::match (const std::string& in)
{
if (!_compiled)
compile ();
return regexec (&_regex, in.c_str (), 0, NULL, 0) == 0 ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
bool RegX::match (
std::vector<std::string>& matches,
const std::string& in)
{
if (!_compiled)
compile ();
regmatch_t rm[MAX_MATCHES];
if (regexec (&_regex, in.c_str (), MAX_MATCHES, rm, 0) == 0)
{
for (unsigned int i = 1; i < 1 + _regex.re_nsub; ++i)
matches.push_back (in.substr (rm[i].rm_so, rm[i].rm_eo - rm[i].rm_so));
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool RegX::match (
std::vector <int>& start,
std::vector <int>& end,
const std::string& in)
{
if (!_compiled)
compile ();
regmatch_t rm[MAX_MATCHES];
if (regexec (&_regex, in.c_str (), MAX_MATCHES, rm, 0) == 0)
{
for (unsigned int i = 1; i < 1 + _regex.re_nsub; ++i)
{
start.push_back (rm[i].rm_so);
end.push_back (rm[i].rm_eo);
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -25,16 +25,36 @@
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_RX
#define INCLuDED_RX
#ifndef INCLUDED_REGX
#define INCLUDED_REGX
#define L10N // Localization complete.
#include <string>
#include <vector>
#include <regex.h>
bool regexMatch (const std::string&, const std::string&, bool caseSensitive = true);
bool regexMatch (std::vector<std::string>&, const std::string&, const std::string&, bool caseSensitive = true);
bool regexMatch (std::vector<int>&, std::vector<int>&, const std::string&, const std::string&, bool caseSensitive = true);
class RegX
{
public:
RegX (const std::string&, bool caseSensitive = true);
RegX (const RegX&);
RegX& operator= (const RegX&);
bool operator== (const RegX&) const;
~RegX ();
bool match (const std::string&);
bool match (std::vector<std::string>&, const std::string&);
bool match (std::vector <int>&, std::vector <int>&, const std::string&);
private:
void compile ();
private:
bool _compiled;
std::string _pattern;
bool _case_sensitive;
regex_t _regex;
};
#endif

View file

@ -29,7 +29,7 @@
#include <sstream>
#include <algorithm>
#include <stdlib.h>
#include <rx.h>
#include <RegX.h>
#include <Context.h>
#include <util.h>
#include <cmake.h>
@ -223,9 +223,10 @@ int CmdDiagnostics::execute (std::string& output)
char* p = fgets (buffer, 1023, fp);
pclose (fp);
RegX r ("usage", false);
if (p)
out << " scp: "
<< (regexMatch (buffer, "usage") ? "found" : "n/a")
<< (r.match (buffer) ? "found" : "n/a")
<< "\n";
}
@ -237,8 +238,9 @@ int CmdDiagnostics::execute (std::string& output)
// rsync version 2.6.9 protocol version 29
if (p)
{
RegX r ("version ([0-9]+\\.[0-9]+\\.[0-9]+)", false);
matches.clear ();
regexMatch (matches, buffer, "version ([0-9]+\\.[0-9]+\\.[0-9]+)");
r.match (matches, buffer);
out << " rsync: "
<< (matches.size () ? matches[0] : "n/a")
<< "\n";
@ -253,8 +255,9 @@ int CmdDiagnostics::execute (std::string& output)
// curl 7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3
if (p)
{
RegX r ("curl ([0-9]+\\.[0-9]+\\.[0-9]+)", false);
matches.clear ();
regexMatch (matches, buffer, "curl ([0-9]+\\.[0-9]+\\.[0-9]+)");
r.match (matches, buffer);
out << " curl: "
<< (matches.size () ? matches[0] : "n/a")
<< "\n";

View file

@ -1,138 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2010 - 2011, 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 <stdlib.h>
#include <regex.h>
#include <rx.h>
#define L10N // Localization complete.
//#define _POSIX_C_SOURCE 1
#define MAX_MATCHES 8
////////////////////////////////////////////////////////////////////////////////
bool regexMatch (
const std::string& in,
const std::string& pattern,
bool caseSensitive /* = true */)
{
regex_t r = {0};
int result;
if ((result = regcomp (&r, pattern.c_str (),
REG_EXTENDED | REG_NOSUB | REG_NEWLINE |
(caseSensitive ? 0 : REG_ICASE))) == 0)
{
if ((result = regexec (&r, in.c_str (), 0, NULL, 0)) == 0)
{
regfree (&r);
return true;
}
if (result == REG_NOMATCH)
return false;
}
char message[256];
regerror (result, &r, message, 256);
throw std::string (message);
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool regexMatch (
std::vector<std::string>& out,
const std::string& in,
const std::string& pattern,
bool caseSensitive /* = true */)
{
regex_t r = {0};
int result;
if ((result = regcomp (&r, pattern.c_str (),
REG_EXTENDED | REG_NEWLINE |
(caseSensitive ? 0 : REG_ICASE))) == 0)
{
regmatch_t rm[MAX_MATCHES];
if ((result = regexec (&r, in.c_str (), MAX_MATCHES, rm, 0)) == 0)
{
for (unsigned int i = 1; i < 1 + r.re_nsub; ++i)
out.push_back (in.substr (rm[i].rm_so, rm[i].rm_eo - rm[i].rm_so));
regfree (&r);
return true;
}
if (result == REG_NOMATCH)
return false;
}
char message[256];
regerror (result, &r, message, 256);
throw std::string (message);
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool regexMatch (
std::vector <int>& start,
std::vector <int>& end,
const std::string& in,
const std::string& pattern,
bool caseSensitive /* = true */)
{
regex_t r = {0};
int result;
if ((result = regcomp (&r, pattern.c_str (),
REG_EXTENDED | REG_NEWLINE |
(caseSensitive ? 0 : REG_ICASE))) == 0)
{
regmatch_t rm[MAX_MATCHES];
if ((result = regexec (&r, in.c_str (), MAX_MATCHES, rm, 0)) == 0)
{
for (unsigned int i = 1; i < 1 + r.re_nsub; ++i)
{
start.push_back (rm[i].rm_so);
end.push_back (rm[i].rm_eo);
}
regfree (&r);
return true;
}
if (result == REG_NOMATCH)
return false;
}
char message[256];
regerror (result, &r, message, 256);
throw std::string (message);
return false;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -7,9 +7,9 @@ include_directories (${CMAKE_SOURCE_DIR}
${TASK_INCLUDE_DIRS})
set (test_SRCS arguments.t att.t autocomplete.t color.t config.t date.t
directory.t dom.t duration.t file.t filt.t i18n.t json.t lexer.t
list.t nibbler.t path.t record.t rx.t seq.t t.benchmark.t t.t
taskmod.t tdb.t tdb2.t text.t uri.t util.t variant.t view.t
directory.t dom.t duration.t file.t i18n.t json.t lexer.t list.t
nibbler.t path.t record.t rx.t t.benchmark.t t.t taskmod.t tdb.t
tdb2.t text.t uri.t util.t variant.t view.t
json_test)
add_custom_target (test ./run_all DEPENDS ${test_SRCS}

View file

@ -1,168 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, 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 <main.h>
#include <test.h>
#include <Filter.h>
#include <Task.h>
Context context;
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
UnitTest test (20);
// Create a filter consisting of two Att criteria.
Filter f;
f.push_back (Att ("name1", "value1"));
f.push_back (Att ("name2", "value2"));
test.is (f.size (), (size_t)2, "Filter created");
// Create a Task to match against.
Task yes;
yes.set ("name1", "value1");
yes.set ("name2", "value2");
test.ok (f.pass (yes), "full match");
yes.set ("name3", "value3");
test.ok (f.pass (yes), "over match");
// Negative tests.
Task no0;
test.notok (f.pass (no0), "no match against default Task");
Task no1;
no1.set ("name3", "value3");
test.notok (f.pass (no1), "no match against mismatch Task");
Task partial;
partial.set ("name1", "value1");
test.notok (f.pass (partial), "no match against partial Task");
// Modifiers.
Task mods;
mods.set ("name", "value");
mods.set ("description", "hello, world.");
Att a ("name", "is", "value");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.is:value = match");
// TODO test inverse.
a = Att ("name", "isnt", "value");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "name:value -> name.isnt:value = no match");
// TODO test inverse.
a = Att ("name", "startswith", "val");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.startswith:val = match");
// TODO test inverse.
a = Att ("name", "endswith", "lue");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.endswith:lue = match");
// TODO test inverse.
a = Att ("name", "has", "alu");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.has:alu = match");
// TODO test inverse.
a = Att ("name", "hasnt", "alu");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "name:value -> name.hasnt:alu = no match");
// TODO test inverse.
a = Att ("name", "any", "");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.any: = match");
// TODO test inverse.
a = Att ("name", "none", "");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "name:value -> name.none: = no match");
// TODO test inverse.
/*
"before"
"after"
"under"
"over"
"above"
"below"
*/
a = Att ("description", "word", "hello");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "description:hello, world. -> description.word:hello = match");
// TODO test inverse.
a = Att ("description", "word", "world");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "description:hello, world. -> description.word:world = match");
// TODO test inverse.
a = Att ("description", "word", "pig");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "description:hello, world. -> description.word:pig = no match");
// TODO test inverse.
a = Att ("description", "noword", "hello");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "description:hello, world. -> description.noword:hello = no match");
// TODO test inverse.
a = Att ("description", "noword", "world");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "description:hello, world. -> description.noword:world = no match");
// TODO test inverse.
a = Att ("description", "noword", "pig");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "description:hello, world. -> description.noword:pig = match");
// TODO test inverse.
return 0;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -25,7 +25,7 @@
//
////////////////////////////////////////////////////////////////////////////////
#include <Context.h>
#include <rx.h>
#include <RegX.h>
#include <test.h>
Context context;
@ -36,30 +36,41 @@ int main (int argc, char** argv)
std::string text = "This is a test.";
ut.ok (regexMatch (text, "i. ", true), text + " =~ /i. /");
RegX r1 ("i. ", true);
ut.ok (r1.match (text), text + " =~ /i. /");
std::vector <std::string> matches;
ut.ok (regexMatch (matches, text, "(i.) ", false), text + " =~ /(i.) /");
RegX r2 ("(i.) ", false);
ut.ok (r2.match (matches, text), text + " =~ /(i.) /");
ut.ok (matches.size () == 1, "1 match");
ut.is (matches[0], "is", "$1 == is");
text = "abcdefghijklmnopqrstuvwxyz";
ut.ok (regexMatch (text, "t..", true), "t..");
ut.ok (regexMatch (text, "T..", false), "T..");
ut.ok (!regexMatch (text, "T..", true), "! T..");
RegX r3 ("t..", true);
ut.ok (r3.match (text), "t..");
RegX r4 ("T..", false);
ut.ok (r4.match (text), "T..");
RegX r5 ("T..", true);
ut.ok (!r5.match (text), "! T..");
text = "this is a test of the regex engine.";
// |...:....|....:....|....:....|....:
ut.ok (regexMatch (text, "^this"), "^this matches");
ut.ok (regexMatch (text, "engine\\.$"), "engine\\.$ matches");
RegX r6 ("^this");
ut.ok (r6.match (text), "^this matches");
RegX r7 ("engine\\.$");
ut.ok (r7.match (text), "engine\\.$ matches");
std::vector <std::string> results;
std::vector <int> start;
std::vector <int> end;
ut.ok (regexMatch (results, text, "(e..)", true), "(e..) there are matches");
ut.ok (regexMatch (start, end, text, "(e..)", true), "(e..) there are matches");
RegX r8 ("(e..)", true);
ut.ok (r8.match (results, text), "(e..) there are matches");
ut.ok (r8.match (start, end, text), "(e..) there are matches");
ut.is (results.size (), (size_t) 1, "(e..) == 1 match");
ut.is (results[0], "est", "(e..)[0] == 'est'");
ut.is (start[0], 11, "(e..)[0] == 11->");

View file

@ -1,137 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, 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 <iostream>
#include <Context.h>
#include <Sequence.h>
#include <test.h>
Context context;
////////////////////////////////////////////////////////////////////////////////
Sequence parseSequence (const std::string& input)
{
try { Sequence s (input); return s; }
catch (...) {}
return Sequence ();
}
int main (int argc, char** argv)
{
UnitTest t (30);
// Test for validity.
Sequence seq;
t.notok (seq.valid ("1--2"), "not valid 1--2");
t.notok (seq.valid ("1-2-3"), "not valid 1-2-3");
t.notok (seq.valid ("-1-2"), "not valid -1-2");
t.notok (seq.valid ("1-two"), "not valid 1-two");
t.notok (seq.valid ("one-2"), "not valid one-2");
t.ok (seq.valid ("1"), "valid 1");
t.ok (seq.valid ("1,3"), "valid 1,3");
t.ok (seq.valid ("3,1"), "valid 3,1");
t.ok (seq.valid ("1,3-5,7"), "valid 1,3-5,7");
t.ok (seq.valid ("1-1000"), "valid 1-1000");
t.ok (seq.valid ("1-1001"), "valid 1-1001");
t.ok (seq.valid ("1-5,3-7"), "valid 1-5,3-7");
// 1
seq = parseSequence ("1");
t.is (seq.size (), (size_t)1, "seq '1' -> 1 item");
if (seq.size () == 1)
{
t.is (seq[0], 1, "seq '1' -> [0] == 1");
}
else
{
t.fail ("seq '1' -> [0] == 1");
}
// 1,3
seq = parseSequence ("1,3");
t.is (seq.size (), (size_t)2, "seq '1,3' -> 2 items");
if (seq.size () == 2)
{
t.is (seq[0], 1, "seq '1,3' -> [0] == 1");
t.is (seq[1], 3, "seq '1,3' -> [1] == 3");
}
else
{
t.fail ("seq '1,3' -> [0] == 1");
t.fail ("seq '1,3' -> [1] == 3");
}
// 1,3-5,7
seq = parseSequence ("1,3-5,7");
t.is (seq.size (), (size_t)5, "seq '1,3-5,7' -> 5 items");
if (seq.size () == 5)
{
t.is (seq[0], 1, "seq '1,3-5,7' -> [0] == 1");
t.is (seq[1], 3, "seq '1,3-5,7' -> [1] == 3");
t.is (seq[2], 4, "seq '1,3-5,7' -> [2] == 4");
t.is (seq[3], 5, "seq '1,3-5,7' -> [3] == 5");
t.is (seq[4], 7, "seq '1,3-5,7' -> [4] == 7");
}
else
{
t.fail ("seq '1,3-5,7' -> [0] == 1");
t.fail ("seq '1,3-5,7' -> [1] == 3");
t.fail ("seq '1,3-5,7' -> [2] == 4");
t.fail ("seq '1,3-5,7' -> [3] == 5");
t.fail ("seq '1,3-5,7' -> [4] == 7");
}
// 1--2
seq = parseSequence ("1--2");
t.is (seq.size (), (size_t)0, "seq '1--2' -> 0 items (error)");
// 1-1000 (SEQUENCE_MAX);
seq = parseSequence ("1-1000");
t.is (seq.size (), (size_t)1000, "seq '1-1000' -> 1000 items");
if (seq.size () == 1000)
{
t.is (seq[0], 1, "seq '1-1000' -> [0] == 1");
t.is (seq[1], 2, "seq '1-1000' -> [1] == 3");
t.is (seq[998], 999, "seq '1-1000' -> [998] == 999");
t.is (seq[999], 1000, "seq '1-1000' -> [999] == 1000");
}
else
{
t.fail ("seq '1-1000' -> [0] == 1");
t.fail ("seq '1-1000' -> [1] == 2");
t.fail ("seq '1-1000' -> [998] == 999");
t.fail ("seq '1-1000' -> [999] == 1000");
}
// 1-1001
seq = parseSequence ("1-1001");
t.is (seq.size (), (size_t)0, "seq '1-1001' -> 0 items (error)");
return 0;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -38,9 +38,8 @@ void get (std::vector <Task>& pending, std::vector <Task>& completed)
TDB tdb;
tdb.location (".");
tdb.lock ();
Filter filter;
tdb.loadPending (pending, filter);
tdb.loadCompleted (completed, filter);
tdb.loadPending (pending);
tdb.loadCompleted (completed);
tdb.unlock ();
}
@ -60,7 +59,6 @@ int main (int argc, char** argv)
context.config.set ("gc", "on");
// Try reading an empty database.
Filter filter;
std::vector <Task> all;
std::vector <Task> pending;
std::vector <Task> completed;
@ -100,7 +98,7 @@ int main (int argc, char** argv)
completed.clear ();
tdb.lock ();
tdb.load (all, filter);
tdb.load (all);
all[0].set ("name", "value2");
tdb.update (all[0]); // P1 C0 N0 M1
tdb.commit (); // P1 C0 N0 M0
@ -118,7 +116,7 @@ int main (int argc, char** argv)
all.clear ();
tdb.lock ();
tdb.loadPending (all, filter);
tdb.loadPending (all);
all[0].setStatus (Task::completed);
tdb.update (all[0]); // P1 C0 N0 M1
Task t2 ("[foo:\"bar\" status:\"pending\"]");

View file

@ -38,9 +38,8 @@ void get (std::vector <Task>& pending, std::vector <Task>& completed)
TDB tdb;
tdb.location (".");
tdb.lock ();
Filter filter;
tdb.loadPending (pending, filter);
tdb.loadCompleted (completed, filter);
tdb.loadPending (pending);
tdb.loadCompleted (completed);
tdb.unlock ();
}

View file

@ -38,6 +38,7 @@ int main (int argc, char** argv)
try
{
/*
Variant v = Variant (1) + Variant (2);
t.ok (v.type () == Variant::v_integer, "1 + 2 --> integer");
t.ok (v.format () == "3", "1 + 2 --> 3");
@ -49,6 +50,7 @@ int main (int argc, char** argv)
v = Variant (1.2) + Variant (2);
t.ok (v.type () == Variant::v_double, "1.2 + 2 --> double");
t.ok (v.format () == "3.2", "1.2 + 2 --> 3.2");
*/
}
catch (std::string& e)