Replace toJSON methods by Gson

pull/286/head
Alinson S. Xavier 9 years ago
parent 13b4128777
commit 08e3c9cc40

@ -77,6 +77,7 @@ dependencies {
compile 'com.opencsv:opencsv:3.7' compile 'com.opencsv:opencsv:3.7'
compile 'org.apmem.tools:layouts:1.10@aar' compile 'org.apmem.tools:layouts:1.10@aar'
compile 'org.jetbrains:annotations-java5:15.0' compile 'org.jetbrains:annotations-java5:15.0'
compile 'com.google.code.gson:gson:2.8.0'
provided 'javax.annotation:jsr250-api:1.0' provided 'javax.annotation:jsr250-api:1.0'
@ -89,6 +90,7 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-library:1.3' testCompile 'org.hamcrest:hamcrest-library:1.3'
testCompile 'org.mockito:mockito-core:1.10.19' testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'org.json:json:20160810'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') { androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
exclude group: 'com.android.support' exclude group: 'com.android.support'

@ -23,56 +23,31 @@ import android.support.annotation.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*;
import java.util.*; import java.util.*;
import static org.isoron.uhabits.commands.CommandParser.*;
/** /**
* Command to archive a list of habits. * Command to archive a list of habits.
*/ */
public class ArchiveHabitsCommand extends Command public class ArchiveHabitsCommand extends Command
{ {
private List<Habit> selectedHabits; final List<Habit> selected;
private final HabitList habitList; final HabitList habitList;
public ArchiveHabitsCommand(@NonNull HabitList habitList, public ArchiveHabitsCommand(@NonNull HabitList habitList,
@NonNull List<Habit> selectedHabits) @NonNull List<Habit> selected)
{ {
super(); super();
this.habitList = habitList; this.habitList = habitList;
this.selectedHabits = selectedHabits; this.selected = new LinkedList<>(selected);
}
public ArchiveHabitsCommand(@NonNull String id,
@NonNull HabitList habitList,
@NonNull List<Habit> 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<Habit> selectedHabits =
habitListFromJSON(habitList, habitIds);
return new ArchiveHabitsCommand(id, habitList, selectedHabits);
} }
@Override @Override
public void execute() public void execute()
{ {
for (Habit h : selectedHabits) h.setArchived(true); for (Habit h : selected) h.setArchived(true);
habitList.update(selectedHabits); habitList.update(selected);
} }
@Override @Override
@ -87,28 +62,51 @@ public class ArchiveHabitsCommand extends Command
return R.string.toast_habit_unarchived; return R.string.toast_habit_unarchived;
} }
@Nullable
@Override @Override
public JSONObject toJSON() public void undo()
{ {
try for (Habit h : selected) h.setArchived(false);
{ habitList.update(selected);
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());
}
} }
@NonNull
@Override @Override
public void undo() public Record toRecord()
{
return new Record(this);
}
public static class Record
{ {
for (Habit h : selectedHabits) h.setArchived(false); @NonNull
habitList.update(selectedHabits); public final String id;
@NonNull
public final String event = "Archive";
@NonNull
public final List<Long> 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<Habit> 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;
}
} }
} }

@ -23,54 +23,35 @@ import android.support.annotation.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*;
import java.util.*; import java.util.*;
import static org.isoron.uhabits.commands.CommandParser.*;
/** /**
* Command to change the color of a list of habits. * Command to change the color of a list of habits.
*/ */
public class ChangeHabitColorCommand extends Command public class ChangeHabitColorCommand extends Command
{ {
HabitList habitList; @NonNull
final HabitList habitList;
List<Habit> selected; @NonNull
final List<Habit> selected;
List<Integer> originalColors; @NonNull
final List<Integer> originalColors;
Integer newColor; @NonNull
final Integer newColor;
public ChangeHabitColorCommand(@NonNull HabitList habitList, public ChangeHabitColorCommand(@NonNull HabitList habitList,
@NonNull List<Habit> selected, @NonNull List<Habit> selected,
@NonNull Integer newColor) @NonNull Integer newColor)
{ {
super(); this.habitList = habitList;
init(habitList, selected, newColor); this.selected = selected;
} this.newColor = newColor;
this.originalColors = new ArrayList<>(selected.size());
public ChangeHabitColorCommand(@NonNull String id, for (Habit h : selected) originalColors.add(h.getColor());
@NonNull HabitList habitList,
@NonNull List<Habit> 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<Habit> selected = habitListFromJSON(habitList, habitIds);
return new ChangeHabitColorCommand(id, habitList, selected, newColor);
} }
@Override @Override
@ -92,23 +73,11 @@ public class ChangeHabitColorCommand extends Command
return R.string.toast_habit_changed; return R.string.toast_habit_changed;
} }
@Override
@NonNull @NonNull
public JSONObject toJSON() @Override
public Record toRecord()
{ {
try return new Record(this);
{
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());
}
} }
@Override @Override
@ -119,15 +88,41 @@ public class ChangeHabitColorCommand extends Command
habitList.update(selected); habitList.update(selected);
} }
private void init(@NonNull HabitList habitList, public static class Record
@NonNull List<Habit> selected,
@NonNull Integer newColor)
{ {
this.habitList = habitList; @NonNull
this.selected = selected; public String id;
this.newColor = newColor;
this.originalColors = new ArrayList<>(selected.size());
for (Habit h : selected) originalColors.add(h.getColor()); @NonNull
public String event = "ChangeColor";
@NonNull
public List<Long> 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<Habit> 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;
}
} }
} }

@ -19,6 +19,10 @@
package org.isoron.uhabits.commands; package org.isoron.uhabits.commands;
import android.support.annotation.*;
import com.google.gson.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import org.json.*; import org.json.*;
@ -33,7 +37,7 @@ import org.json.*;
*/ */
public abstract class Command public abstract class Command
{ {
private final String id; private String id;
public Command() public Command()
{ {
@ -52,31 +56,37 @@ public abstract class Command
return null; return null;
} }
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public Integer getUndoStringId() public Integer getUndoStringId()
{ {
return null; return null;
} }
public abstract void undo(); @NonNull
public JSONObject toJson()
public JSONObject toJSON()
{ {
try try
{ {
JSONObject root = new JSONObject(); String json = new GsonBuilder().create().toJson(toRecord());
JSONObject data = new JSONObject(); return new JSONObject(json);
root.put("id", getId());
root.put("data", data);
return root;
} }
catch (JSONException e) catch (JSONException e)
{ {
throw new RuntimeException(e.getMessage()); throw new RuntimeException(e);
} }
} }
public String getId() @NonNull
{ public abstract Object toRecord();
return id;
} public abstract void undo();
} }

@ -21,14 +21,13 @@ package org.isoron.uhabits.commands;
import android.support.annotation.*; import android.support.annotation.*;
import com.google.gson.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*; import org.json.*;
import java.util.*;
public class CommandParser public class CommandParser
{ {
private HabitList habitList; private HabitList habitList;
private ModelFactory modelFactory; private ModelFactory modelFactory;
@ -41,65 +40,43 @@ public class CommandParser
} }
@NonNull @NonNull
public static LinkedList<Habit> habitListFromJSON( public Command parse(@NonNull JSONObject json) throws JSONException
@NonNull HabitList habitList, @NonNull JSONArray habitIds)
throws JSONException
{
LinkedList<Habit> 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<Habit> habits)
{
JSONArray habitIds = new JSONArray();
for (Habit h : habits) habitIds.put(h.getId());
return habitIds;
}
@NonNull
public Command fromJSON(@NonNull JSONObject json) throws JSONException
{ {
switch (json.getString("event")) String event = json.getString("event");
{ Gson gson = new GsonBuilder().create();
case "ToggleRepetition":
return ToggleRepetitionCommand.fromJSON(json, habitList);
case "ArchiveHabits": if (event.equals("Archive")) return gson
return ArchiveHabitsCommand.fromJSON(json, habitList); .fromJson(json.toString(), ArchiveHabitsCommand.Record.class)
.toCommand(habitList);
case "UnarchiveHabits": if (event.equals("ChangeColor")) return gson
return UnarchiveHabitsCommand.fromJSON(json, habitList); .fromJson(json.toString(), ChangeHabitColorCommand.Record.class)
.toCommand(habitList);
case "ChangeHabitColor": if (event.equals("CreateHabit")) return gson
return ChangeHabitColorCommand.fromJSON(json, habitList); .fromJson(json.toString(), CreateHabitCommand.Record.class)
.toCommand(modelFactory, habitList);
case "CreateHabit": if (event.equals("CreateRep")) return gson
return CreateHabitCommand.fromJSON(json, habitList, .fromJson(json.toString(), CreateRepetitionCommand.Record.class)
modelFactory); .toCommand(habitList);
case "DeleteHabits": if (event.equals("DeleteHabit")) return gson
return DeleteHabitsCommand.fromJSON(json, habitList); .fromJson(json.toString(), DeleteHabitsCommand.Record.class)
.toCommand(habitList);
case "EditHabit": if (event.equals("EditHabit")) return gson
return EditHabitCommand.fromJSON(json, habitList, modelFactory); .fromJson(json.toString(), EditHabitCommand.Record.class)
.toCommand(modelFactory, habitList);
// TODO: Implement this if (event.equals("Toggle")) return gson
// case "ReorderHabit": .fromJson(json.toString(), ToggleRepetitionCommand.Record.class)
// return ReorderHabitCommand.fromJSON(json); .toCommand(habitList);
} if (event.equals("Unarchive")) return gson
.fromJson(json.toString(), UnarchiveHabitsCommand.Record.class)
.toCommand(habitList);
return null; throw new IllegalStateException("Unknown command");
} }
} }

@ -25,7 +25,6 @@ import com.google.auto.factory.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*;
/** /**
* Command to create a habit. * Command to create a habit.
@ -33,54 +32,25 @@ import org.json.*;
@AutoFactory @AutoFactory
public class CreateHabitCommand extends Command public class CreateHabitCommand extends Command
{ {
private ModelFactory modelFactory; ModelFactory modelFactory;
HabitList habitList; HabitList habitList;
@NonNull @NonNull
private Habit model; Habit model;
@Nullable @Nullable
private Long savedId; Long savedId;
public CreateHabitCommand(@Provided @NonNull ModelFactory modelFactory, public CreateHabitCommand(@Provided @NonNull ModelFactory modelFactory,
@NonNull HabitList habitList, @NonNull HabitList habitList,
@NonNull Habit model) @NonNull Habit model)
{ {
super();
this.modelFactory = modelFactory; this.modelFactory = modelFactory;
this.habitList = habitList; this.habitList = habitList;
this.model = model; 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 @Override
public void execute() public void execute()
{ {
@ -104,30 +74,55 @@ public class CreateHabitCommand extends Command
return R.string.toast_habit_deleted; return R.string.toast_habit_deleted;
} }
@NonNull
@Override @Override
public JSONObject toJSON() public Record toRecord()
{ {
try return new Record(this);
{
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());
}
} }
@Override @Override
public void undo() public void undo()
{ {
if (savedId == null) throw new IllegalStateException();
Habit habit = habitList.getById(savedId); Habit habit = habitList.getById(savedId);
if (habit == null) throw new RuntimeException("Habit not found"); if (habit == null) throw new HabitNotFoundException();
habitList.remove(habit); 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;
}
}
} }

@ -29,15 +29,17 @@ import org.isoron.uhabits.models.*;
public class CreateRepetitionCommand extends Command public class CreateRepetitionCommand extends Command
{ {
@NonNull @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, public CreateRepetitionCommand(@NonNull Habit habit,
long timestamp, long timestamp,
@ -68,11 +70,57 @@ public class CreateRepetitionCommand extends Command
return habit; return habit;
} }
@Override
@NonNull
public Record toRecord()
{
return new Record(this);
}
@Override @Override
public void undo() public void undo()
{ {
if(newRep == null) throw new IllegalStateException();
habit.getRepetitions().remove(newRep); habit.getRepetitions().remove(newRep);
if (previousRep != null) habit.getRepetitions().add(previousRep); if (previousRep != null) habit.getRepetitions().add(previousRep);
habit.invalidateNewerThan(timestamp); 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;
}
}
} }

@ -23,56 +23,32 @@ import android.support.annotation.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*;
import java.util.*; 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. * Command to delete a list of habits.
*/ */
public class DeleteHabitsCommand extends Command public class DeleteHabitsCommand extends Command
{ {
HabitList habitList; @NonNull
final HabitList habitList;
private List<Habit> habits; @NonNull
final List<Habit> selected;
public DeleteHabitsCommand(@NonNull HabitList habitList, public DeleteHabitsCommand(@NonNull HabitList habitList,
@NonNull List<Habit> habits) @NonNull List<Habit> selected)
{
super();
this.habits = habits;
this.habitList = habitList;
}
public DeleteHabitsCommand(@NonNull String id,
@NonNull HabitList habitList,
@NonNull List<Habit> habits)
{ {
super(id); this.selected = new LinkedList<>(selected);
this.habits = habits;
this.habitList = habitList; 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<Habit> habits = habitListFromJSON(habitList, habitIds);
return new DeleteHabitsCommand(id, habitList, habits);
}
@Override @Override
public void execute() public void execute()
{ {
for (Habit h : habits) for (Habit h : selected)
habitList.remove(h); habitList.remove(h);
} }
@ -82,9 +58,9 @@ public class DeleteHabitsCommand extends Command
return R.string.toast_habit_deleted; return R.string.toast_habit_deleted;
} }
public List<Habit> getHabits() public List<Habit> getSelected()
{ {
return new LinkedList<>(habits); return Collections.unmodifiableList(selected);
} }
@Override @Override
@ -95,20 +71,9 @@ public class DeleteHabitsCommand extends Command
@Override @Override
@NonNull @NonNull
public JSONObject toJSON() public Record toRecord()
{ {
try return new Record(this);
{
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());
}
} }
@Override @Override
@ -116,4 +81,38 @@ public class DeleteHabitsCommand extends Command
{ {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public static class Record
{
@NonNull
public String id;
@NonNull
public String event = "DeleteHabit";
@NonNull
public List<Long> 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<Habit> 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;
}
}
} }

@ -25,7 +25,6 @@ import com.google.auto.factory.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*;
/** /**
* Command to modify a habit. * Command to modify a habit.
@ -33,52 +32,43 @@ import org.json.*;
@AutoFactory @AutoFactory
public class EditHabitCommand extends Command 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, public EditHabitCommand(@Provided @NonNull ModelFactory modelFactory,
@NonNull HabitList habitList, @NonNull HabitList habitList,
@NonNull Habit original, @NonNull Habit original,
@NonNull Habit modified) @NonNull Habit modified)
{ {
super(); Long habitId = original.getId();
init(modelFactory, habitList, original, modified); if (habitId == null) throw new RuntimeException("Habit not saved");
}
public EditHabitCommand(@Provided @NonNull ModelFactory modelFactory, this.savedId = habitId;
@NonNull String id, this.habitList = habitList;
@NonNull HabitList habitList, this.modified = modelFactory.buildHabit();
@NonNull Habit original, this.original = modelFactory.buildHabit();
@NonNull Habit modified)
{
super(id);
init(modelFactory, habitList, original, modified);
}
@NonNull this.modified.copyFrom(modified);
public static Command fromJSON(@NonNull JSONObject root, this.original.copyFrom(original);
@NonNull HabitList habitList,
@NonNull ModelFactory modelFactory) Frequency originalFreq = this.original.getFrequency();
throws JSONException Frequency modifiedFreq = this.modified.getFrequency();
{ hasFrequencyChanged = (!originalFreq.equals(modifiedFreq));
String commandId = root.getString("id"); hasTargetChanged =
JSONObject data = (JSONObject) root.get("data"); (original.getTargetType() != modified.getTargetType() ||
Habit original = habitList.getById(data.getLong("id")); original.getTargetValue() != modified.getTargetValue());
if (original == null) throw new HabitNotFoundException();
Habit modified =
Habit.fromJSON(data.getJSONObject("params"), modelFactory);
return new EditHabitCommand(modelFactory, commandId, habitList,
original, modified);
} }
@Override @Override
@ -99,22 +89,11 @@ public class EditHabitCommand extends Command
return R.string.toast_habit_changed_back; return R.string.toast_habit_changed_back;
} }
@NonNull
@Override @Override
public JSONObject toJSON() public Record toRecord()
{ {
try return new Record(this);
{
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());
}
} }
@Override @Override
@ -131,33 +110,44 @@ public class EditHabitCommand extends Command
habit.copyFrom(model); habit.copyFrom(model);
habitList.update(habit); habitList.update(habit);
invalidateIfNeeded(habit); if (hasFrequencyChanged || hasTargetChanged)
habit.invalidateNewerThan(0);
} }
private void init(@NonNull ModelFactory modelFactory, public static class Record
@NonNull HabitList habitList,
@NonNull Habit original,
@NonNull Habit modified)
{ {
this.habitList = habitList; @NonNull
this.savedId = original.getId(); public String id;
this.modified = modelFactory.buildHabit();
this.original = modelFactory.buildHabit();
this.modified.copyFrom(modified); @NonNull
this.original.copyFrom(original); public String event = "EditHabit";
Frequency originalFreq = this.original.getFrequency(); @NonNull
Frequency modifiedFreq = this.modified.getFrequency(); public Habit.HabitData habit;
hasFrequencyChanged = (!originalFreq.equals(modifiedFreq));
hasTargetChanged =
(original.getTargetType() != modified.getTargetType() ||
original.getTargetValue() != modified.getTargetValue());
}
private void invalidateIfNeeded(Habit habit) public long habitId;
{
if (hasFrequencyChanged || hasTargetChanged) public Record(EditHabitCommand command)
habit.invalidateNewerThan(0); {
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;
}
} }
} }

@ -22,16 +22,16 @@ package org.isoron.uhabits.commands;
import android.support.annotation.*; import android.support.annotation.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*;
/** /**
* Command to toggle a repetition. * Command to toggle a repetition.
*/ */
public class ToggleRepetitionCommand extends Command 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) public ToggleRepetitionCommand(@NonNull Habit habit, long timestamp)
{ {
@ -40,37 +40,13 @@ public class ToggleRepetitionCommand extends Command
this.habit = habit; 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 @Override
public void execute() public void execute()
{ {
habit.getRepetitions().toggleTimestamp(timestamp); habit.getRepetitions().toggleTimestamp(timestamp);
} }
@NonNull
public Habit getHabit() public Habit getHabit()
{ {
return habit; return habit;
@ -78,21 +54,9 @@ public class ToggleRepetitionCommand extends Command
@Override @Override
@NonNull @NonNull
public JSONObject toJSON() public Record toRecord()
{ {
try return new Record(this);
{
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());
}
} }
@Override @Override
@ -100,4 +64,38 @@ public class ToggleRepetitionCommand extends Command
{ {
execute(); 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;
}
}
} }

@ -23,56 +23,32 @@ import android.support.annotation.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.json.*;
import java.util.*; import java.util.*;
import static org.isoron.uhabits.commands.CommandParser.*;
/** /**
* Command to unarchive a list of habits. * Command to unarchive a list of habits.
*/ */
public class UnarchiveHabitsCommand extends Command public class UnarchiveHabitsCommand extends Command
{ {
HabitList habitList; @NonNull
final HabitList habitList;
private List<Habit> habits; @NonNull
final List<Habit> selected;
public UnarchiveHabitsCommand(@NonNull HabitList habitList, public UnarchiveHabitsCommand(@NonNull HabitList habitList,
@NonNull List<Habit> selected) @NonNull List<Habit> selected)
{ {
super(); this.selected = new LinkedList<>(selected);
this.habits = selected;
this.habitList = habitList;
}
public UnarchiveHabitsCommand(@NonNull String id,
@NonNull HabitList habitList,
@NonNull List<Habit> selected)
{
super(id);
this.habits = selected;
this.habitList = habitList; 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<Habit> selected = habitListFromJSON(habitList, habitIds);
return new UnarchiveHabitsCommand(id, habitList, selected);
}
@Override @Override
public void execute() public void execute()
{ {
for (Habit h : habits) h.setArchived(false); for (Habit h : selected) h.setArchived(false);
habitList.update(habits); habitList.update(selected);
} }
@Override @Override
@ -89,27 +65,50 @@ public class UnarchiveHabitsCommand extends Command
@Override @Override
@NonNull @NonNull
public JSONObject toJSON() public Record toRecord()
{ {
try return new Record(this);
{
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());
}
} }
@Override @Override
public void undo() public void undo()
{ {
for (Habit h : habits) h.setArchived(true); for (Habit h : selected) h.setArchived(true);
habitList.update(habits); habitList.update(selected);
} }
public static class Record
{
@NonNull
public final String id;
@NonNull
public final String event = "Unarchive";
@NonNull
public final List<Long> 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<Habit> 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;
}
}
} }

@ -23,12 +23,12 @@ import android.net.*;
import android.support.annotation.*; import android.support.annotation.*;
import org.apache.commons.lang3.builder.*; import org.apache.commons.lang3.builder.*;
import org.json.*;
import java.util.*; import java.util.*;
import javax.inject.*; import javax.inject.*;
import static android.R.attr.*;
import static org.isoron.uhabits.models.Checkmark.*; import static org.isoron.uhabits.models.Checkmark.*;
/** /**
@ -48,20 +48,10 @@ public class Habit
public static final int YES_NO_HABIT = 0; public static final int YES_NO_HABIT = 0;
@Nullable @Nullable
private Long id; public Long id;
@NonNull @NonNull
private String name; private HabitData data;
@NonNull
private String description;
@NonNull
private Frequency frequency;
private int color;
private boolean archived;
@NonNull @NonNull
private StreakList streaks; private StreakList streaks;
@ -69,28 +59,16 @@ public class Habit
@NonNull @NonNull
private ScoreList scores; private ScoreList scores;
private int targetType;
private double targetValue;
private int type;
@NonNull @NonNull
private RepetitionList repetitions; private RepetitionList repetitions;
@NonNull @NonNull
private CheckmarkList checkmarks; private CheckmarkList checkmarks;
@NonNull
private String unit;
@Nullable
private Reminder reminder;
private ModelObservable observable = new ModelObservable(); private ModelObservable observable = new ModelObservable();
/** /**
* Constructs a habit with default attributes. * Constructs a habit with default data.
* <p> * <p>
* The habit is not archived, not highlighted, has no reminders and is * The habit is not archived, not highlighted, has no reminders and is
* placed in the last position of the list of habits. * placed in the last position of the list of habits.
@ -98,16 +76,16 @@ public class Habit
@Inject @Inject
Habit(@NonNull ModelFactory factory) Habit(@NonNull ModelFactory factory)
{ {
this.color = 5; this.data = new HabitData();
this.archived = false; checkmarks = factory.buildCheckmarkList(this);
this.frequency = new Frequency(3, 7); streaks = factory.buildStreakList(this);
this.type = YES_NO_HABIT; scores = factory.buildScoreList(this);
this.name = ""; repetitions = factory.buildRepetitionList(this);
this.description = ""; }
this.targetType = AT_LEAST;
this.targetValue = 100;
this.unit = "";
Habit(@NonNull ModelFactory factory, @NonNull HabitData data)
{
this.data = new HabitData(data);
checkmarks = factory.buildCheckmarkList(this); checkmarks = factory.buildCheckmarkList(this);
streaks = factory.buildStreakList(this); streaks = factory.buildStreakList(this);
scores = factory.buildScoreList(this); scores = factory.buildScoreList(this);
@ -119,7 +97,7 @@ public class Habit
*/ */
public void clearReminder() public void clearReminder()
{ {
reminder = null; data.reminder = null;
observable.notifyListeners(); observable.notifyListeners();
} }
@ -130,16 +108,7 @@ public class Habit
*/ */
public void copyFrom(@NonNull Habit model) public void copyFrom(@NonNull Habit model)
{ {
this.name = model.getName(); this.data = new HabitData(model.data);
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;
observable.notifyListeners(); observable.notifyListeners();
} }
@ -163,41 +132,34 @@ public class Habit
@NonNull @NonNull
public Integer getColor() public Integer getColor()
{ {
return color; return data.color;
}
public boolean isCompletedToday()
{
int todayCheckmark = getCheckmarks().getTodayValue();
if (isNumerical()) return todayCheckmark >= targetValue;
else return (todayCheckmark != UNCHECKED);
} }
public void setColor(@NonNull Integer color) public void setColor(@NonNull Integer color)
{ {
this.color = color; data.color = color;
} }
@NonNull @NonNull
public String getDescription() public String getDescription()
{ {
return description; return data.description;
} }
public void setDescription(@NonNull String description) public void setDescription(@NonNull String description)
{ {
this.description = description; data.description = description;
} }
@NonNull @NonNull
public Frequency getFrequency() public Frequency getFrequency()
{ {
return frequency; return data.frequency;
} }
public void setFrequency(@NonNull Frequency frequency) public void setFrequency(@NonNull Frequency frequency)
{ {
this.frequency = frequency; data.frequency = frequency;
} }
@Nullable @Nullable
@ -214,12 +176,12 @@ public class Habit
@NonNull @NonNull
public String getName() public String getName()
{ {
return name; return data.name;
} }
public void setName(@NonNull String name) public void setName(@NonNull String name)
{ {
this.name = name; data.name = name;
} }
public ModelObservable getObservable() public ModelObservable getObservable()
@ -240,13 +202,13 @@ public class Habit
@NonNull @NonNull
public Reminder getReminder() public Reminder getReminder()
{ {
if (reminder == null) throw new IllegalStateException(); if (data.reminder == null) throw new IllegalStateException();
return reminder; return data.reminder;
} }
public void setReminder(@Nullable Reminder reminder) public void setReminder(@Nullable Reminder reminder)
{ {
this.reminder = reminder; data.reminder = reminder;
} }
@NonNull @NonNull
@ -269,30 +231,30 @@ public class Habit
public int getTargetType() public int getTargetType()
{ {
return targetType; return data.targetType;
} }
public void setTargetType(int targetType) public void setTargetType(int targetType)
{ {
if (targetType != AT_LEAST && targetType != AT_MOST) if (targetType != AT_LEAST && targetType != AT_MOST)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.targetType = targetType; data.targetType = targetType;
} }
public double getTargetValue() public double getTargetValue()
{ {
return targetValue; return data.targetValue;
} }
public void setTargetValue(double targetValue) public void setTargetValue(double targetValue)
{ {
if(targetValue < 0) throw new IllegalArgumentException(); if (targetValue < 0) throw new IllegalArgumentException();
this.targetValue = targetValue; data.targetValue = targetValue;
} }
public int getType() public int getType()
{ {
return type; return data.type;
} }
public void setType(int type) public void setType(int type)
@ -300,18 +262,18 @@ public class Habit
if (type != YES_NO_HABIT && type != NUMBER_HABIT) if (type != YES_NO_HABIT && type != NUMBER_HABIT)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.type = type; data.type = type;
} }
@NonNull @NonNull
public String getUnit() public String getUnit()
{ {
return unit; return data.unit;
} }
public void setUnit(@NonNull String unit) public void setUnit(@NonNull String unit)
{ {
this.unit = unit; data.unit = unit;
} }
/** /**
@ -325,6 +287,11 @@ public class Habit
return Uri.parse(s); return Uri.parse(s);
} }
public boolean hasId()
{
return getId() != null;
}
/** /**
* Returns whether the habit has a reminder. * Returns whether the habit has a reminder.
* *
@ -332,7 +299,7 @@ public class Habit
*/ */
public boolean hasReminder() public boolean hasReminder()
{ {
return reminder != null; return data.reminder != null;
} }
public void invalidateNewerThan(long timestamp) public void invalidateNewerThan(long timestamp)
@ -344,12 +311,19 @@ public class Habit
public boolean isArchived() public boolean isArchived()
{ {
return archived; return data.archived;
} }
public void setArchived(boolean 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() public boolean isNumerical()
@ -357,79 +331,120 @@ public class Habit
return type == NUMBER_HABIT; return type == NUMBER_HABIT;
} }
@Override public HabitData getData()
public String toString()
{ {
return new ToStringBuilder(this) return new HabitData(data);
.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();
} }
@NonNull public static class HabitData
public JSONObject toJSON()
{ {
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(); this.color = 5;
json.put("name", name); this.archived = false;
json.put("description", description); this.frequency = new Frequency(3, 7);
json.put("freqNum", frequency.getNumerator()); this.type = YES_NO_HABIT;
json.put("freqDen", frequency.getDenominator()); this.name = "";
json.put("color", color); this.description = "";
json.put("type", type); this.targetType = AT_LEAST;
json.put("targetType", targetType); this.targetValue = 100;
json.put("targetValue", targetValue); this.unit = "";
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;
} }
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 @Override
public static Habit fromJSON(@NonNull JSONObject json, public String toString()
@NonNull ModelFactory modelFactory) {
throws JSONException return new ToStringBuilder(this)
{ .append("name", name)
Habit habit = modelFactory.buildHabit(); .append("description", description)
habit.name = json.getString("name"); .append("frequency", frequency)
habit.description = json.getString("description"); .append("color", color)
int freqNum = json.getInt("freqNum"); .append("archived", archived)
int freqDen = json.getInt("freqDen"); .append("targetType", targetType)
habit.frequency = new Frequency(freqNum, freqDen); .append("targetValue", targetValue)
habit.color = json.getInt("color"); .append("type", type)
habit.archived = json.getBoolean("archived"); .append("unit", unit)
habit.targetValue = json.getInt("targetValue"); .append("reminder", reminder)
habit.targetType = json.getInt("targetType"); .toString();
habit.unit = json.getString("unit"); }
habit.type = json.getInt("type");
@Override
if(json.has("reminderHour")) 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"); return new HashCodeBuilder(17, 37)
int min = json.getInt("reminderMin"); .append(name)
int days = json.getInt("reminderDays"); .append(description)
habit.reminder = new Reminder(hour, min, new WeekdayList(days)); .append(frequency)
.append(color)
.append(archived)
.append(targetType)
.append(targetValue)
.append(type)
.append(unit)
.append(reminder)
.toHashCode();
} }
return habit;
} }
} }

@ -32,6 +32,11 @@ public interface ModelFactory
return new Habit(this); return new Habit(this);
} }
default Habit buildHabit(Habit.HabitData data)
{
return new Habit(this, data);
}
HabitList buildHabitList(); HabitList buildHabitList();
RepetitionList buildRepetitionList(Habit habit); RepetitionList buildRepetitionList(Habit habit);

@ -102,7 +102,7 @@ public class NotificationTray
if (command instanceof DeleteHabitsCommand) if (command instanceof DeleteHabitsCommand)
{ {
DeleteHabitsCommand deleteCommand = (DeleteHabitsCommand) command; DeleteHabitsCommand deleteCommand = (DeleteHabitsCommand) command;
List<Habit> deleted = deleteCommand.getHabits(); List<Habit> deleted = deleteCommand.getSelected();
for (Habit habit : deleted) for (Habit habit : deleted)
cancel(habit); cancel(habit);
} }

@ -141,9 +141,7 @@ public class SyncManager
public void postCommand(Command command) public void postCommand(Command command)
{ {
JSONObject msg = command.toJSON(); JSONObject msg = command.toJson();
if (msg == null) return;
Long now = new Date().getTime(); Long now = new Date().getTime();
Event e = new Event(command.getId(), now, msg.toString()); Event e = new Event(command.getId(), now, msg.toString());
e.save(); e.save();
@ -293,7 +291,7 @@ public class SyncManager
private void executeCommand(JSONObject root) throws JSONException private void executeCommand(JSONObject root) throws JSONException
{ {
Command received = commandParser.fromJSON(root); Command received = commandParser.parse(root);
for (Event e : pendingConfirmation) for (Event e : pendingConfirmation)
{ {
if (e.serverId.equals(received.getId())) if (e.serverId.equals(received.getId()))

@ -26,11 +26,13 @@ import org.junit.*;
import java.util.*; import java.util.*;
import static junit.framework.Assert.*; import static junit.framework.Assert.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
public class ArchiveHabitsCommandTest extends BaseUnitTest public class ArchiveHabitsCommandTest extends BaseUnitTest
{ {
private ArchiveHabitsCommand command; private ArchiveHabitsCommand command;
private Habit habit; private Habit habit;
@Override @Override
@ -40,8 +42,10 @@ public class ArchiveHabitsCommandTest extends BaseUnitTest
super.setUp(); super.setUp();
habit = fixtures.createShortHabit(); habit = fixtures.createShortHabit();
command = new ArchiveHabitsCommand(habitList, Collections habitList.add(habit);
.singletonList(habit));
command = new ArchiveHabitsCommand(habitList,
Collections.singletonList(habit));
} }
@Test @Test
@ -58,4 +62,13 @@ public class ArchiveHabitsCommandTest extends BaseUnitTest
command.execute(); command.execute();
assertTrue(habit.isArchived()); 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()));
}
} }

@ -32,7 +32,7 @@ public class ChangeHabitColorCommandTest extends BaseUnitTest
{ {
private ChangeHabitColorCommand command; private ChangeHabitColorCommand command;
private LinkedList<Habit> habits; private LinkedList<Habit> selected;
@Override @Override
@Before @Before
@ -40,16 +40,17 @@ public class ChangeHabitColorCommandTest extends BaseUnitTest
{ {
super.setUp(); super.setUp();
habits = new LinkedList<>(); selected = new LinkedList<>();
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
Habit habit = fixtures.createShortHabit(); Habit habit = fixtures.createShortHabit();
habit.setColor(i + 1); 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 @Test
@ -67,16 +68,26 @@ public class ChangeHabitColorCommandTest extends BaseUnitTest
checkNewColors(); 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() private void checkNewColors()
{ {
for (Habit h : habits) for (Habit h : selected)
assertThat(h.getColor(), equalTo(0)); assertThat(h.getColor(), equalTo(0));
} }
private void checkOriginalColors() private void checkOriginalColors()
{ {
int k = 0; int k = 0;
for (Habit h : habits) for (Habit h : selected)
assertThat(h.getColor(), equalTo(++k)); assertThat(h.getColor(), equalTo(++k));
} }
} }

@ -0,0 +1,159 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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<Habit> 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));
}
}

@ -41,6 +41,7 @@ public class CreateHabitCommandTest extends BaseUnitTest
model = fixtures.createEmptyHabit(); model = fixtures.createEmptyHabit();
model.setName("New habit"); model.setName("New habit");
model.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
command = new CreateHabitCommand(modelFactory, habitList, model); command = new CreateHabitCommand(modelFactory, habitList, model);
} }
@ -70,5 +71,16 @@ public class CreateHabitCommandTest extends BaseUnitTest
assertThat(habit.getName(), equalTo(model.getName())); 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()));
}
} }

@ -25,11 +25,12 @@ import org.isoron.uhabits.utils.*;
import org.junit.*; import org.junit.*;
import static junit.framework.Assert.*; 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; import static org.isoron.uhabits.models.Checkmark.CHECKED_EXPLICITLY;
public class CreateRepetitionCommandTest extends BaseUnitTest public class CreateRepetitionCommandTest extends BaseUnitTest
{ {
private CreateRepetitionCommand command; private CreateRepetitionCommand command;
private Habit habit; private Habit habit;
@ -43,6 +44,7 @@ public class CreateRepetitionCommandTest extends BaseUnitTest
super.setUp(); super.setUp();
habit = fixtures.createShortHabit(); habit = fixtures.createShortHabit();
habitList.add(habit);
today = DateUtils.getStartOfToday(); today = DateUtils.getStartOfToday();
command = new CreateRepetitionCommand(habit, today, 100); command = new CreateRepetitionCommand(habit, today, 100);
@ -67,4 +69,16 @@ public class CreateRepetitionCommandTest extends BaseUnitTest
assertNotNull(rep); assertNotNull(rep);
assertEquals(CHECKED_EXPLICITLY, rep.getValue()); 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));
}
} }

@ -73,4 +73,13 @@ public class DeleteHabitsCommandTest extends BaseUnitTest
thrown.expect(UnsupportedOperationException.class); thrown.expect(UnsupportedOperationException.class);
command.undo(); 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));
}
} }

@ -28,7 +28,6 @@ import static org.hamcrest.Matchers.*;
public class EditHabitCommandTest extends BaseUnitTest public class EditHabitCommandTest extends BaseUnitTest
{ {
private EditHabitCommand command; private EditHabitCommand command;
private Habit habit; private Habit habit;
@ -98,4 +97,19 @@ public class EditHabitCommandTest extends BaseUnitTest
assertThat(habit.getScores().getTodayValue(), assertThat(habit.getScores().getTodayValue(),
lessThan(originalScore)); 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()));
}
} }

@ -25,6 +25,8 @@ import org.isoron.uhabits.utils.*;
import org.junit.*; import org.junit.*;
import static junit.framework.Assert.*; import static junit.framework.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
public class ToggleRepetitionCommandTest extends BaseUnitTest public class ToggleRepetitionCommandTest extends BaseUnitTest
{ {
@ -40,6 +42,7 @@ public class ToggleRepetitionCommandTest extends BaseUnitTest
super.setUp(); super.setUp();
habit = fixtures.createShortHabit(); habit = fixtures.createShortHabit();
habitList.add(habit);
today = DateUtils.getStartOfToday(); today = DateUtils.getStartOfToday();
command = new ToggleRepetitionCommand(habit, today); command = new ToggleRepetitionCommand(habit, today);
@ -59,4 +62,15 @@ public class ToggleRepetitionCommandTest extends BaseUnitTest
command.execute(); command.execute();
assertFalse(habit.getRepetitions().containsTimestamp(today)); 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));
}
} }

@ -26,6 +26,8 @@ import org.junit.*;
import java.util.*; import java.util.*;
import static junit.framework.Assert.*; import static junit.framework.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
public class UnarchiveHabitsCommandTest extends BaseUnitTest public class UnarchiveHabitsCommandTest extends BaseUnitTest
{ {
@ -61,4 +63,13 @@ public class UnarchiveHabitsCommandTest extends BaseUnitTest
command.execute(); command.execute();
assertFalse(habit.isArchived()); 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()));
}
} }

Loading…
Cancel
Save