Move overlap resolution from CmdContinue to function autoAdjust

- Only an open interval can truncate another open interval.
  Otherwise the `:adjust` hint has to be applied

Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
This commit is contained in:
Thomas Lauf 2020-07-01 07:32:48 +02:00
parent c6598b9ac8
commit 6db29f1df5
3 changed files with 75 additions and 16 deletions

View file

@ -52,7 +52,6 @@ int CmdContinue (
flattenDatabase (database, rules); flattenDatabase (database, rules);
Interval to_copy; Interval to_copy;
Interval latest = getLatestInterval (database);
if (ids.size() == 1) if (ids.size() == 1)
{ {
@ -68,6 +67,8 @@ int CmdContinue (
} }
else else
{ {
Interval latest = getLatestInterval (database);
if (latest.empty ()) if (latest.empty ())
{ {
throw std::string ("There is no previous tracking to continue."); throw std::string ("There is no previous tracking to continue.");
@ -100,17 +101,6 @@ int CmdContinue (
to_copy.start = start_time; to_copy.start = start_time;
to_copy.end = end_time; to_copy.end = end_time;
if (latest.is_open ())
{
Interval modified {latest};
modified.end = start_time;
database.modifyInterval(latest, modified, verbose);
if (verbose)
{
std::cout << '\n' << intervalSummarize (database, rules, modified);
}
}
validate (cli, rules, database, to_copy); validate (cli, rules, database, to_copy);
database.addInterval (to_copy, verbose); database.addInterval (to_copy, verbose);

View file

@ -112,8 +112,31 @@ static void autoAdjust (
debug (" " + overlap.dump ()); debug (" " + overlap.dump ());
} }
auto verbose = rules.getBoolean ("verbose");
if (! adjust) if (! adjust)
{ {
// standard overlap resolution: an open interval can truncate another open interval
if (overlaps.size () == 1)
{
auto overlap = overlaps[0];
if (overlap.is_open () && interval.is_open () && interval.startsWithin (overlap))
{
// start date of new interval within old interval
Interval modified {overlap};
modified.end = interval.start;
database.modifyInterval (overlap, modified, verbose);
if (verbose)
{
std::cout << '\n' << intervalSummarize (database, rules, modified);
}
return;
}
}
throw std::string("You cannot overlap intervals. Correct the start/end " throw std::string("You cannot overlap intervals. Correct the start/end "
"time, or specify the :adjust hint."); "time, or specify the :adjust hint.");
} }
@ -130,14 +153,14 @@ static void autoAdjust (
// start date of new interval within old interval // start date of new interval within old interval
Interval modified {overlap}; Interval modified {overlap};
modified.end = interval.start; modified.end = interval.start;
database.modifyInterval (overlap, modified, rules.getBoolean ("verbose")); database.modifyInterval (overlap, modified, verbose);
} }
else if (!start_within_overlap && end_within_overlap) else if (!start_within_overlap && end_within_overlap)
{ {
// end date of new interval within old interval // end date of new interval within old interval
Interval modified {overlap}; Interval modified {overlap};
modified.start = interval.end; modified.start = interval.end;
database.modifyInterval (overlap, modified, rules.getBoolean ("verbose")); database.modifyInterval (overlap, modified, verbose);
} }
else if (!start_within_overlap && !end_within_overlap) else if (!start_within_overlap && !end_within_overlap)
{ {
@ -159,12 +182,12 @@ static void autoAdjust (
} }
else else
{ {
database.modifyInterval (overlap, split1, rules.getBoolean ("verbose")); database.modifyInterval (overlap, split1, verbose);
} }
if (! split2.is_empty ()) if (! split2.is_empty ())
{ {
database.addInterval (split2, rules.getBoolean ("verbose")); database.addInterval (split2, verbose);
} }
} }
} }

View file

@ -150,6 +150,52 @@ class TestContinue(TestCase):
expectedTags=["FOO"], expectedTags=["FOO"],
description="continued interval") description="continued interval")
def test_continue_without_adjust_hint(self):
"""Verify that continuing without the :adjust hint fails to overwrite"""
now_utc = datetime.now().utcnow()
two_hours_before_utc = now_utc - timedelta(hours=2)
three_hours_before_utc = now_utc - timedelta(hours=3)
four_hours_before_utc = now_utc - timedelta(hours=4)
five_hours_before_utc = now_utc - timedelta(hours=5)
self.t("track FOO {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(five_hours_before_utc, four_hours_before_utc))
self.t("track BAR {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(four_hours_before_utc, two_hours_before_utc))
self.t.runError("continue @2 {:%Y-%m-%dT%H}:00:00Z".format(three_hours_before_utc))
def test_continue_with_adjust_hint(self):
"""Verify that continuing with the :adjust hint works"""
now_utc = datetime.now().utcnow()
two_hours_before_utc = now_utc - timedelta(hours=2)
three_hours_before_utc = now_utc - timedelta(hours=3)
four_hours_before_utc = now_utc - timedelta(hours=4)
five_hours_before_utc = now_utc - timedelta(hours=5)
self.t("track FOO {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(five_hours_before_utc, four_hours_before_utc))
self.t("track BAR {:%Y-%m-%dT%H}:00:00Z - {:%Y-%m-%dT%H}:00:00Z".format(four_hours_before_utc, two_hours_before_utc))
self.t("continue @2 {:%Y-%m-%dT%H}:00:00Z :adjust".format(three_hours_before_utc))
j = self.t.export()
self.assertEqual(len(j), 3)
self.assertClosedInterval(j[0],
expectedStart="{:%Y%m%dT%H}0000Z".format(five_hours_before_utc),
expectedEnd="{:%Y%m%dT%H}0000Z".format(four_hours_before_utc),
expectedTags=["FOO"],
description="first interval")
self.assertClosedInterval(j[1],
expectedStart="{:%Y%m%dT%H}0000Z".format(four_hours_before_utc),
expectedEnd="{:%Y%m%dT%H}0000Z".format(three_hours_before_utc),
expectedTags=["BAR"],
description="second interval")
self.assertOpenInterval(j[2],
expectedStart="{:%Y%m%dT%H}0000Z".format(three_hours_before_utc),
expectedTags=["FOO"],
description="continued interval")
def test_continue_with_id_and_range(self): def test_continue_with_id_and_range(self):
"""Verify that continue with a range adds a copy with same tags""" """Verify that continue with a range adds a copy with same tags"""
now_utc = datetime.now().utcnow() now_utc = datetime.now().utcnow()