Skip to content
Snippets Groups Projects
Commit 059d3b32 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Støtte for frister i core og json m/tester

parent 315a64ef
No related branches found
No related tags found
No related merge requests found
Showing
with 139 additions and 44 deletions
......@@ -10,7 +10,8 @@ public class TodoItem {
@Override
public String toString() {
return String.format("[TodoItem text=%s checked=%s]", getText(), isChecked());
return String.format("[TodoItem text=%s checked=%s deadline=%s]", getText(), isChecked(),
getDeadline());
}
public String getText() {
......@@ -29,20 +30,18 @@ public class TodoItem {
this.checked = checked;
}
/**
* @return the deadline
*/
public LocalDateTime getDeadline() {
return deadline;
}
/**
* @param deadline the deadline to set
*/
public void setDeadline(LocalDateTime deadline) {
this.deadline = deadline;
}
public boolean isOverdue() {
return deadline != null && deadline.isBefore(LocalDateTime.now()) && (! isChecked());
}
/**
* Copies all properties of other TodoItem into this TodoItem.
*
......@@ -65,6 +64,11 @@ public class TodoItem {
return this;
}
public TodoItem deadline(LocalDateTime deadline) {
setDeadline(deadline);
return this;
}
public TodoItem as(TodoItem other) {
setAs(other);
return this;
......@@ -77,4 +81,8 @@ public class TodoItem {
public TodoItem withText(String text) {
return new TodoItem().as(this).text(text);
}
public TodoItem withDeadline(LocalDateTime deadline) {
return new TodoItem().as(this).deadline(deadline);
}
}
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
public class TodoList implements Iterable<TodoItem> {
......@@ -16,16 +17,10 @@ public class TodoList implements Iterable<TodoItem> {
addTodoItems(items);
}
/**
* @return the deadline
*/
public LocalDateTime getDeadline() {
return deadline;
}
/**
* @param deadline the deadline to set
*/
public void setDeadline(LocalDateTime deadline) {
this.deadline = deadline;
}
......@@ -36,6 +31,8 @@ public class TodoList implements Iterable<TodoItem> {
/**
* Adds the provided TodoItems to this TodoList.
* If a TodoItem is not an instance of TodoListItem,
* its contents is copied in to a new TodoListItem and that is added instead.
*
* @param items the TodoItems to add
*/
......@@ -48,6 +45,7 @@ public class TodoList implements Iterable<TodoItem> {
todoListItem = new TodoListItem(this);
todoListItem.setText(item.getText());
todoListItem.setChecked(item.isChecked());
todoListItem.setDeadline(item.getDeadline());
}
this.items.add(todoListItem);
}
......@@ -101,6 +99,19 @@ public class TodoList implements Iterable<TodoItem> {
return getTodoItems(false);
}
// methods related to deadlines
public boolean isOverdue() {
return deadline != null && deadline.isBefore(LocalDateTime.now())
&& (!getUncheckedTodoItems().isEmpty());
}
public Collection<TodoItem> getOverdueTodoItems() {
return items.stream().filter(TodoItem::isOverdue).collect(Collectors.toList());
}
// index-oriented methods
public int indexOf(TodoItem item) {
return items.indexOf(item);
}
......
package todolist.core;
import java.time.LocalDateTime;
import java.util.Objects;
public class TodoListItem extends TodoItem {
private final TodoList todoList;
......@@ -14,29 +17,35 @@ public class TodoListItem extends TodoItem {
@Override
public void setText(String text) {
String oldText = getText();
if (! Objects.equals(text, getText())) {
super.setText(text);
if (oldText != text || oldText != null && !(oldText.equals(text))) {
todoList.fireTodoListChanged(this);
}
}
@Override
public void setChecked(boolean checked) {
boolean oldChecked = isChecked();
if (checked != isChecked()) {
super.setChecked(checked);
if (oldChecked != checked) {
todoList.fireTodoListChanged(this);
}
}
@Override
public void setDeadline(LocalDateTime deadline) {
if (! Objects.equals(deadline, getDeadline())) {
super.setDeadline(deadline);
todoList.fireTodoListChanged(this);
}
}
@Override
public void setAs(TodoItem other) {
boolean oldChecked = isChecked();
String oldText = getText();
boolean equals = isChecked() == other.isChecked()
&& Objects.equals(getText(), other.getText())
&& Objects.equals(getDeadline(), other.getDeadline());
if (! equals) {
super.setAs(other);
if (oldChecked != other.isChecked() || oldText != other.getText()
|| oldText != null && !(oldText.equals(other.getText()))) {
todoList.fireTodoListChanged(this);
}
}
......
......@@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import java.io.IOException;
import java.time.LocalDateTime;
import todolist.core.TodoItem;
class TodoItemDeserializer extends JsonDeserializer<TodoItem> {
......@@ -27,11 +28,15 @@ class TodoItemDeserializer extends JsonDeserializer<TodoItem> {
TodoItem item = new TodoItem();
JsonNode textNode = objectNode.get("text");
if (textNode instanceof TextNode) {
item.setText(((TextNode) textNode).asText());
item.setText(textNode.asText());
}
JsonNode checkedNode = objectNode.get("checked");
if (checkedNode instanceof BooleanNode) {
item.setChecked(((BooleanNode) checkedNode).asBoolean(false));
item.setChecked(checkedNode.asBoolean(false));
}
JsonNode deadlineNode = objectNode.get("deadline");
if (deadlineNode instanceof TextNode) {
item.setDeadline(LocalDateTime.parse(deadlineNode.asText()));
}
return item;
}
......
......@@ -9,7 +9,7 @@ import todolist.core.TodoItem;
class TodoItemSerializer extends JsonSerializer<TodoItem> {
/*
* format: { "text": "...", "checked": false }
* format: { "text": "...", "checked": false, "deadline": ... }
*/
@Override
......@@ -18,6 +18,9 @@ class TodoItemSerializer extends JsonSerializer<TodoItem> {
jsonGen.writeStartObject();
jsonGen.writeStringField("text", item.getText());
jsonGen.writeBooleanField("checked", item.isChecked());
if (item.getDeadline() != null) {
jsonGen.writeStringField("deadline", item.getDeadline().toString());
}
jsonGen.writeEndObject();
}
}
......@@ -8,7 +8,9 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import java.io.IOException;
import java.time.LocalDateTime;
import todolist.core.TodoItem;
import todolist.core.TodoList;
......@@ -26,6 +28,10 @@ class TodoListDeserializer extends JsonDeserializer<TodoList> {
if (treeNode instanceof ObjectNode) {
ObjectNode objectNode = (ObjectNode) treeNode;
TodoList list = new TodoList();
JsonNode deadlineNode = objectNode.get("deadline");
if (deadlineNode instanceof TextNode) {
list.setDeadline(LocalDateTime.parse(deadlineNode.asText()));
}
JsonNode itemsNode = objectNode.get("items");
if (itemsNode instanceof ArrayNode) {
for (JsonNode elementNode : ((ArrayNode) itemsNode)) {
......
......@@ -17,6 +17,9 @@ class TodoListSerializer extends JsonSerializer<TodoList> {
public void serialize(TodoList list, JsonGenerator jsonGen, SerializerProvider serializerProvider)
throws IOException {
jsonGen.writeStartObject();
if (list.getDeadline() != null) {
jsonGen.writeStringField("deadline", list.getDeadline().toString());
}
jsonGen.writeArrayFieldStart("items");
for (TodoItem item : list) {
jsonGen.writeObject(item);
......
package todolist.json;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import com.fasterxml.jackson.databind.ObjectMapper;
import todolist.core.TodoList;
public class TodoPersistence {
......
package todolist.core;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.junit.jupiter.api.Assertions.assertSame;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Iterator;
import org.junit.jupiter.api.BeforeEach;
......@@ -20,6 +22,22 @@ public class TodoListTest {
newList = new TodoList();
}
@Test
public void testAddToDoItem() {
TodoItem item = new TodoItem();
item.setText("an item");
item.setChecked(true);
LocalDateTime now = LocalDateTime.now();
item.setDeadline(now);
newList.addTodoItem(item);
assertTrue(newList.iterator().hasNext());
TodoItem addedItem = newList.iterator().next();
// check that values are correctly copied
assertEquals(item.getText(), addedItem.getText());
assertTrue(item.isOverdue() == addedItem.isOverdue());
assertEquals(item.getDeadline(), addedItem.getDeadline());
}
// tests for getCheckedItems
@Test
......@@ -162,6 +180,22 @@ public class TodoListTest {
checkIterator(newList.iterator());
}
// test for list and item deadline
@Test
public void testIsOverdue() {
assertFalse(newList.isOverdue(), "A list without deadline is not overdue");
newList.setDeadline(LocalDateTime.now().plusSeconds(1));
assertFalse(newList.isOverdue(), "A list with deadline in the future is not overdue");
newList.setDeadline(LocalDateTime.now().minusSeconds(1));
assertFalse(newList.isOverdue(), "A list with deadline in the past, but with no overdue items is overdue");
TodoItem item = newList.createTodoItem();
newList.addTodoItem(item);
assertTrue(newList.isOverdue(), "A list with deadline in the past and with overdue item(s) is overdue");
item.setChecked(true);
assertFalse(newList.isOverdue(), "A list with deadline in the past, but with no overdue items is overdue");
}
private int receivedNotificationCount = 0;
@Test
......@@ -180,14 +214,21 @@ public class TodoListTest {
assertEquals(3, receivedNotificationCount);
item.setChecked(true);
assertEquals(4, receivedNotificationCount);
item.setAs(new TodoItem().checked(true).text("enda en endret verdi"));
assertEquals(5, receivedNotificationCount);
item.setAs(new TodoItem().checked(true).text("enda en endret verdi"));
LocalDateTime now = LocalDateTime.now();
item.setDeadline(now);
assertEquals(5, receivedNotificationCount);
String altText = "enda en endret verdi";
// (at least) one change
item.setAs(new TodoItem().checked(true).text(altText).deadline(now));
assertEquals(6, receivedNotificationCount);
// no change
item.setAs(new TodoItem().checked(true).text(altText).deadline(now));
assertEquals(6, receivedNotificationCount);
// test removeTodoListListener, too
newList.removeTodoListListener(listener);
item.setChecked(false);
assertEquals(5, receivedNotificationCount);
assertEquals(6, receivedNotificationCount);
}
@Test
......@@ -204,5 +245,8 @@ public class TodoListTest {
verify(listener, times(3)).todoListChanged(newList);
item.setChecked(true);
verify(listener, times(4)).todoListChanged(newList);
LocalDateTime now = LocalDateTime.now();
item.setDeadline(now);
verify(listener, times(5)).todoListChanged(newList);
}
}
......@@ -2,6 +2,7 @@ package todolist.json;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDateTime;
import java.util.Iterator;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
......@@ -24,7 +25,7 @@ public class TodoModuleTest {
mapper.registerModule(new TodoModule());
}
private final static String todoListWithTwoItems = "{\"items\":[{\"text\":\"item1\",\"checked\":false},{\"text\":\"item2\",\"checked\":true}]}";
private final static String todoListWithTwoItems = "{\"items\":[{\"text\":\"item1\",\"checked\":false},{\"text\":\"item2\",\"checked\":true,\"deadline\":\"2020-10-01T14:53:11\"}]}";
@Test
public void testSerializers() {
......@@ -34,6 +35,7 @@ public class TodoModuleTest {
TodoItem item2 = list.createTodoItem();
item2.setText("item2");
item2.setChecked(true);
item2.setDeadline(LocalDateTime.parse("2020-10-01T14:53:11"));
list.addTodoItem(item1);
list.addTodoItem(item2);
try {
......@@ -43,13 +45,14 @@ public class TodoModuleTest {
}
}
static void checkTodoItem(TodoItem item, String text, boolean checked) {
static void checkTodoItem(TodoItem item, String text, boolean checked, LocalDateTime deadline) {
assertEquals(text, item.getText());
assertTrue(checked == item.isChecked());
assertEquals(deadline, item.getDeadline());
}
static void checkTodoItem(TodoItem item1, TodoItem item2) {
checkTodoItem(item1, item2.getText(), item2.isChecked());
checkTodoItem(item1, item2.getText(), item2.isChecked(), item2.getDeadline());
}
@Test
......@@ -58,9 +61,9 @@ public class TodoModuleTest {
TodoList list = mapper.readValue(todoListWithTwoItems, TodoList.class);
Iterator<TodoItem> it = list.iterator();
assertTrue(it.hasNext());
checkTodoItem(it.next(), "item1", false);
checkTodoItem(it.next(), "item1", false, null);
assertTrue(it.hasNext());
checkTodoItem(it.next(), "item2", true);
checkTodoItem(it.next(), "item2", true, LocalDateTime.parse("2020-10-01T14:53:11"));
assertFalse(it.hasNext());
} catch (JsonProcessingException e) {
fail();
......@@ -75,6 +78,7 @@ public class TodoModuleTest {
TodoItem item2 = new TodoItem();
item2.setText("item2");
item2.setChecked(true);
item2.setDeadline(LocalDateTime.parse("2020-10-01T14:53:11"));
list.addTodoItem(item1);
list.addTodoItem(item2);
try {
......
......@@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.util.Iterator;
import org.junit.jupiter.api.Test;
import todolist.core.TodoItem;
......@@ -20,10 +21,11 @@ public class TodoPersistenceTest {
TodoList list = new TodoList();
TodoItem item1 = new TodoItem();
item1.setText("item1");
list.addTodoItem(item1);
TodoItem item2 = new TodoItem();
item2.setText("item2");
item2.setChecked(true);
list.addTodoItem(item1);
item2.setDeadline(LocalDateTime.parse("2020-10-01T14:53:11"));
list.addTodoItem(item2);
try {
StringWriter writer = new StringWriter();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment