diff --git a/app/build.gradle b/app/build.gradle index b3b26b28a..0ee5a61f5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -77,6 +77,7 @@ dependencies { compile 'com.opencsv:opencsv:3.7' compile 'org.apmem.tools:layouts:1.10@aar' compile 'org.jetbrains:annotations-java5:15.0' + compile 'com.google.code.gson:gson:2.8.0' provided 'javax.annotation:jsr250-api:1.0' @@ -89,6 +90,7 @@ dependencies { testCompile 'junit:junit:4.12' testCompile 'org.hamcrest:hamcrest-library:1.3' testCompile 'org.mockito:mockito-core:1.10.19' + testCompile 'org.json:json:20160810' androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') { exclude group: 'com.android.support' diff --git a/app/src/main/java/org/isoron/uhabits/commands/ArchiveHabitsCommand.java b/app/src/main/java/org/isoron/uhabits/commands/ArchiveHabitsCommand.java index 8215ad2d5..1d508356f 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/ArchiveHabitsCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/ArchiveHabitsCommand.java @@ -23,56 +23,31 @@ import android.support.annotation.*; import org.isoron.uhabits.*; import org.isoron.uhabits.models.*; -import org.json.*; import java.util.*; -import static org.isoron.uhabits.commands.CommandParser.*; - /** * Command to archive a list of habits. */ public class ArchiveHabitsCommand extends Command { - private List selectedHabits; + final List selected; - private final HabitList habitList; + final HabitList habitList; public ArchiveHabitsCommand(@NonNull HabitList habitList, - @NonNull List selectedHabits) + @NonNull List selected) { super(); this.habitList = habitList; - this.selectedHabits = selectedHabits; - } - - public ArchiveHabitsCommand(@NonNull String id, - @NonNull HabitList habitList, - @NonNull List selectedHabits) - { - super(id); - this.habitList = habitList; - this.selectedHabits = selectedHabits; - } - - public static Command fromJSON(@NonNull JSONObject json, - @NonNull HabitList habitList) - throws JSONException - { - String id = json.getString("id"); - JSONObject data = (JSONObject) json.get("data"); - JSONArray habitIds = data.getJSONArray("ids"); - - LinkedList selectedHabits = - habitListFromJSON(habitList, habitIds); - return new ArchiveHabitsCommand(id, habitList, selectedHabits); + this.selected = new LinkedList<>(selected); } @Override public void execute() { - for (Habit h : selectedHabits) h.setArchived(true); - habitList.update(selectedHabits); + for (Habit h : selected) h.setArchived(true); + habitList.update(selected); } @Override @@ -87,28 +62,51 @@ public class ArchiveHabitsCommand extends Command return R.string.toast_habit_unarchived; } - @Nullable @Override - public JSONObject toJSON() + public void undo() { - try - { - JSONObject root = super.toJSON(); - JSONObject data = root.getJSONObject("data"); - root.put("event", "ArchiveHabits"); - data.put("ids", habitListToJSON(selectedHabits)); - return root; - } - catch (JSONException e) - { - throw new RuntimeException(e.getMessage()); - } + for (Habit h : selected) h.setArchived(false); + habitList.update(selected); } + @NonNull @Override - public void undo() + public Record toRecord() + { + return new Record(this); + } + + public static class Record { - for (Habit h : selectedHabits) h.setArchived(false); - habitList.update(selectedHabits); + @NonNull + public final String id; + + @NonNull + public final String event = "Archive"; + + @NonNull + public final List habits; + + public Record(@NonNull ArchiveHabitsCommand command) + { + id = command.getId(); + habits = new LinkedList<>(); + for (Habit h : command.selected) + { + habits.add(h.getId()); + } + } + + @NonNull + public ArchiveHabitsCommand toCommand(@NonNull HabitList habitList) + { + List selected = new LinkedList<>(); + for (Long id : this.habits) selected.add(habitList.getById(id)); + + ArchiveHabitsCommand command; + command = new ArchiveHabitsCommand(habitList, selected); + command.setId(id); + return command; + } } } \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/commands/ChangeHabitColorCommand.java b/app/src/main/java/org/isoron/uhabits/commands/ChangeHabitColorCommand.java index 6b4f0ddc8..ab1e4b7e3 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/ChangeHabitColorCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/ChangeHabitColorCommand.java @@ -23,54 +23,35 @@ import android.support.annotation.*; import org.isoron.uhabits.*; import org.isoron.uhabits.models.*; -import org.json.*; import java.util.*; -import static org.isoron.uhabits.commands.CommandParser.*; - /** * Command to change the color of a list of habits. */ public class ChangeHabitColorCommand extends Command { - HabitList habitList; + @NonNull + final HabitList habitList; - List selected; + @NonNull + final List selected; - List originalColors; + @NonNull + final List originalColors; - Integer newColor; + @NonNull + final Integer newColor; public ChangeHabitColorCommand(@NonNull HabitList habitList, @NonNull List selected, @NonNull Integer newColor) { - super(); - init(habitList, selected, newColor); - } - - public ChangeHabitColorCommand(@NonNull String id, - @NonNull HabitList habitList, - @NonNull List selected, - @NonNull Integer newColor) - { - super(id); - init(habitList, selected, newColor); - } - - @NonNull - public static Command fromJSON(@NonNull JSONObject json, - @NonNull HabitList habitList) - throws JSONException - { - String id = json.getString("id"); - JSONObject data = (JSONObject) json.get("data"); - JSONArray habitIds = data.getJSONArray("ids"); - int newColor = data.getInt("color"); - - LinkedList selected = habitListFromJSON(habitList, habitIds); - return new ChangeHabitColorCommand(id, habitList, selected, newColor); + this.habitList = habitList; + this.selected = selected; + this.newColor = newColor; + this.originalColors = new ArrayList<>(selected.size()); + for (Habit h : selected) originalColors.add(h.getColor()); } @Override @@ -92,23 +73,11 @@ public class ChangeHabitColorCommand extends Command return R.string.toast_habit_changed; } - @Override @NonNull - public JSONObject toJSON() + @Override + public Record toRecord() { - try - { - JSONObject root = super.toJSON(); - JSONObject data = root.getJSONObject("data"); - root.put("event", "ChangeHabitColor"); - data.put("ids", habitListToJSON(selected)); - data.put("color", newColor); - return root; - } - catch (JSONException e) - { - throw new RuntimeException(e.getMessage()); - } + return new Record(this); } @Override @@ -119,15 +88,41 @@ public class ChangeHabitColorCommand extends Command habitList.update(selected); } - private void init(@NonNull HabitList habitList, - @NonNull List selected, - @NonNull Integer newColor) + public static class Record { - this.habitList = habitList; - this.selected = selected; - this.newColor = newColor; - this.originalColors = new ArrayList<>(selected.size()); + @NonNull + public String id; - for (Habit h : selected) originalColors.add(h.getColor()); + @NonNull + public String event = "ChangeColor"; + + @NonNull + public List habits; + + @NonNull + public Integer color; + + public Record(ChangeHabitColorCommand command) + { + id = command.getId(); + color = command.newColor; + habits = new LinkedList<>(); + for (Habit h : command.selected) + { + if (!h.hasId()) throw new RuntimeException("Habit not saved"); + habits.add(h.getId()); + } + } + + public ChangeHabitColorCommand toCommand(@NonNull HabitList habitList) + { + List selected = new LinkedList<>(); + for (Long id : this.habits) selected.add(habitList.getById(id)); + + ChangeHabitColorCommand command; + command = new ChangeHabitColorCommand(habitList, selected, color); + command.setId(id); + return command; + } } } diff --git a/app/src/main/java/org/isoron/uhabits/commands/Command.java b/app/src/main/java/org/isoron/uhabits/commands/Command.java index e6e397d51..27794cccc 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/Command.java +++ b/app/src/main/java/org/isoron/uhabits/commands/Command.java @@ -19,6 +19,10 @@ package org.isoron.uhabits.commands; +import android.support.annotation.*; + +import com.google.gson.*; + import org.isoron.uhabits.utils.*; import org.json.*; @@ -33,7 +37,7 @@ import org.json.*; */ public abstract class Command { - private final String id; + private String id; public Command() { @@ -52,31 +56,37 @@ public abstract class Command return null; } + public String getId() + { + return id; + } + + public void setId(String id) + { + this.id = id; + } + public Integer getUndoStringId() { return null; } - public abstract void undo(); - - public JSONObject toJSON() + @NonNull + public JSONObject toJson() { try { - JSONObject root = new JSONObject(); - JSONObject data = new JSONObject(); - root.put("id", getId()); - root.put("data", data); - return root; + String json = new GsonBuilder().create().toJson(toRecord()); + return new JSONObject(json); } catch (JSONException e) { - throw new RuntimeException(e.getMessage()); + throw new RuntimeException(e); } } - public String getId() - { - return id; - } + @NonNull + public abstract Object toRecord(); + + public abstract void undo(); } diff --git a/app/src/main/java/org/isoron/uhabits/commands/CommandParser.java b/app/src/main/java/org/isoron/uhabits/commands/CommandParser.java index 4519d673f..104e308a4 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/CommandParser.java +++ b/app/src/main/java/org/isoron/uhabits/commands/CommandParser.java @@ -21,14 +21,13 @@ package org.isoron.uhabits.commands; import android.support.annotation.*; +import com.google.gson.*; + import org.isoron.uhabits.models.*; import org.json.*; -import java.util.*; - public class CommandParser { - private HabitList habitList; private ModelFactory modelFactory; @@ -41,65 +40,43 @@ public class CommandParser } @NonNull - public static LinkedList habitListFromJSON( - @NonNull HabitList habitList, @NonNull JSONArray habitIds) - throws JSONException - { - LinkedList habits = new LinkedList<>(); - - for (int i = 0; i < habitIds.length(); i++) - { - Long hId = habitIds.getLong(i); - Habit h = habitList.getById(hId); - if (h == null) continue; - - habits.add(h); - } - - return habits; - } - - @NonNull - protected static JSONArray habitListToJSON(List habits) - { - JSONArray habitIds = new JSONArray(); - for (Habit h : habits) habitIds.put(h.getId()); - return habitIds; - } - - @NonNull - public Command fromJSON(@NonNull JSONObject json) throws JSONException + public Command parse(@NonNull JSONObject json) throws JSONException { - switch (json.getString("event")) - { - case "ToggleRepetition": - return ToggleRepetitionCommand.fromJSON(json, habitList); + String event = json.getString("event"); + Gson gson = new GsonBuilder().create(); - case "ArchiveHabits": - return ArchiveHabitsCommand.fromJSON(json, habitList); + if (event.equals("Archive")) return gson + .fromJson(json.toString(), ArchiveHabitsCommand.Record.class) + .toCommand(habitList); - case "UnarchiveHabits": - return UnarchiveHabitsCommand.fromJSON(json, habitList); + if (event.equals("ChangeColor")) return gson + .fromJson(json.toString(), ChangeHabitColorCommand.Record.class) + .toCommand(habitList); - case "ChangeHabitColor": - return ChangeHabitColorCommand.fromJSON(json, habitList); + if (event.equals("CreateHabit")) return gson + .fromJson(json.toString(), CreateHabitCommand.Record.class) + .toCommand(modelFactory, habitList); - case "CreateHabit": - return CreateHabitCommand.fromJSON(json, habitList, - modelFactory); + if (event.equals("CreateRep")) return gson + .fromJson(json.toString(), CreateRepetitionCommand.Record.class) + .toCommand(habitList); - case "DeleteHabits": - return DeleteHabitsCommand.fromJSON(json, habitList); + if (event.equals("DeleteHabit")) return gson + .fromJson(json.toString(), DeleteHabitsCommand.Record.class) + .toCommand(habitList); - case "EditHabit": - return EditHabitCommand.fromJSON(json, habitList, modelFactory); + if (event.equals("EditHabit")) return gson + .fromJson(json.toString(), EditHabitCommand.Record.class) + .toCommand(modelFactory, habitList); -// TODO: Implement this -// case "ReorderHabit": -// return ReorderHabitCommand.fromJSON(json); + if (event.equals("Toggle")) return gson + .fromJson(json.toString(), ToggleRepetitionCommand.Record.class) + .toCommand(habitList); - } + if (event.equals("Unarchive")) return gson + .fromJson(json.toString(), UnarchiveHabitsCommand.Record.class) + .toCommand(habitList); - return null; + throw new IllegalStateException("Unknown command"); } } diff --git a/app/src/main/java/org/isoron/uhabits/commands/CreateHabitCommand.java b/app/src/main/java/org/isoron/uhabits/commands/CreateHabitCommand.java index 792d60f79..c0800b8e6 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/CreateHabitCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/CreateHabitCommand.java @@ -25,7 +25,6 @@ import com.google.auto.factory.*; import org.isoron.uhabits.*; import org.isoron.uhabits.models.*; -import org.json.*; /** * Command to create a habit. @@ -33,54 +32,25 @@ import org.json.*; @AutoFactory public class CreateHabitCommand extends Command { - private ModelFactory modelFactory; + ModelFactory modelFactory; HabitList habitList; @NonNull - private Habit model; + Habit model; @Nullable - private Long savedId; + Long savedId; public CreateHabitCommand(@Provided @NonNull ModelFactory modelFactory, @NonNull HabitList habitList, @NonNull Habit model) { - super(); this.modelFactory = modelFactory; this.habitList = habitList; this.model = model; } - public CreateHabitCommand(@Provided @NonNull ModelFactory modelFactory, - @NonNull String commandId, - @NonNull HabitList habitList, - @NonNull Habit model, - @Nullable Long savedId) - { - super(commandId); - this.modelFactory = modelFactory; - this.habitList = habitList; - this.model = model; - this.savedId = savedId; - } - - @NonNull - public static Command fromJSON(@NonNull JSONObject root, - @NonNull HabitList habitList, - @NonNull ModelFactory modelFactory) - throws JSONException - { - String commandId = root.getString("id"); - JSONObject data = (JSONObject) root.get("data"); - Habit model = Habit.fromJSON(data.getJSONObject("habit"), modelFactory); - Long savedId = data.getLong("id"); - - return new CreateHabitCommand(modelFactory, commandId, habitList, model, - savedId); - } - @Override public void execute() { @@ -104,30 +74,55 @@ public class CreateHabitCommand extends Command return R.string.toast_habit_deleted; } + @NonNull @Override - public JSONObject toJSON() + public Record toRecord() { - try - { - JSONObject root = super.toJSON(); - JSONObject data = root.getJSONObject("data"); - root.put("event", "CreateHabit"); - data.put("habit", model.toJSON()); - data.put("id", savedId); - return root; - } - catch (JSONException e) - { - throw new RuntimeException(e.getMessage()); - } + return new Record(this); } @Override public void undo() { + if (savedId == null) throw new IllegalStateException(); + Habit habit = habitList.getById(savedId); - if (habit == null) throw new RuntimeException("Habit not found"); + if (habit == null) throw new HabitNotFoundException(); habitList.remove(habit); } + + public static class Record + { + @NonNull + public String id; + + @NonNull + public String event = "CreateHabit"; + + @NonNull + public Habit.HabitData habit; + + @Nullable + public Long savedId; + + public Record(CreateHabitCommand command) + { + id = command.getId(); + habit = command.model.getData(); + savedId = command.savedId; + } + + public CreateHabitCommand toCommand(@NonNull ModelFactory modelFactory, + @NonNull HabitList habitList) + { + Habit h = modelFactory.buildHabit(habit); + + CreateHabitCommand command; + command = new CreateHabitCommand(modelFactory, habitList, h); + command.savedId = savedId; + command.setId(id); + return command; + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/commands/CreateRepetitionCommand.java b/app/src/main/java/org/isoron/uhabits/commands/CreateRepetitionCommand.java index 5422d7f1b..eff7a4149 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/CreateRepetitionCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/CreateRepetitionCommand.java @@ -29,15 +29,17 @@ import org.isoron.uhabits.models.*; public class CreateRepetitionCommand extends Command { @NonNull - private final Habit habit; + final Habit habit; - private final long timestamp; + final long timestamp; - private final int value; + final int value; - private Repetition previousRep; + @Nullable + Repetition previousRep; - private Repetition newRep; + @Nullable + Repetition newRep; public CreateRepetitionCommand(@NonNull Habit habit, long timestamp, @@ -68,11 +70,57 @@ public class CreateRepetitionCommand extends Command return habit; } + @Override + @NonNull + public Record toRecord() + { + return new Record(this); + } + @Override public void undo() { + if(newRep == null) throw new IllegalStateException(); habit.getRepetitions().remove(newRep); + if (previousRep != null) habit.getRepetitions().add(previousRep); habit.invalidateNewerThan(timestamp); } + + public static class Record + { + @NonNull + public String id; + + @NonNull + public String event = "CreateRep"; + + public long habitId; + + public long timestamp; + + public int value; + + public Record(CreateRepetitionCommand command) + { + id = command.getId(); + Long habitId = command.habit.getId(); + if(habitId == null) throw new RuntimeException("Habit not saved"); + + this.habitId = habitId; + this.timestamp = command.timestamp; + this.value = command.value; + } + + public CreateRepetitionCommand toCommand(@NonNull HabitList habitList) + { + Habit h = habitList.getById(habitId); + if(h == null) throw new HabitNotFoundException(); + + CreateRepetitionCommand command; + command = new CreateRepetitionCommand(h, timestamp, value); + command.setId(id); + return command; + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/commands/DeleteHabitsCommand.java b/app/src/main/java/org/isoron/uhabits/commands/DeleteHabitsCommand.java index 17c28b08f..fbc74c257 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/DeleteHabitsCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/DeleteHabitsCommand.java @@ -23,56 +23,32 @@ import android.support.annotation.*; import org.isoron.uhabits.*; import org.isoron.uhabits.models.*; -import org.json.*; import java.util.*; -import static org.isoron.uhabits.commands.CommandParser.habitListFromJSON; -import static org.isoron.uhabits.commands.CommandParser.habitListToJSON; - /** * Command to delete a list of habits. */ public class DeleteHabitsCommand extends Command { - HabitList habitList; + @NonNull + final HabitList habitList; - private List habits; + @NonNull + final List selected; public DeleteHabitsCommand(@NonNull HabitList habitList, - @NonNull List habits) - { - super(); - this.habits = habits; - this.habitList = habitList; - } - - public DeleteHabitsCommand(@NonNull String id, - @NonNull HabitList habitList, - @NonNull List habits) + @NonNull List selected) { - super(id); - this.habits = habits; + this.selected = new LinkedList<>(selected); this.habitList = habitList; } - @NonNull - public static Command fromJSON(@NonNull JSONObject json, - @NonNull HabitList habitList) - throws JSONException - { - String id = json.getString("id"); - JSONObject data = (JSONObject) json.get("data"); - JSONArray habitIds = data.getJSONArray("ids"); - - LinkedList habits = habitListFromJSON(habitList, habitIds); - return new DeleteHabitsCommand(id, habitList, habits); - } @Override public void execute() { - for (Habit h : habits) + for (Habit h : selected) habitList.remove(h); } @@ -82,9 +58,9 @@ public class DeleteHabitsCommand extends Command return R.string.toast_habit_deleted; } - public List getHabits() + public List getSelected() { - return new LinkedList<>(habits); + return Collections.unmodifiableList(selected); } @Override @@ -95,20 +71,9 @@ public class DeleteHabitsCommand extends Command @Override @NonNull - public JSONObject toJSON() + public Record toRecord() { - try - { - JSONObject root = super.toJSON(); - JSONObject data = root.getJSONObject("data"); - root.put("event", "DeleteHabits"); - data.put("ids", habitListToJSON(habits)); - return root; - } - catch (JSONException e) - { - throw new RuntimeException(e.getMessage()); - } + return new Record(this); } @Override @@ -116,4 +81,38 @@ public class DeleteHabitsCommand extends Command { throw new UnsupportedOperationException(); } + + public static class Record + { + @NonNull + public String id; + + @NonNull + public String event = "DeleteHabit"; + + @NonNull + public List habits; + + public Record(DeleteHabitsCommand command) + { + id = command.getId(); + habits = new LinkedList<>(); + for (Habit h : command.selected) + { + if (!h.hasId()) throw new RuntimeException("Habit not saved"); + habits.add(h.getId()); + } + } + + public DeleteHabitsCommand toCommand(@NonNull HabitList habitList) + { + List selected = new LinkedList<>(); + for (Long id : this.habits) selected.add(habitList.getById(id)); + + DeleteHabitsCommand command; + command = new DeleteHabitsCommand(habitList, selected); + command.setId(id); + return command; + } + } } diff --git a/app/src/main/java/org/isoron/uhabits/commands/EditHabitCommand.java b/app/src/main/java/org/isoron/uhabits/commands/EditHabitCommand.java index 13646a099..0f4ccb6aa 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/EditHabitCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/EditHabitCommand.java @@ -25,7 +25,6 @@ import com.google.auto.factory.*; import org.isoron.uhabits.*; import org.isoron.uhabits.models.*; -import org.json.*; /** * Command to modify a habit. @@ -33,52 +32,43 @@ import org.json.*; @AutoFactory public class EditHabitCommand extends Command { - HabitList habitList; + @NonNull + final HabitList habitList; - private Habit original; + @NonNull + final Habit original; - private Habit modified; + @NonNull + final Habit modified; - private long savedId; + final long savedId; - private boolean hasFrequencyChanged; + final boolean hasFrequencyChanged; - private boolean hasTargetChanged; + final boolean hasTargetChanged; public EditHabitCommand(@Provided @NonNull ModelFactory modelFactory, @NonNull HabitList habitList, @NonNull Habit original, @NonNull Habit modified) { - super(); - init(modelFactory, habitList, original, modified); - } + Long habitId = original.getId(); + if (habitId == null) throw new RuntimeException("Habit not saved"); - public EditHabitCommand(@Provided @NonNull ModelFactory modelFactory, - @NonNull String id, - @NonNull HabitList habitList, - @NonNull Habit original, - @NonNull Habit modified) - { - super(id); - init(modelFactory, habitList, original, modified); - } + this.savedId = habitId; + this.habitList = habitList; + this.modified = modelFactory.buildHabit(); + this.original = modelFactory.buildHabit(); - @NonNull - public static Command fromJSON(@NonNull JSONObject root, - @NonNull HabitList habitList, - @NonNull ModelFactory modelFactory) - throws JSONException - { - String commandId = root.getString("id"); - JSONObject data = (JSONObject) root.get("data"); - Habit original = habitList.getById(data.getLong("id")); - if (original == null) throw new HabitNotFoundException(); - - Habit modified = - Habit.fromJSON(data.getJSONObject("params"), modelFactory); - return new EditHabitCommand(modelFactory, commandId, habitList, - original, modified); + this.modified.copyFrom(modified); + this.original.copyFrom(original); + + Frequency originalFreq = this.original.getFrequency(); + Frequency modifiedFreq = this.modified.getFrequency(); + hasFrequencyChanged = (!originalFreq.equals(modifiedFreq)); + hasTargetChanged = + (original.getTargetType() != modified.getTargetType() || + original.getTargetValue() != modified.getTargetValue()); } @Override @@ -99,22 +89,11 @@ public class EditHabitCommand extends Command return R.string.toast_habit_changed_back; } + @NonNull @Override - public JSONObject toJSON() + public Record toRecord() { - try - { - JSONObject root = super.toJSON(); - JSONObject data = root.getJSONObject("data"); - root.put("event", "EditHabit"); - data.put("id", savedId); - data.put("params", modified.toJSON()); - return root; - } - catch (JSONException e) - { - throw new RuntimeException(e.getMessage()); - } + return new Record(this); } @Override @@ -131,33 +110,44 @@ public class EditHabitCommand extends Command habit.copyFrom(model); habitList.update(habit); - invalidateIfNeeded(habit); + if (hasFrequencyChanged || hasTargetChanged) + habit.invalidateNewerThan(0); } - private void init(@NonNull ModelFactory modelFactory, - @NonNull HabitList habitList, - @NonNull Habit original, - @NonNull Habit modified) + public static class Record { - this.habitList = habitList; - this.savedId = original.getId(); - this.modified = modelFactory.buildHabit(); - this.original = modelFactory.buildHabit(); + @NonNull + public String id; - this.modified.copyFrom(modified); - this.original.copyFrom(original); + @NonNull + public String event = "EditHabit"; - Frequency originalFreq = this.original.getFrequency(); - Frequency modifiedFreq = this.modified.getFrequency(); - hasFrequencyChanged = (!originalFreq.equals(modifiedFreq)); - hasTargetChanged = - (original.getTargetType() != modified.getTargetType() || - original.getTargetValue() != modified.getTargetValue()); - } + @NonNull + public Habit.HabitData habit; - private void invalidateIfNeeded(Habit habit) - { - if (hasFrequencyChanged || hasTargetChanged) - habit.invalidateNewerThan(0); + public long habitId; + + public Record(EditHabitCommand command) + { + id = command.getId(); + this.habitId = command.savedId; + this.habit = command.modified.getData(); + } + + @NonNull + public EditHabitCommand toCommand(@NonNull ModelFactory modelFactory, + @NonNull HabitList habitList) + { + Habit original = habitList.getById(habitId); + if(original == null) throw new HabitNotFoundException(); + + Habit modified = modelFactory.buildHabit(habit); + + EditHabitCommand command; + command = new EditHabitCommand(modelFactory, habitList, original, + modified); + command.setId(id); + return command; + } } } \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/commands/ToggleRepetitionCommand.java b/app/src/main/java/org/isoron/uhabits/commands/ToggleRepetitionCommand.java index b08823bfa..996a406fd 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/ToggleRepetitionCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/ToggleRepetitionCommand.java @@ -22,16 +22,16 @@ package org.isoron.uhabits.commands; import android.support.annotation.*; import org.isoron.uhabits.models.*; -import org.json.*; /** * Command to toggle a repetition. */ public class ToggleRepetitionCommand extends Command { - private Long timestamp; + final long timestamp; - private Habit habit; + @NonNull + final Habit habit; public ToggleRepetitionCommand(@NonNull Habit habit, long timestamp) { @@ -40,37 +40,13 @@ public class ToggleRepetitionCommand extends Command this.habit = habit; } - public ToggleRepetitionCommand(@NonNull String id, - @NonNull Habit habit, - long timestamp) - { - super(id); - this.timestamp = timestamp; - this.habit = habit; - } - - @NonNull - public static Command fromJSON(@NonNull JSONObject json, - @NonNull HabitList habitList) - throws JSONException - { - String id = json.getString("id"); - JSONObject data = (JSONObject) json.get("data"); - Long habitId = data.getLong("habit"); - Long timestamp = data.getLong("timestamp"); - - Habit habit = habitList.getById(habitId); - if (habit == null) throw new HabitNotFoundException(); - - return new ToggleRepetitionCommand(id, habit, timestamp); - } - @Override public void execute() { habit.getRepetitions().toggleTimestamp(timestamp); } + @NonNull public Habit getHabit() { return habit; @@ -78,21 +54,9 @@ public class ToggleRepetitionCommand extends Command @Override @NonNull - public JSONObject toJSON() + public Record toRecord() { - try - { - JSONObject root = super.toJSON(); - JSONObject data = root.getJSONObject("data"); - root.put("event", "ToggleRepetition"); - data.put("habit", habit.getId()); - data.put("timestamp", timestamp); - return root; - } - catch (JSONException e) - { - throw new RuntimeException(e.getMessage()); - } + return new Record(this); } @Override @@ -100,4 +64,38 @@ public class ToggleRepetitionCommand extends Command { execute(); } + + public static class Record + { + @NonNull + public String id; + + @NonNull + public String event = "Toggle"; + + public long habitId; + + public long timestamp; + + public Record(@NonNull ToggleRepetitionCommand command) + { + id = command.getId(); + Long habitId = command.habit.getId(); + if(habitId == null) throw new RuntimeException("Habit not saved"); + + this.timestamp = command.timestamp; + this.habitId = habitId; + } + + public ToggleRepetitionCommand toCommand(@NonNull HabitList habitList) + { + Habit h = habitList.getById(habitId); + if(h == null) throw new HabitNotFoundException(); + + ToggleRepetitionCommand command; + command = new ToggleRepetitionCommand(h, timestamp); + command.setId(id); + return command; + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/commands/UnarchiveHabitsCommand.java b/app/src/main/java/org/isoron/uhabits/commands/UnarchiveHabitsCommand.java index e832cd6c0..d66425348 100644 --- a/app/src/main/java/org/isoron/uhabits/commands/UnarchiveHabitsCommand.java +++ b/app/src/main/java/org/isoron/uhabits/commands/UnarchiveHabitsCommand.java @@ -23,56 +23,32 @@ import android.support.annotation.*; import org.isoron.uhabits.*; import org.isoron.uhabits.models.*; -import org.json.*; import java.util.*; -import static org.isoron.uhabits.commands.CommandParser.*; - /** * Command to unarchive a list of habits. */ public class UnarchiveHabitsCommand extends Command { - HabitList habitList; + @NonNull + final HabitList habitList; - private List habits; + @NonNull + final List selected; public UnarchiveHabitsCommand(@NonNull HabitList habitList, @NonNull List selected) { - super(); - this.habits = selected; - this.habitList = habitList; - } - - public UnarchiveHabitsCommand(@NonNull String id, - @NonNull HabitList habitList, - @NonNull List selected) - { - super(id); - this.habits = selected; + this.selected = new LinkedList<>(selected); this.habitList = habitList; } - @NonNull - public static Command fromJSON(@NonNull JSONObject json, - @NonNull HabitList habitList) - throws JSONException - { - String id = json.getString("id"); - JSONObject data = (JSONObject) json.get("data"); - JSONArray habitIds = data.getJSONArray("ids"); - - LinkedList selected = habitListFromJSON(habitList, habitIds); - return new UnarchiveHabitsCommand(id, habitList, selected); - } - @Override public void execute() { - for (Habit h : habits) h.setArchived(false); - habitList.update(habits); + for (Habit h : selected) h.setArchived(false); + habitList.update(selected); } @Override @@ -89,27 +65,50 @@ public class UnarchiveHabitsCommand extends Command @Override @NonNull - public JSONObject toJSON() + public Record toRecord() { - try - { - JSONObject root = super.toJSON(); - JSONObject data = root.getJSONObject("data"); - root.put("event", "UnarchiveHabits"); - data.put("ids", habitListToJSON(habits)); - return root; - } - catch (JSONException e) - { - throw new RuntimeException(e.getMessage()); - } + return new Record(this); } @Override public void undo() { - for (Habit h : habits) h.setArchived(true); - habitList.update(habits); + for (Habit h : selected) h.setArchived(true); + habitList.update(selected); } + public static class Record + { + @NonNull + public final String id; + + @NonNull + public final String event = "Unarchive"; + + @NonNull + public final List habits; + + public Record(@NonNull UnarchiveHabitsCommand command) + { + id = command.getId(); + habits = new LinkedList<>(); + for (Habit h : command.selected) + { + if (!h.hasId()) throw new RuntimeException("Habit not saved"); + habits.add(h.getId()); + } + } + + @NonNull + public UnarchiveHabitsCommand toCommand(@NonNull HabitList habitList) + { + List selected = new LinkedList<>(); + for (Long id : this.habits) selected.add(habitList.getById(id)); + + UnarchiveHabitsCommand command; + command = new UnarchiveHabitsCommand(habitList, selected); + command.setId(id); + return command; + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/models/Habit.java b/app/src/main/java/org/isoron/uhabits/models/Habit.java index 59edf63ba..5500f588d 100644 --- a/app/src/main/java/org/isoron/uhabits/models/Habit.java +++ b/app/src/main/java/org/isoron/uhabits/models/Habit.java @@ -23,12 +23,12 @@ import android.net.*; import android.support.annotation.*; import org.apache.commons.lang3.builder.*; -import org.json.*; import java.util.*; import javax.inject.*; +import static android.R.attr.*; import static org.isoron.uhabits.models.Checkmark.*; /** @@ -48,20 +48,10 @@ public class Habit public static final int YES_NO_HABIT = 0; @Nullable - private Long id; + public Long id; @NonNull - private String name; - - @NonNull - private String description; - - @NonNull - private Frequency frequency; - - private int color; - - private boolean archived; + private HabitData data; @NonNull private StreakList streaks; @@ -69,28 +59,16 @@ public class Habit @NonNull private ScoreList scores; - private int targetType; - - private double targetValue; - - private int type; - @NonNull private RepetitionList repetitions; @NonNull private CheckmarkList checkmarks; - @NonNull - private String unit; - - @Nullable - private Reminder reminder; - private ModelObservable observable = new ModelObservable(); /** - * Constructs a habit with default attributes. + * Constructs a habit with default data. *

* The habit is not archived, not highlighted, has no reminders and is * placed in the last position of the list of habits. @@ -98,16 +76,16 @@ public class Habit @Inject Habit(@NonNull ModelFactory factory) { - this.color = 5; - this.archived = false; - this.frequency = new Frequency(3, 7); - this.type = YES_NO_HABIT; - this.name = ""; - this.description = ""; - this.targetType = AT_LEAST; - this.targetValue = 100; - this.unit = ""; + this.data = new HabitData(); + checkmarks = factory.buildCheckmarkList(this); + streaks = factory.buildStreakList(this); + scores = factory.buildScoreList(this); + repetitions = factory.buildRepetitionList(this); + } + Habit(@NonNull ModelFactory factory, @NonNull HabitData data) + { + this.data = new HabitData(data); checkmarks = factory.buildCheckmarkList(this); streaks = factory.buildStreakList(this); scores = factory.buildScoreList(this); @@ -119,7 +97,7 @@ public class Habit */ public void clearReminder() { - reminder = null; + data.reminder = null; observable.notifyListeners(); } @@ -130,16 +108,7 @@ public class Habit */ public void copyFrom(@NonNull Habit model) { - this.name = model.getName(); - this.description = model.getDescription(); - this.color = model.getColor(); - this.archived = model.isArchived(); - this.frequency = model.frequency; - this.reminder = model.reminder; - this.type = model.type; - this.targetValue = model.targetValue; - this.targetType = model.targetType; - this.unit = model.unit; + this.data = new HabitData(model.data); observable.notifyListeners(); } @@ -163,41 +132,34 @@ public class Habit @NonNull public Integer getColor() { - return color; - } - - public boolean isCompletedToday() - { - int todayCheckmark = getCheckmarks().getTodayValue(); - if (isNumerical()) return todayCheckmark >= targetValue; - else return (todayCheckmark != UNCHECKED); + return data.color; } public void setColor(@NonNull Integer color) { - this.color = color; + data.color = color; } @NonNull public String getDescription() { - return description; + return data.description; } public void setDescription(@NonNull String description) { - this.description = description; + data.description = description; } @NonNull public Frequency getFrequency() { - return frequency; + return data.frequency; } public void setFrequency(@NonNull Frequency frequency) { - this.frequency = frequency; + data.frequency = frequency; } @Nullable @@ -214,12 +176,12 @@ public class Habit @NonNull public String getName() { - return name; + return data.name; } public void setName(@NonNull String name) { - this.name = name; + data.name = name; } public ModelObservable getObservable() @@ -240,13 +202,13 @@ public class Habit @NonNull public Reminder getReminder() { - if (reminder == null) throw new IllegalStateException(); - return reminder; + if (data.reminder == null) throw new IllegalStateException(); + return data.reminder; } public void setReminder(@Nullable Reminder reminder) { - this.reminder = reminder; + data.reminder = reminder; } @NonNull @@ -269,30 +231,30 @@ public class Habit public int getTargetType() { - return targetType; + return data.targetType; } public void setTargetType(int targetType) { if (targetType != AT_LEAST && targetType != AT_MOST) throw new IllegalArgumentException(); - this.targetType = targetType; + data.targetType = targetType; } public double getTargetValue() { - return targetValue; + return data.targetValue; } public void setTargetValue(double targetValue) { - if(targetValue < 0) throw new IllegalArgumentException(); - this.targetValue = targetValue; + if (targetValue < 0) throw new IllegalArgumentException(); + data.targetValue = targetValue; } public int getType() { - return type; + return data.type; } public void setType(int type) @@ -300,18 +262,18 @@ public class Habit if (type != YES_NO_HABIT && type != NUMBER_HABIT) throw new IllegalArgumentException(); - this.type = type; + data.type = type; } @NonNull public String getUnit() { - return unit; + return data.unit; } public void setUnit(@NonNull String unit) { - this.unit = unit; + data.unit = unit; } /** @@ -325,6 +287,11 @@ public class Habit return Uri.parse(s); } + public boolean hasId() + { + return getId() != null; + } + /** * Returns whether the habit has a reminder. * @@ -332,7 +299,7 @@ public class Habit */ public boolean hasReminder() { - return reminder != null; + return data.reminder != null; } public void invalidateNewerThan(long timestamp) @@ -344,12 +311,19 @@ public class Habit public boolean isArchived() { - return archived; + return data.archived; } public void setArchived(boolean archived) { - this.archived = archived; + data.archived = archived; + } + + public boolean isCompletedToday() + { + int todayCheckmark = getCheckmarks().getTodayValue(); + if (isNumerical()) return todayCheckmark >= data.targetValue; + else return (todayCheckmark != UNCHECKED); } public boolean isNumerical() @@ -357,79 +331,120 @@ public class Habit return type == NUMBER_HABIT; } - @Override - public String toString() + public HabitData getData() { - return new ToStringBuilder(this) - .append("id", id) - .append("name", name) - .append("description", description) - .append("color", color) - .append("archived", archived) - .append("type", type) - .append("targetType", targetType) - .append("targetValue", targetValue) - .append("unit", unit) - .toString(); + return new HabitData(data); } - @NonNull - public JSONObject toJSON() + public static class HabitData { - try + @NonNull + public String name; + + @NonNull + public String description; + + @NonNull + public Frequency frequency; + + public int color; + + public boolean archived; + + public int targetType; + + public double targetValue; + + public int type; + + @NonNull + public String unit; + + @Nullable + public Reminder reminder; + + public HabitData() { - JSONObject json = new JSONObject(); - json.put("name", name); - json.put("description", description); - json.put("freqNum", frequency.getNumerator()); - json.put("freqDen", frequency.getDenominator()); - json.put("color", color); - json.put("type", type); - json.put("targetType", targetType); - json.put("targetValue", targetValue); - json.put("unit", unit); - json.put("archived", archived); - - if(reminder != null) - { - json.put("reminderHour", reminder.getHour()); - json.put("reminderMin", reminder.getMinute()); - json.put("reminderDays", reminder.getDays().toInteger()); - } - - return json; + this.color = 5; + this.archived = false; + this.frequency = new Frequency(3, 7); + this.type = YES_NO_HABIT; + this.name = ""; + this.description = ""; + this.targetType = AT_LEAST; + this.targetValue = 100; + this.unit = ""; } - catch(JSONException e) + + public HabitData(@NonNull HabitData model) { - throw new RuntimeException(e.getMessage()); + this.name = model.name; + this.description = model.description; + this.frequency = model.frequency; + this.color = model.color; + this.archived = model.archived; + this.targetType = model.targetType; + this.targetValue = model.targetValue; + this.type = model.type; + this.unit = model.unit; + this.reminder = model.reminder; } - } - @NonNull - public static Habit fromJSON(@NonNull JSONObject json, - @NonNull ModelFactory modelFactory) - throws JSONException - { - Habit habit = modelFactory.buildHabit(); - habit.name = json.getString("name"); - habit.description = json.getString("description"); - int freqNum = json.getInt("freqNum"); - int freqDen = json.getInt("freqDen"); - habit.frequency = new Frequency(freqNum, freqDen); - habit.color = json.getInt("color"); - habit.archived = json.getBoolean("archived"); - habit.targetValue = json.getInt("targetValue"); - habit.targetType = json.getInt("targetType"); - habit.unit = json.getString("unit"); - habit.type = json.getInt("type"); - - if(json.has("reminderHour")) + @Override + public String toString() + { + return new ToStringBuilder(this) + .append("name", name) + .append("description", description) + .append("frequency", frequency) + .append("color", color) + .append("archived", archived) + .append("targetType", targetType) + .append("targetValue", targetValue) + .append("type", type) + .append("unit", unit) + .append("reminder", reminder) + .toString(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + HabitData habitData = (HabitData) o; + + return new EqualsBuilder() + .append(color, habitData.color) + .append(archived, habitData.archived) + .append(targetType, habitData.targetType) + .append(targetValue, habitData.targetValue) + .append(type, habitData.type) + .append(name, habitData.name) + .append(description, habitData.description) + .append(frequency, habitData.frequency) + .append(unit, habitData.unit) + .append(reminder, habitData.reminder) + .isEquals(); + } + + @Override + public int hashCode() { - int hour = json.getInt("reminderHour"); - int min = json.getInt("reminderMin"); - int days = json.getInt("reminderDays"); - habit.reminder = new Reminder(hour, min, new WeekdayList(days)); + return new HashCodeBuilder(17, 37) + .append(name) + .append(description) + .append(frequency) + .append(color) + .append(archived) + .append(targetType) + .append(targetValue) + .append(type) + .append(unit) + .append(reminder) + .toHashCode(); } - return habit; } } diff --git a/app/src/main/java/org/isoron/uhabits/models/ModelFactory.java b/app/src/main/java/org/isoron/uhabits/models/ModelFactory.java index 50c352411..2556b9755 100644 --- a/app/src/main/java/org/isoron/uhabits/models/ModelFactory.java +++ b/app/src/main/java/org/isoron/uhabits/models/ModelFactory.java @@ -32,6 +32,11 @@ public interface ModelFactory return new Habit(this); } + default Habit buildHabit(Habit.HabitData data) + { + return new Habit(this, data); + } + HabitList buildHabitList(); RepetitionList buildRepetitionList(Habit habit); diff --git a/app/src/main/java/org/isoron/uhabits/notifications/NotificationTray.java b/app/src/main/java/org/isoron/uhabits/notifications/NotificationTray.java index d6a0253a2..f05e51720 100644 --- a/app/src/main/java/org/isoron/uhabits/notifications/NotificationTray.java +++ b/app/src/main/java/org/isoron/uhabits/notifications/NotificationTray.java @@ -102,7 +102,7 @@ public class NotificationTray if (command instanceof DeleteHabitsCommand) { DeleteHabitsCommand deleteCommand = (DeleteHabitsCommand) command; - List deleted = deleteCommand.getHabits(); + List deleted = deleteCommand.getSelected(); for (Habit habit : deleted) cancel(habit); } diff --git a/app/src/main/java/org/isoron/uhabits/sync/SyncManager.java b/app/src/main/java/org/isoron/uhabits/sync/SyncManager.java index 2a769ffa6..35d536db7 100644 --- a/app/src/main/java/org/isoron/uhabits/sync/SyncManager.java +++ b/app/src/main/java/org/isoron/uhabits/sync/SyncManager.java @@ -141,9 +141,7 @@ public class SyncManager public void postCommand(Command command) { - JSONObject msg = command.toJSON(); - if (msg == null) return; - + JSONObject msg = command.toJson(); Long now = new Date().getTime(); Event e = new Event(command.getId(), now, msg.toString()); e.save(); @@ -293,7 +291,7 @@ public class SyncManager private void executeCommand(JSONObject root) throws JSONException { - Command received = commandParser.fromJSON(root); + Command received = commandParser.parse(root); for (Event e : pendingConfirmation) { if (e.serverId.equals(received.getId())) diff --git a/app/src/test/java/org/isoron/uhabits/commands/ArchiveHabitsCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/ArchiveHabitsCommandTest.java index fe2a61d3e..516c01ddf 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/ArchiveHabitsCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/ArchiveHabitsCommandTest.java @@ -26,11 +26,13 @@ import org.junit.*; import java.util.*; import static junit.framework.Assert.*; +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; public class ArchiveHabitsCommandTest extends BaseUnitTest { - private ArchiveHabitsCommand command; + private Habit habit; @Override @@ -40,8 +42,10 @@ public class ArchiveHabitsCommandTest extends BaseUnitTest super.setUp(); habit = fixtures.createShortHabit(); - command = new ArchiveHabitsCommand(habitList, Collections - .singletonList(habit)); + habitList.add(habit); + + command = new ArchiveHabitsCommand(habitList, + Collections.singletonList(habit)); } @Test @@ -58,4 +62,13 @@ public class ArchiveHabitsCommandTest extends BaseUnitTest command.execute(); assertTrue(habit.isArchived()); } + + @Test + public void testRecord() + { + ArchiveHabitsCommand.Record rec = command.toRecord(); + ArchiveHabitsCommand other = rec.toCommand(habitList); + assertThat(other.selected, equalTo(command.selected)); + assertThat(other.getId(), equalTo(command.getId())); + } } diff --git a/app/src/test/java/org/isoron/uhabits/commands/ChangeHabitColorCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/ChangeHabitColorCommandTest.java index 7e2a40b0a..78c39306d 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/ChangeHabitColorCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/ChangeHabitColorCommandTest.java @@ -32,7 +32,7 @@ public class ChangeHabitColorCommandTest extends BaseUnitTest { private ChangeHabitColorCommand command; - private LinkedList habits; + private LinkedList selected; @Override @Before @@ -40,16 +40,17 @@ public class ChangeHabitColorCommandTest extends BaseUnitTest { super.setUp(); - habits = new LinkedList<>(); + selected = new LinkedList<>(); for (int i = 0; i < 3; i++) { Habit habit = fixtures.createShortHabit(); habit.setColor(i + 1); - habits.add(habit); + selected.add(habit); + habitList.add(habit); } - command = new ChangeHabitColorCommand(habitList, habits, 0); + command = new ChangeHabitColorCommand(habitList, selected, 0); } @Test @@ -67,16 +68,26 @@ public class ChangeHabitColorCommandTest extends BaseUnitTest checkNewColors(); } + @Test + public void testRecord() + { + ChangeHabitColorCommand.Record rec = command.toRecord(); + ChangeHabitColorCommand other = rec.toCommand(habitList); + assertThat(other.getId(), equalTo(command.getId())); + assertThat(other.newColor, equalTo(command.newColor)); + assertThat(other.selected, equalTo(command.selected)); + } + private void checkNewColors() { - for (Habit h : habits) + for (Habit h : selected) assertThat(h.getColor(), equalTo(0)); } private void checkOriginalColors() { int k = 0; - for (Habit h : habits) + for (Habit h : selected) assertThat(h.getColor(), equalTo(++k)); } } diff --git a/app/src/test/java/org/isoron/uhabits/commands/CommandParserTest.java b/app/src/test/java/org/isoron/uhabits/commands/CommandParserTest.java new file mode 100644 index 000000000..c043bc8b6 --- /dev/null +++ b/app/src/test/java/org/isoron/uhabits/commands/CommandParserTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.commands; + +import android.support.annotation.*; + +import org.isoron.uhabits.*; +import org.isoron.uhabits.models.*; +import org.json.*; +import org.junit.*; + +import java.util.*; + +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; + + +public class CommandParserTest extends BaseUnitTest +{ + @NonNull + private CommandParser parser; + + private Habit habit; + + private List selected; + + @Override + @Before + public void setUp() + { + super.setUp(); + parser = new CommandParser(habitList, modelFactory); + habit = fixtures.createShortHabit(); + selected = Collections.singletonList(habit); + habitList.add(habit); + } + + @Test + public void testDecodeArchiveCommand() throws JSONException + { + ArchiveHabitsCommand original, decoded; + original = new ArchiveHabitsCommand(habitList, selected); + decoded = (ArchiveHabitsCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.selected, equalTo(original.selected)); + } + + @Test + public void testDecodeChangeColorCommand() throws JSONException + { + ChangeHabitColorCommand original, decoded; + original = new ChangeHabitColorCommand(habitList, selected, 20); + decoded = (ChangeHabitColorCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.newColor, equalTo(original.newColor)); + assertThat(decoded.selected, equalTo(original.selected)); + } + + @Test + public void testDecodeCreateHabitCommand() throws JSONException + { + Habit model = modelFactory.buildHabit(); + model.setName("JSON"); + + CreateHabitCommand original, decoded; + original = new CreateHabitCommand(modelFactory, habitList, model); + original.execute(); + + decoded = (CreateHabitCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.savedId, equalTo(original.savedId)); + assertThat(decoded.model.getData(), equalTo(model.getData())); + } + + @Test + public void testDecodeCreateRepCommand() throws JSONException + { + CreateRepetitionCommand original, decoded; + original = new CreateRepetitionCommand(habit, 1000, 5); + decoded = (CreateRepetitionCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.timestamp, equalTo(original.timestamp)); + assertThat(decoded.value, equalTo(original.value)); + assertThat(decoded.habit, equalTo(original.habit)); + } + + @Test + public void testDecodeDeleteCommand() throws JSONException + { + DeleteHabitsCommand original, decoded; + original = new DeleteHabitsCommand(habitList, selected); + decoded = (DeleteHabitsCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.selected, equalTo(original.selected)); + } + + @Test + public void testDecodeEditHabitCommand() throws JSONException + { + Habit modified = modelFactory.buildHabit(); + modified.setName("Edited JSON"); + modified.setColor(2); + + EditHabitCommand original, decoded; + original = new EditHabitCommand(modelFactory, habitList, habit, modified); + original.execute(); + + decoded = (EditHabitCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.savedId, equalTo(original.savedId)); + assertThat(decoded.modified.getData(), equalTo(modified.getData())); + } + + @Test + public void testDecodeToggleCommand() throws JSONException + { + ToggleRepetitionCommand original, decoded; + original = new ToggleRepetitionCommand(habit, 1000); + decoded = (ToggleRepetitionCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.timestamp, equalTo(original.timestamp)); + assertThat(decoded.habit, equalTo(original.habit)); + } + + @Test + public void testDecodeUnarchiveCommand() throws JSONException + { + UnarchiveHabitsCommand original, decoded; + original = new UnarchiveHabitsCommand(habitList, selected); + decoded = (UnarchiveHabitsCommand) parser.parse(original.toJson()); + + assertThat(decoded.getId(), equalTo(original.getId())); + assertThat(decoded.selected, equalTo(original.selected)); + } +} \ No newline at end of file diff --git a/app/src/test/java/org/isoron/uhabits/commands/CreateHabitCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/CreateHabitCommandTest.java index b0c5fb84d..566a91b6f 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/CreateHabitCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/CreateHabitCommandTest.java @@ -41,6 +41,7 @@ public class CreateHabitCommandTest extends BaseUnitTest model = fixtures.createEmptyHabit(); model.setName("New habit"); + model.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY)); command = new CreateHabitCommand(modelFactory, habitList, model); } @@ -70,5 +71,16 @@ public class CreateHabitCommandTest extends BaseUnitTest assertThat(habit.getName(), equalTo(model.getName())); } + @Test + public void testRecord() + { + command.execute(); + CreateHabitCommand.Record rec = command.toRecord(); + CreateHabitCommand other = rec.toCommand(modelFactory, habitList); + + assertThat(other.getId(), equalTo(command.getId())); + assertThat(other.savedId, equalTo(command.savedId)); + assertThat(other.model.getData(), equalTo(command.model.getData())); + } } diff --git a/app/src/test/java/org/isoron/uhabits/commands/CreateRepetitionCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/CreateRepetitionCommandTest.java index 45816c559..23ceb1192 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/CreateRepetitionCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/CreateRepetitionCommandTest.java @@ -25,11 +25,12 @@ import org.isoron.uhabits.utils.*; import org.junit.*; import static junit.framework.Assert.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.isoron.uhabits.models.Checkmark.CHECKED_EXPLICITLY; public class CreateRepetitionCommandTest extends BaseUnitTest { - private CreateRepetitionCommand command; private Habit habit; @@ -43,6 +44,7 @@ public class CreateRepetitionCommandTest extends BaseUnitTest super.setUp(); habit = fixtures.createShortHabit(); + habitList.add(habit); today = DateUtils.getStartOfToday(); command = new CreateRepetitionCommand(habit, today, 100); @@ -67,4 +69,16 @@ public class CreateRepetitionCommandTest extends BaseUnitTest assertNotNull(rep); assertEquals(CHECKED_EXPLICITLY, rep.getValue()); } + + @Test + public void testRecord() + { + CreateRepetitionCommand.Record rec = command.toRecord(); + CreateRepetitionCommand other = rec.toCommand(habitList); + + assertThat(command.getId(), equalTo(other.getId())); + assertThat(command.timestamp, equalTo(other.timestamp)); + assertThat(command.value, equalTo(other.value)); + assertThat(command.habit, equalTo(other.habit)); + } } diff --git a/app/src/test/java/org/isoron/uhabits/commands/DeleteHabitsCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/DeleteHabitsCommandTest.java index 09b2871d5..b3fc7aa53 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/DeleteHabitsCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/DeleteHabitsCommandTest.java @@ -73,4 +73,13 @@ public class DeleteHabitsCommandTest extends BaseUnitTest thrown.expect(UnsupportedOperationException.class); command.undo(); } + + @Test + public void testRecord() + { + DeleteHabitsCommand.Record rec = command.toRecord(); + DeleteHabitsCommand other = rec.toCommand(habitList); + assertThat(other.getId(), equalTo(command.getId())); + assertThat(other.selected, equalTo(command.selected)); + } } diff --git a/app/src/test/java/org/isoron/uhabits/commands/EditHabitCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/EditHabitCommandTest.java index 0345d34c5..6766497a4 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/EditHabitCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/EditHabitCommandTest.java @@ -28,7 +28,6 @@ import static org.hamcrest.Matchers.*; public class EditHabitCommandTest extends BaseUnitTest { - private EditHabitCommand command; private Habit habit; @@ -98,4 +97,19 @@ public class EditHabitCommandTest extends BaseUnitTest assertThat(habit.getScores().getTodayValue(), lessThan(originalScore)); } + + @Test + public void testRecord() + { + command = + new EditHabitCommand(modelFactory, habitList, habit, modified); + + EditHabitCommand.Record rec = command.toRecord(); + EditHabitCommand other = rec.toCommand(modelFactory, habitList); + + assertThat(other.getId(), equalTo(command.getId())); + assertThat(other.savedId, equalTo(command.savedId)); + assertThat(other.original.getData(), equalTo(command.original.getData())); + assertThat(other.modified.getData(), equalTo(command.modified.getData())); + } } diff --git a/app/src/test/java/org/isoron/uhabits/commands/ToggleRepetitionCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/ToggleRepetitionCommandTest.java index e9e5fd0a7..4f0eb461a 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/ToggleRepetitionCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/ToggleRepetitionCommandTest.java @@ -25,6 +25,8 @@ import org.isoron.uhabits.utils.*; import org.junit.*; import static junit.framework.Assert.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; public class ToggleRepetitionCommandTest extends BaseUnitTest { @@ -40,6 +42,7 @@ public class ToggleRepetitionCommandTest extends BaseUnitTest super.setUp(); habit = fixtures.createShortHabit(); + habitList.add(habit); today = DateUtils.getStartOfToday(); command = new ToggleRepetitionCommand(habit, today); @@ -59,4 +62,15 @@ public class ToggleRepetitionCommandTest extends BaseUnitTest command.execute(); assertFalse(habit.getRepetitions().containsTimestamp(today)); } + + @Test + public void testRecord() + { + ToggleRepetitionCommand.Record rec = command.toRecord(); + ToggleRepetitionCommand other = rec.toCommand(habitList); + + assertThat(command.getId(), equalTo(other.getId())); + assertThat(command.timestamp, equalTo(other.timestamp)); + assertThat(command.habit, equalTo(other.habit)); + } } diff --git a/app/src/test/java/org/isoron/uhabits/commands/UnarchiveHabitsCommandTest.java b/app/src/test/java/org/isoron/uhabits/commands/UnarchiveHabitsCommandTest.java index ee251e0e2..9485962d8 100644 --- a/app/src/test/java/org/isoron/uhabits/commands/UnarchiveHabitsCommandTest.java +++ b/app/src/test/java/org/isoron/uhabits/commands/UnarchiveHabitsCommandTest.java @@ -26,6 +26,8 @@ import org.junit.*; import java.util.*; import static junit.framework.Assert.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; public class UnarchiveHabitsCommandTest extends BaseUnitTest { @@ -61,4 +63,13 @@ public class UnarchiveHabitsCommandTest extends BaseUnitTest command.execute(); assertFalse(habit.isArchived()); } + + @Test + public void testRecord() + { + UnarchiveHabitsCommand.Record rec = command.toRecord(); + UnarchiveHabitsCommand other = rec.toCommand(habitList); + assertThat(other.selected, equalTo(command.selected)); + assertThat(other.getId(), equalTo(command.getId())); + } }