示例#1
0
def test_insert_task_empty_planned():
    """
    Insert a task into the planned schedule of an empty session.
    """

    # Construct session.
    session = Session("test")

    # Insert task.
    session.insert_task(
        day=0,
        planned=True,
        name="test",
        priority=1.0,
        start_time=time(hour=12),
        hours=1.5,
    )

    # Test session values.
    assert session.history_pos == 1
    assert len(session.edit_history) == 2
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
    assert len(session.edit_history[1][0].tasks) == 1
    assert len(session.edit_history[1][1].tasks) == 0
    task = session.edit_history[1][0].tasks[0]
    assert task.name == "test"
    assert task.priority == 1.0
    assert task.start_time == datetime.combine(session.base_date, time(hour=12))
    assert task.end_time == datetime.combine(
        session.base_date, time(hour=13, minute=30)
    )
示例#2
0
def test_undo_filled_planned():
    """
    Test undoing an edit task action on a filled out planned schedule.
    """

    # Set up case. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules(
    )[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())
    planned = True
    day = 4
    task_index = 0
    new_values = {"name": "new_name"}

    # Store pre-edit values.
    old_history_pos = session.history_pos
    old_planned, old_actual = session.current_schedules()

    # Edit task, then undo.
    session.edit_task(
        planned=planned,
        day=day,
        task_index=task_index,
        new_values=new_values,
    )
    session.undo()

    # Test session values.
    new_planned, new_actual = session.current_schedules()
    assert session.history_pos == old_history_pos
    assert old_planned == new_planned
    assert old_actual == new_actual
示例#3
0
def test_redo_filled():
    """
    Test redoing an action on a filled out planned schedule.
    """

    # Set up case. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules(
    )[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())

    # Store pre-edit values.
    old_history_pos = session.history_pos
    old_history_len = len(session.edit_history)
    old_planned, old_actual = session.current_schedules()

    # Undo then redo last action.
    session.undo()
    session.redo()

    # Test session values.
    new_planned, new_actual = session.current_schedules()
    assert session.history_pos == old_history_pos
    assert old_planned == new_planned
    assert old_actual == new_actual
    assert len(session.edit_history) == old_history_len
示例#4
0
def test_insert_task_overlap():
    """
    Insert an invalid (overlapping) task into the planned schedule of a nonempty
    session, and check that an error gets raised.
    """

    # Construct session.
    session = Session("example", load=True)

    # Store pre-insert session values.
    pre_history_pos = session.history_pos
    pre_edit_history = list(session.edit_history)

    # Insert task.
    error = False
    try:
        session.insert_task(
            day=5,
            planned=True,
            name="test",
            priority=1.0,
            start_time=time(hour=13),
            hours=1,
        )
    except ValueError:
        error = True

    # Ensure error was thrown.
    assert error
示例#5
0
def test_delete_task_single_actual():
    """
    Test deleting task from a schedule with only one task in actual.
    """

    # Construct session. Note that we have to manually set the base date of the session
    # in order to access the task, since it has a hard-coded date.
    session = Session("test")
    session.insert_task(
        day=4,
        planned=False,
        name="test",
        priority=1.0,
        start_time=time(hour=12),
        hours=1.5,
    )
    session.base_date = session.current_schedules(
    )[1].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())

    # Delete the task.
    session.delete_task(planned=False, day=4, task_index=0)

    # Test session values.
    assert session.history_pos == 2
    assert len(session.edit_history) == 3
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
    assert len(session.edit_history[1][0].tasks) == 0
    assert len(session.edit_history[1][1].tasks) == 1
    assert len(session.edit_history[2][0].tasks) == 0
    assert len(session.edit_history[2][1].tasks) == 0
示例#6
0
def test_daily_points_score_empty():
    """ Daily points for an empty schedule. """

    # Construct session.
    session = Session("test")

    # Construct expected point/score values.
    p_ind_pts = [0.0] * DAYS_IN_WEEK
    p_cum_pts = [0.0] * DAYS_IN_WEEK
    a_ind_pts = [0.0] * DAYS_IN_WEEK
    a_cum_pts = [0.0] * DAYS_IN_WEEK
    ind_score = [100.0] * DAYS_IN_WEEK
    cum_score = [100.0] * DAYS_IN_WEEK

    # Test point values.
    for day in range(DAYS_IN_WEEK):
        assert (session.daily_points(day, planned=False,
                                     cumulative=False) == p_ind_pts[day])
        assert (session.daily_points(day, planned=False,
                                     cumulative=True) == p_cum_pts[day])
        assert (session.daily_points(day, planned=True,
                                     cumulative=False) == a_ind_pts[day])
        assert (session.daily_points(day, planned=True,
                                     cumulative=True) == a_cum_pts[day])
        assert session.daily_score(day, cumulative=False) == ind_score[day]
        assert session.daily_score(day, cumulative=True) == cum_score[day]
示例#7
0
def test_redo_edge():
    """
    Test redoing when there is nothing to redo.
    """

    # Construct session.
    session = Session("test")

    # Undo.
    session.redo()

    # Test session values.
    assert session.history_pos == 0
    assert len(session.edit_history) == 1
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
示例#8
0
def test_insert_task_nonempty_planned():
    """
    Insert a task into the planned schedule of a nonempty session.
    """

    # Construct session.
    session = Session("example", load=True)

    # Store pre-insert session values.
    pre_history_pos = session.history_pos
    pre_edit_history = list(session.edit_history)

    # Insert task.
    task = Task(
        "test",
        priority=1.0,
        start_time=datetime(2020, 5, 1, hour=15),
        end_time=datetime(2020, 5, 1, hour=16),
    )
    session.insert_task(
        day=4,
        planned=True,
        name="test",
        priority=1.0,
        start_time=time(hour=15),
        hours=1,
    )

    # Test session values.
    assert session.history_pos == pre_history_pos + 1
    assert len(session.edit_history) == len(pre_edit_history) + 1
    assert session.edit_history[:-1] == pre_edit_history
    assert session.edit_history[-1][1] == pre_edit_history[-1][1]
    assert (
        list_exclude(session.edit_history[-1][0].tasks, 2)
        == pre_edit_history[-1][0].tasks
    )
    task = session.edit_history[-1][0].tasks[2]
    assert task.name == "test"
    assert task.priority == 1.0
    assert task.start_time == datetime.combine(
        session.base_date, time(hour=15)
    ) + timedelta(days=4)
    assert task.end_time == datetime.combine(
        session.base_date, time(hour=16)
    ) + timedelta(days=4)
示例#9
0
def test_delete_task_full():
    """
    Test deleting task from a full schedule.
    """

    # Construct session. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules(
    )[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())
    planned = True
    day = 5
    task_index = 0

    # Store pre-delete session values.
    pre_history_pos = session.history_pos
    pre_edit_history = list(session.edit_history)
    original_task = session.get_task(planned=planned,
                                     day=day,
                                     task_index=task_index)

    # Delete task.
    session.delete_task(planned=planned, day=day, task_index=task_index)

    # Test session values.
    assert session.history_pos == pre_history_pos + 1
    assert len(session.edit_history) == len(pre_edit_history) + 1
    assert session.edit_history[:-1] == pre_edit_history
    assert pre_edit_history[-1][0].tasks[2] == original_task
    assert session.edit_history[-1][0].tasks == list_exclude(
        pre_edit_history[-1][0].tasks, 2)
    assert session.edit_history[-1][1] == pre_edit_history[-1][1]
示例#10
0
def test_edit_task_time_valid():
    """
    Edit the time of a single task in a valid way, i.e. it doesn't interfere with other
    tasks.
    """

    # Set up case. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules()[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())
    planned = True
    day = 4
    task_index = 0
    new_values = {"start_time": datetime(2020, 5, 1, hour=13)}

    # Store pre-insert session values.
    pre_history_pos = session.history_pos
    pre_edit_history = list(session.edit_history)
    original_task = session.get_task(planned=planned, day=day, task_index=task_index)
    new_task = deepcopy(original_task)
    new_task.start_time = new_values["start_time"]

    # Edit task.
    session.edit_task(
        planned=planned, day=day, task_index=task_index, new_values=new_values,
    )

    # Test session values.
    assert session.history_pos == pre_history_pos + 1
    assert len(session.edit_history) == len(pre_edit_history) + 1
    assert session.edit_history[:-1] == pre_edit_history
    assert pre_edit_history[-1][0].tasks[0] == original_task
    assert session.edit_history[-1][0].tasks[0] == new_task
    assert session.edit_history[-1][1] == pre_edit_history[-1][1]
示例#11
0
def test_redo_empty_planned():
    """
    Test redoing the addition of a task to an empty session.
    """

    # Construct session.
    session = Session("test")

    # Insert task.
    session.insert_task(
        day=4,
        planned=True,
        name="test",
        priority=1.0,
        start_time=time(hour=12),
        hours=1.5,
    )

    # Store session values.
    old_planned, old_actual = session.current_schedules()

    # Undo, then redo insertion.
    session.undo()
    session.redo()

    # Test session values.
    new_planned, new_actual = session.current_schedules()
    assert session.history_pos == 1
    assert len(session.edit_history) == 2
    assert new_planned == old_planned
    assert new_actual == old_actual
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
    assert len(session.edit_history[1][0].tasks) == 1
    assert len(session.edit_history[1][1].tasks) == 0
    task = session.edit_history[1][0].tasks[0]
    assert task.name == "test"
    assert task.priority == 1.0
    assert task.start_time.date() == session.base_date + timedelta(days=4)
    assert task.start_time.time() == time(hour=12)
    assert task.end_time.date() == session.base_date + timedelta(days=4)
    assert task.end_time.time() == time(hour=13, minute=30)
示例#12
0
def test_insert_task_sorted():
    """
    Insert a task into the actual schedule of a nonempty session, and check that the new
    task gets sorted correctly.
    """

    # Construct session.
    session = Session("example", load=True)

    # Store pre-insert session values.
    pre_history_pos = session.history_pos
    pre_edit_history = list(session.edit_history)

    # Insert task.
    session.insert_task(
        day=5,
        planned=False,
        name="test",
        priority=1.0,
        start_time=time(hour=12, minute=30),
        hours=0.5,
    )

    # Test session values.
    assert session.history_pos == pre_history_pos + 1
    assert len(session.edit_history) == len(pre_edit_history) + 1
    assert session.edit_history[:-1] == pre_edit_history
    assert session.edit_history[-1][0] == pre_edit_history[-1][0]
    assert (
        list_exclude(session.edit_history[-1][1].tasks, 3)
        == pre_edit_history[-1][1].tasks
    )
    task = session.edit_history[-1][1].tasks[3]
    assert task.name == "test"
    assert task.priority == 1.0
    assert task.start_time == datetime.combine(
        session.base_date, time(hour=12, minute=30)
    ) + timedelta(days=5)
    assert task.end_time == datetime.combine(
        session.base_date, time(hour=13)
    ) + timedelta(days=5)
示例#13
0
def test_undo_empty_planned():
    """
    Test undoing the addition of a task to an empty session.
    """

    # Construct session.
    session = Session("test")

    # Insert task and undo insertion.
    session.insert_task(
        day=4,
        planned=True,
        name="test",
        priority=1.0,
        start_time=time(hour=12),
        hours=1.5,
    )
    session.undo()

    # Test session values.
    assert session.history_pos == 0
    assert len(session.edit_history) == 2
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
    assert len(session.edit_history[1][0].tasks) == 1
    assert len(session.edit_history[1][1].tasks) == 0
    task = session.edit_history[1][0].tasks[0]
    assert task.name == "test"
    assert task.priority == 1.0
    assert task.start_time.date() == session.base_date + timedelta(days=4)
    assert task.start_time.time() == time(hour=12)
    assert task.end_time.date() == session.base_date + timedelta(days=4)
    assert task.end_time.time() == time(hour=13, minute=30)
示例#14
0
def test_move_tasks_invalid():
    """
    Test moving tasks in an invalid way.
    """

    # Construct session. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules(
    )[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())
    planned = True
    day = 4
    start_task_index = 0
    end_task_index = 1

    # Move task into invalid time slot.
    error = False
    try:
        session.move_tasks(
            planned=planned,
            day=day,
            start_task_index=start_task_index,
            end_task_index=end_task_index,
            time_delta=timedelta(hours=2),
        )
    except:
        error = True

    # Ensure that error was thrown.
    assert error
示例#15
0
def test_edit_task_time_invalid():
    """
    Edit the time of a single task in an invalid way, i.e. it interferes with other
    tasks.
    """

    # Set up case. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules()[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())
    planned = True
    day = 4
    task_index = 0
    new_values = {
        "start_time": datetime(2020, 5, 1, hour=13),
        "end_time": datetime(2020, 5, 1, hour=14),
    }

    # Edit task in a way that creates overlap, i.e. should throw an error.
    error = False
    try:
        session.edit_task(
            planned=planned, day=day, task_index=task_index, new_values=new_values,
        )
    except:
        error = True

    # Ensure error was thrown.
    assert error
示例#16
0
def test_set_new_schedules_1():
    """
    Call `set_new_schedules()` in the first case of edit history (cases listed in
    docstring of `set_new_schedules()`).
    """

    # Construct session.
    session = Session("test")

    # Construct planned and new schedules.
    planned_task = Task(
        "planned_task",
        priority=1.0,
        start_time=datetime(2020, 5, 1, hour=12),
        end_time=datetime(2020, 5, 1, hour=13, minute=30),
    )
    actual_task = Task(
        "actual_task",
        priority=1.0,
        start_time=datetime(2020, 5, 1, hour=13),
        end_time=datetime(2020, 5, 1, hour=14, minute=30),
    )
    planned = Schedule("planned", [planned_task])
    actual = Schedule("actual", [actual_task])

    # Set new schedules in session.
    session.set_new_schedules(planned, actual)

    # Test session values.
    assert session.history_pos == 1
    assert len(session.edit_history) == 2
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
    assert len(session.edit_history[1][0].tasks) == 1
    assert len(session.edit_history[1][1].tasks) == 1
    assert session.edit_history[1][0].tasks[0] == planned_task
    assert session.edit_history[1][1].tasks[0] == actual_task
示例#17
0
def test_load_from_invalid():
    """
    Test loading in a saved session wehn given an invalid name to load. We just check
    that an error gets raised.
    """

    # Try to load session.
    error = False
    try:
        session = Session("bad_example", load=True)
    except:
        error = True

    # Ensure an error was raised.
    assert error
示例#18
0
def test_move_tasks_single_planned():
    """
    Test moving a single task from a planned schedule with only a single task.
    """

    # Construct session. Note that we have to manually set the base date of the session
    # in order to access the task, since it has a hard-coded date.
    session = Session("test")
    session.insert_task(
        day=4,
        planned=True,
        name="test",
        priority=1.0,
        start_time=time(hour=12),
        hours=1.5,
    )
    session.base_date = session.current_schedules(
    )[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())

    # Move the task.
    session.move_tasks(
        planned=True,
        day=4,
        start_task_index=0,
        end_task_index=1,
        time_delta=timedelta(hours=2),
    )

    # Test session values.
    assert session.history_pos == 2
    assert len(session.edit_history) == 3
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
    assert len(session.edit_history[1][0].tasks) == 1
    assert len(session.edit_history[1][1].tasks) == 0
    assert len(session.edit_history[2][0].tasks) == 1
    assert len(session.edit_history[2][1].tasks) == 0
    task = session.edit_history[2][0].tasks[0]
    assert task.name == "test"
    assert task.priority == 1.0
    assert task.start_time.date() == session.base_date + timedelta(days=4)
    assert task.start_time.time() == time(hour=14)
    assert task.end_time.date() == session.base_date + timedelta(days=4)
    assert task.end_time.time() == time(hour=15, minute=30)
示例#19
0
def test_move_tasks_full():
    """
    Test moving multiple tasks in a full schedule.
    """

    # Construct session. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules(
    )[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())
    planned = True
    day = 4
    start_task_index = 0
    end_task_index = 2

    # Store pre-move session values.
    pre_history_pos = session.history_pos
    pre_edit_history = list(session.edit_history)
    original_tasks = [
        session.get_task(planned=planned, day=day, task_index=i)
        for i in range(start_task_index, end_task_index)
    ]

    # Move tasks.
    session.move_tasks(
        planned=planned,
        day=day,
        start_task_index=start_task_index,
        end_task_index=end_task_index,
        time_delta=timedelta(hours=2),
    )

    # Test session values.
    edited_tasks = [deepcopy(task) for task in original_tasks]
    edited_tasks[0].start_time = datetime(2020, 5, 1, hour=14)
    edited_tasks[0].end_time = datetime(2020, 5, 1, hour=15, minute=30)
    edited_tasks[1].start_time = datetime(2020, 5, 1, hour=15, minute=30)
    edited_tasks[1].end_time = datetime(2020, 5, 1, hour=16, minute=30)
    assert session.history_pos == pre_history_pos + 1
    assert len(session.edit_history) == len(pre_edit_history) + 1
    assert session.edit_history[:-1] == pre_edit_history
    assert pre_edit_history[-1][0].tasks[0:2] == original_tasks
    assert session.edit_history[-1][0].tasks[0:2] == edited_tasks
    assert session.edit_history[-1][0].tasks[2:] == pre_edit_history[-1][
        0].tasks[2:]
    assert session.edit_history[-1][1] == pre_edit_history[-1][1]
示例#20
0
def test_move_week_backward():
    """
    Test moving the displayed week backward.
    """

    # Construct session. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules()[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())

    # Move the week forward.
    session.move_week(forward=False)

    # Test week value.
    assert session.base_date == date(2020, 4, 20)
示例#21
0
def test_load_from_valid():
    """
    Test loading in a saved session when given a valid save name to load. Note that this
    will have to change in the case that scripts/save_example.py changes, as this
    essentially a hard-coded check for the result of the current implementation of that
    script.
    """

    # Load session.
    session = Session("example", load=True)

    # Compare session values.
    planned_tasks, actual_tasks = EXAMPLE_TASKS
    assert session.history_pos == 12
    assert len(session.edit_history) == 13
    assert session.edit_history[0][0].tasks == []
    assert session.edit_history[0][1].tasks == []
    for i in range(len(planned_tasks)):
        assert session.edit_history[i + 1][0].tasks == planned_tasks[:i + 1]
        assert session.edit_history[i + 1][1].tasks == []
    for i in range(len(actual_tasks)):
        n = len(planned_tasks)
        assert session.edit_history[n + i + 1][0].tasks == planned_tasks
        assert session.edit_history[n + i + 1][1].tasks == actual_tasks[:i + 1]
示例#22
0
def test_delete_task_invalid():
    """
    Test deleting a nonexistent task from a full schedule.
    """

    # Construct session. Note that we have to manually set the base date of the session in
    # order to access the task, since it has a hard-coded date.
    session = Session("example", load=True)
    session.base_date = session.current_schedules(
    )[0].tasks[0].start_time.date()
    session.base_date -= timedelta(days=session.base_date.weekday())
    planned = True
    day = 6
    task_index = 1

    # Delete nonexistent task.
    error = False
    try:
        session.delete_task(planned=planned, day=day, task_index=task_index)
    except:
        error = True

    # Ensure that error was thrown.
    assert error
示例#23
0
def test_daily_points_score_current_week():
    """ Daily points for a schedule with tasks only in current week. """

    # Construct session.
    session = Session("test")
    b = session.base_date
    planned_tasks = [
        {
            "day": 1,
            "planned": True,
            "name": "pt1",
            "priority": 1.0,
            "start_time": time(hour=12),
            "hours": 1.5,
        },
        {
            "day": 1,
            "planned": True,
            "name": "pt1",
            "priority": 2.0,
            "start_time": time(hour=13, minute=30),
            "hours": 2.0,
        },
        {
            "day": 3,
            "planned": True,
            "name": "pt3",
            "priority": 1.0,
            "start_time": time(hour=13, minute=30),
            "hours": 2.0,
        },
    ]
    actual_tasks = [
        {
            "day": 1,
            "planned": False,
            "name": "at2",
            "priority": 2.0,
            "start_time": time(hour=14, minute=30),
            "hours": 1.0,
        },
        {
            "day": 3,
            "planned": False,
            "name": "at3",
            "priority": 1.0,
            "start_time": time(hour=19, minute=30),
            "hours": 2.0,
        },
    ]
    for task_kwargs in planned_tasks:
        session.insert_task(**task_kwargs)
    for task_kwargs in actual_tasks:
        session.insert_task(**task_kwargs)

    # Construct expected point/score values.
    p_ind_pts = [0.0, 5.5, 0.0, 2.0, 0.0, 0.0, 0.0]
    p_cum_pts = [0.0, 5.5, 5.5, 7.5, 7.5, 7.5, 7.5]
    a_ind_pts = [0.0, 2.0, 0.0, 2.0, 0.0, 0.0, 0.0]
    a_cum_pts = [0.0, 2.0, 2.0, 4.0, 4.0, 4.0, 4.0]
    ind_score = [100.0, 100.0 * 2.0 / 5.5] + [100.0] * 5
    cum_score = [100.0] + [100.0 * 2.0 / 5.5] * 2 + [100.0 * 4.0 / 7.5] * 4

    # Test point values.
    for day in range(DAYS_IN_WEEK):
        assert (session.daily_points(day, planned=True,
                                     cumulative=False) == p_ind_pts[day])
        assert (session.daily_points(day, planned=True,
                                     cumulative=True) == p_cum_pts[day])
        assert (session.daily_points(day, planned=False,
                                     cumulative=False) == a_ind_pts[day])
        assert (session.daily_points(day, planned=False,
                                     cumulative=True) == a_cum_pts[day])
        assert session.daily_score(day, cumulative=False) == ind_score[day]
        assert session.daily_score(day, cumulative=True) == cum_score[day]
示例#24
0
def test_set_new_schedules_2():
    """
    Call `set_new_schedules()` in the second case of edit history (cases listed in
    docstring of `set_new_schedules()`).
    """

    # Construct session.
    session = Session("test")

    # Construct planned and new schedules.
    planned_tasks = [
        Task(
            "planned_task_1",
            priority=1.0,
            start_time=datetime(2020, 5, 1, hour=12),
            end_time=datetime(2020, 5, 1, hour=13, minute=30),
        ),
        Task(
            "planned_task_2",
            priority=1.0,
            start_time=datetime(2020, 5, 1, hour=12, minute=30),
            end_time=datetime(2020, 5, 1, hour=14),
        ),
    ]
    actual_tasks = [
        Task(
            "actual_task_1",
            priority=1.0,
            start_time=datetime(2020, 5, 1, hour=13),
            end_time=datetime(2020, 5, 1, hour=14, minute=30),
        ),
        Task(
            "actual_task_2",
            priority=1.0,
            start_time=datetime(2020, 5, 1, hour=13, minute=30),
            end_time=datetime(2020, 5, 1, hour=15),
        ),
    ]

    planned = [
        Schedule("planned_1", [planned_tasks[0]]),
        Schedule("planned_2", [planned_tasks[1]]),
    ]
    actual = [
        Schedule("actual_1", [actual_tasks[0]]),
        Schedule("actual_2", [actual_tasks[1]]),
    ]

    # Set new schedules in session, undo, then redo with new versions.
    session.set_new_schedules(planned[0], actual[0])
    session.undo()
    session.set_new_schedules(planned[1], actual[1])

    # Test session values.
    assert session.history_pos == 1
    assert len(session.edit_history) == 2
    assert len(session.edit_history[0][0].tasks) == 0
    assert len(session.edit_history[0][1].tasks) == 0
    assert len(session.edit_history[1][0].tasks) == 1
    assert len(session.edit_history[1][1].tasks) == 1
    assert session.edit_history[1][0].tasks[0] == planned_tasks[1]
    assert session.edit_history[1][1].tasks[0] == actual_tasks[1]