- Fixed bug #542, which sorted the countdown columns incorrectly (thanks to
  Michelle Crane).
- Duration could not parse all varieties of it's own output, which is why the
  sorting was broken, in particular negative durations and real numbers in
  durations (such as (1.2y').
- Sorting in Table::sort_compare for Table::periodAscending and
  Table::periodDescending was broken.
- Missing unit tests for countdown_compact.
- Imported Nibbler::getNumber from the Attitash project.
- Additional Duration unit tests.
- Additional Nibbler unit tests.
- Additional countdown.t unit tests.
This commit is contained in:
Paul Beckingham 2010-11-26 14:00:49 -05:00
parent c2a84c7cf6
commit 38ffa390ea
8 changed files with 311 additions and 102 deletions

View file

@ -19,6 +19,8 @@
+ Fixed bug #538, where some color legend items were not readable. + Fixed bug #538, where some color legend items were not readable.
+ Fixed bug #539, where the man page task-color(5) contained a line that + Fixed bug #539, where the man page task-color(5) contained a line that
began with a ' and was not displayed. began with a ' and was not displayed.
+ Fixed bug #542, which sorted the countdown columns incorrectly (thanks to
Michelle Crane).
+ Fixed bug #555, which caused a segfault when logging a task with a project + Fixed bug #555, which caused a segfault when logging a task with a project
(thanks to Itay Perl). (thanks to Itay Perl).

View file

@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager. // taskwarrior - a command line task list manager.
// //
// Copyright 2006 - 2010, Paul Beckingham. // Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@ -242,13 +242,13 @@ bool Duration::valid (const std::string& input) const
std::string lower_input = lowerCase (input); std::string lower_input = lowerCase (input);
// Assume the ordinal is 1, but look for an integer, just in case. // Assume the ordinal is 1, but look for an integer, just in case.
int value = 1; double value = 1;
Nibbler n (lower_input); Nibbler n (lower_input);
n.skipAll (' '); n.skipAll (' ');
n.getInt (value); n.getNumber (value);
n.skipAll (' '); n.skipAll (' ');
if (value < 0) if (value < 0.0)
value = -value; value = -value;
std::string units; std::string units;
@ -272,14 +272,14 @@ void Duration::parse (const std::string& input)
std::string lower_input = lowerCase (input); std::string lower_input = lowerCase (input);
// Assume the ordinal is 1, but look for an integer, just in case. // Assume the ordinal is 1, but look for an integer, just in case.
int value = 1; double value = 1;
Nibbler n (lower_input); Nibbler n (lower_input);
n.skipAll (' '); n.skipAll (' ');
n.getInt (value); n.getNumber (value);
n.skipAll (' '); n.skipAll (' ');
if (value < 0) if (value < 0.0)
{ {
mNegative = true; mNegative = true;
value = -value; value = -value;
@ -301,62 +301,62 @@ void Duration::parse (const std::string& input)
{ {
std::string match = matches[0]; std::string match = matches[0];
if (match == "biannual") mSecs = value * 86400 * 730; if (match == "biannual") mSecs = (int) (value * 86400 * 730);
else if (match == "biyearly") mSecs = value * 86400 * 730; else if (match == "biyearly") mSecs = (int) (value * 86400 * 730);
else if (match == "yearly") mSecs = value * 86400 * 365; else if (match == "yearly") mSecs = (int) (value * 86400 * 365);
else if (match == "annual") mSecs = value * 86400 * 365; else if (match == "annual") mSecs = (int) (value * 86400 * 365);
else if (match == "years") mSecs = value * 86400 * 365; else if (match == "years") mSecs = (int) (value * 86400 * 365);
else if (match == "yrs") mSecs = value * 86400 * 365; else if (match == "yrs") mSecs = (int) (value * 86400 * 365);
else if (match == "y") mSecs = value * 86400 * 365; else if (match == "y") mSecs = (int) (value * 86400 * 365);
else if (match == "yearly") mSecs = value * 86400 * 365; else if (match == "yearly") mSecs = (int) (value * 86400 * 365);
else if (match == "annual") mSecs = value * 86400 * 365; else if (match == "annual") mSecs = (int) (value * 86400 * 365);
else if (match == "semiannual") mSecs = value * 86400 * 183; else if (match == "semiannual") mSecs = (int) (value * 86400 * 183);
else if (match == "bimonthly") mSecs = value * 86400 * 61; else if (match == "bimonthly") mSecs = (int) (value * 86400 * 61);
else if (match == "quarterly") mSecs = value * 86400 * 91; else if (match == "quarterly") mSecs = (int) (value * 86400 * 91);
else if (match == "quarters") mSecs = value * 86400 * 91; else if (match == "quarters") mSecs = (int) (value * 86400 * 91);
else if (match == "qrtrs") mSecs = value * 86400 * 91; else if (match == "qrtrs") mSecs = (int) (value * 86400 * 91);
else if (match == "qtrs") mSecs = value * 86400 * 91; else if (match == "qtrs") mSecs = (int) (value * 86400 * 91);
else if (match == "q") mSecs = value * 86400 * 91; else if (match == "q") mSecs = (int) (value * 86400 * 91);
else if (match == "monthly") mSecs = value * 86400 * 30; else if (match == "monthly") mSecs = (int) (value * 86400 * 30);
else if (match == "month") mSecs = value * 86400 * 30; else if (match == "month") mSecs = (int) (value * 86400 * 30);
else if (match == "months") mSecs = value * 86400 * 30; else if (match == "months") mSecs = (int) (value * 86400 * 30);
else if (match == "mnths") mSecs = value * 86400 * 30; else if (match == "mnths") mSecs = (int) (value * 86400 * 30);
else if (match == "mos") mSecs = value * 86400 * 30; else if (match == "mos") mSecs = (int) (value * 86400 * 30);
else if (match == "mo") mSecs = value * 86400 * 30; else if (match == "mo") mSecs = (int) (value * 86400 * 30);
else if (match == "mths") mSecs = value * 86400 * 30; else if (match == "mths") mSecs = (int) (value * 86400 * 30);
else if (match == "biweekly") mSecs = value * 86400 * 14; else if (match == "biweekly") mSecs = (int) (value * 86400 * 14);
else if (match == "fortnight") mSecs = value * 86400 * 14; else if (match == "fortnight") mSecs = (int) (value * 86400 * 14);
else if (match == "weekly") mSecs = value * 86400 * 7; else if (match == "weekly") mSecs = (int) (value * 86400 * 7);
else if (match == "sennight") mSecs = value * 86400 * 7; else if (match == "sennight") mSecs = (int) (value * 86400 * 7);
else if (match == "weeks") mSecs = value * 86400 * 7; else if (match == "weeks") mSecs = (int) (value * 86400 * 7);
else if (match == "wks") mSecs = value * 86400 * 7; else if (match == "wks") mSecs = (int) (value * 86400 * 7);
else if (match == "w") mSecs = value * 86400 * 7; else if (match == "w") mSecs = (int) (value * 86400 * 7);
else if (match == "daily") mSecs = value * 86400 * 1; else if (match == "daily") mSecs = (int) (value * 86400 * 1);
else if (match == "day") mSecs = value * 86400 * 1; else if (match == "day") mSecs = (int) (value * 86400 * 1);
else if (match == "weekdays") mSecs = value * 86400 * 1; else if (match == "weekdays") mSecs = (int) (value * 86400 * 1);
else if (match == "days") mSecs = value * 86400 * 1; else if (match == "days") mSecs = (int) (value * 86400 * 1);
else if (match == "d") mSecs = value * 86400 * 1; else if (match == "d") mSecs = (int) (value * 86400 * 1);
else if (match == "hours") mSecs = value * 3600; else if (match == "hours") mSecs = (int) (value * 3600);
else if (match == "hrs") mSecs = value * 3600; else if (match == "hrs") mSecs = (int) (value * 3600);
else if (match == "h") mSecs = value * 3600; else if (match == "h") mSecs = (int) (value * 3600);
else if (match == "minutes") mSecs = value * 60; else if (match == "minutes") mSecs = (int) (value * 60);
else if (match == "mins") mSecs = value * 60; else if (match == "mins") mSecs = (int) (value * 60);
else if (match == "min") mSecs = value * 60; else if (match == "min") mSecs = (int) (value * 60);
else if (match == "m") mSecs = value * 60; else if (match == "m") mSecs = (int) (value * 60);
else if (match == "seconds") mSecs = value; else if (match == "seconds") mSecs = (int) value;
else if (match == "secs") mSecs = value; else if (match == "secs") mSecs = (int) value;
else if (match == "sec") mSecs = value; else if (match == "sec") mSecs = (int) value;
else if (match == "s") mSecs = value; else if (match == "s") mSecs = (int) value;
else if (match == "-") mSecs = 0; else if (match == "-") mSecs = 0;
} }

View file

@ -323,6 +323,78 @@ bool Nibbler::getUnsignedInt (int& result)
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////
// number:
// int frac? exp?
//
// int:
// -? digit+
//
// frac:
// . digit+
//
// exp:
// e digit+
//
// e:
// e|E (+|-)?
//
bool Nibbler::getNumber (double& result)
{
std::string::size_type i = mCursor;
// [+-]?
if (i < mLength && mInput[i] == '-')
++i;
// digit+
if (i < mLength && isdigit (mInput[i]))
{
++i;
while (i < mLength && isdigit (mInput[i]))
++i;
// ( . digit+ )?
if (i < mLength && mInput[i] == '.')
{
++i;
while (i < mLength && isdigit (mInput[i]))
++i;
}
// ( [eE] [+-]? digit+ )?
if (i < mLength && (mInput[i] == 'e' || mInput[i] == 'E'))
{
++i;
if (i < mLength && (mInput[i] == '+' || mInput[i] == '-'))
++i;
if (i < mLength && isdigit (mInput[i]))
{
++i;
while (i < mLength && isdigit (mInput[i]))
++i;
result = atof (mInput.substr (mCursor, i - mCursor).c_str ());
mCursor = i;
return true;
}
return false;
}
result = atof (mInput.substr (mCursor, i - mCursor).c_str ());
mCursor = i;
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getLiteral (const std::string& literal) bool Nibbler::getLiteral (const std::string& literal)
{ {

View file

@ -50,6 +50,7 @@ public:
bool getQuoted (char, std::string&, bool unescape = true, bool quote = false); bool getQuoted (char, std::string&, bool unescape = true, bool quote = false);
bool getInt (int&); bool getInt (int&);
bool getUnsignedInt (int&); bool getUnsignedInt (int&);
bool getNumber (double&);
bool getLiteral (const std::string&); bool getLiteral (const std::string&);
bool getRx (const std::string&, std::string&); bool getRx (const std::string&, std::string&);

View file

@ -763,8 +763,8 @@ bool sort_compare (int left, int right)
return true; return true;
else if ((std::string)*cell_left != "" && (std::string)*cell_right == "") else if ((std::string)*cell_left != "" && (std::string)*cell_right == "")
return false; return false;
else if (Duration ((std::string)*cell_left) < Duration ((std::string)*cell_right)) else
return true; return Duration ((std::string)*cell_left) < Duration ((std::string)*cell_right) ? true : false;
break; break;
case Table::descendingPeriod: case Table::descendingPeriod:
@ -772,8 +772,8 @@ bool sort_compare (int left, int right)
return false; return false;
else if ((std::string)*cell_left == "" && (std::string)*cell_right != "") else if ((std::string)*cell_left == "" && (std::string)*cell_right != "")
return true; return true;
else if (Duration ((std::string)*cell_left) < Duration ((std::string)*cell_right)) else
return false; return Duration ((std::string)*cell_left) < Duration ((std::string)*cell_right) ? false : true;
break; break;
} }
} }

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
## taskwarrior - a command line task list manager. ## taskwarrior - a command line task list manager.
## ##
## Copyright 2006 - 2010, Paul Beckingham. ## Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
## All rights reserved. ## All rights reserved.
## ##
## This program is free software; you can redistribute it and/or modify it under ## This program is free software; you can redistribute it and/or modify it under
@ -28,57 +28,151 @@
use strict; use strict;
use warnings; use warnings;
use Test::More tests => 12; use Test::More tests => 85;
# Create the rc file. # Create the rc file.
if (open my $fh, '>', 'countdown.rc') if (open my $fh, '>', 'countdown.rc')
{ {
print $fh "data.location=.\n"; print $fh "data.location=.\n";
print $fh "report.countdown.description=Countdown report\n"; print $fh "report.up.description=countdown+ report\n";
print $fh "report.countdown.columns=id,countdown,description\n"; print $fh "report.up.columns=id,countdown,description\n";
print $fh "report.countdown.labels=ID,Countdown,Description\n"; print $fh "report.up.labels=ID,Countdown,Description\n";
print $fh "report.countdown.sort=countdown-"; print $fh "report.up.filter=status:pending\n";
print $fh "report.up.sort=countdown+\n";
print $fh "report.down.description=countdown- report\n";
print $fh "report.down.columns=id,countdown,description\n";
print $fh "report.down.labels=ID,Countdown,Description\n";
print $fh "report.down.filter=status:pending\n";
print $fh "report.down.sort=countdown-\n";
print $fh "report.upc.description=countdown_compact+ report\n";
print $fh "report.upc.columns=id,countdown_compact,description\n";
print $fh "report.upc.labels=ID,Countdown,Description\n";
print $fh "report.upc.filter=status:pending\n";
print $fh "report.upc.sort=countdown_compact+\n";
print $fh "report.downc.description=countdown_compact- report\n";
print $fh "report.downc.columns=id,countdown_compact,description\n";
print $fh "report.downc.labels=ID,Countdown,Description\n";
print $fh "report.downc.filter=status:pending\n";
print $fh "report.downc.sort=countdown_compact-\n";
close $fh; close $fh;
ok (-r 'countdown.rc', 'Created countdown.rc'); ok (-r 'countdown.rc', 'Created countdown.rc');
} }
# Create a variety of pending tasks with increasingly higher due dates # Create a variety of pending tasks with increasingly higher due dates
# and ensure sort order. # to ensure proper sort order.
qx{../task rc:countdown.rc add one due:-1.2y};
qx{../task rc:countdown.rc add two due:-9mo};
qx{../task rc:countdown.rc add three due:-2mo};
qx{../task rc:countdown.rc add four due:-3wk};
qx{../task rc:countdown.rc add five due:-7d};
qx{../task rc:countdown.rc add six due:-2d};
qx{../task rc:countdown.rc add seven due:-1d};
qx{../task rc:countdown.rc add eight due:-12h};
qx{../task rc:countdown.rc add nine due:-6h};
qx{../task rc:countdown.rc add ten due:-1h};
qx{../task rc:countdown.rc add eleven due:-30s};
qx{../task rc:countdown.rc add twelve due:1h};
qx{../task rc:countdown.rc add thirteen due:6h};
qx{../task rc:countdown.rc add fourteen due:12h};
qx{../task rc:countdown.rc add fifteen due:1d};
qx{../task rc:countdown.rc add sixteen due:2d};
qx{../task rc:countdown.rc add seventeen due:7d};
qx{../task rc:countdown.rc add eighteen due:3wk};
qx{../task rc:countdown.rc add nineteen due:2mo};
qx{../task rc:countdown.rc add twenty due:9mo};
qx{../task rc:countdown.rc add twentyone due:1.2y};
# The -1 guarantees that no duration will be rendered as '-'. my $output = qx{../task rc:countdown.rc up};
my $now = time () - 1; like ($output, qr/\bone\b.+\btwo\b/ms, 'up: one < two');
like ($output, qr/\btwo\b.+\bthree/ms, 'up: two < three');
like ($output, qr/\bthree\b.+\bfour/ms, 'up: three < four');
like ($output, qr/\bfour\b.+\bfive/ms, 'up: four < five');
like ($output, qr/\bfive\b.+\bsix/ms, 'up: five < six');
like ($output, qr/\bsix\b.+\bseven/ms, 'up: six < seven');
like ($output, qr/\bseven\b.+\beight/ms, 'up: seven < eight');
like ($output, qr/\beight\b.+\bnine/ms, 'up: eight < nine');
like ($output, qr/\bnine\b.+\bten/ms, 'up: nine < ten');
like ($output, qr/\bten\b.+\beleven/ms, 'up: ten < eleven');
like ($output, qr/\beleven\b.+\btwelve/ms, 'up: eleven < twelve');
like ($output, qr/\btwelve\b.+\bthirteen/ms, 'up: twelve < thirteen');
like ($output, qr/\bthirteen\b.+\bfourteen/ms, 'up: thirteen < fourteen');
like ($output, qr/\bfourteen\b.+\bfifteen/ms, 'up: fourteen < fifteen');
like ($output, qr/\bfifteen\b.+\bsixteen/ms, 'up: fifteen < sixteen');
like ($output, qr/\bsixteen\b.+\bseventeen/ms, 'up: sixteen < seventeen');
like ($output, qr/\bseventeen\b.+\beighteen/ms, 'up: seventeen < eighteen');
like ($output, qr/\beighteen\b.+\bnineteen/ms, 'up: eighteen < nineteen');
like ($output, qr/\bnineteen\b.+\btwenty/ms, 'up: nineteen < twenty');
like ($output, qr/\btwenty\b.+\btwentyone/ms, 'up: twenty < twentyone');
my $nowminusone = $now - 3600; $output = qx{../task rc:countdown.rc down};
my $nowplusone = $now + 3600; like ($output, qr/\btwentyone\b.+\btwenty/ms, 'down: twentyone < twenty');
my $nowplusseven = $now + 7 * 3600; like ($output, qr/\btwenty\b.+\bnineteen/ms, 'down: twenty < nineteen');
my $nowplustwelve = $now + 12 * 3600; like ($output, qr/\bnineteen\b.+\beighteen/ms, 'down: nineteen < eighteen');
my $nowplusthirtysix = $now + 36 * 3600; like ($output, qr/\beighteen\b.+\bseventeen/ms, 'down: eighteen < seventeen');
my $nowplusseventytwo = $now + 72 * 3600; like ($output, qr/\bseventeen\b.+\bsixteen/ms, 'down: seventeen < sixteen');
like ($output, qr/\bsixteen\b.+\bfifteen/ms, 'down: sixteen < fifteen');
like ($output, qr/\bfifteen\b.+\bfourteen/ms, 'down: fifteen < fourteen');
like ($output, qr/\bfourteen\b.+\bthirteen/ms, 'down: fourteen < thirteen');
like ($output, qr/\bthirteen\b.+\btwelve/ms, 'down: thirteen < twelve');
like ($output, qr/\btwelve\b.+\beleven/ms, 'down: twelve < eleven');
like ($output, qr/\beleven\b.+\bten/ms, 'down: eleven < ten');
like ($output, qr/\bten\b.+\bnine/ms, 'down: ten < nine');
like ($output, qr/\bnine\b.+\beight/ms, 'down: nine < eight');
like ($output, qr/\beight\b.+\bseven/ms, 'down: eight < seven');
like ($output, qr/\bseven\b.+\bsix/ms, 'down: seven < six');
like ($output, qr/\bsix\b.+\bfive/ms, 'down: six < five');
like ($output, qr/\bfive\b.+\bfour/ms, 'down: five < four');
like ($output, qr/\bfour\b.+\bthree/ms, 'down: four < three');
like ($output, qr/\bthree\b.+\btwo/ms, 'down: three < two');
like ($output, qr/\btwo\b.+\bone\b/ms, 'down: two < one');
if (open my $fh, '>', 'pending.data') $output = qx{../task rc:countdown.rc upc};
{ like ($output, qr/\bone\b.+\btwo\b/ms, 'upc: one < two');
print $fh <<EOF; like ($output, qr/\btwo\b.+\bthree/ms, 'upc: two < three');
[status:"pending" description:"Due one hour ago" entry:"$now" due:"$nowminusone"] like ($output, qr/\bthree\b.+\bfour/ms, 'upc: three < four');
[status:"pending" description:"Due now" entry:"$now" due:"$now"] like ($output, qr/\bfour\b.+\bfive/ms, 'upc: four < five');
[status:"pending" description:"Due one hour in the future" entry:"$now" due:"$nowplusone"] like ($output, qr/\bfive\b.+\bsix/ms, 'upc: five < six');
[status:"pending" description:"Due seven hours in the future" entry:"$now" due:"$nowplusseven"] like ($output, qr/\bsix\b.+\bseven/ms, 'upc: six < seven');
[status:"pending" description:"Due twelve hours in the future" entry:"$now" due:"$nowplustwelve"] like ($output, qr/\bseven\b.+\beight/ms, 'upc: seven < eight');
[status:"pending" description:"Due thirty-six hours in the future" entry:"$now" due:"$nowplusthirtysix"] like ($output, qr/\beight\b.+\bnine/ms, 'upc: eight < nine');
[status:"pending" description:"Due seventy-two hours in the future" entry:"$now" due:"$nowplusseventytwo"] like ($output, qr/\bnine\b.+\bten/ms, 'upc: nine < ten');
like ($output, qr/\bten\b.+\beleven/ms, 'upc: ten < eleven');
like ($output, qr/\beleven\b.+\btwelve/ms, 'upc: eleven < twelve');
like ($output, qr/\btwelve\b.+\bthirteen/ms, 'upc: twelve < thirteen');
like ($output, qr/\bthirteen\b.+\bfourteen/ms, 'upc: thirteen < fourteen');
like ($output, qr/\bfourteen\b.+\bfifteen/ms, 'upc: fourteen < fifteen');
like ($output, qr/\bfifteen\b.+\bsixteen/ms, 'upc: fifteen < sixteen');
like ($output, qr/\bsixteen\b.+\bseventeen/ms, 'upc: sixteen < seventeen');
like ($output, qr/\bseventeen\b.+\beighteen/ms, 'upc: seventeen < eighteen');
like ($output, qr/\beighteen\b.+\bnineteen/ms, 'upc: eighteen < nineteen');
like ($output, qr/\bnineteen\b.+\btwenty/ms, 'upc: nineteen < twenty');
like ($output, qr/\btwenty\b.+\btwentyone/ms, 'upc: twenty < twentyone');
EOF $output = qx{../task rc:countdown.rc downc};
close $fh; like ($output, qr/\btwentyone\b.+\btwenty/ms, 'downc: twentyone < twenty');
ok (-r 'pending.data', 'Created pending.data'); like ($output, qr/\btwenty\b.+\bnineteen/ms, 'downc: twenty < nineteen');
} like ($output, qr/\bnineteen\b.+\beighteen/ms, 'downc: nineteen < eighteen');
like ($output, qr/\beighteen\b.+\bseventeen/ms, 'downc: eighteen < seventeen');
my $output = qx{../task rc:countdown.rc countdown}; like ($output, qr/\bseventeen\b.+\bsixteen/ms, 'downc: seventeen < sixteen');
like ($output, qr/-2 days.+-1 day/s, 'countdown - oldest first'); like ($output, qr/\bsixteen\b.+\bfifteen/ms, 'downc: sixteen < fifteen');
like ($output, qr/-1 day.+-11 hrs/s, 'countdown - next second oldest'); like ($output, qr/\bfifteen\b.+\bfourteen/ms, 'downc: fifteen < fourteen');
like ($output, qr/-11 hrs.+-6 hrs/s, 'countdown - next third oldest'); like ($output, qr/\bfourteen\b.+\bthirteen/ms, 'downc: fourteen < thirteen');
like ($output, qr/-6 hrs.+-59 mins/s, 'countdown - next fourth oldest'); like ($output, qr/\bthirteen\b.+\btwelve/ms, 'downc: thirteen < twelve');
like ($output, qr/-59 mins.+ Due now/s, 'countdown - next fifth oldest'); like ($output, qr/\btwelve\b.+\beleven/ms, 'downc: twelve < eleven');
like ($output, qr/ Due now.+1 hr/s, 'countdown - next sixth oldest'); like ($output, qr/\beleven\b.+\bten/ms, 'downc: eleven < ten');
like ($output, qr/\bten\b.+\bnine/ms, 'downc: ten < nine');
like ($output, qr/\bnine\b.+\beight/ms, 'downc: nine < eight');
like ($output, qr/\beight\b.+\bseven/ms, 'downc: eight < seven');
like ($output, qr/\bseven\b.+\bsix/ms, 'downc: seven < six');
like ($output, qr/\bsix\b.+\bfive/ms, 'downc: six < five');
like ($output, qr/\bfive\b.+\bfour/ms, 'downc: five < four');
like ($output, qr/\bfour\b.+\bthree/ms, 'downc: four < three');
like ($output, qr/\bthree\b.+\btwo/ms, 'downc: three < two');
like ($output, qr/\btwo\b.+\bone\b/ms, 'downc: two < one');
# Cleanup. # Cleanup.
unlink 'pending.data'; unlink 'pending.data';

View file

@ -48,7 +48,7 @@ int convertDuration (const std::string& input)
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
UnitTest t (579); UnitTest t (606);
Duration d; Duration d;
@ -531,6 +531,10 @@ int main (int argc, char** argv)
t.ok (d.valid ("10 yrs"), "valid duration 10 yrs"); t.ok (d.valid ("10 yrs"), "valid duration 10 yrs");
t.ok (d.valid ("10 yr"), "valid duration 10 yr"); t.ok (d.valid ("10 yr"), "valid duration 10 yr");
t.ok (d.valid ("10y"), "valid duration 10y"); t.ok (d.valid ("10y"), "valid duration 10y");
t.ok (d.valid ("1.1 yrs"), "valid duration 1.1 yrs");
t.ok (d.valid ("-1.1 yrs"), "valid duration -1.1 yrs");
t.ok (d.valid ("1.1y"), "valid duration 1.1y");
t.ok (d.valid ("-1.1y"), "valid duration -1.1y");
t.ok (d.valid ("0 qtrs"), "valid duration 0 qtrs"); t.ok (d.valid ("0 qtrs"), "valid duration 0 qtrs");
t.ok (d.valid ("0 qtr"), "valid duration 0 qtr"); t.ok (d.valid ("0 qtr"), "valid duration 0 qtr");
@ -542,15 +546,20 @@ int main (int argc, char** argv)
t.ok (d.valid ("10 qtr"), "valid duration 10 qtr"); t.ok (d.valid ("10 qtr"), "valid duration 10 qtr");
t.ok (d.valid ("10q"), "valid duration 10q"); t.ok (d.valid ("10q"), "valid duration 10q");
t.ok (d.valid ("0 mnths"), "valid duration 0 mths"); t.ok (d.valid ("0 mnths"), "valid duration 0 mnths");
t.ok (d.valid ("0 mnth"), "valid duration 0 mth"); t.ok (d.valid ("0 mnth"), "valid duration 0 mnth");
t.ok (d.valid ("0mo"), "valid duration 0mo"); t.ok (d.valid ("0mo"), "valid duration 0mo");
t.ok (d.valid ("1 mnths"), "valid duration 1 mths"); t.ok (d.valid ("1 mnths"), "valid duration 1 mnths");
t.ok (d.valid ("1 mth"), "valid duration 1 mth"); t.ok (d.valid ("1 mnth"), "valid duration 1 mnth");
t.ok (d.valid ("1mo"), "valid duration 1mo"); t.ok (d.valid ("1mo"), "valid duration 1mo");
t.ok (d.valid ("10 mnths"), "valid duration 10 mths"); t.ok (d.valid ("10 mnths"), "valid duration 10 mnths");
t.ok (d.valid ("10 mnth"), "valid duration 10 mth"); t.ok (d.valid ("10 mnth"), "valid duration 10 mnth");
t.ok (d.valid ("10mo"), "valid duration 10mo"); t.ok (d.valid ("10mo"), "valid duration 10mo");
t.ok (d.valid ("-1 mnths"), "valid duration -1 mnths");
t.ok (d.valid ("-1 mnth"), "valid duration -1 mnth");
t.ok (d.valid ("-1 mths"), "valid duration -1 mths");
t.ok (d.valid ("-1 mth"), "valid duration -1 mth");
t.ok (d.valid ("-1mo"), "valid duration -1mo");
t.ok (d.valid ("0 wks"), "valid duration 0 wks"); t.ok (d.valid ("0 wks"), "valid duration 0 wks");
t.ok (d.valid ("0 wk"), "valid duration 0 wk"); t.ok (d.valid ("0 wk"), "valid duration 0 wk");
@ -561,6 +570,10 @@ int main (int argc, char** argv)
t.ok (d.valid ("10 wks"), "valid duration 10 wks"); t.ok (d.valid ("10 wks"), "valid duration 10 wks");
t.ok (d.valid ("10 wk"), "valid duration 10 wk"); t.ok (d.valid ("10 wk"), "valid duration 10 wk");
t.ok (d.valid ("10w"), "valid duration 10w"); t.ok (d.valid ("10w"), "valid duration 10w");
t.ok (d.valid ("-1 wks"), "valid duration -1 wks");
t.ok (d.valid ("-1 wk"), "valid duration -1 wk");
t.ok (d.valid ("-1wk"), "valid duration -1wk");
t.ok (d.valid ("-1w"), "valid duration -1w");
t.ok (d.valid ("0 days"), "valid duration 0 days"); t.ok (d.valid ("0 days"), "valid duration 0 days");
t.ok (d.valid ("0 day"), "valid duration 0 day"); t.ok (d.valid ("0 day"), "valid duration 0 day");
@ -571,6 +584,9 @@ int main (int argc, char** argv)
t.ok (d.valid ("10 days"), "valid duration 10 days"); t.ok (d.valid ("10 days"), "valid duration 10 days");
t.ok (d.valid ("10 day"), "valid duration 10 day"); t.ok (d.valid ("10 day"), "valid duration 10 day");
t.ok (d.valid ("10d"), "valid duration 10d"); t.ok (d.valid ("10d"), "valid duration 10d");
t.ok (d.valid ("-1 days"), "valid duration -1 days");
t.ok (d.valid ("-1 day"), "valid duration -1 day");
t.ok (d.valid ("-1d"), "valid duration -1d");
t.ok (d.valid ("0 hrs"), "valid duration 0 hrs"); t.ok (d.valid ("0 hrs"), "valid duration 0 hrs");
t.ok (d.valid ("0 hr"), "valid duration 0 hr"); t.ok (d.valid ("0 hr"), "valid duration 0 hr");
@ -581,6 +597,9 @@ int main (int argc, char** argv)
t.ok (d.valid ("10 hrs"), "valid duration 10 hrs"); t.ok (d.valid ("10 hrs"), "valid duration 10 hrs");
t.ok (d.valid ("10 hr"), "valid duration 10 hr"); t.ok (d.valid ("10 hr"), "valid duration 10 hr");
t.ok (d.valid ("10h"), "valid duration 10h"); t.ok (d.valid ("10h"), "valid duration 10h");
t.ok (d.valid ("-1 hrs"), "valid duration -1 hrs");
t.ok (d.valid ("-1 hr"), "valid duration -1 hr");
t.ok (d.valid ("-1h"), "valid duration -1h");
t.ok (d.valid ("0 mins"), "valid duration 0 mins"); t.ok (d.valid ("0 mins"), "valid duration 0 mins");
t.ok (d.valid ("0 min"), "valid duration 0 min"); t.ok (d.valid ("0 min"), "valid duration 0 min");
@ -591,6 +610,9 @@ int main (int argc, char** argv)
t.ok (d.valid ("10 mins"), "valid duration 10 mins"); t.ok (d.valid ("10 mins"), "valid duration 10 mins");
t.ok (d.valid ("10 min"), "valid duration 10 min"); t.ok (d.valid ("10 min"), "valid duration 10 min");
t.ok (d.valid ("10m"), "valid duration 10m"); t.ok (d.valid ("10m"), "valid duration 10m");
t.ok (d.valid ("-1 mins"), "valid duration -1 mins");
t.ok (d.valid ("-1 min"), "valid duration -1 min");
t.ok (d.valid ("-1m"), "valid duration -1m");
t.ok (d.valid ("0 secs"), "valid duration 0 secs"); t.ok (d.valid ("0 secs"), "valid duration 0 secs");
t.ok (d.valid ("0 sec"), "valid duration 0 sec"); t.ok (d.valid ("0 sec"), "valid duration 0 sec");
@ -601,6 +623,9 @@ int main (int argc, char** argv)
t.ok (d.valid ("10 secs"), "valid duration 10 secs"); t.ok (d.valid ("10 secs"), "valid duration 10 secs");
t.ok (d.valid ("10 sec"), "valid duration 10 sec"); t.ok (d.valid ("10 sec"), "valid duration 10 sec");
t.ok (d.valid ("10s"), "valid duration 10s"); t.ok (d.valid ("10s"), "valid duration 10s");
t.ok (d.valid ("-1 secs"), "valid duration -1 secs");
t.ok (d.valid ("-1 sec"), "valid duration -1 sec");
t.ok (d.valid ("-1s"), "valid duration -1s");
t.notok (d.valid ("woof"), "valid duration woof = fail"); t.notok (d.valid ("woof"), "valid duration woof = fail");
@ -685,6 +710,8 @@ int main (int argc, char** argv)
left = Duration ("1mo"); right = Duration ("1q"); t.ok (left < right, "duration 1mo < 1q"); left = Duration ("1mo"); right = Duration ("1q"); t.ok (left < right, "duration 1mo < 1q");
left = Duration ("1q"); right = Duration ("1y"); t.ok (left < right, "duration 1q < 1y"); left = Duration ("1q"); right = Duration ("1y"); t.ok (left < right, "duration 1q < 1y");
left = Duration ("-3s"); right = Duration ("-6s"); t.ok (right < left, "duration -6s < -3s");
// operator> // operator>
left = Duration ("2secs"); right = Duration ("1sec"); t.ok (left > right, "2sec > 1secs"); left = Duration ("2secs"); right = Duration ("1sec"); t.ok (left > right, "2sec > 1secs");
left = Duration ("-1sec"); right = Duration ("-2secs"); t.ok (left > right, "-1secs > -2sec"); left = Duration ("-1sec"); right = Duration ("-2secs"); t.ok (left > right, "-1secs > -2sec");
@ -695,6 +722,8 @@ int main (int argc, char** argv)
left = Duration ("1mo"); right = Duration ("1w"); t.ok (left > right, "1mo > 1w"); left = Duration ("1mo"); right = Duration ("1w"); t.ok (left > right, "1mo > 1w");
left = Duration ("1q"); right = Duration ("1mo"); t.ok (left > right, "1q > 1mo"); left = Duration ("1q"); right = Duration ("1mo"); t.ok (left > right, "1q > 1mo");
left = Duration ("1y"); right = Duration ("1q"); t.ok (left > right, "1y > 1q"); left = Duration ("1y"); right = Duration ("1q"); t.ok (left > right, "1y > 1q");
left = Duration ("-3s"); right = Duration ("-6s"); t.ok (left > right, "duration -3s > -6s");
} }
catch (const std::string& e) { t.diag (e); } catch (const std::string& e) { t.diag (e); }

View file

@ -33,13 +33,14 @@ Context context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
UnitTest t (149); UnitTest t (155);
try try
{ {
Nibbler n; Nibbler n;
std::string s; std::string s;
int i; int i;
double d;
// Make sure the nibbler behaves itself with trivial input. // Make sure the nibbler behaves itself with trivial input.
t.diag ("Test all nibbler calls given empty input"); t.diag ("Test all nibbler calls given empty input");
@ -228,6 +229,16 @@ int main (int argc, char** argv)
t.is (i, 4, " '4' : getUnsignedInt () -> '4'"); t.is (i, 4, " '4' : getUnsignedInt () -> '4'");
t.ok (n.depleted (), " '' : depleted () -> true"); t.ok (n.depleted (), " '' : depleted () -> true");
// bool getNumber (double&);
t.diag ("Nibbler::getNumber");
n = Nibbler ("-1.234 2.3e4");
t.ok (n.getNumber (d), "'-1.234 2.3e4' : getNumber () -> true");
t.is (d, -1.234, "'-1.234 2.3e4' : getNumber () -> '-1.234'");
t.ok (n.skip (' '), " ' 2.3e4' : skip (' ') -> true");
t.ok (n.getNumber (d), " '2.3e4' : getNumber () -> true");
t.is (d, 2.3e4, " '2.3e4' : getNumber () -> '2.3e4'");
t.ok (n.depleted (), " '' : depleted () -> true");
// bool getLiteral (const std::string&); // bool getLiteral (const std::string&);
t.diag ("Nibbler::getLiteral"); t.diag ("Nibbler::getLiteral");
n = Nibbler ("foobar"); n = Nibbler ("foobar");