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);
}
@NonNull
@Override
public Record toRecord()
{ {
JSONObject root = super.toJSON(); return new Record(this);
JSONObject data = root.getJSONObject("data");
root.put("event", "ArchiveHabits");
data.put("ids", habitListToJSON(selectedHabits));
return root;
} }
catch (JSONException e)
public static class Record
{
@NonNull
public final String id;
@NonNull
public final String event = "Archive";
@NonNull
public final List<Long> habits;
public Record(@NonNull ArchiveHabitsCommand command)
{ {
throw new RuntimeException(e.getMessage()); id = command.getId();
habits = new LinkedList<>();
for (Habit h : command.selected)
{
habits.add(h.getId());
} }
} }
@Override @NonNull
public void undo() public ArchiveHabitsCommand toCommand(@NonNull HabitList habitList)
{ {
for (Habit h : selectedHabits) h.setArchived(false); List<Habit> selected = new LinkedList<>();
habitList.update(selectedHabits); 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
{
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 @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(); String event = json.getString("event");
for (Habit h : habits) habitIds.put(h.getId()); Gson gson = new GsonBuilder().create();
return habitIds;
}
@NonNull if (event.equals("Archive")) return gson
public Command fromJSON(@NonNull JSONObject json) throws JSONException .fromJson(json.toString(), ArchiveHabitsCommand.Record.class)
{ .toCommand(habitList);
switch (json.getString("event"))
{
case "ToggleRepetition":
return ToggleRepetitionCommand.fromJSON(json, habitList);
case "ArchiveHabits": if (event.equals("ChangeColor")) return gson
return ArchiveHabitsCommand.fromJSON(json, habitList); .fromJson(json.toString(), ChangeHabitColorCommand.Record.class)
.toCommand(habitList);
case "UnarchiveHabits": if (event.equals("CreateHabit")) return gson
return UnarchiveHabitsCommand.fromJSON(json, habitList); .fromJson(json.toString(), CreateHabitCommand.Record.class)
.toCommand(modelFactory, habitList);
case "ChangeHabitColor": if (event.equals("CreateRep")) return gson
return ChangeHabitColorCommand.fromJSON(json, habitList); .fromJson(json.toString(), CreateRepetitionCommand.Record.class)
.toCommand(habitList);
case "CreateHabit": if (event.equals("DeleteHabit")) return gson
return CreateHabitCommand.fromJSON(json, habitList, .fromJson(json.toString(), DeleteHabitsCommand.Record.class)
modelFactory); .toCommand(habitList);
case "DeleteHabits": if (event.equals("EditHabit")) return gson
return DeleteHabitsCommand.fromJSON(json, habitList); .fromJson(json.toString(), EditHabitCommand.Record.class)
.toCommand(modelFactory, habitList);
case "EditHabit": if (event.equals("Toggle")) return gson
return EditHabitCommand.fromJSON(json, habitList, modelFactory); .fromJson(json.toString(), ToggleRepetitionCommand.Record.class)
.toCommand(habitList);
// TODO: Implement this if (event.equals("Unarchive")) return gson
// case "ReorderHabit": .fromJson(json.toString(), UnarchiveHabitsCommand.Record.class)
// return ReorderHabitCommand.fromJSON(json); .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.selected = new LinkedList<>(selected);
this.habits = habits;
this.habitList = habitList; this.habitList = habitList;
} }
public DeleteHabitsCommand(@NonNull String id,
@NonNull HabitList habitList,
@NonNull List<Habit> habits)
{
super(id);
this.habits = habits;
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,25 +71,48 @@ public class DeleteHabitsCommand extends Command
@Override @Override
@NonNull @NonNull
public JSONObject toJSON() public Record toRecord()
{ {
try return new Record(this);
}
@Override
public void undo()
{ {
JSONObject root = super.toJSON(); throw new UnsupportedOperationException();
JSONObject data = root.getJSONObject("data");
root.put("event", "DeleteHabits");
data.put("ids", habitListToJSON(habits));
return root;
} }
catch (JSONException e)
public static class Record
{ {
throw new RuntimeException(e.getMessage()); @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());
} }
} }
@Override public DeleteHabitsCommand toCommand(@NonNull HabitList habitList)
public void undo()
{ {
throw new UnsupportedOperationException(); 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)
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 = Frequency originalFreq = this.original.getFrequency();
Habit.fromJSON(data.getJSONObject("params"), modelFactory); Frequency modifiedFreq = this.modified.getFrequency();
return new EditHabitCommand(modelFactory, commandId, habitList, hasFrequencyChanged = (!originalFreq.equals(modifiedFreq));
original, modified); hasTargetChanged =
(original.getTargetType() != modified.getTargetType() ||
original.getTargetValue() != modified.getTargetValue());
} }
@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
{ {
JSONObject root = super.toJSON(); return new Record(this);
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 = public long habitId;
(original.getTargetType() != modified.getTargetType() ||
original.getTargetValue() != modified.getTargetValue()); public Record(EditHabitCommand command)
{
id = command.getId();
this.habitId = command.savedId;
this.habit = command.modified.getData();
} }
private void invalidateIfNeeded(Habit habit) @NonNull
public EditHabitCommand toCommand(@NonNull ModelFactory modelFactory,
@NonNull HabitList habitList)
{ {
if (hasFrequencyChanged || hasTargetChanged) Habit original = habitList.getById(habitId);
habit.invalidateNewerThan(0); 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);
}
@Override
public void undo()
{ {
JSONObject root = super.toJSON(); for (Habit h : selected) h.setArchived(true);
JSONObject data = root.getJSONObject("data"); habitList.update(selected);
root.put("event", "UnarchiveHabits");
data.put("ids", habitListToJSON(habits));
return root;
} }
catch (JSONException e)
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)
{ {
throw new RuntimeException(e.getMessage()); if (!h.hasId()) throw new RuntimeException("Habit not saved");
habits.add(h.getId());
} }
} }
@Override @NonNull
public void undo() public UnarchiveHabitsCommand toCommand(@NonNull HabitList habitList)
{ {
for (Habit h : habits) h.setArchived(true); List<Habit> selected = new LinkedList<>();
habitList.update(habits); 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;
} }
public HabitData getData()
{
return new HabitData(data);
}
public static class HabitData
{
@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()
{
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 = "";
}
public HabitData(@NonNull HabitData model)
{
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;
}
@Override @Override
public String toString() public String toString()
{ {
return new ToStringBuilder(this) return new ToStringBuilder(this)
.append("id", id)
.append("name", name) .append("name", name)
.append("description", description) .append("description", description)
.append("frequency", frequency)
.append("color", color) .append("color", color)
.append("archived", archived) .append("archived", archived)
.append("type", type)
.append("targetType", targetType) .append("targetType", targetType)
.append("targetValue", targetValue) .append("targetValue", targetValue)
.append("type", type)
.append("unit", unit) .append("unit", unit)
.append("reminder", reminder)
.toString(); .toString();
} }
@NonNull @Override
public JSONObject toJSON() public boolean equals(Object o)
{
try
{ {
JSONObject json = new JSONObject(); if (this == o) return true;
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) if (o == null || getClass() != o.getClass()) return false;
{
json.put("reminderHour", reminder.getHour());
json.put("reminderMin", reminder.getMinute());
json.put("reminderDays", reminder.getDays().toInteger());
}
return json; HabitData habitData = (HabitData) o;
}
catch(JSONException e) return new EqualsBuilder()
{ .append(color, habitData.color)
throw new RuntimeException(e.getMessage()); .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();
} }
@NonNull @Override
public static Habit fromJSON(@NonNull JSONObject json, public int hashCode()
@NonNull ModelFactory modelFactory) {
throws JSONException return new HashCodeBuilder(17, 37)
{ .append(name)
Habit habit = modelFactory.buildHabit(); .append(description)
habit.name = json.getString("name"); .append(frequency)
habit.description = json.getString("description"); .append(color)
int freqNum = json.getInt("freqNum"); .append(archived)
int freqDen = json.getInt("freqDen"); .append(targetType)
habit.frequency = new Frequency(freqNum, freqDen); .append(targetValue)
habit.color = json.getInt("color"); .append(type)
habit.archived = json.getBoolean("archived"); .append(unit)
habit.targetValue = json.getInt("targetValue"); .append(reminder)
habit.targetType = json.getInt("targetType"); .toHashCode();
habit.unit = json.getString("unit"); }
habit.type = json.getInt("type");
if(json.has("reminderHour"))
{
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 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