mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Merge branch '2.4.5' of ssh://git.tasktools.org/tm/task into 2.4.5
This commit is contained in:
commit
5d02291077
36 changed files with 324 additions and 750 deletions
|
@ -24,7 +24,7 @@
|
||||||
and enabling more flexible use of the function.
|
and enabling more flexible use of the function.
|
||||||
- Enable "task sync" support by default. "cmake -DENABLE_SYNC=OFF" allows
|
- Enable "task sync" support by default. "cmake -DENABLE_SYNC=OFF" allows
|
||||||
disabling it and building Taskwarrior without libgnutls available.
|
disabling it and building Taskwarrior without libgnutls available.
|
||||||
|
- An attempt to add or remove a virtual tag is now an error (thanks to Scott M).
|
||||||
|
|
||||||
------ current release ---------------------------
|
------ current release ---------------------------
|
||||||
|
|
||||||
|
|
6
NEWS
6
NEWS
|
@ -2,6 +2,7 @@
|
||||||
New Features in Taskwarrior 2.4.5
|
New Features in Taskwarrior 2.4.5
|
||||||
|
|
||||||
- The active context, if one is set, is now identified in "task context list"
|
- The active context, if one is set, is now identified in "task context list"
|
||||||
|
- It is an error to attempt and add or remove of a virtual tag.
|
||||||
|
|
||||||
New commands in Taskwarrior 2.4.5
|
New commands in Taskwarrior 2.4.5
|
||||||
|
|
||||||
|
@ -12,6 +13,11 @@ Newly deprecated features in Taskwarrior 2.4.5
|
||||||
Removed features in 2.4.5
|
Removed features in 2.4.5
|
||||||
|
|
||||||
- The script 'context' was removed, now that context is a core feature.
|
- The script 'context' was removed, now that context is a core feature.
|
||||||
|
- Nonextended forms of ISO-8601 date/time support is removed. This means
|
||||||
|
that 'YYYYMMDD' is no longer supported, but 'YYYY-MM-DD' is. For times,
|
||||||
|
'hhmmss' is no longer supported, but 'hh:mm:ss' is. The non-enxtended
|
||||||
|
forms all contain sequences of digits that make the identification of
|
||||||
|
IDs, UUIDs, and various date/time formats problematic.
|
||||||
|
|
||||||
Known Issues
|
Known Issues
|
||||||
|
|
||||||
|
|
|
@ -506,7 +506,8 @@ Shows a report of aggregated task status by project.
|
||||||
.B task <filter> tags
|
.B task <filter> tags
|
||||||
Show a list of all tags used. Any special tags used are highlighted. Note that
|
Show a list of all tags used. Any special tags used are highlighted. Note that
|
||||||
virtual tags are not listed - they don't really exist, and are just a convenient
|
virtual tags are not listed - they don't really exist, and are just a convenient
|
||||||
notation for other task metadata.
|
notation for other task metadata. It is an error to attempt to add or remove a
|
||||||
|
virtual tag.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B task timesheet [weeks]
|
.B task timesheet [weeks]
|
||||||
|
@ -666,7 +667,8 @@ are:
|
||||||
DELETED Matches if the task has deleted status
|
DELETED Matches if the task has deleted status
|
||||||
|
|
||||||
You can use +BLOCKED to filter blocked tasks, or -BLOCKED for unblocked tasks.
|
You can use +BLOCKED to filter blocked tasks, or -BLOCKED for unblocked tasks.
|
||||||
Similarly, -BLOCKED is equivalent to +UNBLOCKED.
|
Similarly, -BLOCKED is equivalent to +UNBLOCKED. It is an error to attempt to
|
||||||
|
add or remove a virtual tag.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B project:<project-name>
|
.B project:<project-name>
|
||||||
|
@ -905,7 +907,7 @@ task ... due:7/14/2008
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
ISO-8601
|
ISO-8601
|
||||||
task ... due:20130314T223000Z
|
task ... due:2013-03-14T22:30:00Z
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
Relative wording
|
Relative wording
|
||||||
|
|
143
src/CLI2.cpp
143
src/CLI2.cpp
|
@ -340,7 +340,33 @@ void CLI2::lexArguments ()
|
||||||
{
|
{
|
||||||
// Note: Starts interating at index 1, because ::handleArg0 has already
|
// Note: Starts interating at index 1, because ::handleArg0 has already
|
||||||
// processed it.
|
// processed it.
|
||||||
|
bool terminated = false;
|
||||||
for (unsigned int i = 1; i < _original_args.size (); ++i)
|
for (unsigned int i = 1; i < _original_args.size (); ++i)
|
||||||
|
{
|
||||||
|
// The terminator itself is captured.
|
||||||
|
if (_original_args[i] == "--")
|
||||||
|
{
|
||||||
|
terminated = true;
|
||||||
|
_args.push_back (A2 (_original_args[i], Lexer::Type::separator));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any arguments that are after the terminator are captured as words.
|
||||||
|
else if (terminated)
|
||||||
|
{
|
||||||
|
A2 word (_original_args[i], Lexer::Type::word);
|
||||||
|
word.tag ("TERMINATED");
|
||||||
|
_args.push_back (word);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rc:<file> and rc.<name>[:=]<value> argumenst are captured whole.
|
||||||
|
else if (_original_args[i].substr (0, 3) == "rc:" ||
|
||||||
|
_original_args[i].substr (0, 3) == "rc.")
|
||||||
|
{
|
||||||
|
_args.push_back (A2 (_original_args[i], Lexer::Type::pair));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything else gets lexed.
|
||||||
|
else
|
||||||
{
|
{
|
||||||
std::string lexeme;
|
std::string lexeme;
|
||||||
Lexer::Type type;
|
Lexer::Type type;
|
||||||
|
@ -350,6 +376,7 @@ void CLI2::lexArguments ()
|
||||||
while (lex.token (lexeme, type))
|
while (lex.token (lexeme, type))
|
||||||
_args.push_back (A2 (lexeme, type));
|
_args.push_back (A2 (lexeme, type));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (context.config.getInteger ("debug.parser") >= 3)
|
if (context.config.getInteger ("debug.parser") >= 3)
|
||||||
context.debug (dump ("CLI2::analyze lexArguments"));
|
context.debug (dump ("CLI2::analyze lexArguments"));
|
||||||
|
@ -414,51 +441,6 @@ void CLI2::analyze ()
|
||||||
context.debug (dump ("CLI2::analyze end"));
|
context.debug (dump ("CLI2::analyze end"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// There are situations where a context filter is applied. This method
|
|
||||||
// determines whether one applies, and if so, applies it. Disqualifiers include:
|
|
||||||
// - filter contains ID or UUID
|
|
||||||
void CLI2::addContextFilter ()
|
|
||||||
{
|
|
||||||
// Detect if any context is set, and bail out if not
|
|
||||||
std::string contextName = context.config.get ("context");
|
|
||||||
if (contextName == "")
|
|
||||||
{
|
|
||||||
context.debug ("No context applied.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect if UUID or ID is set, and bail out
|
|
||||||
for (auto& a : _args)
|
|
||||||
{
|
|
||||||
// TODO This looks wrong.
|
|
||||||
if (a.hasTag ("FILTER") &&
|
|
||||||
a.hasTag ("ATTRIBUTE") &&
|
|
||||||
! a.hasTag ("TERMINATED") &&
|
|
||||||
! a.hasTag ("WORD") &&
|
|
||||||
(a.attribute ("raw") == "id" || a.attribute ("raw") == "uuid"))
|
|
||||||
{
|
|
||||||
context.debug (format ("UUID/ID lexeme found '{1}', not applying context.", a.attribute ("raw")));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply context
|
|
||||||
context.debug ("Applying context: " + contextName);
|
|
||||||
std::string contextFilter = context.config.get ("context." + contextName);
|
|
||||||
|
|
||||||
if (contextFilter == "")
|
|
||||||
context.debug ("Context '" + contextName + "' not defined.");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
addRawFilter ("( " + contextFilter + " )");
|
|
||||||
if (context.verbose ("context"))
|
|
||||||
context.footnote (format ("Context '{1}' set. Use 'task context none' to remove.", contextName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Process raw string.
|
// Process raw string.
|
||||||
void CLI2::addFilter (const std::string& arg)
|
void CLI2::addFilter (const std::string& arg)
|
||||||
|
@ -480,6 +462,52 @@ void CLI2::addFilter (const std::string& arg)
|
||||||
analyze ();
|
analyze ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// There are situations where a context filter is applied. This method
|
||||||
|
// determines whether one applies, and if so, applies it. Disqualifiers include:
|
||||||
|
// - filter contains ID or UUID
|
||||||
|
void CLI2::addContextFilter ()
|
||||||
|
{
|
||||||
|
// Detect if any context is set, and bail out if not
|
||||||
|
std::string contextName = context.config.get ("context");
|
||||||
|
if (contextName == "")
|
||||||
|
{
|
||||||
|
context.debug ("No context applied.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Detect if UUID or ID is set, and bail out
|
||||||
|
for (auto& a : _args)
|
||||||
|
{
|
||||||
|
// TODO This is needed, but the parsing is not yet complete, so the logic
|
||||||
|
// below is not valid.
|
||||||
|
if (a.hasTag ("FILTER") &&
|
||||||
|
a.hasTag ("ATTRIBUTE") &&
|
||||||
|
! a.hasTag ("TERMINATED") &&
|
||||||
|
! a.hasTag ("WORD") &&
|
||||||
|
(a.attribute ("raw") == "id" || a.attribute ("raw") == "uuid"))
|
||||||
|
{
|
||||||
|
context.debug (format ("UUID/ID lexeme found '{1}', not applying context.", a.attribute ("raw")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Apply context
|
||||||
|
context.debug ("Applying context: " + contextName);
|
||||||
|
std::string contextFilter = context.config.get ("context." + contextName);
|
||||||
|
|
||||||
|
if (contextFilter == "")
|
||||||
|
context.debug ("Context '" + contextName + "' not defined.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addFilter (contextFilter);
|
||||||
|
if (context.verbose ("context"))
|
||||||
|
context.footnote (format ("Context '{1}' set. Use 'task context none' to remove.", contextName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Parse the command line, identifiying filter components, expanding syntactic
|
// Parse the command line, identifiying filter components, expanding syntactic
|
||||||
// sugar as necessary.
|
// sugar as necessary.
|
||||||
|
@ -489,6 +517,9 @@ void CLI2::prepareFilter (bool applyContext)
|
||||||
_id_ranges.clear ();
|
_id_ranges.clear ();
|
||||||
_uuid_list.clear ();
|
_uuid_list.clear ();
|
||||||
|
|
||||||
|
if (applyContext)
|
||||||
|
addContextFilter ();
|
||||||
|
|
||||||
// Classify FILTER and MODIFICATION args, based on CMD and READCMD/WRITECMD.
|
// Classify FILTER and MODIFICATION args, based on CMD and READCMD/WRITECMD.
|
||||||
bool changes = false;
|
bool changes = false;
|
||||||
bool foundCommand = false;
|
bool foundCommand = false;
|
||||||
|
@ -711,13 +742,15 @@ void CLI2::aliasExpansion ()
|
||||||
for (auto& i : _args)
|
for (auto& i : _args)
|
||||||
{
|
{
|
||||||
raw = i.attribute ("raw");
|
raw = i.attribute ("raw");
|
||||||
if (_aliases.find (raw) != _aliases.end ())
|
if (i.hasTag ("TERMINATED"))
|
||||||
|
{
|
||||||
|
reconstructed.push_back (i);
|
||||||
|
}
|
||||||
|
else if (_aliases.find (raw) != _aliases.end ())
|
||||||
{
|
{
|
||||||
for (auto& l : Lexer::split (_aliases[raw]))
|
for (auto& l : Lexer::split (_aliases[raw]))
|
||||||
{
|
{
|
||||||
A2 a (l, Lexer::Type::word);
|
A2 a (l, Lexer::Type::word);
|
||||||
a.tag ("ALIAS");
|
|
||||||
a.tag ("LEX");
|
|
||||||
reconstructed.push_back (a);
|
reconstructed.push_back (a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -725,15 +758,25 @@ void CLI2::aliasExpansion ()
|
||||||
changes = true;
|
changes = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
reconstructed.push_back (i);
|
reconstructed.push_back (i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_args = reconstructed;
|
_args = reconstructed;
|
||||||
|
|
||||||
std::vector <std::string> reconstructedOriginals;
|
std::vector <std::string> reconstructedOriginals;
|
||||||
|
bool terminated = false;
|
||||||
for (auto& i : _original_args)
|
for (auto& i : _original_args)
|
||||||
{
|
{
|
||||||
if (_aliases.find (i) != _aliases.end ())
|
if (i == "--")
|
||||||
|
terminated = true;
|
||||||
|
|
||||||
|
if (terminated)
|
||||||
|
{
|
||||||
|
reconstructedOriginals.push_back (i);
|
||||||
|
}
|
||||||
|
else if (_aliases.find (i) != _aliases.end ())
|
||||||
{
|
{
|
||||||
for (auto& l : Lexer::split (_aliases[i]))
|
for (auto& l : Lexer::split (_aliases[i]))
|
||||||
reconstructedOriginals.push_back (l);
|
reconstructedOriginals.push_back (l);
|
||||||
|
@ -742,8 +785,10 @@ void CLI2::aliasExpansion ()
|
||||||
changes = true;
|
changes = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
reconstructedOriginals.push_back (i);
|
reconstructedOriginals.push_back (i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_original_args = reconstructedOriginals;
|
_original_args = reconstructedOriginals;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,10 +73,8 @@ public:
|
||||||
|
|
||||||
void add (const std::string&);
|
void add (const std::string&);
|
||||||
void analyze ();
|
void analyze ();
|
||||||
/*
|
|
||||||
void addContextFilter ();
|
|
||||||
*/
|
|
||||||
void addFilter (const std::string& arg);
|
void addFilter (const std::string& arg);
|
||||||
|
void addContextFilter ();
|
||||||
void prepareFilter (bool applyContext = true);
|
void prepareFilter (bool applyContext = true);
|
||||||
const std::vector <std::string> getWords (bool filtered = true);
|
const std::vector <std::string> getWords (bool filtered = true);
|
||||||
bool canonicalize (std::string&, const std::string&, const std::string&) const;
|
bool canonicalize (std::string&, const std::string&, const std::string&) const;
|
||||||
|
|
|
@ -73,7 +73,8 @@ void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output
|
||||||
context.timer_filter.start ();
|
context.timer_filter.start ();
|
||||||
_startCount = (int) input.size ();
|
_startCount = (int) input.size ();
|
||||||
|
|
||||||
// context.cli2.prepareFilter (applyContext);
|
context.cli2.prepareFilter (applyContext);
|
||||||
|
|
||||||
std::vector <std::pair <std::string, Lexer::Type>> precompiled;
|
std::vector <std::pair <std::string, Lexer::Type>> precompiled;
|
||||||
for (auto& a : context.cli2._args)
|
for (auto& a : context.cli2._args)
|
||||||
if (a.hasTag ("FILTER"))
|
if (a.hasTag ("FILTER"))
|
||||||
|
@ -118,6 +119,8 @@ void Filter::subset (std::vector <Task>& output, bool applyContext /* = true */)
|
||||||
{
|
{
|
||||||
context.timer_filter.start ();
|
context.timer_filter.start ();
|
||||||
|
|
||||||
|
context.cli2.prepareFilter (applyContext);
|
||||||
|
|
||||||
std::vector <std::pair <std::string, Lexer::Type>> precompiled;
|
std::vector <std::pair <std::string, Lexer::Type>> precompiled;
|
||||||
for (auto& a : context.cli2._args)
|
for (auto& a : context.cli2._args)
|
||||||
if (a.hasTag ("FILTER"))
|
if (a.hasTag ("FILTER"))
|
||||||
|
@ -179,7 +182,7 @@ void Filter::subset (std::vector <Task>& output, bool applyContext /* = true */)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
safety (precompiled.size ());
|
safety ();
|
||||||
context.timer_filter.stop ();
|
context.timer_filter.stop ();
|
||||||
|
|
||||||
for (auto& task : context.tdb2.pending.get_tasks ())
|
for (auto& task : context.tdb2.pending.get_tasks ())
|
||||||
|
@ -258,15 +261,13 @@ bool Filter::pendingOnly ()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Disaster avoidance mechanism. If a WRITECMD has no filter, then it can cause
|
// Disaster avoidance mechanism. If a WRITECMD has no filter, then it can cause
|
||||||
// all tasks to be modified. This is usually not intended.
|
// all tasks to be modified. This is usually not intended.
|
||||||
void Filter::safety (unsigned int terms)
|
void Filter::safety ()
|
||||||
{
|
{
|
||||||
for (auto& a : context.cli2._args)
|
for (auto& a : context.cli2._args)
|
||||||
{
|
{
|
||||||
if (a.hasTag ("CMD"))
|
if (a.hasTag ("CMD"))
|
||||||
{
|
{
|
||||||
if (a.hasTag ("WRITECMD"))
|
if (a.hasTag ("WRITECMD"))
|
||||||
{
|
|
||||||
if (terms)
|
|
||||||
{
|
{
|
||||||
if (! context.config.getBoolean ("allow.empty.filter"))
|
if (! context.config.getBoolean ("allow.empty.filter"))
|
||||||
throw std::string (STRING_TASK_SAFETY_ALLOW);
|
throw std::string (STRING_TASK_SAFETY_ALLOW);
|
||||||
|
@ -279,7 +280,6 @@ void Filter::safety (unsigned int terms)
|
||||||
// Sounds the alarm.
|
// Sounds the alarm.
|
||||||
throw std::string (STRING_TASK_SAFETY_FAIL);
|
throw std::string (STRING_TASK_SAFETY_FAIL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// CMD was found.
|
// CMD was found.
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
void subset (const std::vector <Task>&, std::vector <Task>&, bool applyContext = true);
|
void subset (const std::vector <Task>&, std::vector <Task>&, bool applyContext = true);
|
||||||
void subset (std::vector <Task>&, bool applyContext = true);
|
void subset (std::vector <Task>&, bool applyContext = true);
|
||||||
bool pendingOnly ();
|
bool pendingOnly ();
|
||||||
void safety (unsigned int);
|
void safety ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _startCount;
|
int _startCount;
|
||||||
|
|
243
src/ISO8601.cpp
243
src/ISO8601.cpp
|
@ -61,16 +61,9 @@ void ISO8601d::ambiguity (bool value)
|
||||||
// | date-ext 'T' time-ext offset-ext # Specified TZ
|
// | date-ext 'T' time-ext offset-ext # Specified TZ
|
||||||
// | date-ext 'T' time-ext # Local
|
// | date-ext 'T' time-ext # Local
|
||||||
// | date-ext # Local
|
// | date-ext # Local
|
||||||
// | date 'T' time 'Z'
|
|
||||||
// | date 'T' time offset-ext
|
|
||||||
// | date 'T' time
|
|
||||||
// | date
|
|
||||||
// | time-ext 'Z'
|
// | time-ext 'Z'
|
||||||
// | time-ext offset-ext Not needed
|
// | time-ext offset-ext Not needed
|
||||||
// | time-ext
|
// | time-ext
|
||||||
// | time 'Z'
|
|
||||||
// | time offset
|
|
||||||
// | time
|
|
||||||
// ;
|
// ;
|
||||||
//
|
//
|
||||||
// date-ext ::= ±YYYYY-MM-DD Νot needed
|
// date-ext ::= ±YYYYY-MM-DD Νot needed
|
||||||
|
@ -83,37 +76,14 @@ void ISO8601d::ambiguity (bool value)
|
||||||
// | YYYY-Www
|
// | YYYY-Www
|
||||||
// ;
|
// ;
|
||||||
//
|
//
|
||||||
// date ::= ±YYYYYMMDD Νot needed
|
|
||||||
// | ±YYYYYWwwD Νot needed
|
|
||||||
// | ±YYYYYWww Νot needed
|
|
||||||
// | ±YYYYYDDD Νot needed
|
|
||||||
// | ±YYYYYMM Νot needed
|
|
||||||
// | ±YYYYY Νot needed
|
|
||||||
// | ±YYY Νot needed
|
|
||||||
// | YYYYMMDD Ambiguous (number)
|
|
||||||
// | YYYYWwwD
|
|
||||||
// | YYYYWww
|
|
||||||
// | YYYYDDD Ambiguous (number)
|
|
||||||
// | YYYY-MM
|
|
||||||
// | YYYY Ambiguous (number)
|
|
||||||
// | YY Ambiguous (number)
|
|
||||||
// ;
|
|
||||||
//
|
|
||||||
// time-ext ::= hh:mm:ss[,ss]
|
// time-ext ::= hh:mm:ss[,ss]
|
||||||
// | hh:mm[,mm]
|
// | hh:mm[,mm]
|
||||||
// | hh[,hh] Ambiguous (number)
|
// | hh[,hh] Ambiguous (number)
|
||||||
// ;
|
// ;
|
||||||
//
|
//
|
||||||
// time ::= hhmmss[,ss] Ambiguous (number)
|
|
||||||
// | hhmm[,mm] Ambiguous (number)
|
|
||||||
// | hh[,hh] Ambiguous (number)
|
|
||||||
// ;
|
|
||||||
//
|
|
||||||
// time-utc-ext ::= hh:mm[:ss] 'Z' ;
|
// time-utc-ext ::= hh:mm[:ss] 'Z' ;
|
||||||
// time-utc ::= hh[mm[ss]] 'Z' ;
|
|
||||||
//
|
//
|
||||||
// offset-ext ::= ±hh[:mm] ;
|
// offset-ext ::= ±hh[:mm] ;
|
||||||
// offset ::= ±hh[mm] ;
|
|
||||||
//
|
//
|
||||||
// Not yet supported:
|
// Not yet supported:
|
||||||
//
|
//
|
||||||
|
@ -136,12 +106,7 @@ bool ISO8601d::parse (const std::string& input, std::string::size_type& start)
|
||||||
parse_date_ext (n) ||
|
parse_date_ext (n) ||
|
||||||
parse_time_utc_ext (n) ||
|
parse_time_utc_ext (n) ||
|
||||||
parse_time_off_ext (n) ||
|
parse_time_off_ext (n) ||
|
||||||
parse_date_time (n) ||
|
parse_time_ext (n)) // Time last, as it is the most permissive.
|
||||||
parse_date (n, _ambiguity) ||
|
|
||||||
parse_time_utc (n) ||
|
|
||||||
parse_time_off (n) ||
|
|
||||||
parse_time_ext (n) || // Time last, as it is the most permissive.
|
|
||||||
parse_time (n, _ambiguity))
|
|
||||||
{
|
{
|
||||||
// Check the values and determine time_t.
|
// Check the values and determine time_t.
|
||||||
if (validate ())
|
if (validate ())
|
||||||
|
@ -214,47 +179,6 @@ bool ISO8601d::parse_date_time_ext (Nibbler& n)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// date 'T' time 'Z'
|
|
||||||
// date 'T' time offset
|
|
||||||
// date 'T' time
|
|
||||||
bool ISO8601d::parse_date_time (Nibbler& n)
|
|
||||||
{
|
|
||||||
Nibbler backup (n);
|
|
||||||
if (parse_date (n, true))
|
|
||||||
{
|
|
||||||
if (n.skip ('T') &&
|
|
||||||
parse_time (n, true))
|
|
||||||
{
|
|
||||||
if (n.skip ('Z'))
|
|
||||||
{
|
|
||||||
_utc = true;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (parse_off (n))
|
|
||||||
{
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore date
|
|
||||||
_year = 0;
|
|
||||||
_month = 0;
|
|
||||||
_week = 0;
|
|
||||||
_weekday = 0;
|
|
||||||
_julian = 0;
|
|
||||||
_day = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = backup;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// YYYY-MM-DD
|
// YYYY-MM-DD
|
||||||
// YYYY-DDD
|
// YYYY-DDD
|
||||||
|
@ -303,64 +227,6 @@ bool ISO8601d::parse_date_ext (Nibbler& n)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// YYYYMMDD Ambiguous (number)
|
|
||||||
// YYYYWwwD
|
|
||||||
// YYYYWww
|
|
||||||
// YYYYDDD Ambiguous (number)
|
|
||||||
// YYYY-MM
|
|
||||||
bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
|
|
||||||
{
|
|
||||||
Nibbler backup (n);
|
|
||||||
int year;
|
|
||||||
if (n.getDigit4 (year))
|
|
||||||
{
|
|
||||||
int month;
|
|
||||||
if (n.skip ('W'))
|
|
||||||
{
|
|
||||||
int week;
|
|
||||||
if (n.getDigit2 (week))
|
|
||||||
{
|
|
||||||
_week = week;
|
|
||||||
|
|
||||||
int day;
|
|
||||||
if (n.getDigit (day))
|
|
||||||
_weekday = day;
|
|
||||||
|
|
||||||
_year = year;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (n.skip ('-'))
|
|
||||||
{
|
|
||||||
if (n.getDigit2 (_month))
|
|
||||||
{
|
|
||||||
_year = year;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (n.getDigit4 (month))
|
|
||||||
{
|
|
||||||
_year = year;
|
|
||||||
_month = month / 100;
|
|
||||||
_day = month % 100;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ambiguous && n.getDigit3 (_julian))
|
|
||||||
{
|
|
||||||
_year = year;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n = backup;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// ±hh[:mm]
|
// ±hh[:mm]
|
||||||
bool ISO8601d::parse_off_ext (Nibbler& n)
|
bool ISO8601d::parse_off_ext (Nibbler& n)
|
||||||
|
@ -394,37 +260,7 @@ bool ISO8601d::parse_off_ext (Nibbler& n)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// ±hh[mm]
|
// hh:mm[:ss]
|
||||||
bool ISO8601d::parse_off (Nibbler& n)
|
|
||||||
{
|
|
||||||
Nibbler backup (n);
|
|
||||||
std::string sign;
|
|
||||||
if (n.getN (1, sign))
|
|
||||||
{
|
|
||||||
if (sign == "+" || sign == "-")
|
|
||||||
{
|
|
||||||
int offset;
|
|
||||||
int hh;
|
|
||||||
if (n.getDigit2 (hh))
|
|
||||||
{
|
|
||||||
offset = hh * 3600;
|
|
||||||
int mm;
|
|
||||||
if (n.getDigit2 (mm))
|
|
||||||
offset += mm * 60;
|
|
||||||
|
|
||||||
_offset = (sign == "-") ? -offset : offset;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n = backup;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// hh[:mm[:ss]]
|
|
||||||
bool ISO8601d::parse_time_ext (Nibbler& n)
|
bool ISO8601d::parse_time_ext (Nibbler& n)
|
||||||
{
|
{
|
||||||
Nibbler backup (n);
|
Nibbler backup (n);
|
||||||
|
@ -433,20 +269,15 @@ bool ISO8601d::parse_time_ext (Nibbler& n)
|
||||||
int mm;
|
int mm;
|
||||||
int ss;
|
int ss;
|
||||||
if (n.getDigit2 (hh) &&
|
if (n.getDigit2 (hh) &&
|
||||||
!n.getDigit (mm))
|
n.skip (':') &&
|
||||||
|
n.getDigit2 (mm))
|
||||||
{
|
{
|
||||||
seconds = hh * 3600;
|
seconds = (hh * 3600) + (mm * 60);
|
||||||
|
|
||||||
if (n.skip (':') &&
|
|
||||||
n.getDigit2 (mm) &&
|
|
||||||
!n.getDigit (ss))
|
|
||||||
{
|
|
||||||
seconds += mm * 60;
|
|
||||||
|
|
||||||
if (n.skip (':') &&
|
if (n.skip (':') &&
|
||||||
n.getDigit2 (ss))
|
n.getDigit2 (ss))
|
||||||
|
{
|
||||||
seconds += ss;
|
seconds += ss;
|
||||||
|
|
||||||
_seconds = seconds;
|
_seconds = seconds;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -463,35 +294,6 @@ bool ISO8601d::parse_time_ext (Nibbler& n)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// hhmm[ss]
|
|
||||||
bool ISO8601d::parse_time (Nibbler& n, bool ambiguous)
|
|
||||||
{
|
|
||||||
if (!ambiguous)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Nibbler backup (n);
|
|
||||||
int seconds = 0;
|
|
||||||
int hh;
|
|
||||||
int mm;
|
|
||||||
if (n.getDigit2 (hh) &&
|
|
||||||
n.getDigit2 (mm))
|
|
||||||
{
|
|
||||||
seconds = hh * 3600 + mm * 60;
|
|
||||||
|
|
||||||
int ss;
|
|
||||||
if (n.getDigit2 (ss))
|
|
||||||
seconds += ss;
|
|
||||||
|
|
||||||
_seconds = seconds;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = backup;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// time-ext 'Z'
|
// time-ext 'Z'
|
||||||
bool ISO8601d::parse_time_utc_ext (Nibbler& n)
|
bool ISO8601d::parse_time_utc_ext (Nibbler& n)
|
||||||
|
@ -509,23 +311,6 @@ bool ISO8601d::parse_time_utc_ext (Nibbler& n)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// time 'Z'
|
|
||||||
bool ISO8601d::parse_time_utc (Nibbler& n)
|
|
||||||
{
|
|
||||||
n.save ();
|
|
||||||
if (parse_time (n, true) &&
|
|
||||||
n.skip ('Z'))
|
|
||||||
{
|
|
||||||
_utc = true;
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
n.restore ();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// time-ext offset-ext
|
// time-ext offset-ext
|
||||||
bool ISO8601d::parse_time_off_ext (Nibbler& n)
|
bool ISO8601d::parse_time_off_ext (Nibbler& n)
|
||||||
|
@ -542,22 +327,6 @@ bool ISO8601d::parse_time_off_ext (Nibbler& n)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// time offset
|
|
||||||
bool ISO8601d::parse_time_off (Nibbler& n)
|
|
||||||
{
|
|
||||||
Nibbler backup (n);
|
|
||||||
if (parse_time (n, true) &&
|
|
||||||
parse_off (n))
|
|
||||||
{
|
|
||||||
if (!Lexer::isDigit (n.next ()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = backup;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Using Zeller's Congruence.
|
// Using Zeller's Congruence.
|
||||||
int ISO8601d::dayOfWeek (int year, int month, int day)
|
int ISO8601d::dayOfWeek (int year, int month, int day)
|
||||||
|
|
|
@ -45,17 +45,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool parse_date_time_ext (Nibbler&);
|
bool parse_date_time_ext (Nibbler&);
|
||||||
bool parse_date_time (Nibbler&);
|
|
||||||
bool parse_date_ext (Nibbler&);
|
bool parse_date_ext (Nibbler&);
|
||||||
bool parse_date (Nibbler&, bool);
|
|
||||||
bool parse_off_ext (Nibbler&);
|
bool parse_off_ext (Nibbler&);
|
||||||
bool parse_off (Nibbler&);
|
|
||||||
bool parse_time_ext (Nibbler&);
|
bool parse_time_ext (Nibbler&);
|
||||||
bool parse_time (Nibbler&, bool);
|
|
||||||
bool parse_time_utc_ext (Nibbler&);
|
bool parse_time_utc_ext (Nibbler&);
|
||||||
bool parse_time_utc (Nibbler&);
|
|
||||||
bool parse_time_off_ext (Nibbler&);
|
bool parse_time_off_ext (Nibbler&);
|
||||||
bool parse_time_off (Nibbler&);
|
|
||||||
int dayOfWeek (int, int, int);
|
int dayOfWeek (int, int, int);
|
||||||
bool validate ();
|
bool validate ();
|
||||||
void resolve ();
|
void resolve ();
|
||||||
|
|
|
@ -324,6 +324,15 @@ void Lexer::dequote (std::string& input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool Lexer::wasQuoted (const std::string& input)
|
||||||
|
{
|
||||||
|
if (input.find_first_of (" \t()") != std::string::npos)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool Lexer::isEOS () const
|
bool Lexer::isEOS () const
|
||||||
{
|
{
|
||||||
|
|
|
@ -75,6 +75,7 @@ public:
|
||||||
static bool isBoundary (int, int);
|
static bool isBoundary (int, int);
|
||||||
static bool isPunctuation (int);
|
static bool isPunctuation (int);
|
||||||
static void dequote (std::string&);
|
static void dequote (std::string&);
|
||||||
|
static bool wasQuoted (const std::string&);
|
||||||
|
|
||||||
// Helpers.
|
// Helpers.
|
||||||
bool isEOS () const;
|
bool isEOS () const;
|
||||||
|
|
|
@ -1092,6 +1092,7 @@ bool Task::hasTag (const std::string& tag) const
|
||||||
{
|
{
|
||||||
// Synthetic tags - dynamically generated, but do not occupy storage space.
|
// Synthetic tags - dynamically generated, but do not occupy storage space.
|
||||||
// Note: This list must match that in CmdInfo::execute.
|
// Note: This list must match that in CmdInfo::execute.
|
||||||
|
// Note: This list must match that in ::feedback_reserved_tags.
|
||||||
if (tag == "BLOCKED") return is_blocked;
|
if (tag == "BLOCKED") return is_blocked;
|
||||||
if (tag == "UNBLOCKED") return !is_blocked;
|
if (tag == "UNBLOCKED") return !is_blocked;
|
||||||
if (tag == "BLOCKING") return is_blocking;
|
if (tag == "BLOCKING") return is_blocking;
|
||||||
|
@ -2094,11 +2095,13 @@ void Task::modify (modType type, bool text_required /* = false */)
|
||||||
else if (a._lextype == Lexer::Type::tag)
|
else if (a._lextype == Lexer::Type::tag)
|
||||||
{
|
{
|
||||||
std::string tag = a.attribute ("name");
|
std::string tag = a.attribute ("name");
|
||||||
|
feedback_reserved_tags (tag);
|
||||||
|
|
||||||
if (a.attribute ("sign") == "+")
|
if (a.attribute ("sign") == "+")
|
||||||
{
|
{
|
||||||
context.debug (label + "tags <-- add '" + tag + "'");
|
context.debug (label + "tags <-- add '" + tag + "'");
|
||||||
addTag (tag);
|
addTag (tag);
|
||||||
feedback_special_tags ((*this), tag);
|
feedback_special_tags (*this, tag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,8 +63,7 @@ int CmdCalc::execute (std::string& output)
|
||||||
|
|
||||||
// Compile all the args into one expression.
|
// Compile all the args into one expression.
|
||||||
std::string expression;
|
std::string expression;
|
||||||
std::vector <std::string> words = context.cli2.getWords ();
|
for (auto& word : context.cli2.getWords ())
|
||||||
for (auto& word : words)
|
|
||||||
expression += word + " ";
|
expression += word + " ";
|
||||||
|
|
||||||
// Evaluate according to preference.
|
// Evaluate according to preference.
|
||||||
|
|
|
@ -81,10 +81,7 @@ int CmdCustom::execute (std::string& output)
|
||||||
|
|
||||||
// Add the report filter to any existing filter.
|
// Add the report filter to any existing filter.
|
||||||
if (reportFilter != "")
|
if (reportFilter != "")
|
||||||
{
|
|
||||||
context.cli2.addFilter (reportFilter);
|
context.cli2.addFilter (reportFilter);
|
||||||
context.cli2.prepareFilter ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply filter.
|
// Apply filter.
|
||||||
handleRecurrence ();
|
handleRecurrence ();
|
||||||
|
|
|
@ -303,6 +303,7 @@ int CmdInfo::execute (std::string& output)
|
||||||
// Virtual tags.
|
// Virtual tags.
|
||||||
{
|
{
|
||||||
// Note: This list must match that in Task::hasTag.
|
// Note: This list must match that in Task::hasTag.
|
||||||
|
// Note: This list must match that in ::feedback_reserved_tags.
|
||||||
std::string virtualTags = "";
|
std::string virtualTags = "";
|
||||||
if (task.hasTag ("ACTIVE")) virtualTags += "ACTIVE ";
|
if (task.hasTag ("ACTIVE")) virtualTags += "ACTIVE ";
|
||||||
if (task.hasTag ("ANNOTATED")) virtualTags += "ANNOTATED ";
|
if (task.hasTag ("ANNOTATED")) virtualTags += "ANNOTATED ";
|
||||||
|
|
|
@ -351,6 +351,41 @@ void feedback_affected (const std::string& effect, const Task& task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Implements feedback and error when adding a reserved tag name.
|
||||||
|
void feedback_reserved_tags (const std::string& tag)
|
||||||
|
{
|
||||||
|
// Note: This list must match that in Task::hasTag.
|
||||||
|
// Note: This list must match that in CmdInfo::execute.
|
||||||
|
if (tag == "BLOCKED" ||
|
||||||
|
tag == "UNBLOCKED" ||
|
||||||
|
tag == "BLOCKING" ||
|
||||||
|
tag == "READY" ||
|
||||||
|
tag == "DUE" ||
|
||||||
|
tag == "DUETODAY" ||
|
||||||
|
tag == "TODAY" ||
|
||||||
|
tag == "YESTERDAY" ||
|
||||||
|
tag == "TOMORROW" ||
|
||||||
|
tag == "OVERDUE" ||
|
||||||
|
tag == "WEEK" ||
|
||||||
|
tag == "MONTH" ||
|
||||||
|
tag == "YEAR" ||
|
||||||
|
tag == "ACTIVE" ||
|
||||||
|
tag == "SCHEDULED" ||
|
||||||
|
tag == "CHILD" ||
|
||||||
|
tag == "UNTIL" ||
|
||||||
|
tag == "ANNOTATED" ||
|
||||||
|
tag == "TAGGED" ||
|
||||||
|
tag == "PARENT" ||
|
||||||
|
tag == "WAITING" ||
|
||||||
|
tag == "PENDING" ||
|
||||||
|
tag == "COMPLETED" ||
|
||||||
|
tag == "DELETED")
|
||||||
|
{
|
||||||
|
throw format (STRING_FEEDBACK_TAG_VIRTUAL, tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Implements feedback when adding special tags to a task.
|
// Implements feedback when adding special tags to a task.
|
||||||
void feedback_special_tags (const Task& task, const std::string& tag)
|
void feedback_special_tags (const Task& task, const std::string& tag)
|
||||||
|
|
|
@ -792,6 +792,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "Das besondere Schlagwort 'nonag' verhindert Nachfragen, wenn diese Aufgabe geändert wird."
|
#define STRING_FEEDBACK_TAG_NONAG "Das besondere Schlagwort 'nonag' verhindert Nachfragen, wenn diese Aufgabe geändert wird."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "Das besondere Schlagwort 'nocal' verhindert, dass diese Aufgabe im 'calendar'-Report erscheint."
|
#define STRING_FEEDBACK_TAG_NOCAL "Das besondere Schlagwort 'nocal' verhindert, dass diese Aufgabe im 'calendar'-Report erscheint."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "Das besondere Schlagwort 'next' erhöht die Dringlichkeit dieser Aufgabe, sodass sie im 'next'-Report erscheint."
|
#define STRING_FEEDBACK_TAG_NEXT "Das besondere Schlagwort 'next' erhöht die Dringlichkeit dieser Aufgabe, sodass sie im 'next'-Report erscheint."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Aufgabe {1} '{2}' entsperrt."
|
#define STRING_FEEDBACK_UNBLOCKED "Aufgabe {1} '{2}' entsperrt."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Aufgabe {1} '{2}' ist abgelaufen und wurde gelöscht."
|
#define STRING_FEEDBACK_EXPIRED "Aufgabe {1} '{2}' ist abgelaufen und wurde gelöscht."
|
||||||
#define STRING_FEEDBACK_BACKLOG "Lokale Änderungen. Datenabgleich erforderlich."
|
#define STRING_FEEDBACK_BACKLOG "Lokale Änderungen. Datenabgleich erforderlich."
|
||||||
|
|
|
@ -372,7 +372,7 @@
|
||||||
#define STRING_CMD_UDAS_ORPHANS "{1} Orphan UDAs"
|
#define STRING_CMD_UDAS_ORPHANS "{1} Orphan UDAs"
|
||||||
|
|
||||||
#define STRING_CMD_DELETE_USAGE "Deletes the specified task"
|
#define STRING_CMD_DELETE_USAGE "Deletes the specified task"
|
||||||
#define STRING_CMD_DELETE_CONFIRM "Permanently delete task {1} '{2}'?"
|
#define STRING_CMD_DELETE_CONFIRM "Delete task {1} '{2}'?"
|
||||||
#define STRING_CMD_DELETE_TASK "Deleting task {1} '{2}'."
|
#define STRING_CMD_DELETE_TASK "Deleting task {1} '{2}'."
|
||||||
#define STRING_CMD_DELETE_TASK_R "Deleting recurring task {1} '{2}'."
|
#define STRING_CMD_DELETE_TASK_R "Deleting recurring task {1} '{2}'."
|
||||||
#define STRING_CMD_DELETE_CONFIRM_R "This is a recurring task. Do you want to delete all pending recurrences of this same task?"
|
#define STRING_CMD_DELETE_CONFIRM_R "This is a recurring task. Do you want to delete all pending recurrences of this same task?"
|
||||||
|
@ -792,6 +792,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "The 'nonag' special tag will prevent nagging when this task is modified."
|
#define STRING_FEEDBACK_TAG_NONAG "The 'nonag' special tag will prevent nagging when this task is modified."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the 'calendar' report."
|
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the 'calendar' report."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Task {1} '{2}' expired and was deleted."
|
#define STRING_FEEDBACK_EXPIRED "Task {1} '{2}' expired and was deleted."
|
||||||
#define STRING_FEEDBACK_BACKLOG "There are local changes. Sync required."
|
#define STRING_FEEDBACK_BACKLOG "There are local changes. Sync required."
|
||||||
|
|
|
@ -792,6 +792,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "Speciala etikedo 'nonag' antaŭmalebligitos molestojn, kiam oni modifus tiun taskon."
|
#define STRING_FEEDBACK_TAG_NONAG "Speciala etikedo 'nonag' antaŭmalebligitos molestojn, kiam oni modifus tiun taskon."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "Speciala etikedo 'nocal' ekskluzivos tiun taskon ĉe raporto 'calendar'."
|
#define STRING_FEEDBACK_TAG_NOCAL "Speciala etikedo 'nocal' ekskluzivos tiun taskon ĉe raporto 'calendar'."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "Speciala etikedo 'next' pligrandigos la urĝecon de tiu tasko por ke ĝi aperus ĉe raporto 'next'."
|
#define STRING_FEEDBACK_TAG_NEXT "Speciala etikedo 'next' pligrandigos la urĝecon de tiu tasko por ke ĝi aperus ĉe raporto 'next'."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Malblokis {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Malblokis {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Tasko {1} '{2}' fortempiĝis do estis viŝata."
|
#define STRING_FEEDBACK_EXPIRED "Tasko {1} '{2}' fortempiĝis do estis viŝata."
|
||||||
#define STRING_FEEDBACK_BACKLOG "Estas lokaj ŝanĝoj. Sinkronigo devita."
|
#define STRING_FEEDBACK_BACKLOG "Estas lokaj ŝanĝoj. Sinkronigo devita."
|
||||||
|
|
|
@ -804,6 +804,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "La marca especial 'nonag' evitará el recuerdo fastidioso cuando la tarea sea modificada."
|
#define STRING_FEEDBACK_TAG_NONAG "La marca especial 'nonag' evitará el recuerdo fastidioso cuando la tarea sea modificada."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "La marca especial 'nocal' mantendrá esta tarea fuera del informe 'calendar'."
|
#define STRING_FEEDBACK_TAG_NOCAL "La marca especial 'nocal' mantendrá esta tarea fuera del informe 'calendar'."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "La etiqueta especial 'next' aumentará la urgencia de esta tarea para que aparezca en el informe 'next'."
|
#define STRING_FEEDBACK_TAG_NEXT "La etiqueta especial 'next' aumentará la urgencia de esta tarea para que aparezca en el informe 'next'."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Desbloqueada {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Desbloqueada {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "La tarea {1} '{2}' caducó y fue eliminada."
|
#define STRING_FEEDBACK_EXPIRED "La tarea {1} '{2}' caducó y fue eliminada."
|
||||||
#define STRING_FEEDBACK_BACKLOG "Hay modificaciones locales. Se require una sincronización."
|
#define STRING_FEEDBACK_BACKLOG "Hay modificaciones locales. Se require una sincronización."
|
||||||
|
|
|
@ -792,6 +792,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "The 'nonag' special tag will prevent nagging when this task is modified."
|
#define STRING_FEEDBACK_TAG_NONAG "The 'nonag' special tag will prevent nagging when this task is modified."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the 'calendar' report."
|
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the 'calendar' report."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Tâche {1} '{2}' a expiré et a été supprimée."
|
#define STRING_FEEDBACK_EXPIRED "Tâche {1} '{2}' a expiré et a été supprimée."
|
||||||
#define STRING_FEEDBACK_BACKLOG "Il y a des changements locaux. Synchronisation requise."
|
#define STRING_FEEDBACK_BACKLOG "Il y a des changements locaux. Synchronisation requise."
|
||||||
|
|
|
@ -791,6 +791,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "Il tag speciale 'nonag' eviterà problemi quando il task è modificato."
|
#define STRING_FEEDBACK_TAG_NONAG "Il tag speciale 'nonag' eviterà problemi quando il task è modificato."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "Il tag speciale 'nocal' manterrà il task fuori dal report 'calendar'."
|
#define STRING_FEEDBACK_TAG_NOCAL "Il tag speciale 'nocal' manterrà il task fuori dal report 'calendar'."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "Il tag speciale 'next' aumenterà l'urgenza di questo task in modo che appaia nel report 'next'."
|
#define STRING_FEEDBACK_TAG_NEXT "Il tag speciale 'next' aumenterà l'urgenza di questo task in modo che appaia nel report 'next'."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Sbloccato {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Sbloccato {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Il task {1} '{2}' è scaduto ed è stato eliminato"
|
#define STRING_FEEDBACK_EXPIRED "Il task {1} '{2}' è scaduto ed è stato eliminato"
|
||||||
#define STRING_FEEDBACK_BACKLOG "There are local changes. Sync required."
|
#define STRING_FEEDBACK_BACKLOG "There are local changes. Sync required."
|
||||||
|
|
|
@ -792,6 +792,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "The 'nonag' special tag will prevent nagging when this task is modified."
|
#define STRING_FEEDBACK_TAG_NONAG "The 'nonag' special tag will prevent nagging when this task is modified."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the 'calendar' report."
|
#define STRING_FEEDBACK_TAG_NOCAL "The 'nocal' special tag will keep this task off the 'calendar' report."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
#define STRING_FEEDBACK_TAG_NEXT "The 'next' special tag will boost the urgency of this task so it appears on the 'next' report."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Unblocked {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Task {1} '{2}' expired and was deleted."
|
#define STRING_FEEDBACK_EXPIRED "Task {1} '{2}' expired and was deleted."
|
||||||
#define STRING_FEEDBACK_BACKLOG "There are local changes. Sync required."
|
#define STRING_FEEDBACK_BACKLOG "There are local changes. Sync required."
|
||||||
|
|
|
@ -792,6 +792,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "Specjalny tag 'nonag' uchroni przed upierdliwością kiedy zadanie jest modyfikowane."
|
#define STRING_FEEDBACK_TAG_NONAG "Specjalny tag 'nonag' uchroni przed upierdliwością kiedy zadanie jest modyfikowane."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "Specjalny tag 'nocal' spowoduje nie dodawanie zadania do kalendarza."
|
#define STRING_FEEDBACK_TAG_NOCAL "Specjalny tag 'nocal' spowoduje nie dodawanie zadania do kalendarza."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "Specjalny tag 'next' podniesie pilność tego zadania co spowoduje wyświetlenie go w raporcie 'next'."
|
#define STRING_FEEDBACK_TAG_NEXT "Specjalny tag 'next' podniesie pilność tego zadania co spowoduje wyświetlenie go w raporcie 'next'."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Odblokowane {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Odblokowane {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Zadanie {1} '{2}' jest przedawnione i zostało usunięte."
|
#define STRING_FEEDBACK_EXPIRED "Zadanie {1} '{2}' jest przedawnione i zostało usunięte."
|
||||||
#define STRING_FEEDBACK_BACKLOG "Wykryto lokalne zmiany. Wymagana synchronizacja."
|
#define STRING_FEEDBACK_BACKLOG "Wykryto lokalne zmiany. Wymagana synchronizacja."
|
||||||
|
|
|
@ -792,6 +792,7 @@
|
||||||
#define STRING_FEEDBACK_TAG_NONAG "A marca especial 'nonag' irá prevenir avisos quando a tarefa é modificada."
|
#define STRING_FEEDBACK_TAG_NONAG "A marca especial 'nonag' irá prevenir avisos quando a tarefa é modificada."
|
||||||
#define STRING_FEEDBACK_TAG_NOCAL "A marca especial 'nocal' irá manter esta tarefa ausente do relatório de 'calendário'."
|
#define STRING_FEEDBACK_TAG_NOCAL "A marca especial 'nocal' irá manter esta tarefa ausente do relatório de 'calendário'."
|
||||||
#define STRING_FEEDBACK_TAG_NEXT "A marca especial 'next' irá aumentar a urgência desta tarefa de modo a que apareça no relatório 'next'."
|
#define STRING_FEEDBACK_TAG_NEXT "A marca especial 'next' irá aumentar a urgência desta tarefa de modo a que apareça no relatório 'next'."
|
||||||
|
#define STRING_FEEDBACK_TAG_VIRTUAL "Virtual tags (including '{1}') are reserved and may not be added or removed."
|
||||||
#define STRING_FEEDBACK_UNBLOCKED "Desbloqueada {1} '{2}'."
|
#define STRING_FEEDBACK_UNBLOCKED "Desbloqueada {1} '{2}'."
|
||||||
#define STRING_FEEDBACK_EXPIRED "Tarefa {1} '{2}' expirou e foi eliminada."
|
#define STRING_FEEDBACK_EXPIRED "Tarefa {1} '{2}' expirou e foi eliminada."
|
||||||
#define STRING_FEEDBACK_BACKLOG "Há modificações locais. Necessário sincronizar (sync)."
|
#define STRING_FEEDBACK_BACKLOG "Há modificações locais. Necessário sincronizar (sync)."
|
||||||
|
|
|
@ -67,6 +67,7 @@ std::string renderAttribute (const std::string&, const std::string&, const std::
|
||||||
void feedback_affected (const std::string&);
|
void feedback_affected (const std::string&);
|
||||||
void feedback_affected (const std::string&, int);
|
void feedback_affected (const std::string&, int);
|
||||||
void feedback_affected (const std::string&, const Task&);
|
void feedback_affected (const std::string&, const Task&);
|
||||||
|
void feedback_reserved_tags (const std::string&);
|
||||||
void feedback_special_tags (const Task&, const std::string&);
|
void feedback_special_tags (const Task&, const std::string&);
|
||||||
void feedback_unblocked (const Task&);
|
void feedback_unblocked (const Task&);
|
||||||
void feedback_backlog ();
|
void feedback_backlog ();
|
||||||
|
|
|
@ -36,35 +36,29 @@ from basetest import Task, TestCase
|
||||||
|
|
||||||
|
|
||||||
class TestIDPosition(TestCase):
|
class TestIDPosition(TestCase):
|
||||||
def setUp(self):
|
@classmethod
|
||||||
"""Executed before each test in the class"""
|
def setUpClass(cls):
|
||||||
self.t = Task()
|
"""Executed once before any test in the class"""
|
||||||
|
cls.t = Task()
|
||||||
|
|
||||||
self.t(("add", "one"))
|
cls.t(("add", "one"))
|
||||||
self.t(("add", "two"))
|
cls.t(("add", "two"))
|
||||||
self.t(("add", "three"))
|
|
||||||
|
|
||||||
def test_id(self):
|
|
||||||
"""Test id before and after command"""
|
|
||||||
code, out, err = self.t(("list",))
|
|
||||||
|
|
||||||
|
def test_id_read_cmd(self):
|
||||||
|
"""Test id before and after read command"""
|
||||||
|
code, out, err = self.t(("1", "info"))
|
||||||
self.assertIn("one", out)
|
self.assertIn("one", out)
|
||||||
self.assertIn("two", out)
|
self.assertNotIn("two", out)
|
||||||
self.assertIn("three", out)
|
|
||||||
|
|
||||||
code, out, err = self.t(("1", "done"))
|
code, out, err = self.t(("info", "1"))
|
||||||
self.assertIn("Completed 1 task.", out)
|
self.assertIn("one", out)
|
||||||
|
self.assertNotIn("two", out)
|
||||||
|
|
||||||
filter = "rc.allow.empty.filter:yes"
|
def test_id_write_cmd(self):
|
||||||
code, out, err = self.t.runError((filter, "done", "2"))
|
"""Test id before write command"""
|
||||||
self.assertIn("Command prevented from running.", err)
|
code, out, err = self.t(("2", "done"))
|
||||||
self.assertNotIn("Completed 1 task.", out)
|
self.assertIn("Completed task 2", out)
|
||||||
|
|
||||||
filter = "rc.allow.empty.filter:no"
|
|
||||||
code, out, err = self.t.runError((filter, "done", "2"))
|
|
||||||
self.assertIn("You did not specify a filter, and with the "
|
|
||||||
"'allow.empty.filter' value, no action is taken.", err)
|
|
||||||
self.assertNotIn("Completed 1 task.", out)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from simpletap import TAPTestRunner
|
from simpletap import TAPTestRunner
|
||||||
|
|
|
@ -84,17 +84,17 @@ $output = qx{../src/task rc:caseless.rc info 1 2>&1};
|
||||||
like ($output, qr/four five six/, 'one two three\nfour FIVE six -> /five/five/ = caseless succeed');
|
like ($output, qr/four five six/, 'one two three\nfour FIVE six -> /five/five/ = caseless succeed');
|
||||||
|
|
||||||
# Description filter.
|
# Description filter.
|
||||||
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:yes ls One 2>&1};
|
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:yes ls /One/ 2>&1};
|
||||||
unlike ($output, qr/one two three/, 'one two three\nfour five six -> ls One = fail');
|
unlike ($output, qr/one two three/, 'one two three\nfour five six -> ls /One/ = fail');
|
||||||
|
|
||||||
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:no ls One 2>&1};
|
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:no ls /One/ 2>&1};
|
||||||
like ($output, qr/one two three/, 'one two three\nfour five six -> ls One caseless = succeed');
|
like ($output, qr/one two three/, 'one two three\nfour five six -> ls One caseless = succeed');
|
||||||
|
|
||||||
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:yes ls Five 2>&1};
|
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:yes ls /Five/ 2>&1};
|
||||||
unlike ($output, qr/four five six/, 'one two three\nfour five six -> ls Five = fail');
|
unlike ($output, qr/four five six/, 'one two three\nfour five six -> ls /Five/ = fail');
|
||||||
|
|
||||||
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:no ls Five 2>&1};
|
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:no ls /Five/ 2>&1};
|
||||||
like ($output, qr/four five six/, 'one two three\nfour five six -> ls Five caseless = succeed');
|
like ($output, qr/four five six/, 'one two three\nfour five six -> ls /Five/ caseless = succeed');
|
||||||
|
|
||||||
# Annotation filter.
|
# Annotation filter.
|
||||||
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:yes ls description.contains:Three 2>&1};
|
$output = qx{../src/task rc:caseless.rc rc.search.case.sensitive:yes ls description.contains:Three 2>&1};
|
||||||
|
|
|
@ -56,49 +56,49 @@ qx{../src/task rc:$rc add foo 2>&1} for 1..10;
|
||||||
|
|
||||||
# Test the various forms of "Yes".
|
# Test the various forms of "Yes".
|
||||||
my $output = qx{echo "Yes" | ../src/task rc:$rc 1 del 2>&1};
|
my $output = qx{echo "Yes" | ../src/task rc:$rc 1 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 1 'foo'\? \(yes\/no\)/, 'confirmation - Yes works');
|
like ($output, qr/Delete task 1 'foo'\? \(yes\/no\)/, 'confirmation - Yes works');
|
||||||
unlike ($output, qr/Task not deleted\./, 'confirmation - Yes works');
|
unlike ($output, qr/Task not deleted\./, 'confirmation - Yes works');
|
||||||
|
|
||||||
$output = qx{echo "ye" | ../src/task rc:$rc 2 del 2>&1};
|
$output = qx{echo "ye" | ../src/task rc:$rc 2 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 2 'foo'\? \(yes\/no\)/, 'confirmation - ye works');
|
like ($output, qr/Delete task 2 'foo'\? \(yes\/no\)/, 'confirmation - ye works');
|
||||||
unlike ($output, qr/Task not deleted\./, 'confirmation - ye works');
|
unlike ($output, qr/Task not deleted\./, 'confirmation - ye works');
|
||||||
|
|
||||||
$output = qx{echo "y" | ../src/task rc:$rc 3 del 2>&1};
|
$output = qx{echo "y" | ../src/task rc:$rc 3 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 3 'foo'\? \(yes\/no\)/, 'confirmation - y works');
|
like ($output, qr/Delete task 3 'foo'\? \(yes\/no\)/, 'confirmation - y works');
|
||||||
unlike ($output, qr/Task not deleted\./, 'confirmation - y works');
|
unlike ($output, qr/Task not deleted\./, 'confirmation - y works');
|
||||||
|
|
||||||
$output = qx{echo "YES" | ../src/task rc:$rc 4 del 2>&1};
|
$output = qx{echo "YES" | ../src/task rc:$rc 4 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 4 'foo'\? \(yes\/no\)/, 'confirmation - YES works');
|
like ($output, qr/Delete task 4 'foo'\? \(yes\/no\)/, 'confirmation - YES works');
|
||||||
unlike ($output, qr/Task not deleted\./, 'confirmation - YES works'); # 10
|
unlike ($output, qr/Task not deleted\./, 'confirmation - YES works'); # 10
|
||||||
|
|
||||||
$output = qx{echo "YE" | ../src/task rc:$rc 5 del 2>&1};
|
$output = qx{echo "YE" | ../src/task rc:$rc 5 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 5 'foo'\? \(yes\/no\)/, 'confirmation - YE works');
|
like ($output, qr/Delete task 5 'foo'\? \(yes\/no\)/, 'confirmation - YE works');
|
||||||
unlike ($output, qr/Task not deleted\./, 'confirmation - YE works');
|
unlike ($output, qr/Task not deleted\./, 'confirmation - YE works');
|
||||||
|
|
||||||
$output = qx{echo "Y" | ../src/task rc:$rc 6 del 2>&1};
|
$output = qx{echo "Y" | ../src/task rc:$rc 6 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 6 'foo'\? \(yes\/no\)/, 'confirmation - Y works');
|
like ($output, qr/Delete task 6 'foo'\? \(yes\/no\)/, 'confirmation - Y works');
|
||||||
unlike ($output, qr/Task not deleted\./, 'confirmation - Y works');
|
unlike ($output, qr/Task not deleted\./, 'confirmation - Y works');
|
||||||
|
|
||||||
# Test the various forms of "no".
|
# Test the various forms of "no".
|
||||||
$output = qx{echo "no" | ../src/task rc:$rc 7 del 2>&1};
|
$output = qx{echo "no" | ../src/task rc:$rc 7 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - no works');
|
like ($output, qr/Delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - no works');
|
||||||
like ($output, qr/Task not deleted\./, 'confirmation - no works');
|
like ($output, qr/Task not deleted\./, 'confirmation - no works');
|
||||||
|
|
||||||
$output = qx{echo "n" | ../src/task rc:$rc 7 del 2>&1};
|
$output = qx{echo "n" | ../src/task rc:$rc 7 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - n works');
|
like ($output, qr/Delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - n works');
|
||||||
like ($output, qr/Task not deleted\./, 'confirmation - n works');
|
like ($output, qr/Task not deleted\./, 'confirmation - n works');
|
||||||
|
|
||||||
$output = qx{echo "NO" | ../src/task rc:$rc 7 del 2>&1};
|
$output = qx{echo "NO" | ../src/task rc:$rc 7 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - NO works');
|
like ($output, qr/Delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - NO works');
|
||||||
like ($output, qr/Task not deleted\./, 'confirmation - NO works'); # 20
|
like ($output, qr/Task not deleted\./, 'confirmation - NO works'); # 20
|
||||||
|
|
||||||
$output = qx{echo "N" | ../src/task rc:$rc 7 del 2>&1};
|
$output = qx{echo "N" | ../src/task rc:$rc 7 del 2>&1};
|
||||||
like ($output, qr/Permanently delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - N works');
|
like ($output, qr/Delete task 7 'foo'\? \(yes\/no\)/, 'confirmation - N works');
|
||||||
like ($output, qr/Task not deleted\./, 'confirmation - N works');
|
like ($output, qr/Task not deleted\./, 'confirmation - N works');
|
||||||
|
|
||||||
# Test newlines.
|
# Test newlines.
|
||||||
$output = qx{cat response.txt | ../src/task rc:$rc 7 del 2>&1};
|
$output = qx{cat response.txt | ../src/task rc:$rc 7 del 2>&1};
|
||||||
like ($output, qr/(Permanently delete task 7 'foo'\? \(yes\/no\)) \1 \1/, 'confirmation - \n re-prompt works'); # 43
|
like ($output, qr/(Delete task 7 'foo'\? \(yes\/no\)) \1 \1/, 'confirmation - \n re-prompt works'); # 43
|
||||||
|
|
||||||
# Cleanup.
|
# Cleanup.
|
||||||
unlink qw(pending.data completed.data undo.data backlog.data response.txt), $rc;
|
unlink qw(pending.data completed.data undo.data backlog.data response.txt), $rc;
|
||||||
|
|
|
@ -103,38 +103,6 @@ class TestIncorrectDate(BaseDateTimeNegativeTest):
|
||||||
def test_set_incorrect_datetime_day_two_hundred_in_YYYY_WwwD(self):
|
def test_set_incorrect_datetime_day_two_hundred_in_YYYY_WwwD(self):
|
||||||
self.assertInvalidDatetimeFormat('2014-W24200')
|
self.assertInvalidDatetimeFormat('2014-W24200')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_week_with_the_number_zero_in_YYYYWww(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W00')
|
|
||||||
|
|
||||||
def test_set_incorrect_datetime_overflow_in_week_in_YYYYWww(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W54')
|
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_week_zero_in_YYYYWwwD(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W001')
|
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_fifth_day_of_week_zero_in_YYYYWwwD(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W005')
|
|
||||||
|
|
||||||
def test_set_incorrect_datetime_overflow_week_in_YYYYWwwD(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W541')
|
|
||||||
|
|
||||||
def test_set_incorrect_datetime_huge_overflow_week_in_YYYYWwwD(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W991')
|
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_day_zero_in_YYYYWwwD(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W240')
|
|
||||||
|
|
||||||
def test_set_incorrect_datetime_day_eight_in_YYYYWwwD(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W248')
|
|
||||||
|
|
||||||
def test_set_incorrect_datetime_day_two_hundred_in_YYYYWwwD(self):
|
|
||||||
self.assertInvalidDatetimeFormat('2014W24200')
|
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_month_zero_in_YYYY_MM(self):
|
def test_set_incorrect_datetime_month_zero_in_YYYY_MM(self):
|
||||||
self.assertInvalidDatetimeFormat('2014-00')
|
self.assertInvalidDatetimeFormat('2014-00')
|
||||||
|
|
||||||
|
@ -211,18 +179,15 @@ class TestIncorrectTime(BaseDateTimeNegativeTest):
|
||||||
def test_set_incorrect_datetime_negative_minutes_in_hh_mmZ(self):
|
def test_set_incorrect_datetime_negative_minutes_in_hh_mmZ(self):
|
||||||
self.assertInvalidDatetimeFormat('12:-12Z')
|
self.assertInvalidDatetimeFormat('12:-12Z')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_hour_overflow_in_hh_mm_plus_hh_mm(self):
|
def test_set_incorrect_datetime_hour_overflow_in_hh_mm_plus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('24:00+01:00')
|
self.assertInvalidDatetimeFormat('24:00+01:00')
|
||||||
|
|
||||||
def test_set_incorrect_datetime_huge_hour_overflow_in_hh_mm_plus_hh_mm(self):
|
def test_set_incorrect_datetime_huge_hour_overflow_in_hh_mm_plus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('99:00+01:00')
|
self.assertInvalidDatetimeFormat('99:00+01:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_minute_overflow_in_hh_mm_plus_hh_mm(self):
|
def test_set_incorrect_datetime_minute_overflow_in_hh_mm_plus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:60+01:00')
|
self.assertInvalidDatetimeFormat('12:60+01:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_huge_minute_overflow_in_hh_mm_plus_hh_mm(self):
|
def test_set_incorrect_datetime_huge_minute_overflow_in_hh_mm_plus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:99+01:00')
|
self.assertInvalidDatetimeFormat('12:99+01:00')
|
||||||
|
|
||||||
|
@ -241,18 +206,15 @@ class TestIncorrectTime(BaseDateTimeNegativeTest):
|
||||||
def test_set_incorrect_datetime_negative_minutes_in_hh_mm_plus_hh_mm(self):
|
def test_set_incorrect_datetime_negative_minutes_in_hh_mm_plus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:-12+01:00')
|
self.assertInvalidDatetimeFormat('12:-12+01:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_hour_overflow_in_hh_mm_minus_hh_mm(self):
|
def test_set_incorrect_datetime_hour_overflow_in_hh_mm_minus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('24:00-01:00')
|
self.assertInvalidDatetimeFormat('24:00-01:00')
|
||||||
|
|
||||||
def test_set_incorrect_datetime_huge_hour_overflow_in_hh_mm_minus_hh_mm(self):
|
def test_set_incorrect_datetime_huge_hour_overflow_in_hh_mm_minus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('99:00-01:00')
|
self.assertInvalidDatetimeFormat('99:00-01:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_minute_overflow_in_hh_mm_minus_hh_mm(self):
|
def test_set_incorrect_datetime_minute_overflow_in_hh_mm_minus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:60-01:00')
|
self.assertInvalidDatetimeFormat('12:60-01:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_huge_minute_overflow_in_hh_mm_minus_hh_mm(self):
|
def test_set_incorrect_datetime_huge_minute_overflow_in_hh_mm_minus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:99-01:00')
|
self.assertInvalidDatetimeFormat('12:99-01:00')
|
||||||
|
|
||||||
|
@ -312,7 +274,6 @@ class TestIncorrectTime(BaseDateTimeNegativeTest):
|
||||||
def test_set_incorrect_datetime_negative_minutes_in_hh_mm_ss(self):
|
def test_set_incorrect_datetime_negative_minutes_in_hh_mm_ss(self):
|
||||||
self.assertInvalidDatetimeFormat('12:-12:12')
|
self.assertInvalidDatetimeFormat('12:-12:12')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_negative_seconds_in_hh_mm_ss(self):
|
def test_set_incorrect_datetime_negative_seconds_in_hh_mm_ss(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12:-12')
|
self.assertInvalidDatetimeFormat('12:12:-12')
|
||||||
|
|
||||||
|
@ -445,7 +406,6 @@ class TestIncorrectTime(BaseDateTimeNegativeTest):
|
||||||
def test_set_incorrect_datetime_negative_minutes_in_hh_mm_ss_minus_hh_mm(self):
|
def test_set_incorrect_datetime_negative_minutes_in_hh_mm_ss_minus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:-12:12-01:00')
|
self.assertInvalidDatetimeFormat('12:-12:12-01:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_negative_seconds_in_hh_mm_ss_minus_hh_mm(self):
|
def test_set_incorrect_datetime_negative_seconds_in_hh_mm_ss_minus_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12:-12-01:00')
|
self.assertInvalidDatetimeFormat('12:12:-12-01:00')
|
||||||
|
|
||||||
|
@ -505,22 +465,18 @@ class TestIncorrectTime(BaseDateTimeNegativeTest):
|
||||||
def test_set_incorrect_datetime_invalid_negative_offset_length_in_hh_mm_ss(self):
|
def test_set_incorrect_datetime_invalid_negative_offset_length_in_hh_mm_ss(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12:12-3:2')
|
self.assertInvalidDatetimeFormat('12:12:12-3:2')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_hour_positive_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_hour_positive_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12+13:00')
|
self.assertInvalidDatetimeFormat('12:12+13:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_medium_hour_positive_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_medium_hour_positive_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12+24:00')
|
self.assertInvalidDatetimeFormat('12:12+24:00')
|
||||||
|
|
||||||
def test_set_incorrect_datetime_invalid_huge_hour_positive_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_huge_hour_positive_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12+99:00')
|
self.assertInvalidDatetimeFormat('12:12+99:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_minute_positive_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_minute_positive_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12+03:60')
|
self.assertInvalidDatetimeFormat('12:12+03:60')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_huge_minute_positive_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_huge_minute_positive_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12+03:99')
|
self.assertInvalidDatetimeFormat('12:12+03:99')
|
||||||
|
|
||||||
|
@ -533,22 +489,18 @@ class TestIncorrectTime(BaseDateTimeNegativeTest):
|
||||||
def test_set_incorrect_datetime_invalid_positive_offset_length_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_positive_offset_length_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12+3:2')
|
self.assertInvalidDatetimeFormat('12:12+3:2')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_hour_negative_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_hour_negative_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12-13:00')
|
self.assertInvalidDatetimeFormat('12:12-13:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_medium_hour_negative_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_medium_hour_negative_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12-24:00')
|
self.assertInvalidDatetimeFormat('12:12-24:00')
|
||||||
|
|
||||||
def test_set_incorrect_datetime_invalid_huge_hour_negative_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_huge_hour_negative_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12-99:00')
|
self.assertInvalidDatetimeFormat('12:12-99:00')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_minute_negative_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_minute_negative_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12-03:60')
|
self.assertInvalidDatetimeFormat('12:12-03:60')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_set_incorrect_datetime_invalid_huge_minute_negative_offset_in_hh_mm(self):
|
def test_set_incorrect_datetime_invalid_huge_minute_negative_offset_in_hh_mm(self):
|
||||||
self.assertInvalidDatetimeFormat('12:12-03:99')
|
self.assertInvalidDatetimeFormat('12:12-03:99')
|
||||||
|
|
||||||
|
|
|
@ -1,205 +1,63 @@
|
||||||
#! /usr/bin/env perl
|
#!/usr/bin/env python2.7
|
||||||
################################################################################
|
# -*- coding: utf-8 -*-
|
||||||
##
|
###############################################################################
|
||||||
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
|
#
|
||||||
##
|
# Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
|
||||||
## Permission is hereby granted, free of charge, to any person obtaining a copy
|
#
|
||||||
## of this software and associated documentation files (the "Software"), to deal
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
## in the Software without restriction, including without limitation the rights
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# in the Software without restriction, including without limitation the rights
|
||||||
## copies of the Software, and to permit persons to whom the Software is
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
## furnished to do so, subject to the following conditions:
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
##
|
# furnished to do so, subject to the following conditions:
|
||||||
## The above copyright notice and this permission notice shall be included
|
#
|
||||||
## in all copies or substantial portions of the Software.
|
# The above copyright notice and this permission notice shall be included
|
||||||
##
|
# in all copies or substantial portions of the Software.
|
||||||
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
#
|
||||||
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
## SOFTWARE.
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
##
|
# SOFTWARE.
|
||||||
## http://www.opensource.org/licenses/mit-license.php
|
#
|
||||||
##
|
# http://www.opensource.org/licenses/mit-license.php
|
||||||
################################################################################
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
use strict;
|
import sys
|
||||||
use warnings;
|
import os
|
||||||
use Time::Local;
|
import unittest
|
||||||
use Test::More tests => 34;
|
# Ensure python finds the local simpletap module
|
||||||
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
# Ensure environment has no influence.
|
from basetest import Task, TestCase
|
||||||
delete $ENV{'TASKDATA'};
|
|
||||||
delete $ENV{'TASKRC'};
|
|
||||||
|
|
||||||
use File::Basename;
|
|
||||||
my $ut = basename ($0);
|
|
||||||
my $rc = $ut . '.rc';
|
|
||||||
|
|
||||||
# Create the rc file.
|
class TestFeature891(TestCase):
|
||||||
if (open my $fh, '>', $rc)
|
@classmethod
|
||||||
{
|
def setUp(self):
|
||||||
print $fh "data.location=.\n",
|
self.t = Task()
|
||||||
"confirmation=off\n";
|
self.t(("add", "one"))
|
||||||
close $fh;
|
self.t(("add", "two"))
|
||||||
}
|
|
||||||
|
|
||||||
# Feature 891: UUID filter should be uuid.endswith by default
|
code, self.uuid, err = self.t(("_get", "1.uuid"))
|
||||||
# Create some example data directly. This is so that we have complete control
|
self.uuid = self.uuid.strip()
|
||||||
# over the UUID.
|
|
||||||
if (open my $fh, '>', 'pending.data')
|
|
||||||
{
|
|
||||||
my $timeA = timegm (00,00,12,22,11,2008);
|
|
||||||
my $timeB = timegm (00,00,12,17,03,2009);
|
|
||||||
print $fh <<EOF;
|
|
||||||
[description:"one" entry:"$timeA" status:"pending" uuid:"a7097693-91c2-4cbe-ba89-ddcc87e5582c"]
|
|
||||||
[description:"two" entry:"$timeB" status:"pending" uuid:"e8f72d91-964c-424b-8fd5-556434648b6b"]
|
|
||||||
EOF
|
|
||||||
|
|
||||||
close $fh;
|
def test_uuid_filter(self):
|
||||||
}
|
for i in range(35,7,-1):
|
||||||
|
self.tap("UUID %s" % self.uuid[0:i])
|
||||||
|
code, out, err = self.t((self.uuid[0:i], "list"))
|
||||||
|
self.assertIn("one", out)
|
||||||
|
self.assertNotIn("two", out)
|
||||||
|
|
||||||
my $output = qx{../src/task rc:$rc 1 info 2>&1};
|
# TODO This should fail because a 7-character UUID is not a UUID, but
|
||||||
my ($uuid) = $output =~ /UUID\s+(\S{36})/ms;
|
# instead it blindly does nothing, and succeeds.
|
||||||
|
#code, out, err = self.t((self.uuid[0:6], "list"))
|
||||||
|
|
||||||
$output = qx{../src/task rc:$rc $uuid list 2>&1};
|
if __name__ == "__main__":
|
||||||
like ($output, qr/one/, "Found with $uuid");
|
from simpletap import TAPTestRunner
|
||||||
|
unittest.main(testRunner=TAPTestRunner())
|
||||||
my ($short) = $uuid =~ /^(.{35})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{34})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{33})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{32})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{31})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{30})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{29})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{28})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{27})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{26})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{25})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{24})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{23})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{22})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{21})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{20})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{19})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{18})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{17})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{16})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{15})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{14})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{13})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{12})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{11})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{10})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{9})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{8})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
like ($output, qr/one/, "Found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{7})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
unlike ($output, qr/one/, "Not found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{6})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
unlike ($output, qr/one/, "Not found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{5})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
unlike ($output, qr/one/, "Not found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{4})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
unlike ($output, qr/one/, "Not found with $short");
|
|
||||||
|
|
||||||
($short) = $uuid =~ /^(.{3})/;
|
|
||||||
$output = qx{../src/task rc:$rc $short list 2>&1};
|
|
||||||
unlike ($output, qr/one/, "Not found with $short");
|
|
||||||
|
|
||||||
# Cleanup.
|
|
||||||
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
|
|
||||||
exit 0;
|
|
||||||
|
|
||||||
|
# vim: ai sts=4 et sw=4
|
||||||
|
|
|
@ -42,13 +42,13 @@ if (open my $fh, '>', 'bug.rc')
|
||||||
}
|
}
|
||||||
|
|
||||||
# Feature: variable to control printing of empty columns
|
# Feature: variable to control printing of empty columns
|
||||||
qx{../src/task rc:bug.rc add sample desc 2>&1};
|
qx{../src/task rc:bug.rc add /sample/ desc 2>&1};
|
||||||
qx{../src/task rc:bug.rc add withP project:house 2>&1};
|
qx{../src/task rc:bug.rc add withP project:house 2>&1};
|
||||||
|
|
||||||
my $output = qx{../src/task test sample rc:bug.rc 2>&1};
|
my $output = qx{../src/task test /sample/ rc:bug.rc 2>&1};
|
||||||
unlike ($output, qr/Project/, 'empty \'project\' column is not printed by default');
|
unlike ($output, qr/Project/, 'empty \'project\' column is not printed by default');
|
||||||
|
|
||||||
$output = qx{../src/task test sample rc.print.empty.columns:yes rc:bug.rc 2>&1};
|
$output = qx{../src/task test /sample/ rc.print.empty.columns:yes rc:bug.rc 2>&1};
|
||||||
like ($output, qr/Project/, 'empty \'project\' column is printed if rc.print.empty.columns:yes');
|
like ($output, qr/Project/, 'empty \'project\' column is printed if rc.print.empty.columns:yes');
|
||||||
|
|
||||||
$output = qx{../src/task test rc:bug.rc 2>&1};
|
$output = qx{../src/task test rc:bug.rc 2>&1};
|
||||||
|
|
|
@ -269,8 +269,8 @@ class TestFilter(TestCase):
|
||||||
|
|
||||||
@unittest.expectedFailure
|
@unittest.expectedFailure
|
||||||
def test_regex_list_project(self):
|
def test_regex_list_project(self):
|
||||||
"""filter - rc.regex:on list project:/[A-Z]/"""
|
"""filter - rc.regex:on list project~[A-Z]"""
|
||||||
code, out, err = self.t(("rc.regex:on", "list", "project:/[A-Z]/"))
|
code, out, err = self.t(("rc.regex:on", "list", "project~[A-Z]"))
|
||||||
|
|
||||||
self.assertIn("one", out)
|
self.assertIn("one", out)
|
||||||
self.assertIn("two", out)
|
self.assertIn("two", out)
|
||||||
|
@ -280,10 +280,9 @@ class TestFilter(TestCase):
|
||||||
self.assertNotIn("six", out)
|
self.assertNotIn("six", out)
|
||||||
self.assertNotIn("seven", out)
|
self.assertNotIn("seven", out)
|
||||||
|
|
||||||
@unittest.expectedFailure
|
|
||||||
def test_regex_list_project_any(self):
|
def test_regex_list_project_any(self):
|
||||||
"""filter - rc.regex:on list project:."""
|
"""filter - rc.regex:on list project~."""
|
||||||
code, out, err = self.t(("rc.regex:on", "list", "project:."))
|
code, out, err = self.t(("rc.regex:on", "list", "project~."))
|
||||||
|
|
||||||
self.assertIn("one", out)
|
self.assertIn("one", out)
|
||||||
self.assertIn("two", out)
|
self.assertIn("two", out)
|
||||||
|
|
|
@ -33,9 +33,6 @@
|
||||||
|
|
||||||
Context context;
|
Context context;
|
||||||
|
|
||||||
#define AMBIGUOUS // Include ambiguous forms
|
|
||||||
#undef AMBIGUOUS // Exclude ambiguous forms
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void testParse (
|
void testParse (
|
||||||
UnitTest& t,
|
UnitTest& t,
|
||||||
|
@ -74,11 +71,7 @@ void testParse (
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest t (1214
|
UnitTest t (734);
|
||||||
#ifdef AMBIGUOUS
|
|
||||||
+ 48
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
ISO8601d iso;
|
ISO8601d iso;
|
||||||
std::string::size_type start = 0;
|
std::string::size_type start = 0;
|
||||||
|
@ -139,7 +132,6 @@ int main (int argc, char** argv)
|
||||||
|
|
||||||
int hms = (12 * 3600) + (34 * 60) + 56; // The time 12:34:56 in seconds.
|
int hms = (12 * 3600) + (34 * 60) + 56; // The time 12:34:56 in seconds.
|
||||||
int hm = (12 * 3600) + (34 * 60); // The time 12:34:00 in seconds.
|
int hm = (12 * 3600) + (34 * 60); // The time 12:34:00 in seconds.
|
||||||
int h = (12 * 3600); // The time 12:00:00 in seconds.
|
|
||||||
int z = 3600; // TZ offset.
|
int z = 3600; // TZ offset.
|
||||||
|
|
||||||
int ld = local_s > hms ? 86400 : 0; // Local extra day if now > hms.
|
int ld = local_s > hms ? 86400 : 0; // Local extra day if now > hms.
|
||||||
|
@ -155,31 +147,12 @@ int main (int argc, char** argv)
|
||||||
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
||||||
testParse (t, "12:34:56Z", 9, 0, 0, 0, 0, 0, 0, hms, 0, true, utc+hms+ud );
|
testParse (t, "12:34:56Z", 9, 0, 0, 0, 0, 0, 0, hms, 0, true, utc+hms+ud );
|
||||||
testParse (t, "12:34Z", 6, 0, 0, 0, 0, 0, 0, hm, 0, true, utc+hm+ud );
|
testParse (t, "12:34Z", 6, 0, 0, 0, 0, 0, 0, hm, 0, true, utc+hm+ud );
|
||||||
testParse (t, "12Z", 3, 0, 0, 0, 0, 0, 0, h, 0, true, utc+h+ud );
|
|
||||||
testParse (t, "12:34:56+01:00", 14, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
testParse (t, "12:34:56+01:00", 14, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
||||||
testParse (t, "12:34:56+01", 11, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
testParse (t, "12:34:56+01", 11, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
||||||
testParse (t, "12:34+01:00", 11, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
testParse (t, "12:34+01:00", 11, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
||||||
testParse (t, "12:34+01", 8, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
testParse (t, "12:34+01", 8, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
||||||
// testParse (t, "12+01:00", 8, 0, 0, 0, 0, 0, 0, h, 3600, false, utc+h-z+ud );
|
|
||||||
// testParse (t, "12+01", 5, 0, 0, 0, 0, 0, 0, h, 3600, false, utc+h-z+ud );
|
|
||||||
testParse (t, "12:34:56", 8, 0, 0, 0, 0, 0, 0, hms, 0, false, local+hms+ld );
|
testParse (t, "12:34:56", 8, 0, 0, 0, 0, 0, 0, hms, 0, false, local+hms+ld );
|
||||||
testParse (t, "12:34", 5, 0, 0, 0, 0, 0, 0, hm, 0, false, local+hm+ld );
|
testParse (t, "12:34", 5, 0, 0, 0, 0, 0, 0, hm, 0, false, local+hm+ld );
|
||||||
#ifdef AMBIGUOUS
|
|
||||||
testParse (t, "12", 2, 0, 0, 0, 0, 0, 0, h, 0, false, local+h+ld );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// time
|
|
||||||
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
|
||||||
testParse (t, "123456Z", 7, 0, 0, 0, 0, 0, 0, hms, 0, true, utc+hms+ud );
|
|
||||||
testParse (t, "1234Z", 5, 0, 0, 0, 0, 0, 0, hm, 0, true, utc+hm+ud );
|
|
||||||
testParse (t, "123456+0100", 11, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
|
||||||
testParse (t, "123456+01", 9, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
|
||||||
testParse (t, "1234+0100", 9, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
|
||||||
testParse (t, "1234+01", 7, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
|
||||||
// testParse (t, "12+0100", 7, 0, 0, 0, 0, 0, 0, h, 3600, false, utc+h-z+ud );
|
|
||||||
#ifdef AMBIGUOUS
|
|
||||||
testParse (t, "123456", 6, 0, 0, 0, 0, 0, 0, hms, 0, false, local+hms+ld );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// datetime-ext
|
// datetime-ext
|
||||||
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
||||||
|
@ -239,82 +212,6 @@ int main (int argc, char** argv)
|
||||||
testParse (t, "2013-W49T12:34-01:00", 20, 2013, 0, 49, 0, 0, 0, hm, -3600, false, utc1+hm+z );
|
testParse (t, "2013-W49T12:34-01:00", 20, 2013, 0, 49, 0, 0, 0, hm, -3600, false, utc1+hm+z );
|
||||||
testParse (t, "2013-W49T12:34-01", 17, 2013, 0, 49, 0, 0, 0, hm, -3600, false, utc1+hm+z );
|
testParse (t, "2013-W49T12:34-01", 17, 2013, 0, 49, 0, 0, 0, hm, -3600, false, utc1+hm+z );
|
||||||
|
|
||||||
// datetime
|
|
||||||
#ifdef AMBIGUOUS
|
|
||||||
testParse (t, "20131206", 8, 2013, 12, 0, 0, 0, 6, 0, 0, false, local6 );
|
|
||||||
#endif
|
|
||||||
testParse (t, "2013W495", 8, 2013, 0, 49, 5, 0, 0, 0, 0, false, local6 );
|
|
||||||
testParse (t, "2013W49", 7, 2013, 0, 49, 0, 0, 0, 0, 0, false, local1 );
|
|
||||||
#ifdef AMBIGUOUS
|
|
||||||
testParse (t, "2013340", 7, 2013, 0, 0, 0, 340, 0, 0, 0, false, local6 );
|
|
||||||
#endif
|
|
||||||
testParse (t, "2013-12", 7, 2013, 12, 0, 0, 0, 0, 0, 0, false, local1 );
|
|
||||||
|
|
||||||
testParse (t, "20131206T123456", 15, 2013, 12, 0, 0, 0, 6, hms, 0, false, local6+hms);
|
|
||||||
// testParse (t, "20131206T12", 11, 2013, 12, 0, 0, 0, 6, h, 0, false, local6+h );
|
|
||||||
testParse (t, "2013W495T123456", 15, 2013, 0, 49, 5, 0, 0, hms, 0, false, local6+hms);
|
|
||||||
// testParse (t, "2013W495T12", 11, 2013, 0, 49, 5, 0, 0, h, 0, false, local6+h );
|
|
||||||
testParse (t, "2013W49T123456", 14, 2013, 0, 49, 0, 0, 0, hms, 0, false, local1+hms);
|
|
||||||
// testParse (t, "2013W49T12", 10, 2013, 0, 49, 0, 0, 0, h, 0, false, local1+h );
|
|
||||||
testParse (t, "2013340T123456", 14, 2013, 0, 0, 0, 340, 0, hms, 0, false, local6+hms);
|
|
||||||
// testParse (t, "2013340T12", 10, 2013, 0, 0, 0, 340, 0, h, 0, false, local6+h );
|
|
||||||
testParse (t, "2013-12T1234", 12, 2013, 12, 0, 0, 0, 0, hm, 0, false, local1+hm );
|
|
||||||
// testParse (t, "2013-12T12", 10, 2013, 12, 0, 0, 0, 0, h, 0, false, local1+h );
|
|
||||||
|
|
||||||
testParse (t, "20131206T123456Z", 16, 2013, 12, 0, 0, 0, 6, hms, 0, true, utc6+hms );
|
|
||||||
// testParse (t, "20131206T12Z", 12, 2013, 12, 0, 0, 0, 6, h, 0, true, utc6+h );
|
|
||||||
testParse (t, "2013W495T123456Z", 16, 2013, 0, 49, 5, 0, 0, hms, 0, true, utc6+hms );
|
|
||||||
// testParse (t, "2013W495T12Z", 12, 2013, 0, 49, 5, 0, 0, h, 0, true, utc6+h );
|
|
||||||
testParse (t, "2013W49T123456Z", 15, 2013, 0, 49, 0, 0, 0, hms, 0, true, utc1+hms );
|
|
||||||
// testParse (t, "2013W49T12Z", 11, 2013, 0, 49, 0, 0, 0, h, 0, true, utc1+h );
|
|
||||||
testParse (t, "2013340T123456Z", 15, 2013, 0, 0, 0, 340, 0, hms, 0, true, utc6+hms );
|
|
||||||
// testParse (t, "2013340T12Z", 11, 2013, 0, 0, 0, 340, 0, h, 0, true, utc6+h );
|
|
||||||
testParse (t, "2013-12T123456Z", 15, 2013, 12, 0, 0, 0, 0, hms, 0, true, utc1+hms );
|
|
||||||
// testParse (t, "2013-12T12Z", 11, 2013, 12, 0, 0, 0, 0, h, 0, true, utc1+h );
|
|
||||||
|
|
||||||
testParse (t, "20131206T123456+0100", 20, 2013, 12, 0, 0, 0, 6, hms, 3600, false, utc6+hms-z);
|
|
||||||
testParse (t, "20131206T123456+01", 18, 2013, 12, 0, 0, 0, 6, hms, 3600, false, utc6+hms-z);
|
|
||||||
testParse (t, "20131206T123456-0100", 20, 2013, 12, 0, 0, 0, 6, hms, -3600, false, utc6+hms+z);
|
|
||||||
testParse (t, "20131206T123456-01", 18, 2013, 12, 0, 0, 0, 6, hms, -3600, false, utc6+hms+z);
|
|
||||||
// testParse (t, "20131206T12+0100", 16, 2013, 12, 0, 0, 0, 6, h, 3600, false, utc6+h-z );
|
|
||||||
// testParse (t, "20131206T12+01", 14, 2013, 12, 0, 0, 0, 6, h, 3600, false, utc6+h-z );
|
|
||||||
// testParse (t, "20131206T12-0100", 16, 2013, 12, 0, 0, 0, 6, h, -3600, false, utc6+h+z );
|
|
||||||
// testParse (t, "20131206T12-01", 14, 2013, 12, 0, 0, 0, 6, h, -3600, false, utc6+h+z );
|
|
||||||
testParse (t, "2013W495T123456+0100", 20, 2013, 0, 49, 5, 0, 0, hms, 3600, false, utc6+hms-z);
|
|
||||||
testParse (t, "2013W495T123456+01", 18, 2013, 0, 49, 5, 0, 0, hms, 3600, false, utc6+hms-z);
|
|
||||||
testParse (t, "2013W495T123456-0100", 20, 2013, 0, 49, 5, 0, 0, hms, -3600, false, utc6+hms+z);
|
|
||||||
testParse (t, "2013W495T123456-01", 18, 2013, 0, 49, 5, 0, 0, hms, -3600, false, utc6+hms+z);
|
|
||||||
// testParse (t, "2013W495T12+0100", 16, 2013, 0, 49, 5, 0, 0, h, 3600, false, utc6+h-z );
|
|
||||||
// testParse (t, "2013W495T12+01", 14, 2013, 0, 49, 5, 0, 0, h, 3600, false, utc6+h-z );
|
|
||||||
// testParse (t, "2013W495T12-0100", 16, 2013, 0, 49, 5, 0, 0, h, -3600, false, utc6+h+z );
|
|
||||||
// testParse (t, "2013W495T12-01", 14, 2013, 0, 49, 5, 0, 0, h, -3600, false, utc6+h+z );
|
|
||||||
testParse (t, "2013W49T123456+0100", 19, 2013, 0, 49, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
|
||||||
testParse (t, "2013W49T123456+01", 17, 2013, 0, 49, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
|
||||||
testParse (t, "2013W49T123456-0100", 19, 2013, 0, 49, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
|
||||||
testParse (t, "2013W49T123456-01", 17, 2013, 0, 49, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
|
||||||
// testParse (t, "2013W49T12+0100", 15, 2013, 0, 49, 0, 0, 0, h, 3600, false, utc1+h-z );
|
|
||||||
// testParse (t, "2013W49T12+01", 13, 2013, 0, 49, 0, 0, 0, h, 3600, false, utc1+h-z );
|
|
||||||
// testParse (t, "2013W49T12-0100", 15, 2013, 0, 49, 0, 0, 0, h, -3600, false, utc1+h+z );
|
|
||||||
// testParse (t, "2013W49T12-01", 13, 2013, 0, 49, 0, 0, 0, h, -3600, false, utc1+h+z );
|
|
||||||
testParse (t, "2013340T123456+0100", 19, 2013, 0, 0, 0, 340, 0, hms, 3600, false, utc6+hms-z);
|
|
||||||
testParse (t, "2013340T123456+01", 17, 2013, 0, 0, 0, 340, 0, hms, 3600, false, utc6+hms-z);
|
|
||||||
testParse (t, "2013340T123456-0100", 19, 2013, 0, 0, 0, 340, 0, hms, -3600, false, utc6+hms+z);
|
|
||||||
testParse (t, "2013340T123456-01", 17, 2013, 0, 0, 0, 340, 0, hms, -3600, false, utc6+hms+z);
|
|
||||||
// testParse (t, "2013340T12+0100", 15, 2013, 0, 0, 0, 340, 0, h, 3600, false, utc6+h-z );
|
|
||||||
// testParse (t, "2013340T12+01", 13, 2013, 0, 0, 0, 340, 0, h, 3600, false, utc6+h-z );
|
|
||||||
// testParse (t, "2013340T12-0100", 15, 2013, 0, 0, 0, 340, 0, h, -3600, false, utc6+h+z );
|
|
||||||
// testParse (t, "2013340T12-01", 13, 2013, 0, 0, 0, 340, 0, h, -3600, false, utc6+h+z );
|
|
||||||
testParse (t, "2013-12T123456+0100", 19, 2013, 12, 0, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
|
||||||
testParse (t, "2013-12T123456+01", 17, 2013, 12, 0, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
|
||||||
testParse (t, "2013-12T123456-0100", 19, 2013, 12, 0, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
|
||||||
testParse (t, "2013-12T123456-01", 17, 2013, 12, 0, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
|
||||||
// testParse (t, "2013-12T12+0100", 15, 2013, 12, 0, 0, 0, 0, h, 3600, false, utc1+h-z );
|
|
||||||
// testParse (t, "2013-12T12+01", 13, 2013, 12, 0, 0, 0, 0, h, 3600, false, utc1+h-z );
|
|
||||||
// testParse (t, "2013-12T12-0100", 15, 2013, 12, 0, 0, 0, 0, h, -3600, false, utc1+h+z );
|
|
||||||
// testParse (t, "2013-12T12-01", 13, 2013, 12, 0, 0, 0, 0, h, -3600, false, utc1+h+z );
|
|
||||||
|
|
||||||
// TODO Test validation of individual values.
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ Context context;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest t (801);
|
UnitTest t (799);
|
||||||
|
|
||||||
std::vector <std::pair <std::string, Lexer::Type>> tokens;
|
std::vector <std::pair <std::string, Lexer::Type>> tokens;
|
||||||
std::string token;
|
std::string token;
|
||||||
|
@ -80,6 +80,12 @@ int main (int argc, char** argv)
|
||||||
t.ok (Lexer::isBoundary ('(', '('), "'(' --> '(' = isBoundary");
|
t.ok (Lexer::isBoundary ('(', '('), "'(' --> '(' = isBoundary");
|
||||||
t.notok (Lexer::isBoundary ('r', 'd'), "'r' --> 'd' = isBoundary");
|
t.notok (Lexer::isBoundary ('r', 'd'), "'r' --> 'd' = isBoundary");
|
||||||
|
|
||||||
|
// static bool Lexer::wasQuoted (const std::string&);
|
||||||
|
t.notok (Lexer::wasQuoted (""), "'' --> !wasQuoted");
|
||||||
|
t.notok (Lexer::wasQuoted ("foo"), "'foo' --> !wasQuoted");
|
||||||
|
t.ok (Lexer::wasQuoted ("a b"), "'a b' --> wasQuoted");
|
||||||
|
t.ok (Lexer::wasQuoted ("(a)"), "'(a)' --> wasQuoted");
|
||||||
|
|
||||||
// Should result in no tokens.
|
// Should result in no tokens.
|
||||||
Lexer l0 ("");
|
Lexer l0 ("");
|
||||||
t.notok (l0.token (token, type), "'' --> no tokens");
|
t.notok (l0.token (token, type), "'' --> no tokens");
|
||||||
|
@ -131,7 +137,7 @@ int main (int argc, char** argv)
|
||||||
t.is (tokens[15].first, "'€'", "tokens[15] = \\u20ac --> ''€''");
|
t.is (tokens[15].first, "'€'", "tokens[15] = \\u20ac --> ''€''");
|
||||||
t.is (Lexer::typeName (tokens[15].second), "string", "tokens[15] = string");
|
t.is (Lexer::typeName (tokens[15].second), "string", "tokens[15] = string");
|
||||||
|
|
||||||
// Test for ISO-8601 dates (favoring dates in ambiguous cases).
|
// Test for numbers that are no longer ISO-8601 dates.
|
||||||
Lexer l3 ("1 12 123 1234 12345 123456 1234567 12345678");
|
Lexer l3 ("1 12 123 1234 12345 123456 1234567 12345678");
|
||||||
l3.ambiguity (true);
|
l3.ambiguity (true);
|
||||||
tokens.clear ();
|
tokens.clear ();
|
||||||
|
@ -145,21 +151,21 @@ int main (int argc, char** argv)
|
||||||
t.is (tokens[0].first, "1", "tokens[0] == '1'");
|
t.is (tokens[0].first, "1", "tokens[0] == '1'");
|
||||||
t.is ((int) tokens[0].second, (int) Lexer::Type::number, "tokens[0] == Type::number");
|
t.is ((int) tokens[0].second, (int) Lexer::Type::number, "tokens[0] == Type::number");
|
||||||
t.is (tokens[1].first, "12", "tokens[1] == '12'");
|
t.is (tokens[1].first, "12", "tokens[1] == '12'");
|
||||||
t.is ((int) tokens[1].second, (int) Lexer::Type::date, "tokens[1] == Type::date");
|
t.is ((int) tokens[1].second, (int) Lexer::Type::number, "tokens[1] == Type::date");
|
||||||
t.is (tokens[2].first, "123", "tokens[2] == '123'");
|
t.is (tokens[2].first, "123", "tokens[2] == '123'");
|
||||||
t.is ((int) tokens[2].second, (int) Lexer::Type::number, "tokens[2] == Type::number"); // 70
|
t.is ((int) tokens[2].second, (int) Lexer::Type::number, "tokens[2] == Type::number"); // 70
|
||||||
t.is (tokens[3].first, "1234", "tokens[3] == '1234'");
|
t.is (tokens[3].first, "1234", "tokens[3] == '1234'");
|
||||||
t.is ((int) tokens[3].second, (int) Lexer::Type::date, "tokens[3] == Type::date");
|
t.is ((int) tokens[3].second, (int) Lexer::Type::number, "tokens[3] == Type::date");
|
||||||
t.is (tokens[4].first, "12345", "tokens[4] == '12345'");
|
t.is (tokens[4].first, "12345", "tokens[4] == '12345'");
|
||||||
t.is ((int) tokens[4].second, (int) Lexer::Type::number, "tokens[4] == Type::number");
|
t.is ((int) tokens[4].second, (int) Lexer::Type::number, "tokens[4] == Type::number");
|
||||||
t.is (tokens[5].first, "123456", "tokens[5] == '123456'");
|
t.is (tokens[5].first, "123456", "tokens[5] == '123456'");
|
||||||
t.is ((int) tokens[5].second, (int) Lexer::Type::date, "tokens[5] == Type::date");
|
t.is ((int) tokens[5].second, (int) Lexer::Type::number, "tokens[5] == Type::date");
|
||||||
t.is (tokens[6].first, "1234567", "tokens[6] == '1234567'");
|
t.is (tokens[6].first, "1234567", "tokens[6] == '1234567'");
|
||||||
t.is ((int) tokens[6].second, (int) Lexer::Type::number, "tokens[6] == Type::number");
|
t.is ((int) tokens[6].second, (int) Lexer::Type::number, "tokens[6] == Type::number");
|
||||||
t.is (tokens[7].first, "12345678", "tokens[7] == '12345678'");
|
t.is (tokens[7].first, "12345678", "tokens[7] == '12345678'");
|
||||||
t.is ((int) tokens[7].second, (int) Lexer::Type::number, "tokens[7] == Type::number"); // 80
|
t.is ((int) tokens[7].second, (int) Lexer::Type::number, "tokens[7] == Type::number"); // 80
|
||||||
|
|
||||||
// Test for ISO-8601 dates (favoring numbers in ambiguous cases).
|
// Test for numbers that are no longer ISO-8601 dates.
|
||||||
Lexer l4 ("1 12 123 1234 12345 123456 1234567 12345678");
|
Lexer l4 ("1 12 123 1234 12345 123456 1234567 12345678");
|
||||||
l4.ambiguity (false);
|
l4.ambiguity (false);
|
||||||
tokens.clear ();
|
tokens.clear ();
|
||||||
|
@ -340,7 +346,6 @@ int main (int argc, char** argv)
|
||||||
// Date
|
// Date
|
||||||
{ "2015-W01", { { "2015-W01", Lexer::Type::date }, NO, NO, NO, NO }, },
|
{ "2015-W01", { { "2015-W01", Lexer::Type::date }, NO, NO, NO, NO }, },
|
||||||
{ "2015-02-17", { { "2015-02-17", Lexer::Type::date }, NO, NO, NO, NO }, },
|
{ "2015-02-17", { { "2015-02-17", Lexer::Type::date }, NO, NO, NO, NO }, },
|
||||||
{ "20131129T225800Z", { { "20131129T225800Z", Lexer::Type::date }, NO, NO, NO, NO }, },
|
|
||||||
{ "2013-11-29T22:58:00Z", { { "2013-11-29T22:58:00Z", Lexer::Type::date }, NO, NO, NO, NO }, },
|
{ "2013-11-29T22:58:00Z", { { "2013-11-29T22:58:00Z", Lexer::Type::date }, NO, NO, NO, NO }, },
|
||||||
|
|
||||||
// Duration
|
// Duration
|
||||||
|
|
|
@ -45,7 +45,7 @@ class Test1469(TestCase):
|
||||||
|
|
||||||
def test_implicit_search_sensitive_regex(self):
|
def test_implicit_search_sensitive_regex(self):
|
||||||
"""Implicit search, case sensitive, regex """
|
"""Implicit search, case sensitive, regex """
|
||||||
code, out, err = self.t(('list', 'möbel',
|
code, out, err = self.t(('list', '/möbel/',
|
||||||
'rc.search.case.sensitive=yes',
|
'rc.search.case.sensitive=yes',
|
||||||
'rc.regex=on'))
|
'rc.regex=on'))
|
||||||
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
||||||
|
@ -54,7 +54,7 @@ class Test1469(TestCase):
|
||||||
|
|
||||||
def test_implicit_search_sensitive_noregex(self):
|
def test_implicit_search_sensitive_noregex(self):
|
||||||
"""Implicit search, case sensitive, no regex """
|
"""Implicit search, case sensitive, no regex """
|
||||||
code, out, err = self.t(('list', 'möbel',
|
code, out, err = self.t(('list', '/möbel/',
|
||||||
'rc.search.case.sensitive=yes',
|
'rc.search.case.sensitive=yes',
|
||||||
'rc.regex=off'))
|
'rc.regex=off'))
|
||||||
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
||||||
|
@ -64,7 +64,7 @@ class Test1469(TestCase):
|
||||||
@unittest.skipIf('CYGWIN' in platform.system(), 'Skipping regex case-insensitive test for Cygwin')
|
@unittest.skipIf('CYGWIN' in platform.system(), 'Skipping regex case-insensitive test for Cygwin')
|
||||||
def test_implicit_search_insensitive_regex(self):
|
def test_implicit_search_insensitive_regex(self):
|
||||||
"""Implicit search, case insensitive, regex """
|
"""Implicit search, case insensitive, regex """
|
||||||
code, out, err = self.t(('list', 'möbel',
|
code, out, err = self.t(('list', '/möbel/',
|
||||||
'rc.search.case.sensitive=no',
|
'rc.search.case.sensitive=no',
|
||||||
'rc.regex=on'))
|
'rc.regex=on'))
|
||||||
self.assertEqual(0, code,
|
self.assertEqual(0, code,
|
||||||
|
@ -74,7 +74,7 @@ class Test1469(TestCase):
|
||||||
|
|
||||||
def test_implicit_search_insensitive_noregex(self):
|
def test_implicit_search_insensitive_noregex(self):
|
||||||
"""Implicit search, case insensitive, no regex """
|
"""Implicit search, case insensitive, no regex """
|
||||||
code, out, err = self.t(('list', 'möbel',
|
code, out, err = self.t(('list', '/möbel/',
|
||||||
'rc.search.case.sensitive=no',
|
'rc.search.case.sensitive=no',
|
||||||
'rc.regex=off'))
|
'rc.regex=off'))
|
||||||
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
self.assertEqual(0, code, "Exit code was non-zero ({0})".format(code))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue