Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 81f5b5a1 authored by Marten Gajda's avatar Marten Gajda Committed by GitHub
Browse files

Fix handling calculation of duration of all-day recurring task, fixes #840 (#843)

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.
parent f7d1f5fa
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -200,6 +200,70 @@ public class TaskProviderRecurrenceTest
    }



    /**
     * 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.
     */
+34 −0
Original line number Diff line number Diff line
@@ -335,6 +335,40 @@ public class TaskProviderTest
    }



    /**
     * 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.
     */
+11 −1
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ public final class InstanceValuesIterable implements Iterable<Single<ContentValu

            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());
        }
@@ -104,4 +104,14 @@ public final class InstanceValuesIterable implements Iterable<Single<ContentValu

    }


    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);
    }

}