Skip to content

Commit

Permalink
Fix handling calculation of duration of all-day recurring task, fixes #…
Browse files Browse the repository at this point in the history
…840

Recurring tasks may specify a dtstart and due date (instead of a duration). If the task was an all-day task, we may have tried to add a duration derived from the difference between start and due.
The result was a non-all-day duration (although in most cases being a multiple of 24h) and adding this to an all-day date resulted in an error. It's fixed by converting the duration into a proper
all-day duration.
  • Loading branch information
dmfs committed Sep 13, 2019
1 parent f7d1f5f commit 87b98f4
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,70 @@ public void testRRule() throws InvalidRecurrenceRuleException
}



/**
* Test if instances of a task with an all-day DTSTART, DUE and an RRULE.
*/
@Test
public void testAllDayRRule() throws InvalidRecurrenceRuleException
{
RowSnapshot<TaskLists> taskList = new VirtualRowSnapshot<>(new LocalTaskListsTable(mAuthority));
Table<Instances> instancesTable = new InstanceTable(mAuthority);
RowSnapshot<Tasks> task = new VirtualRowSnapshot<>(new TaskListScoped(taskList, new TasksTable(mAuthority)));

Duration days = new Duration(1, 2, 0);
DateTime start = DateTime.parse("20180104");
DateTime due = start.addDuration(days);
DateTime localStart = start;

Duration day = new Duration(1, 1, 0);

DateTime second = localStart.addDuration(day);
DateTime third = second.addDuration(day);
DateTime fourth = third.addDuration(day);
DateTime fifth = fourth.addDuration(day);

DateTime localDue = due;

assertThat(new Seq<>(
new Put<>(taskList, new EmptyRowData<>()),
new Put<>(task,
new Composite<>(
new TimeData<>(start, due),
new RRuleTaskData(new RecurrenceRule("FREQ=DAILY;COUNT=5", RecurrenceRule.RfcMode.RFC2445_LAX))))

), resultsIn(mClient,
new Assert<>(task,
new Composite<>(
new TimeData<>(start, due),
new CharSequenceRowData<>(Tasks.RRULE, "FREQ=DAILY;COUNT=5"))),
// new Counted<>(5, new AssertRelated<>(instancesTable, Instances.TASK_ID, task)),
new Counted<>(1, new AssertRelated<>(instancesTable, Instances.TASK_ID, task)),
// 1st instance:
new AssertRelated<>(instancesTable, Instances.TASK_ID, task,
new InstanceTestData(localStart, localDue, new Present<>(start), 0),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, start.getTimestamp()))/*,
// 2nd instance:
new AssertRelated<>(instancesTable, Instances.TASK_ID, task,
new InstanceTestData(second, second.addDuration(hour), new Present<>(second), 1),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, second.getTimestamp())),
// 3rd instance:
new AssertRelated<>(instancesTable, Instances.TASK_ID, task,
new InstanceTestData(third, third.addDuration(hour), new Present<>(third), 2),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, third.getTimestamp())),
// 4th instance:
new AssertRelated<>(instancesTable, Instances.TASK_ID, task,
new InstanceTestData(fourth, fourth.addDuration(hour), new Present<>(fourth), 3),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, fourth.getTimestamp())),
// 5th instance:
new AssertRelated<>(instancesTable, Instances.TASK_ID, task,
new InstanceTestData(fifth, fifth.addDuration(hour), new Present<>(fifth), 4),
new EqArg(Instances.INSTANCE_ORIGINAL_TIME, fifth.getTimestamp())) */)
);
}



/**
* Test if instances of a task with a DUE and an RRULE but no DTSTART.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,40 @@ public void testInsertTaskWithStartAndDue()
}



/**
* Create task with start and due, check datetime values including generated duration.
*/
@Test
public void testInsertTaskWithAlldayStartAndDue()
{
RowSnapshot<TaskLists> taskList = new VirtualRowSnapshot<>(new LocalTaskListsTable(mAuthority));
RowSnapshot<Tasks> task = new VirtualRowSnapshot<>(new TaskListScoped(taskList, new TasksTable(mAuthority)));

DateTime start = DateTime.now().toAllDay();
DateTime due = start.addDuration(new Duration(1, 2, 0));

assertThat(new Seq<>(
new Put<>(taskList, new EmptyRowData<TaskLists>()),
new Put<>(task, new TimeData<>(start, due))

), resultsIn(mClient,
new Assert<>(task, new Composite<>(
new TimeData<>(start, due),
new VersionData(0))),
new AssertRelated<>(
new InstanceTable(mAuthority), Instances.TASK_ID, task,
new Composite<Instances>(
new InstanceTestData(
start,
due,
absent(),
0),
new CharSequenceRowData<>(Tasks.TZ, "UTC"))
)));
}


/**
* Create task with start and due, check datetime and INSTANCE_STATUS values after updating the status.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public Iterator<Single<ContentValues>> iterator()

return new Mapped<>(dateTime -> new Distant(mTaskAdapter.valueOf(TaskAdapter.IS_CLOSED) ? -1 : 0,
new Overridden(new Present<>(dateTime),
new Enduring(new DueDated(new Zipped<>(new Present<>(dateTime), effectiveDuration, DateTime::addDuration),
new Enduring(new DueDated(new Zipped<>(new Present<>(dateTime), effectiveDuration, this::addDuration),
new StartDated(new Present<>(dateTime), new VanillaInstanceData()))))),
new TaskInstanceIterable(mTaskAdapter).iterator());
}
Expand All @@ -104,4 +104,14 @@ public Iterator<Single<ContentValues>> iterator()

}


private DateTime addDuration(DateTime dt, Duration dur)
{
if (dt.isAllDay() && dur.getSecondsOfDay() != 0)
{
dur = new Duration(1, dur.getWeeks() * 7 + dur.getDays() + dur.getSecondsOfDay() / (3600 * 24), 0);
}
return dt.addDuration(dur);
}

}

0 comments on commit 87b98f4

Please sign in to comment.