An extension should start with a user-visible rule, not with a new library. Our planner can report all accepted and completed minutes, so an unfinished-time report is a natural next operation. Add remainingMinutes() to Planner, returning plannedMinutes() minus completedMinutes(). The existing completion invariants ensure the result is nonnegative without storing another changing counter.
Write the evidence first
In PlannerTest, add cases for an empty plan (0), a new 25+10 plan (35), after completing the first (10), after completing it again (10), and after completing the second (0). First observe that calling a method that does not yet exist fails compilation; then implement it and rerun the behavioral checks.
A compiler failure proves only that the API is missing. Once the method exists, the meaningful evidence is that its returned values match the contract. Keep that distinction clear when you introduce intentional defects.
Keep one source of truth
It is tempting to add a stored remaining field and update it in add and complete. That creates a new obligation: every mutation must keep three totals synchronized, including repeated completion and failed additions. A derived result avoids that extra mutable state. Reuse already-tested methods instead of copying their loops and hoping future changes keep every version aligned.
Do not add persistence, a GUI or a framework for this task. Finish one precise change, rerun the existing tests, then decide what the next useful capability is. Small steps make regressions easier to locate.
Check your prediction
All planner checks passed The original tests pass before this extension. Edit Planner.java to add the new method inside the class, alongside plannedMinutes and completedMinutes. In PlannerTest.java, put your new checks inside main, before the final success message. Run remains pointed at PlannerTest.java even when another tab is open.
Each playground is a separate copy. Edits made on the previous lesson do not carry over here. Keep your extension in this editor or save your local project.
public class Main {
public static void main(String[] args) {
System.out.println(remaining(35, 0));
System.out.println(remaining(35, 25));
System.out.println(remaining(35, 35));
}
static int remaining(int planned, int completed) {
return planned - completed;
}
}Check your prediction
35
10
0 This example assumes completed never exceeds planned. The project enforces that relation by deriving both totals from the same records. Do not generalize this subtraction to arbitrary unvalidated inputs without stating its preconditions.
Your turn
Design the extension checks
Write a helper remaining(int planned, int completed) for the already-validated relation 0 <= completed <= planned. Verify (0,0), (35,0), (35,25), repeated (35,25) and (35,35), then print Remaining checks passed. This small helper exercise rehearses the subtraction only. Repeating a call with fixed numbers does not test changing object state. In the project editor above, also make the actual complete calls between remainingMinutes checks to test the full extension.
public class Main {
public static void main(String[] args) {
// Implement and check the derived calculation.
}
// Define remaining and check.
}Hint 1: the idea
Derive the answer from current values. Repeated reads should not change state.
Hint 2: a first step
Use the test labels to describe lifecycle stages. When moving to Planner, call the existing instance methods for the two input totals.
Show one solution
public class Main {
public static void main(String[] args) {
check("empty", remaining(0, 0) == 0);
check("new", remaining(35, 0) == 35);
check("first done", remaining(35, 25) == 10);
check("repeat", remaining(35, 25) == 10);
check("all done", remaining(35, 35) == 0);
System.out.println("Remaining checks passed");
}
static int remaining(int planned, int completed) {
return planned - completed;
}
static void check(String label, boolean condition) {
if (!condition) {
throw new AssertionError(label);
}
}
}Remaining checks passed Change it and explain
After implementing the instance method in the project, deliberately return plannedMinutes() without subtracting completion and show which new check fails. Restore it and rerun the old tests too. A new feature should preserve the old contract unless you explicitly decide to change that contract.
For a second extension, consider a method returning the count of unfinished sessions. Define its empty and repeated-completion behavior before coding. Do not expose the internal ArrayList just to make a caller count it; keep the model responsible for its own collection.
Completion is saved in this browser only. It does not measure mastery.