Editor { public boolean edit(Consumer<String> logConsumer) { List<String> lines = supplier.get(); List<String> newLines = new LinkedList<>(); StringBuilder diff = new StringBuilder(); boolean modified = false; for (String line : lines) { LineEdit edit = editor.edit(line); if (!edit.prependLines().isEmpty()) { modified = true; maybeAdd(diff, edit.prependLines()); newLines.addAll(edit.prependLines()); } switch (edit.getType()) { case REPLACE: modified = true; maybeRemove(diff, line); break; case NONE: newLines.add(line); break; default: throw new IllegalArgumentException("Unknown EditType " + edit.getType()); } if (!edit.appendLines().isEmpty()) { modified = true; maybeAdd(diff, edit.appendLines()); newLines.addAll(edit.appendLines()); } } List<String> linesToAppend = editor.onComplete(); if (!linesToAppend.isEmpty()) { modified = true; newLines.addAll(linesToAppend); maybeAdd(diff, linesToAppend); } if (!modified) { return false; } String diffDescription = diffTooLarge() ? ": Diff too large (" + diffSize + ")" : ":\n" + diff.toString(); logConsumer.accept("Patching file " + name + diffDescription); consumer.accept(newLines); return true; } Editor(Path path, LineEditor editor);  Editor(String name,
                  Supplier<List<String>> supplier,
                  Consumer<List<String>> consumer,
                  LineEditor editor); boolean edit(Consumer<String> logConsumer); boolean converge(TaskContext context);  }
@Test public void testEdit() { path.writeUtf8File(joinLines("first", "second", "third")); LineEditor lineEditor = mock(LineEditor.class); when(lineEditor.edit(any())).thenReturn( LineEdit.none(), LineEdit.remove(), LineEdit.replaceWith("replacement")); Editor editor = new Editor(path.toPath(), lineEditor); TaskContext context = mock(TaskContext.class); assertTrue(editor.converge(context)); verify(lineEditor, times(3)).edit(any()); ArgumentCaptor<String> modificationMessage = ArgumentCaptor.forClass(String.class); verify(context).recordSystemModification(any(), modificationMessage.capture()); assertEquals( "Patching file /file:\n-second\n-third\n+replacement\n", modificationMessage.getValue()); assertEquals(joinLines("first", "replacement"), path.readUtf8File()); }