mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Replace RepetitionList by Entries
This commit is contained in:
@@ -75,7 +75,7 @@ public class HabitFixtures
|
|||||||
81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120};
|
81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120};
|
||||||
|
|
||||||
for (int mark : marks)
|
for (int mark : marks)
|
||||||
habit.getOriginalEntries().setValue(today.minus(mark), YES_MANUAL);
|
habit.getOriginalEntries().add(new Entry(today.minus(mark), YES_MANUAL));
|
||||||
|
|
||||||
return habit;
|
return habit;
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ public class HabitFixtures
|
|||||||
582, 583, 584, 586, 589};
|
582, 583, 584, 586, 589};
|
||||||
|
|
||||||
for (int mark : marks)
|
for (int mark : marks)
|
||||||
habit.getOriginalEntries().setValue(today.minus(mark), YES_MANUAL);
|
habit.getOriginalEntries().add(new Entry(today.minus(mark), YES_MANUAL));
|
||||||
|
|
||||||
return habit;
|
return habit;
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ public class HabitFixtures
|
|||||||
Timestamp timestamp = DateUtils.getToday();
|
Timestamp timestamp = DateUtils.getToday();
|
||||||
for (int value : LONG_NUMERICAL_HABIT_ENTRIES)
|
for (int value : LONG_NUMERICAL_HABIT_ENTRIES)
|
||||||
{
|
{
|
||||||
habit.getOriginalEntries().setValue(timestamp, value);
|
habit.getOriginalEntries().add(new Entry(timestamp, value));
|
||||||
timestamp = timestamp.minus(1);
|
timestamp = timestamp.minus(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ public class HabitFixtures
|
|||||||
Timestamp timestamp = DateUtils.getToday();
|
Timestamp timestamp = DateUtils.getToday();
|
||||||
for (boolean c : LONG_HABIT_ENTRIES)
|
for (boolean c : LONG_HABIT_ENTRIES)
|
||||||
{
|
{
|
||||||
if (c) habit.getOriginalEntries().setValue(timestamp, YES_MANUAL);
|
if (c) habit.getOriginalEntries().add(new Entry(timestamp, YES_MANUAL));
|
||||||
timestamp = timestamp.minus(1);
|
timestamp = timestamp.minus(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ public class FrequencyChartTest extends BaseViewTest
|
|||||||
Habit habit = fixtures.createLongHabit();
|
Habit habit = fixtures.createLongHabit();
|
||||||
|
|
||||||
view = new FrequencyChart(targetContext);
|
view = new FrequencyChart(targetContext);
|
||||||
view.setFrequency(habit.getOriginalEntries().getWeekdayFrequency());
|
view.setFrequency(habit.getOriginalEntries().computeWeekdayFrequency(
|
||||||
|
habit.isNumerical()
|
||||||
|
));
|
||||||
view.setColor(PaletteUtilsKt.toFixedAndroidColor(habit.getColor()));
|
view.setColor(PaletteUtilsKt.toFixedAndroidColor(habit.getColor()));
|
||||||
measureView(view, dpToPixels(300), dpToPixels(100));
|
measureView(view, dpToPixels(300), dpToPixels(100));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ class FrequencyCardPresenter(
|
|||||||
) {
|
) {
|
||||||
fun present() = FrequencyCardViewModel(
|
fun present() = FrequencyCardViewModel(
|
||||||
color = habit.color,
|
color = habit.color,
|
||||||
frequency = habit.originalEntries.weekdayFrequency,
|
frequency = habit.originalEntries.computeWeekdayFrequency(
|
||||||
|
isNumerical = habit.isNumerical
|
||||||
|
),
|
||||||
firstWeekday = firstWeekday,
|
firstWeekday = firstWeekday,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@ import android.widget.*
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.isoron.uhabits.*
|
import org.isoron.uhabits.*
|
||||||
import org.isoron.uhabits.core.models.*
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
|
||||||
import org.isoron.uhabits.core.utils.*
|
import org.isoron.uhabits.core.utils.*
|
||||||
import org.isoron.uhabits.databinding.*
|
import org.isoron.uhabits.databinding.*
|
||||||
import org.isoron.uhabits.utils.*
|
import org.isoron.uhabits.utils.*
|
||||||
@@ -74,12 +75,16 @@ class OverviewCardPresenter(val habit: Habit) {
|
|||||||
val scoreToday = scores.todayValue.toFloat()
|
val scoreToday = scores.todayValue.toFloat()
|
||||||
val scoreLastMonth = scores.getValue(lastMonth).toFloat()
|
val scoreLastMonth = scores.getValue(lastMonth).toFloat()
|
||||||
val scoreLastYear = scores.getValue(lastYear).toFloat()
|
val scoreLastYear = scores.getValue(lastYear).toFloat()
|
||||||
|
val totalCount = habit.originalEntries.getKnown()
|
||||||
|
.filter { it.value == YES_MANUAL }
|
||||||
|
.count()
|
||||||
|
.toLong()
|
||||||
return@IO OverviewCardViewModel(
|
return@IO OverviewCardViewModel(
|
||||||
color = habit.color,
|
color = habit.color,
|
||||||
scoreToday = scoreToday,
|
scoreToday = scoreToday,
|
||||||
scoreMonthDiff = scoreToday - scoreLastMonth,
|
scoreMonthDiff = scoreToday - scoreLastMonth,
|
||||||
scoreYearDiff = scoreToday - scoreLastYear,
|
scoreYearDiff = scoreToday - scoreLastYear,
|
||||||
totalCount = habit.originalEntries.totalCount,
|
totalCount = totalCount,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ class FrequencyWidget(
|
|||||||
(widgetView.dataView as FrequencyChart).apply {
|
(widgetView.dataView as FrequencyChart).apply {
|
||||||
setFirstWeekday(firstWeekday)
|
setFirstWeekday(firstWeekday)
|
||||||
setColor(habit.color.toThemedAndroidColor(context))
|
setColor(habit.color.toThemedAndroidColor(context))
|
||||||
setFrequency(habit.originalEntries.weekdayFrequency)
|
setFrequency(habit.originalEntries.computeWeekdayFrequency(habit.isNumerical))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,8 +52,9 @@ public class CreateRepetitionCommand implements Command
|
|||||||
@Override
|
@Override
|
||||||
public void execute()
|
public void execute()
|
||||||
{
|
{
|
||||||
RepetitionList checks = habit.getOriginalEntries();
|
Entries checks = habit.getOriginalEntries();
|
||||||
checks.setValue(timestamp, value);
|
checks.add(new Entry(timestamp, value));
|
||||||
|
habit.invalidateNewerThan(Timestamp.ZERO);
|
||||||
habitList.resort();
|
habitList.resort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public class HabitBullCSVImporter extends AbstractImporter
|
|||||||
map.put(name, h);
|
map.put(name, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
h.getOriginalEntries().setValue(timestamp, YES_MANUAL);
|
h.getOriginalEntries().add(new Entry(timestamp, YES_MANUAL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,10 +244,10 @@ public class HabitsCSVExporter
|
|||||||
Timestamp newest = Timestamp.ZERO;
|
Timestamp newest = Timestamp.ZERO;
|
||||||
for (Habit h : selectedHabits)
|
for (Habit h : selectedHabits)
|
||||||
{
|
{
|
||||||
if(h.getOriginalEntries().getOldest() == null || h.getOriginalEntries().getNewest() == null)
|
List<Entry> entries = h.getOriginalEntries().getKnown();
|
||||||
continue;
|
if (entries.isEmpty()) continue;
|
||||||
Timestamp currOld = h.getOriginalEntries().getOldest().getTimestamp();
|
Timestamp currNew = entries.get(0).getTimestamp();
|
||||||
Timestamp currNew = h.getOriginalEntries().getNewest().getTimestamp();
|
Timestamp currOld = entries.get(entries.size() - 1).getTimestamp();
|
||||||
oldest = currOld.isOlderThan(oldest) ? currOld : oldest;
|
oldest = currOld.isOlderThan(oldest) ? currOld : oldest;
|
||||||
newest = currNew.isNewerThan(newest) ? currNew : newest;
|
newest = currNew.isNewerThan(newest) ? currNew : newest;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,10 +101,10 @@ public class LoopDBImporter extends AbstractImporter
|
|||||||
habitsRepository = new Repository<>(HabitRecord.class, db);
|
habitsRepository = new Repository<>(HabitRecord.class, db);
|
||||||
entryRepository = new Repository<>(EntryRecord.class, db);
|
entryRepository = new Repository<>(EntryRecord.class, db);
|
||||||
|
|
||||||
List<HabitRecord> records = habitsRepository.findAll("order by position");
|
List<HabitRecord> habitRecords = habitsRepository.findAll("order by position");
|
||||||
for (HabitRecord habitRecord : records)
|
for (HabitRecord habitRecord : habitRecords)
|
||||||
{
|
{
|
||||||
List<EntryRecord> reps =
|
List<EntryRecord> entryRecords =
|
||||||
entryRepository.findAll("where habit = ?",
|
entryRepository.findAll("where habit = ?",
|
||||||
habitRecord.id.toString());
|
habitRecord.id.toString());
|
||||||
|
|
||||||
@@ -127,11 +127,11 @@ public class LoopDBImporter extends AbstractImporter
|
|||||||
// Reload saved version of the habit
|
// Reload saved version of the habit
|
||||||
habit = habitList.getByUUID(habitRecord.uuid);
|
habit = habitList.getByUUID(habitRecord.uuid);
|
||||||
|
|
||||||
for (EntryRecord r : reps)
|
for (EntryRecord r : entryRecords)
|
||||||
{
|
{
|
||||||
Timestamp t = new Timestamp(r.timestamp);
|
Timestamp t = new Timestamp(r.timestamp);
|
||||||
Entry entry = habit.getOriginalEntries().getByTimestamp(t);
|
Entry existingEntry = habit.getOriginalEntries().get(t);
|
||||||
if (entry == null || entry.getValue() != r.value)
|
if (existingEntry.getValue() != r.value)
|
||||||
new CreateRepetitionCommand(habitList, habit, t, r.value).execute();
|
new CreateRepetitionCommand(habitList, habit, t, r.value).execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ public class RewireDBImporter extends AbstractImporter
|
|||||||
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
|
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
|
||||||
cal.set(year, month - 1, day);
|
cal.set(year, month - 1, day);
|
||||||
|
|
||||||
habit.getOriginalEntries().setValue(new Timestamp(cal), YES_MANUAL);
|
habit.getOriginalEntries().add(new Entry(new Timestamp(cal), YES_MANUAL));
|
||||||
} while (c.moveToNext());
|
} while (c.moveToNext());
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public class TickmateDBImporter extends AbstractImporter
|
|||||||
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
|
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
|
||||||
cal.set(year, month, day);
|
cal.set(year, month, day);
|
||||||
|
|
||||||
habit.getOriginalEntries().setValue(new Timestamp(cal), YES_MANUAL);
|
habit.getOriginalEntries().add(new Entry(new Timestamp(cal), YES_MANUAL));
|
||||||
} while (c.moveToNext());
|
} while (c.moveToNext());
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN
|
|||||||
import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO
|
import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO
|
||||||
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
|
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
|
||||||
import org.isoron.uhabits.core.utils.*
|
import org.isoron.uhabits.core.utils.*
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.HashMap
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
@@ -136,6 +138,42 @@ open class Entries {
|
|||||||
entriesByTimestamp.clear()
|
entriesByTimestamp.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total number of successful entries for each month, grouped by day of week.
|
||||||
|
* <p>
|
||||||
|
* The checkmarks are returned in a HashMap. The key is the timestamp for
|
||||||
|
* the first day of the month, at midnight (00:00). The value is an integer
|
||||||
|
* array with 7 entries. The first entry contains the total number of
|
||||||
|
* successful checkmarks during the specified month that occurred on a Saturday. The
|
||||||
|
* second entry corresponds to Sunday, and so on. If there are no
|
||||||
|
* successful checkmarks during a certain month, the value is null.
|
||||||
|
*
|
||||||
|
* @return total number of checkmarks by month versus day of week
|
||||||
|
*/
|
||||||
|
fun computeWeekdayFrequency(isNumerical: Boolean): HashMap<Timestamp, Array<Int>> {
|
||||||
|
val entries = getKnown()
|
||||||
|
val map = hashMapOf<Timestamp, Array<Int>>()
|
||||||
|
for ((originalTimestamp, value) in entries) {
|
||||||
|
val weekday = originalTimestamp.weekday
|
||||||
|
val truncatedTimestamp = Timestamp(originalTimestamp.toCalendar().apply {
|
||||||
|
set(Calendar.DAY_OF_MONTH, 1)
|
||||||
|
}.timeInMillis)
|
||||||
|
|
||||||
|
var list = map[truncatedTimestamp]
|
||||||
|
if (list == null) {
|
||||||
|
list = arrayOf(0, 0, 0, 0, 0, 0, 0)
|
||||||
|
map[truncatedTimestamp] = list
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumerical) {
|
||||||
|
list[weekday] += value
|
||||||
|
} else if (value == YES_MANUAL) {
|
||||||
|
list[weekday] += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
data class Interval(val begin: Timestamp, val center: Timestamp, val end: Timestamp) {
|
data class Interval(val begin: Timestamp, val center: Timestamp, val end: Timestamp) {
|
||||||
val length: Int
|
val length: Int
|
||||||
get() = begin.daysUntil(end) + 1;
|
get() = begin.daysUntil(end) + 1;
|
||||||
|
|||||||
@@ -182,8 +182,9 @@ public class EntryList
|
|||||||
@NonNull
|
@NonNull
|
||||||
public synchronized final int[] getAllValues()
|
public synchronized final int[] getAllValues()
|
||||||
{
|
{
|
||||||
Entry oldestOriginal = habit.getOriginalEntries().getOldest();
|
List<Entry> entries = habit.getOriginalEntries().getKnown();
|
||||||
if (oldestOriginal == null) return new int[0];
|
if(entries.isEmpty()) return new int[0];
|
||||||
|
Entry oldestOriginal = entries.get(entries.size() - 1);
|
||||||
|
|
||||||
Timestamp fromTimestamp = oldestOriginal.getTimestamp();
|
Timestamp fromTimestamp = oldestOriginal.getTimestamp();
|
||||||
Timestamp toTimestamp = DateUtils.getTodayWithOffset();
|
Timestamp toTimestamp = DateUtils.getTodayWithOffset();
|
||||||
@@ -365,16 +366,18 @@ public class EntryList
|
|||||||
if (newest != null && newest.getTimestamp().equals(today)) return;
|
if (newest != null && newest.getTimestamp().equals(today)) return;
|
||||||
invalidateNewerThan(Timestamp.ZERO);
|
invalidateNewerThan(Timestamp.ZERO);
|
||||||
|
|
||||||
Entry oldestRep = habit.getOriginalEntries().getOldest();
|
List<Entry> entries = habit.getOriginalEntries().getKnown();
|
||||||
if (oldestRep == null) return;
|
if(entries.isEmpty()) return;
|
||||||
final Timestamp from = oldestRep.getTimestamp();
|
final Timestamp from = entries.get(entries.size() - 1).getTimestamp();
|
||||||
|
|
||||||
if (from.isNewerThan(today)) return;
|
if (from.isNewerThan(today)) return;
|
||||||
|
|
||||||
Entry reps[] = habit
|
Entry[] reps = entries.stream().filter(e ->
|
||||||
.getOriginalEntries()
|
!e.getTimestamp().isOlderThan(from) && !e.getTimestamp().isNewerThan(today)
|
||||||
.getByInterval(from, today)
|
).toArray(Entry[]::new);
|
||||||
.toArray(new Entry[0]);
|
List<Entry> repsAsList = Arrays.asList(reps);
|
||||||
|
Collections.reverse(repsAsList);
|
||||||
|
reps = repsAsList.toArray(reps);
|
||||||
|
|
||||||
if (habit.isNumerical()) computeNumerical(reps);
|
if (habit.isNumerical()) computeNumerical(reps);
|
||||||
else computeYesNo(reps);
|
else computeYesNo(reps);
|
||||||
@@ -425,8 +428,9 @@ public class EntryList
|
|||||||
|
|
||||||
public List<Entry> getAll()
|
public List<Entry> getAll()
|
||||||
{
|
{
|
||||||
Entry oldest = habit.getOriginalEntries().getOldest();
|
List<Entry> entries = habit.getOriginalEntries().getKnown();
|
||||||
if (oldest == null) return new ArrayList<>();
|
if(entries.isEmpty()) return new ArrayList<>();
|
||||||
|
Entry oldest = entries.get(entries.size() - 1);
|
||||||
return getByInterval(oldest.getTimestamp(), DateUtils.getTodayWithOffset());
|
return getByInterval(oldest.getTimestamp(), DateUtils.getTodayWithOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,6 +460,9 @@ public class EntryList
|
|||||||
|
|
||||||
Interval(Timestamp begin, Timestamp center, Timestamp end)
|
Interval(Timestamp begin, Timestamp center, Timestamp end)
|
||||||
{
|
{
|
||||||
|
if(begin.isNewerThan(center)) throw new IllegalArgumentException();
|
||||||
|
if(center.isNewerThan(end)) throw new IllegalArgumentException();
|
||||||
|
|
||||||
this.begin = begin;
|
this.begin = begin;
|
||||||
this.center = center;
|
this.center = center;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ data class Habit(
|
|||||||
var unit: String = "",
|
var unit: String = "",
|
||||||
var uuid: String? = null,
|
var uuid: String? = null,
|
||||||
val computedEntries: EntryList,
|
val computedEntries: EntryList,
|
||||||
val originalEntries: RepetitionList,
|
val originalEntries: Entries,
|
||||||
val scores: ScoreList,
|
val scores: ScoreList,
|
||||||
val streaks: StreakList,
|
val streaks: StreakList,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -29,25 +29,23 @@ interface ModelFactory {
|
|||||||
|
|
||||||
fun buildHabit(): Habit {
|
fun buildHabit(): Habit {
|
||||||
val computedEntries = buildEntryList()
|
val computedEntries = buildEntryList()
|
||||||
val originalEntries = buildRepetitionList()
|
|
||||||
val scores = buildScoreList()
|
val scores = buildScoreList()
|
||||||
val streaks = buildStreakList()
|
val streaks = buildStreakList()
|
||||||
val habit = Habit(
|
val habit = Habit(
|
||||||
computedEntries = computedEntries,
|
computedEntries = computedEntries,
|
||||||
originalEntries = originalEntries,
|
|
||||||
scores = scores,
|
scores = scores,
|
||||||
streaks = streaks,
|
streaks = streaks,
|
||||||
|
originalEntries = buildOriginalEntries(),
|
||||||
)
|
)
|
||||||
computedEntries.setHabit(habit)
|
computedEntries.setHabit(habit)
|
||||||
originalEntries.setHabit(habit)
|
|
||||||
scores.setHabit(habit)
|
scores.setHabit(habit)
|
||||||
streaks.setHabit(habit)
|
streaks.setHabit(habit)
|
||||||
return habit
|
return habit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildOriginalEntries(): Entries
|
||||||
fun buildEntryList(): EntryList
|
fun buildEntryList(): EntryList
|
||||||
fun buildHabitList(): HabitList
|
fun buildHabitList(): HabitList
|
||||||
fun buildRepetitionList(): RepetitionList
|
|
||||||
fun buildScoreList(): ScoreList
|
fun buildScoreList(): ScoreList
|
||||||
fun buildStreakList(): StreakList
|
fun buildStreakList(): StreakList
|
||||||
fun buildHabitListRepository(): Repository<HabitRecord>
|
fun buildHabitListRepository(): Repository<HabitRecord>
|
||||||
|
|||||||
@@ -1,243 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.core.models;
|
|
||||||
|
|
||||||
import androidx.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.utils.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class RepetitionList
|
|
||||||
{
|
|
||||||
protected Habit habit;
|
|
||||||
|
|
||||||
private final ArrayList<Entry> list = new ArrayList<>();
|
|
||||||
|
|
||||||
public void setHabit(Habit habit)
|
|
||||||
{
|
|
||||||
this.habit = habit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a checkmark to the list.
|
|
||||||
* <p>
|
|
||||||
* Any implementation of this method must call observable.notifyListeners()
|
|
||||||
* after the checkmark has been added.
|
|
||||||
*
|
|
||||||
* @param entry the checkmark to be added.
|
|
||||||
*/
|
|
||||||
public void add(Entry entry)
|
|
||||||
{
|
|
||||||
list.add(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of checkmarks that happened within the given time
|
|
||||||
* interval.
|
|
||||||
* <p>
|
|
||||||
* The list is sorted by timestamp in increasing order. That is, the first
|
|
||||||
* element corresponds to oldest timestamp, while the last element
|
|
||||||
* corresponds to the newest. The endpoints of the interval are included.
|
|
||||||
*
|
|
||||||
* @param fromTimestamp timestamp of the beginning of the interval
|
|
||||||
* @param toTimestamp timestamp of the end of the interval
|
|
||||||
* @return list of checkmarks within given time interval
|
|
||||||
*/
|
|
||||||
public List<Entry> getByInterval(Timestamp fromTimestamp, Timestamp toTimestamp)
|
|
||||||
{
|
|
||||||
ArrayList<Entry> filtered = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Entry r : list)
|
|
||||||
{
|
|
||||||
Timestamp t = r.getTimestamp();
|
|
||||||
if (t.isOlderThan(fromTimestamp) || t.isNewerThan(toTimestamp)) continue;
|
|
||||||
filtered.add(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(filtered,
|
|
||||||
(r1, r2) -> r1.getTimestamp().compareTo(r2.getTimestamp()));
|
|
||||||
|
|
||||||
return filtered;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the checkmark that has the given timestamp, or null if none
|
|
||||||
* exists.
|
|
||||||
*
|
|
||||||
* @param timestamp the checkmark timestamp.
|
|
||||||
* @return the checkmark that has the given timestamp.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public Entry getByTimestamp(Timestamp timestamp)
|
|
||||||
{
|
|
||||||
for (Entry r : list)
|
|
||||||
if (r.getTimestamp().equals(timestamp)) return r;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a checkmark with the given timestamp exists, return its value. Otherwise, returns
|
|
||||||
* Checkmark.NO for boolean habits and zero for numerical habits.
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public int getValue(Timestamp timestamp)
|
|
||||||
{
|
|
||||||
Entry check = getByTimestamp(timestamp);
|
|
||||||
if (check == null) return Entry.UNKNOWN;
|
|
||||||
return check.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the oldest checkmark in the list.
|
|
||||||
* <p>
|
|
||||||
* If the list is empty, returns null. Repetitions in the future are
|
|
||||||
* discarded.
|
|
||||||
*
|
|
||||||
* @return oldest checkmark in the list, or null if list is empty.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public Entry getOldest()
|
|
||||||
{
|
|
||||||
Timestamp oldestTimestamp = Timestamp.ZERO.plus(1000000);
|
|
||||||
Entry oldestRep = null;
|
|
||||||
|
|
||||||
for (Entry rep : list)
|
|
||||||
{
|
|
||||||
if (rep.getTimestamp().isOlderThan(oldestTimestamp))
|
|
||||||
{
|
|
||||||
oldestRep = rep;
|
|
||||||
oldestTimestamp = rep.getTimestamp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldestRep;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the newest checkmark in the list.
|
|
||||||
* <p>
|
|
||||||
* If the list is empty, returns null. Repetitions in the past are
|
|
||||||
* discarded.
|
|
||||||
*
|
|
||||||
* @return newest checkmark in the list, or null if list is empty.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public Entry getNewest()
|
|
||||||
{
|
|
||||||
Timestamp newestTimestamp = Timestamp.ZERO;
|
|
||||||
Entry newestRep = null;
|
|
||||||
|
|
||||||
for (Entry rep : list)
|
|
||||||
{
|
|
||||||
if (rep.getTimestamp().isNewerThan(newestTimestamp))
|
|
||||||
{
|
|
||||||
newestRep = rep;
|
|
||||||
newestTimestamp = rep.getTimestamp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newestRep;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the total number of successful checkmarks for each month, from the first
|
|
||||||
* checkmark until today, grouped by day of week.
|
|
||||||
* <p>
|
|
||||||
* The checkmarks are returned in a HashMap. The key is the timestamp for
|
|
||||||
* the first day of the month, at midnight (00:00). The value is an integer
|
|
||||||
* array with 7 entries. The first entry contains the total number of
|
|
||||||
* successful checkmarks during the specified month that occurred on a Saturday. The
|
|
||||||
* second entry corresponds to Sunday, and so on. If there are no
|
|
||||||
* successful checkmarks during a certain month, the value is null.
|
|
||||||
*
|
|
||||||
* @return total number of checkmarks by month versus day of week
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public HashMap<Timestamp, Integer[]> getWeekdayFrequency()
|
|
||||||
{
|
|
||||||
List<Entry> entries =
|
|
||||||
getByInterval(Timestamp.ZERO, DateUtils.getTodayWithOffset());
|
|
||||||
HashMap<Timestamp, Integer[]> map = new HashMap<>();
|
|
||||||
|
|
||||||
for (Entry e : entries)
|
|
||||||
{
|
|
||||||
if (!habit.isNumerical() && e.getValue() != Entry.YES_MANUAL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Calendar date = e.getTimestamp().toCalendar();
|
|
||||||
int weekday = e.getTimestamp().getWeekday();
|
|
||||||
date.set(Calendar.DAY_OF_MONTH, 1);
|
|
||||||
|
|
||||||
Timestamp timestamp = new Timestamp(date.getTimeInMillis());
|
|
||||||
Integer[] list = map.get(timestamp);
|
|
||||||
|
|
||||||
if (list == null)
|
|
||||||
{
|
|
||||||
list = new Integer[7];
|
|
||||||
Arrays.fill(list, 0);
|
|
||||||
map.put(timestamp, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
list[weekday]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a given checkmark from the list.
|
|
||||||
* <p>
|
|
||||||
* If the list does not contain the checkmark, it is unchanged.
|
|
||||||
* <p>
|
|
||||||
* Any implementation of this method must call observable.notifyListeners()
|
|
||||||
* after the checkmark has been added.
|
|
||||||
*
|
|
||||||
* @param entry the checkmark to be removed
|
|
||||||
*/
|
|
||||||
public void remove(@NonNull Entry entry)
|
|
||||||
{
|
|
||||||
list.remove(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public long getTotalCount()
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
for (Entry rep : list)
|
|
||||||
if (rep.getValue() == Entry.YES_MANUAL)
|
|
||||||
count++;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(Timestamp timestamp, int value)
|
|
||||||
{
|
|
||||||
Entry check = getByTimestamp(timestamp);
|
|
||||||
if (check != null) remove(check);
|
|
||||||
add(new Entry(timestamp, value));
|
|
||||||
habit.invalidateNewerThan(timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAll()
|
|
||||||
{
|
|
||||||
list.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -192,9 +192,11 @@ public abstract class ScoreList implements Iterable<Score>
|
|||||||
|
|
||||||
if (newestComputed == null)
|
if (newestComputed == null)
|
||||||
{
|
{
|
||||||
Entry oldest = habit.getOriginalEntries().getOldest();
|
List<Entry> entries = habit.getOriginalEntries().getKnown();
|
||||||
if (oldest != null) from =
|
if (!entries.isEmpty())
|
||||||
Timestamp.oldest(from, oldest.getTimestamp());
|
from = Timestamp.oldest(
|
||||||
|
from,
|
||||||
|
entries.get(entries.size() - 1).getTimestamp());
|
||||||
forceRecompute(from, to, 0);
|
forceRecompute(from, to, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -212,8 +214,9 @@ public abstract class ScoreList implements Iterable<Score>
|
|||||||
*/
|
*/
|
||||||
protected void computeAll()
|
protected void computeAll()
|
||||||
{
|
{
|
||||||
Entry oldest = habit.getOriginalEntries().getOldest();
|
List<Entry> entries = habit.getOriginalEntries().getKnown();
|
||||||
if (oldest == null) return;
|
if(entries.isEmpty()) return;
|
||||||
|
Entry oldest = entries.get(entries.size() - 1);
|
||||||
|
|
||||||
Timestamp today = DateUtils.getTodayWithOffset();
|
Timestamp today = DateUtils.getTodayWithOffset();
|
||||||
compute(oldest.getTimestamp(), today);
|
compute(oldest.getTimestamp(), today);
|
||||||
|
|||||||
@@ -112,9 +112,9 @@ public abstract class StreakList
|
|||||||
Streak newestStreak = getNewestComputed();
|
Streak newestStreak = getNewestComputed();
|
||||||
if (newestStreak != null) return newestStreak.getStart();
|
if (newestStreak != null) return newestStreak.getStart();
|
||||||
|
|
||||||
Entry oldestOriginal = habit.getOriginalEntries().getOldest();
|
List<Entry> entries = habit.getOriginalEntries().getKnown();
|
||||||
if (oldestOriginal != null) return oldestOriginal.getTimestamp();
|
if(entries.isEmpty()) return null;
|
||||||
return null;
|
return entries.get(entries.size() - 1).getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ package org.isoron.uhabits.core.models.memory
|
|||||||
import org.isoron.uhabits.core.models.*
|
import org.isoron.uhabits.core.models.*
|
||||||
|
|
||||||
class MemoryModelFactory : ModelFactory {
|
class MemoryModelFactory : ModelFactory {
|
||||||
|
override fun buildOriginalEntries() = Entries()
|
||||||
override fun buildEntryList() = EntryList()
|
override fun buildEntryList() = EntryList()
|
||||||
override fun buildHabitList() = MemoryHabitList()
|
override fun buildHabitList() = MemoryHabitList()
|
||||||
override fun buildRepetitionList() = RepetitionList()
|
|
||||||
override fun buildScoreList() = MemoryScoreList()
|
override fun buildScoreList() = MemoryScoreList()
|
||||||
override fun buildStreakList() = MemoryStreakList()
|
override fun buildStreakList() = MemoryStreakList()
|
||||||
override fun buildHabitListRepository() = throw NotImplementedError()
|
override fun buildHabitListRepository() = throw NotImplementedError()
|
||||||
|
|||||||
@@ -33,10 +33,9 @@ class SQLModelFactory
|
|||||||
@Inject constructor(
|
@Inject constructor(
|
||||||
val database: Database,
|
val database: Database,
|
||||||
) : ModelFactory {
|
) : ModelFactory {
|
||||||
|
override fun buildOriginalEntries() = SQLiteEntries(database)
|
||||||
override fun buildEntryList() = EntryList()
|
override fun buildEntryList() = EntryList()
|
||||||
override fun buildHabitList() = SQLiteHabitList(this)
|
override fun buildHabitList() = SQLiteHabitList(this)
|
||||||
override fun buildRepetitionList() = SQLiteRepetitionList(this)
|
|
||||||
override fun buildScoreList() = MemoryScoreList()
|
override fun buildScoreList() = MemoryScoreList()
|
||||||
override fun buildStreakList() = MemoryStreakList()
|
override fun buildStreakList() = MemoryStreakList()
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ class SQLiteEntries(database: Database) : Entries() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
throw UnsupportedOperationException()
|
super.clear()
|
||||||
|
repository.execSQL("delete from repetitions where habit = ?",
|
||||||
|
habitId.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ import javax.inject.*;
|
|||||||
*/
|
*/
|
||||||
public class SQLiteHabitList extends HabitList
|
public class SQLiteHabitList extends HabitList
|
||||||
{
|
{
|
||||||
private static SQLiteHabitList instance;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Repository<HabitRecord> repository;
|
private final Repository<HabitRecord> repository;
|
||||||
|
|
||||||
@@ -76,6 +74,7 @@ public class SQLiteHabitList extends HabitList
|
|||||||
|
|
||||||
Habit h = modelFactory.buildHabit();
|
Habit h = modelFactory.buildHabit();
|
||||||
rec.copyTo(h);
|
rec.copyTo(h);
|
||||||
|
((SQLiteEntries) h.getOriginalEntries()).setHabitId(h.getId());
|
||||||
list.add(h);
|
list.add(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +91,7 @@ public class SQLiteHabitList extends HabitList
|
|||||||
record.copyFrom(habit);
|
record.copyFrom(habit);
|
||||||
repository.save(record);
|
repository.save(record);
|
||||||
habit.setId(record.id);
|
habit.setId(record.id);
|
||||||
|
((SQLiteEntries) habit.getOriginalEntries()).setHabitId(record.id);
|
||||||
|
|
||||||
list.add(habit);
|
list.add(habit);
|
||||||
getObservable().notifyListeners();
|
getObservable().notifyListeners();
|
||||||
@@ -201,7 +201,7 @@ public class SQLiteHabitList extends HabitList
|
|||||||
if (record == null) throw new RuntimeException("habit not in database");
|
if (record == null) throw new RuntimeException("habit not in database");
|
||||||
repository.executeAsTransaction(() ->
|
repository.executeAsTransaction(() ->
|
||||||
{
|
{
|
||||||
habit.getOriginalEntries().removeAll();
|
habit.getOriginalEntries().clear();
|
||||||
repository.remove(record);
|
repository.remove(record);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Á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.core.models.sqlite;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.database.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.isoron.uhabits.core.models.sqlite.records.*;
|
|
||||||
import org.jetbrains.annotations.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of a {@link RepetitionList} that is backed by SQLite.
|
|
||||||
*/
|
|
||||||
public class SQLiteRepetitionList extends RepetitionList
|
|
||||||
{
|
|
||||||
private final Repository<EntryRecord> repository;
|
|
||||||
|
|
||||||
private boolean loaded = false;
|
|
||||||
|
|
||||||
public SQLiteRepetitionList(@NonNull ModelFactory modelFactory)
|
|
||||||
{
|
|
||||||
repository = modelFactory.buildRepetitionListRepository();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadRecords()
|
|
||||||
{
|
|
||||||
if (loaded) return;
|
|
||||||
loaded = true;
|
|
||||||
|
|
||||||
check(habit.getId());
|
|
||||||
List<EntryRecord> records =
|
|
||||||
repository.findAll("where habit = ? order by timestamp",
|
|
||||||
habit.getId().toString());
|
|
||||||
|
|
||||||
for (EntryRecord rec : records)
|
|
||||||
super.add(rec.toEntry());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(Entry entry)
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
super.add(entry);
|
|
||||||
check(habit.getId());
|
|
||||||
EntryRecord record = new EntryRecord();
|
|
||||||
record.habitId = habit.getId();
|
|
||||||
record.copyFrom(entry);
|
|
||||||
repository.save(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Entry> getByInterval(Timestamp timeFrom, Timestamp timeTo)
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
return super.getByInterval(timeFrom, timeTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Entry getByTimestamp(Timestamp timestamp)
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
return super.getByTimestamp(timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Entry getOldest()
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
return super.getOldest();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Entry getNewest()
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
return super.getNewest();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove(@NonNull Entry entry)
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
super.remove(entry);
|
|
||||||
check(habit.getId());
|
|
||||||
repository.execSQL(
|
|
||||||
"delete from repetitions where habit = ? and timestamp = ?",
|
|
||||||
habit.getId(), entry.getTimestamp().getUnixTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAll()
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
super.removeAll();
|
|
||||||
check(habit.getId());
|
|
||||||
repository.execSQL("delete from repetitions where habit = ?",
|
|
||||||
habit.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTotalCount()
|
|
||||||
{
|
|
||||||
loadRecords();
|
|
||||||
return super.getTotalCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Contract("null -> fail")
|
|
||||||
private void check(Long value)
|
|
||||||
{
|
|
||||||
if (value == null) throw new RuntimeException("null check failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -65,7 +65,7 @@ public class HabitFixtures
|
|||||||
81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120};
|
81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120};
|
||||||
|
|
||||||
for (int mark : marks)
|
for (int mark : marks)
|
||||||
habit.getOriginalEntries().setValue(today.minus(mark), YES_MANUAL);
|
habit.getOriginalEntries().add(new Entry(today.minus(mark), YES_MANUAL));
|
||||||
|
|
||||||
return habit;
|
return habit;
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ public class HabitFixtures
|
|||||||
for (int i = 0; i < times.length; i++)
|
for (int i = 0; i < times.length; i++)
|
||||||
{
|
{
|
||||||
Timestamp timestamp = today.minus(times[i]);
|
Timestamp timestamp = today.minus(times[i]);
|
||||||
habit.getOriginalEntries().setValue(timestamp, values[i]);
|
habit.getOriginalEntries().add(new Entry(timestamp, values[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return habit;
|
return habit;
|
||||||
@@ -125,7 +125,7 @@ public class HabitFixtures
|
|||||||
for (int i = 0; i < times.length; i++)
|
for (int i = 0; i < times.length; i++)
|
||||||
{
|
{
|
||||||
Timestamp timestamp = reference.minus(times[i]);
|
Timestamp timestamp = reference.minus(times[i]);
|
||||||
habit.getOriginalEntries().setValue(timestamp, values[i]);
|
habit.getOriginalEntries().add(new Entry(timestamp, values[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return habit;
|
return habit;
|
||||||
@@ -144,7 +144,7 @@ public class HabitFixtures
|
|||||||
{
|
{
|
||||||
int value = NO;
|
int value = NO;
|
||||||
if (c) value = YES_MANUAL;
|
if (c) value = YES_MANUAL;
|
||||||
habit.getOriginalEntries().setValue(timestamp, value);
|
habit.getOriginalEntries().add(new Entry(timestamp, value));
|
||||||
timestamp = timestamp.minus(1);
|
timestamp = timestamp.minus(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ public class HabitFixtures
|
|||||||
|
|
||||||
private void saveIfSQLite(Habit habit)
|
private void saveIfSQLite(Habit habit)
|
||||||
{
|
{
|
||||||
if (!(habit.getOriginalEntries() instanceof SQLiteRepetitionList)) return;
|
if (!(habit.getOriginalEntries() instanceof SQLiteEntries)) return;
|
||||||
habitList.add(habit);
|
habitList.add(habit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,14 +58,14 @@ class ShowHabitMenuBehavior(
|
|||||||
|
|
||||||
fun onRandomize() {
|
fun onRandomize() {
|
||||||
val random = Random()
|
val random = Random()
|
||||||
habit.originalEntries.removeAll()
|
habit.originalEntries.clear()
|
||||||
var strength = 50.0
|
var strength = 50.0
|
||||||
for (i in 0 until 365 * 5) {
|
for (i in 0 until 365 * 5) {
|
||||||
if (i % 7 == 0) strength = Math.max(0.0, Math.min(100.0, strength + 10 * random.nextGaussian()))
|
if (i % 7 == 0) strength = Math.max(0.0, Math.min(100.0, strength + 10 * random.nextGaussian()))
|
||||||
if (random.nextInt(100) > strength) continue
|
if (random.nextInt(100) > strength) continue
|
||||||
var value = Entry.YES_MANUAL
|
var value = Entry.YES_MANUAL
|
||||||
if (habit.isNumerical) value = (1000 + 250 * random.nextGaussian() * strength / 100).toInt() * 1000
|
if (habit.isNumerical) value = (1000 + 250 * random.nextGaussian() * strength / 100).toInt() * 1000
|
||||||
habit.originalEntries.setValue(DateUtils.getToday().minus(i), value)
|
habit.originalEntries.add(Entry(DateUtils.getToday().minus(i), value))
|
||||||
}
|
}
|
||||||
habit.invalidateNewerThan(Timestamp.ZERO)
|
habit.invalidateNewerThan(Timestamp.ZERO)
|
||||||
screen.refresh()
|
screen.refresh()
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class WidgetBehavior
|
|||||||
|
|
||||||
public void onToggleRepetition(@NonNull Habit habit, Timestamp timestamp)
|
public void onToggleRepetition(@NonNull Habit habit, Timestamp timestamp)
|
||||||
{
|
{
|
||||||
int currentValue = habit.getOriginalEntries().getValue(timestamp);
|
int currentValue = habit.getOriginalEntries().get(timestamp).getValue();
|
||||||
int newValue;
|
int newValue;
|
||||||
if(preferences.isSkipEnabled())
|
if(preferences.isSkipEnabled())
|
||||||
newValue = Entry.Companion.nextToggleValueWithSkip(currentValue);
|
newValue = Entry.Companion.nextToggleValueWithSkip(currentValue);
|
||||||
|
|||||||
@@ -51,13 +51,12 @@ public class CreateRepetitionCommandTest extends BaseUnitTest
|
|||||||
@Test
|
@Test
|
||||||
public void testExecute()
|
public void testExecute()
|
||||||
{
|
{
|
||||||
RepetitionList originalEntries = habit.getOriginalEntries();
|
Entries originalEntries = habit.getOriginalEntries();
|
||||||
Entry entry = originalEntries.getByTimestamp(today);
|
Entry entry = originalEntries.get(today);
|
||||||
assertNotNull(entry);
|
|
||||||
assertEquals(YES_MANUAL, entry.getValue());
|
assertEquals(YES_MANUAL, entry.getValue());
|
||||||
|
|
||||||
command.execute();
|
command.execute();
|
||||||
entry = originalEntries.getByTimestamp(today);
|
entry = originalEntries.get(today);
|
||||||
assertNotNull(entry);
|
|
||||||
assertEquals(100, entry.getValue());
|
assertEquals(100, entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ public class ImportTest extends BaseUnitTest
|
|||||||
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
|
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
|
||||||
date.set(year, month - 1, day);
|
date.set(year, month - 1, day);
|
||||||
Timestamp timestamp = new Timestamp(date);
|
Timestamp timestamp = new Timestamp(date);
|
||||||
return h.getOriginalEntries().getValue(timestamp) == YES_MANUAL;
|
return h.getOriginalEntries().get(timestamp).getValue() == YES_MANUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void importFromFile(String assetFilename) throws IOException
|
private void importFromFile(String assetFilename) throws IOException
|
||||||
|
|||||||
@@ -297,6 +297,45 @@ class EntriesTest {
|
|||||||
assertThat(actual, equalTo(expected))
|
assertThat(actual, equalTo(expected))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWeekdayFrequency() {
|
||||||
|
val entries = Entries()
|
||||||
|
val random = Random(123L)
|
||||||
|
val weekdayCount = Array(12) { Array(7) { 0 } }
|
||||||
|
val monthCount = Array(12) { 0 }
|
||||||
|
val day = DateUtils.getStartOfTodayCalendar()
|
||||||
|
|
||||||
|
// Add repetitions randomly from January to December
|
||||||
|
day.set(2015, Calendar.JANUARY, 1, 0, 0, 0)
|
||||||
|
for (i in 0..364) {
|
||||||
|
if (random.nextBoolean()) {
|
||||||
|
val month = day[Calendar.MONTH]
|
||||||
|
val week = day[Calendar.DAY_OF_WEEK] % 7
|
||||||
|
|
||||||
|
// Leave the month of March empty, to check that it returns null
|
||||||
|
if (month == Calendar.MARCH) continue
|
||||||
|
|
||||||
|
entries.add(Entry(Timestamp(day), YES_MANUAL))
|
||||||
|
weekdayCount[month][week]++
|
||||||
|
monthCount[month]++
|
||||||
|
}
|
||||||
|
day.add(Calendar.DAY_OF_YEAR, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val freq = entries.computeWeekdayFrequency(isNumerical = false)
|
||||||
|
|
||||||
|
// Repetitions should be counted correctly
|
||||||
|
for (month in 0..11) {
|
||||||
|
day.set(2015, month, 1, 0, 0, 0)
|
||||||
|
val actualCount = freq[Timestamp(day)]
|
||||||
|
if (monthCount[month] == 0) {
|
||||||
|
assertThat(actualCount, equalTo(null))
|
||||||
|
} else {
|
||||||
|
assertThat(actualCount, equalTo(weekdayCount[month]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun day(offset: Int) = DateUtils.getToday().minus(offset)
|
fun day(offset: Int) = DateUtils.getToday().minus(offset)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,468 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Á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.core.models;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.*;
|
|
||||||
import org.isoron.uhabits.core.utils.*;
|
|
||||||
import org.junit.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import nl.jqno.equalsverifier.*;
|
|
||||||
|
|
||||||
import static java.util.Calendar.*;
|
|
||||||
import static org.hamcrest.MatcherAssert.*;
|
|
||||||
import static org.hamcrest.core.IsEqual.*;
|
|
||||||
import static org.isoron.uhabits.core.models.Entry.*;
|
|
||||||
import static org.isoron.uhabits.core.utils.DateUtils.TruncateField.MONTH;
|
|
||||||
import static org.isoron.uhabits.core.utils.DateUtils.TruncateField.QUARTER;
|
|
||||||
import static org.isoron.uhabits.core.utils.DateUtils.TruncateField.YEAR;
|
|
||||||
|
|
||||||
public class EntryListTest extends BaseUnitTest
|
|
||||||
{
|
|
||||||
private long dayLength;
|
|
||||||
|
|
||||||
private Timestamp today;
|
|
||||||
|
|
||||||
private Habit nonDailyHabit;
|
|
||||||
|
|
||||||
private Habit emptyHabit;
|
|
||||||
|
|
||||||
private Habit numericalHabit;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() throws Exception
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
nonDailyHabit = fixtures.createShortHabit();
|
|
||||||
habitList.add(nonDailyHabit);
|
|
||||||
|
|
||||||
emptyHabit = fixtures.createEmptyHabit();
|
|
||||||
habitList.add(emptyHabit);
|
|
||||||
|
|
||||||
numericalHabit = fixtures.createNumericalHabit();
|
|
||||||
habitList.add(numericalHabit);
|
|
||||||
today = DateUtils.getToday();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_buildCheckmarksFromIntervals_1() throws Exception
|
|
||||||
{
|
|
||||||
Entry entries[] = new Entry[]{
|
|
||||||
new Entry(day(10), YES_MANUAL),
|
|
||||||
new Entry(day(5), YES_MANUAL),
|
|
||||||
new Entry(day(2), YES_MANUAL),
|
|
||||||
new Entry(day(1), YES_MANUAL),
|
|
||||||
};
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> intervals = new ArrayList<>();
|
|
||||||
intervals.add(new EntryList.Interval(day(10), day(8), day(8)));
|
|
||||||
intervals.add(new EntryList.Interval(day(6), day(5), day(4)));
|
|
||||||
intervals.add(new EntryList.Interval(day(2), day(2), day(1)));
|
|
||||||
|
|
||||||
List<Entry> expected = new ArrayList<>();
|
|
||||||
expected.add(new Entry(day(0), UNKNOWN));
|
|
||||||
expected.add(new Entry(day(1), YES_MANUAL));
|
|
||||||
expected.add(new Entry(day(2), YES_MANUAL));
|
|
||||||
expected.add(new Entry(day(3), UNKNOWN));
|
|
||||||
expected.add(new Entry(day(4), YES_AUTO));
|
|
||||||
expected.add(new Entry(day(5), YES_MANUAL));
|
|
||||||
expected.add(new Entry(day(6), YES_AUTO));
|
|
||||||
expected.add(new Entry(day(7), UNKNOWN));
|
|
||||||
expected.add(new Entry(day(8), YES_AUTO));
|
|
||||||
expected.add(new Entry(day(9), YES_AUTO));
|
|
||||||
expected.add(new Entry(day(10), YES_MANUAL));
|
|
||||||
|
|
||||||
List<Entry> actual =
|
|
||||||
EntryList.buildEntriesFromInterval(entries, intervals);
|
|
||||||
assertThat(actual, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_buildCheckmarksFromIntervals_2() throws Exception
|
|
||||||
{
|
|
||||||
Entry entries[] = new Entry[]{
|
|
||||||
new Entry(day(0), YES_MANUAL),
|
|
||||||
};
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> intervals = new ArrayList<>();
|
|
||||||
intervals.add(new EntryList.Interval(day(0), day(0), day(-10)));
|
|
||||||
|
|
||||||
List<Entry> expected = new ArrayList<>();
|
|
||||||
expected.add(new Entry(day(0), YES_MANUAL));
|
|
||||||
|
|
||||||
List<Entry> actual =
|
|
||||||
EntryList.buildEntriesFromInterval(entries, intervals);
|
|
||||||
assertThat(actual, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_buildIntervals_1() throws Exception
|
|
||||||
{
|
|
||||||
Entry entries[] = new Entry[]{
|
|
||||||
new Entry(day(23), YES_MANUAL),
|
|
||||||
new Entry(day(18), YES_MANUAL),
|
|
||||||
new Entry(day(8), YES_MANUAL),
|
|
||||||
};
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> expected = new ArrayList<>();
|
|
||||||
expected.add(new EntryList.Interval(day(23), day(23), day(17)));
|
|
||||||
expected.add(new EntryList.Interval(day(18), day(18), day(12)));
|
|
||||||
expected.add(new EntryList.Interval(day(8), day(8), day(2)));
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> actual;
|
|
||||||
actual = EntryList.buildIntervals(Frequency.WEEKLY, entries);
|
|
||||||
assertThat(actual, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_buildIntervals_2() throws Exception
|
|
||||||
{
|
|
||||||
Entry entries[] = new Entry[]{
|
|
||||||
new Entry(day(23), YES_MANUAL),
|
|
||||||
new Entry(day(18), YES_MANUAL),
|
|
||||||
new Entry(day(8), YES_MANUAL),
|
|
||||||
};
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> expected = new ArrayList<>();
|
|
||||||
expected.add(new EntryList.Interval(day(23), day(23), day(23)));
|
|
||||||
expected.add(new EntryList.Interval(day(18), day(18), day(18)));
|
|
||||||
expected.add(new EntryList.Interval(day(8), day(8), day(8)));
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> actual;
|
|
||||||
actual = EntryList.buildIntervals(Frequency.DAILY, entries);
|
|
||||||
assertThat(actual, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_buildIntervals_3() throws Exception
|
|
||||||
{
|
|
||||||
Entry entries[] = new Entry[]{
|
|
||||||
new Entry(day(23), YES_MANUAL),
|
|
||||||
new Entry(day(22), YES_MANUAL),
|
|
||||||
new Entry(day(18), YES_MANUAL),
|
|
||||||
new Entry(day(15), YES_MANUAL),
|
|
||||||
new Entry(day(8), YES_MANUAL),
|
|
||||||
};
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> expected = new ArrayList<>();
|
|
||||||
expected.add(new EntryList.Interval(day(23), day(22), day(17)));
|
|
||||||
expected.add(new EntryList.Interval(day(22), day(18), day(16)));
|
|
||||||
expected.add(new EntryList.Interval(day(18), day(15), day(12)));
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> actual;
|
|
||||||
actual =
|
|
||||||
EntryList.buildIntervals(Frequency.TWO_TIMES_PER_WEEK, entries);
|
|
||||||
assertThat(actual, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_buildIntervals_4() throws Exception
|
|
||||||
{
|
|
||||||
Entry[] entries = new Entry[]{
|
|
||||||
new Entry(day(30), YES_MANUAL),
|
|
||||||
new Entry(day(20), SKIP),
|
|
||||||
new Entry(day(10), YES_MANUAL),
|
|
||||||
};
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> expected = new ArrayList<>();
|
|
||||||
expected.add(new EntryList.Interval(day(30), day(30), day(28)));
|
|
||||||
expected.add(new EntryList.Interval(day(10), day(10), day(8)));
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> actual;
|
|
||||||
actual = EntryList.buildIntervals(new Frequency(1, 3), entries);
|
|
||||||
assertThat(actual, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getAllValues_moveBackwardsInTime()
|
|
||||||
{
|
|
||||||
travelInTime(-3);
|
|
||||||
|
|
||||||
int[] expectedValues = {
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL
|
|
||||||
};
|
|
||||||
|
|
||||||
int[] actualValues = nonDailyHabit.getComputedEntries().getAllValues();
|
|
||||||
|
|
||||||
assertThat(actualValues, equalTo(expectedValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getAllValues_moveForwardInTime()
|
|
||||||
{
|
|
||||||
travelInTime(3);
|
|
||||||
|
|
||||||
int[] expectedValues = {
|
|
||||||
UNKNOWN,
|
|
||||||
UNKNOWN,
|
|
||||||
UNKNOWN,
|
|
||||||
YES_MANUAL,
|
|
||||||
NO,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL
|
|
||||||
};
|
|
||||||
|
|
||||||
int[] actualValues = nonDailyHabit.getComputedEntries().getAllValues();
|
|
||||||
|
|
||||||
assertThat(actualValues, equalTo(expectedValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getAllValues_withEmptyHabit()
|
|
||||||
{
|
|
||||||
int[] expectedValues = new int[0];
|
|
||||||
int[] actualValues = emptyHabit.getComputedEntries().getAllValues();
|
|
||||||
|
|
||||||
assertThat(actualValues, equalTo(expectedValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getAllValues_withNonDailyHabit()
|
|
||||||
{
|
|
||||||
int[] expectedValues = {
|
|
||||||
YES_MANUAL,
|
|
||||||
NO,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL
|
|
||||||
};
|
|
||||||
|
|
||||||
int[] actualValues = nonDailyHabit.getComputedEntries().getAllValues();
|
|
||||||
|
|
||||||
assertThat(actualValues, equalTo(expectedValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getByInterval_withNumericalHabits() throws Exception
|
|
||||||
{
|
|
||||||
EntryList entries = numericalHabit.getComputedEntries();
|
|
||||||
|
|
||||||
List<Entry> expected =
|
|
||||||
Arrays.asList(new Entry(day(1), 200), new Entry(day(2), 0),
|
|
||||||
new Entry(day(3), 300), new Entry(day(4), 0),
|
|
||||||
new Entry(day(5), 400));
|
|
||||||
|
|
||||||
List<Entry> actual = entries.getByInterval(day(5), day(1));
|
|
||||||
assertThat(actual, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getTodayValue()
|
|
||||||
{
|
|
||||||
EntryList entries = nonDailyHabit.getComputedEntries();
|
|
||||||
|
|
||||||
travelInTime(-1);
|
|
||||||
assertThat(entries.getTodayValue(), equalTo(NO));
|
|
||||||
|
|
||||||
travelInTime(0);
|
|
||||||
assertThat(entries.getTodayValue(), equalTo(YES_MANUAL));
|
|
||||||
|
|
||||||
travelInTime(1);
|
|
||||||
assertThat(entries.getTodayValue(), equalTo(UNKNOWN));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getValues_withInvalidInterval()
|
|
||||||
{
|
|
||||||
int values[] = nonDailyHabit
|
|
||||||
.getComputedEntries()
|
|
||||||
.getValues(new Timestamp(0L).plus(100), new Timestamp(0L));
|
|
||||||
assertThat(values, equalTo(new int[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getValues_withValidInterval()
|
|
||||||
{
|
|
||||||
Timestamp from = today.minus(15);
|
|
||||||
Timestamp to = today.minus(5);
|
|
||||||
|
|
||||||
int[] expectedValues = {
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_AUTO,
|
|
||||||
YES_MANUAL,
|
|
||||||
YES_MANUAL,
|
|
||||||
UNKNOWN,
|
|
||||||
UNKNOWN,
|
|
||||||
UNKNOWN,
|
|
||||||
UNKNOWN,
|
|
||||||
UNKNOWN,
|
|
||||||
UNKNOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
int[] actualValues = nonDailyHabit.getComputedEntries().getValues(from, to);
|
|
||||||
assertThat(actualValues, equalTo(expectedValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_snapIntervalsTogether_1() throws Exception
|
|
||||||
{
|
|
||||||
ArrayList<EntryList.Interval> original = new ArrayList<>();
|
|
||||||
original.add(new EntryList.Interval(day(27), day(27), day(21)));
|
|
||||||
original.add(new EntryList.Interval(day(20), day(20), day(14)));
|
|
||||||
original.add(new EntryList.Interval(day(12), day(12), day(6)));
|
|
||||||
original.add(new EntryList.Interval(day(8), day(8), day(2)));
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> expected = new ArrayList<>();
|
|
||||||
expected.add(new EntryList.Interval(day(29), day(27), day(23)));
|
|
||||||
expected.add(new EntryList.Interval(day(22), day(20), day(16)));
|
|
||||||
expected.add(new EntryList.Interval(day(15), day(12), day(9)));
|
|
||||||
expected.add(new EntryList.Interval(day(8), day(8), day(2)));
|
|
||||||
|
|
||||||
EntryList.snapIntervalsTogether(original);
|
|
||||||
assertThat(original, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_snapIntervalsTogether_2() throws Exception
|
|
||||||
{
|
|
||||||
ArrayList<EntryList.Interval> original = new ArrayList<>();
|
|
||||||
original.add(new EntryList.Interval(day(11), day(8), day(5)));
|
|
||||||
original.add(new EntryList.Interval(day(6), day(4), day(0)));
|
|
||||||
|
|
||||||
ArrayList<EntryList.Interval> expected = new ArrayList<>();
|
|
||||||
expected.add(new EntryList.Interval(day(13), day(8), day(7)));
|
|
||||||
expected.add(new EntryList.Interval(day(6), day(4), day(0)));
|
|
||||||
|
|
||||||
EntryList.snapIntervalsTogether(original);
|
|
||||||
assertThat(original, equalTo(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_writeCSV() throws IOException
|
|
||||||
{
|
|
||||||
String expectedCSV = "2015-01-25,2\n2015-01-24,0\n2015-01-23,1\n" +
|
|
||||||
"2015-01-22,2\n2015-01-21,2\n2015-01-20,2\n" +
|
|
||||||
"2015-01-19,1\n2015-01-18,1\n2015-01-17,2\n" +
|
|
||||||
"2015-01-16,2\n";
|
|
||||||
|
|
||||||
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
nonDailyHabit.getComputedEntries().writeCSV(writer);
|
|
||||||
|
|
||||||
assertThat(writer.toString(), equalTo(expectedCSV));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Timestamp day(int offset)
|
|
||||||
{
|
|
||||||
return DateUtils.getToday().minus(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void travelInTime(int days)
|
|
||||||
{
|
|
||||||
DateUtils.setFixedLocalTime(
|
|
||||||
FIXED_LOCAL_TIME + days * Timestamp.DAY_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEquals() throws Exception
|
|
||||||
{
|
|
||||||
EqualsVerifier.forClass(Entry.class).verify();
|
|
||||||
EqualsVerifier.forClass(Timestamp.class).verify();
|
|
||||||
EqualsVerifier.forClass(EntryList.Interval.class).verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGroupBy() throws Exception
|
|
||||||
{
|
|
||||||
Habit habit = fixtures.createLongNumericalHabit(timestamp(2014, JUNE, 1));
|
|
||||||
EntryList entries = habit.getComputedEntries();
|
|
||||||
|
|
||||||
List<Entry> byMonth = entries.groupBy(MONTH, Calendar.SATURDAY);
|
|
||||||
assertThat(byMonth.size(), equalTo(25)); // from 2013-01-01 to 2015-01-01
|
|
||||||
assertThat(byMonth.get(0), equalTo(new Entry(timestamp(2015, JANUARY, 1), 0)));
|
|
||||||
assertThat(byMonth.get(6), equalTo(new Entry(timestamp(2014, JULY, 1), 0)));
|
|
||||||
assertThat(byMonth.get(12), equalTo(new Entry(timestamp(2014, JANUARY, 1), 1706)));
|
|
||||||
assertThat(byMonth.get(18), equalTo(new Entry(timestamp(2013, JULY, 1), 1379)));
|
|
||||||
|
|
||||||
List<Entry> byQuarter = entries.groupBy(QUARTER, Calendar.SATURDAY);
|
|
||||||
assertThat(byQuarter.size(), equalTo(9)); // from 2013-Q1 to 2015-Q1
|
|
||||||
assertThat(byQuarter.get(0), equalTo(new Entry(timestamp(2015, JANUARY, 1), 0)));
|
|
||||||
assertThat(byQuarter.get(4), equalTo(new Entry(timestamp(2014, JANUARY, 1), 4964)));
|
|
||||||
assertThat(byQuarter.get(8), equalTo(new Entry(timestamp(2013, JANUARY, 1), 4975)));
|
|
||||||
|
|
||||||
List<Entry> byYear = entries.groupBy(YEAR, Calendar.SATURDAY);
|
|
||||||
assertThat(byYear.size(), equalTo(3)); // from 2013 to 2015
|
|
||||||
assertThat(byYear.get(0), equalTo(new Entry(timestamp(2015, JANUARY, 1), 0)));
|
|
||||||
assertThat(byYear.get(1), equalTo(new Entry(timestamp(2014, JANUARY, 1), 8227)));
|
|
||||||
assertThat(byYear.get(2), equalTo(new Entry(timestamp(2013, JANUARY, 1), 16172)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetTodayValue() throws Exception
|
|
||||||
{
|
|
||||||
Habit habit = fixtures.createLongNumericalHabit(timestamp(2014, JUNE, 1));
|
|
||||||
EntryList checkmarks = habit.getComputedEntries();
|
|
||||||
|
|
||||||
DateUtils.setFixedLocalTime(unixTime(2050, MAY, 1));
|
|
||||||
assertThat(checkmarks.getTodayValue(), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(SATURDAY), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisMonthValue(), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisQuarterValue(), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisYearValue(), equalTo(0));
|
|
||||||
|
|
||||||
DateUtils.setFixedLocalTime(unixTime(2014, JUNE, 6));
|
|
||||||
assertThat(checkmarks.getTodayValue(), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(SATURDAY), equalTo(230));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(SUNDAY), equalTo(230));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(MONDAY), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisMonthValue(), equalTo(230));
|
|
||||||
assertThat(checkmarks.getThisQuarterValue(), equalTo(3263));
|
|
||||||
assertThat(checkmarks.getThisYearValue(), equalTo(8227));
|
|
||||||
|
|
||||||
DateUtils.setFixedLocalTime(unixTime(2014, JUNE, 1));
|
|
||||||
assertThat(checkmarks.getTodayValue(), equalTo(230));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(SATURDAY), equalTo(230));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(SUNDAY), equalTo(230));
|
|
||||||
assertThat(checkmarks.getThisMonthValue(), equalTo(230));
|
|
||||||
|
|
||||||
DateUtils.setFixedLocalTime(unixTime(2014, MAY, 16));
|
|
||||||
assertThat(checkmarks.getTodayValue(), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(SATURDAY), equalTo(419));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(THURSDAY), equalTo(134));
|
|
||||||
assertThat(checkmarks.getThisMonthValue(), equalTo(1006));
|
|
||||||
|
|
||||||
DateUtils.setFixedLocalTime(unixTime(2000, MAY, 1));
|
|
||||||
assertThat(checkmarks.getTodayValue(), equalTo(UNKNOWN));
|
|
||||||
assertThat(checkmarks.getThisWeekValue(SATURDAY), equalTo(0));
|
|
||||||
assertThat(checkmarks.getThisMonthValue(), equalTo(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,19 +40,6 @@ public class HabitTest extends BaseUnitTest
|
|||||||
super.setUp();
|
super.setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConstructor_default()
|
|
||||||
{
|
|
||||||
Habit habit = modelFactory.buildHabit();
|
|
||||||
assertFalse(habit.isArchived());
|
|
||||||
|
|
||||||
assertThat(habit.hasReminder(), is(false));
|
|
||||||
assertNotNull(habit.getStreaks());
|
|
||||||
assertNotNull(habit.getScores());
|
|
||||||
assertNotNull(habit.getOriginalEntries());
|
|
||||||
assertNotNull(habit.getComputedEntries());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_copyAttributes()
|
public void test_copyAttributes()
|
||||||
{
|
{
|
||||||
@@ -86,7 +73,7 @@ public class HabitTest extends BaseUnitTest
|
|||||||
{
|
{
|
||||||
Habit h = modelFactory.buildHabit();
|
Habit h = modelFactory.buildHabit();
|
||||||
assertFalse(h.isCompletedToday());
|
assertFalse(h.isCompletedToday());
|
||||||
h.getOriginalEntries().setValue(getToday(), Entry.YES_MANUAL);
|
h.getOriginalEntries().add(new Entry(getToday(), Entry.YES_MANUAL));
|
||||||
assertTrue(h.isCompletedToday());
|
assertTrue(h.isCompletedToday());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,19 +86,29 @@ public class HabitTest extends BaseUnitTest
|
|||||||
h.setTargetValue(100.0);
|
h.setTargetValue(100.0);
|
||||||
assertFalse(h.isCompletedToday());
|
assertFalse(h.isCompletedToday());
|
||||||
|
|
||||||
h.getOriginalEntries().setValue(getToday(), 200_000);
|
h.getOriginalEntries().add(new Entry(getToday(), 200_000));
|
||||||
|
h.invalidateNewerThan(Timestamp.ZERO);
|
||||||
assertTrue(h.isCompletedToday());
|
assertTrue(h.isCompletedToday());
|
||||||
h.getOriginalEntries().setValue(getToday(), 100_000);
|
|
||||||
|
h.getOriginalEntries().add(new Entry(getToday(), 100_000));
|
||||||
|
h.invalidateNewerThan(Timestamp.ZERO);
|
||||||
assertTrue(h.isCompletedToday());
|
assertTrue(h.isCompletedToday());
|
||||||
h.getOriginalEntries().setValue(getToday(), 50_000);
|
|
||||||
|
h.getOriginalEntries().add(new Entry(getToday(), 50_000));
|
||||||
|
h.invalidateNewerThan(Timestamp.ZERO);
|
||||||
assertFalse(h.isCompletedToday());
|
assertFalse(h.isCompletedToday());
|
||||||
|
|
||||||
h.setTargetType(Habit.AT_MOST);
|
h.setTargetType(Habit.AT_MOST);
|
||||||
h.getOriginalEntries().setValue(getToday(), 200_000);
|
h.getOriginalEntries().add(new Entry(getToday(), 200_000));
|
||||||
|
h.invalidateNewerThan(Timestamp.ZERO);
|
||||||
assertFalse(h.isCompletedToday());
|
assertFalse(h.isCompletedToday());
|
||||||
h.getOriginalEntries().setValue(getToday(), 100_000);
|
|
||||||
|
h.getOriginalEntries().add(new Entry(getToday(), 100_000));
|
||||||
|
h.invalidateNewerThan(Timestamp.ZERO);
|
||||||
assertTrue(h.isCompletedToday());
|
assertTrue(h.isCompletedToday());
|
||||||
h.getOriginalEntries().setValue(getToday(), 50_000);
|
|
||||||
|
h.getOriginalEntries().add(new Entry(getToday(), 50_000));
|
||||||
|
h.invalidateNewerThan(Timestamp.ZERO);
|
||||||
assertTrue(h.isCompletedToday());
|
assertTrue(h.isCompletedToday());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Á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.core.models;
|
|
||||||
|
|
||||||
import androidx.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.*;
|
|
||||||
import org.isoron.uhabits.core.utils.*;
|
|
||||||
import org.junit.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static java.util.Calendar.*;
|
|
||||||
import static org.hamcrest.MatcherAssert.*;
|
|
||||||
import static org.hamcrest.core.IsEqual.*;
|
|
||||||
import static org.isoron.uhabits.core.models.Entry.*;
|
|
||||||
|
|
||||||
public class RepetitionListTest extends BaseUnitTest
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private RepetitionList reps;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Habit habit;
|
|
||||||
|
|
||||||
private Timestamp today;
|
|
||||||
|
|
||||||
private long day;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
habit = fixtures.createEmptyHabit();
|
|
||||||
reps = habit.getOriginalEntries();
|
|
||||||
|
|
||||||
today = DateUtils.getToday();
|
|
||||||
|
|
||||||
reps.setValue(today.minus(3), YES_MANUAL);
|
|
||||||
reps.setValue(today.minus(2), YES_MANUAL);
|
|
||||||
reps.setValue(today, YES_MANUAL);
|
|
||||||
reps.setValue(today.minus(7), YES_MANUAL);
|
|
||||||
reps.setValue(today.minus(5), YES_MANUAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@After
|
|
||||||
public void tearDown() throws Exception
|
|
||||||
{
|
|
||||||
super.tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getOldest()
|
|
||||||
{
|
|
||||||
Entry check = reps.getOldest();
|
|
||||||
assertThat(check.getTimestamp(), equalTo(today.minus(7)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_getWeekDayFrequency()
|
|
||||||
{
|
|
||||||
habit = fixtures.createEmptyHabit();
|
|
||||||
reps = habit.getOriginalEntries();
|
|
||||||
|
|
||||||
Random random = new Random(123L);
|
|
||||||
Integer weekdayCount[][] = new Integer[12][7];
|
|
||||||
Integer monthCount[] = new Integer[12];
|
|
||||||
|
|
||||||
Arrays.fill(monthCount, 0);
|
|
||||||
for (Integer row[] : weekdayCount) Arrays.fill(row, 0);
|
|
||||||
GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
|
|
||||||
|
|
||||||
// Sets the current date to the end of November
|
|
||||||
day.set(2015, NOVEMBER, 30, 12, 0, 0);
|
|
||||||
DateUtils.setFixedLocalTime(day.getTimeInMillis());
|
|
||||||
|
|
||||||
// Add repetitions randomly from January to December
|
|
||||||
day.set(2015, JANUARY, 1, 0, 0, 0);
|
|
||||||
for (int i = 0; i < 365; i++)
|
|
||||||
{
|
|
||||||
if (random.nextBoolean())
|
|
||||||
{
|
|
||||||
int month = day.get(Calendar.MONTH);
|
|
||||||
int week = day.get(Calendar.DAY_OF_WEEK) % 7;
|
|
||||||
|
|
||||||
// Leave the month of March empty, to check that it returns null
|
|
||||||
if (month == MARCH) continue;
|
|
||||||
|
|
||||||
reps.setValue(new Timestamp(day), YES_MANUAL);
|
|
||||||
|
|
||||||
// Repetitions in December should not be counted
|
|
||||||
if (month == DECEMBER) continue;
|
|
||||||
|
|
||||||
weekdayCount[month][week]++;
|
|
||||||
monthCount[month]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
day.add(Calendar.DAY_OF_YEAR, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<Timestamp, Integer[]> freq = reps.getWeekdayFrequency();
|
|
||||||
|
|
||||||
// Repetitions until November should be counted correctly
|
|
||||||
for (int month = 0; month < 11; month++)
|
|
||||||
{
|
|
||||||
day.set(2015, month, 1, 0, 0, 0);
|
|
||||||
Integer actualCount[] = freq.get(new Timestamp(day));
|
|
||||||
if (monthCount[month] == 0) assertThat(actualCount, equalTo(null));
|
|
||||||
else assertThat(actualCount, equalTo(weekdayCount[month]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repetitions in December should be discarded
|
|
||||||
day.set(2015, DECEMBER, 1, 0, 0, 0);
|
|
||||||
assertThat(freq.get(new Timestamp(day)), equalTo(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test_setValue()
|
|
||||||
{
|
|
||||||
assertThat(reps.getValue(today), equalTo(YES_MANUAL));
|
|
||||||
reps.setValue(today, NO);
|
|
||||||
assertThat(reps.getValue(today), equalTo(NO));
|
|
||||||
|
|
||||||
habit.setType(Habit.NUMBER_HABIT);
|
|
||||||
reps.setValue(today, 100);
|
|
||||||
assertThat(reps.getValue(today), equalTo(100));
|
|
||||||
|
|
||||||
reps.setValue(today, 500);
|
|
||||||
assertThat(reps.getValue(today), equalTo(500));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -327,34 +327,35 @@ public class ScoreListTest extends BaseUnitTest
|
|||||||
|
|
||||||
private void check(final int offset)
|
private void check(final int offset)
|
||||||
{
|
{
|
||||||
RepetitionList entries = habit.getOriginalEntries();
|
Entries entries = habit.getOriginalEntries();
|
||||||
Timestamp today = DateUtils.getToday();
|
Timestamp today = DateUtils.getToday();
|
||||||
entries.setValue(today.minus(offset), YES_MANUAL);
|
entries.add(new Entry(today.minus(offset), YES_MANUAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void check(final int from, final int to)
|
private void check(final int from, final int to)
|
||||||
{
|
{
|
||||||
RepetitionList entries = habit.getOriginalEntries();
|
Entries entries = habit.getOriginalEntries();
|
||||||
Timestamp today = DateUtils.getToday();
|
Timestamp today = DateUtils.getToday();
|
||||||
|
|
||||||
for (int i = from; i < to; i++)
|
for (int i = from; i < to; i++)
|
||||||
entries.setValue(today.minus(i), YES_MANUAL);
|
entries.add(new Entry(today.minus(i), YES_MANUAL));
|
||||||
|
habit.invalidateNewerThan(Timestamp.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void check(ArrayList<Integer> values)
|
private void check(ArrayList<Integer> values)
|
||||||
{
|
{
|
||||||
RepetitionList entries = habit.getOriginalEntries();
|
Entries entries = habit.getOriginalEntries();
|
||||||
Timestamp today = DateUtils.getToday();
|
Timestamp today = DateUtils.getToday();
|
||||||
for (int i = 0; i < values.size(); i++)
|
for (int i = 0; i < values.size(); i++)
|
||||||
if (values.get(i) == YES_MANUAL)
|
if (values.get(i) == YES_MANUAL)
|
||||||
entries.setValue(today.minus(i), YES_MANUAL);
|
entries.add(new Entry(today.minus(i), YES_MANUAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSkip(final int day)
|
private void addSkip(final int day)
|
||||||
{
|
{
|
||||||
RepetitionList entries = habit.getOriginalEntries();
|
Entries entries = habit.getOriginalEntries();
|
||||||
Timestamp today = DateUtils.getToday();
|
Timestamp today = DateUtils.getToday();
|
||||||
entries.setValue(today.minus(day), Entry.SKIP);
|
entries.add(new Entry(today.minus(day), Entry.SKIP));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkScoreValues(double[] expectedValues)
|
private void checkScoreValues(double[] expectedValues)
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Á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.core.models.sqlite;
|
|
||||||
|
|
||||||
import androidx.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.*;
|
|
||||||
import org.isoron.uhabits.core.database.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.isoron.uhabits.core.models.sqlite.records.*;
|
|
||||||
import org.isoron.uhabits.core.test.*;
|
|
||||||
import org.isoron.uhabits.core.utils.*;
|
|
||||||
import org.junit.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static junit.framework.TestCase.*;
|
|
||||||
import static org.hamcrest.MatcherAssert.*;
|
|
||||||
import static org.hamcrest.core.IsEqual.*;
|
|
||||||
import static org.isoron.uhabits.core.models.Entry.*;
|
|
||||||
|
|
||||||
public class SQLiteRepetitionListTest extends BaseUnitTest
|
|
||||||
{
|
|
||||||
private Habit habit;
|
|
||||||
|
|
||||||
private Timestamp today;
|
|
||||||
|
|
||||||
private RepetitionList originalCheckmarks;
|
|
||||||
|
|
||||||
private long day;
|
|
||||||
|
|
||||||
private Repository<EntryRecord> repository;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() throws Exception
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
Database db = buildMemoryDatabase();
|
|
||||||
modelFactory = new SQLModelFactory(db);
|
|
||||||
habitList = modelFactory.buildHabitList();
|
|
||||||
fixtures = new HabitFixtures(modelFactory, habitList);
|
|
||||||
repository = new Repository<>(EntryRecord.class, db);
|
|
||||||
habit = fixtures.createLongHabit();
|
|
||||||
|
|
||||||
originalCheckmarks = habit.getOriginalEntries();
|
|
||||||
today = DateUtils.getToday();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAdd()
|
|
||||||
{
|
|
||||||
EntryRecord record = getByTimestamp(today.plus(1));
|
|
||||||
assertNull(record);
|
|
||||||
|
|
||||||
Entry rep = new Entry(today.plus(1), YES_MANUAL);
|
|
||||||
habit.getOriginalEntries().add(rep);
|
|
||||||
|
|
||||||
record = getByTimestamp(today.plus(1));
|
|
||||||
assertNotNull(record);
|
|
||||||
assertThat(record.value, equalTo(YES_MANUAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetByInterval()
|
|
||||||
{
|
|
||||||
List<Entry> checks =
|
|
||||||
originalCheckmarks.getByInterval(today.minus(10), today);
|
|
||||||
|
|
||||||
assertThat(checks.size(), equalTo(8));
|
|
||||||
assertThat(checks.get(0).getTimestamp(), equalTo(today.minus(10)));
|
|
||||||
assertThat(checks.get(4).getTimestamp(), equalTo(today.minus(5)));
|
|
||||||
assertThat(checks.get(5).getTimestamp(), equalTo(today.minus(3)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetByTimestamp()
|
|
||||||
{
|
|
||||||
Entry rep = originalCheckmarks.getByTimestamp(today);
|
|
||||||
assertNotNull(rep);
|
|
||||||
assertThat(rep.getTimestamp(), equalTo(today));
|
|
||||||
|
|
||||||
rep = originalCheckmarks.getByTimestamp(today.minus(2));
|
|
||||||
assertNull(rep);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetOldest()
|
|
||||||
{
|
|
||||||
Entry rep = originalCheckmarks.getOldest();
|
|
||||||
assertNotNull(rep);
|
|
||||||
assertThat(rep.getTimestamp(), equalTo(today.minus(120)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetOldest_withEmptyHabit()
|
|
||||||
{
|
|
||||||
Habit empty = fixtures.createEmptyHabit();
|
|
||||||
Entry rep = empty.getOriginalEntries().getOldest();
|
|
||||||
assertNull(rep);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRemove()
|
|
||||||
{
|
|
||||||
EntryRecord record = getByTimestamp(today);
|
|
||||||
assertNotNull(record);
|
|
||||||
|
|
||||||
Entry rep = record.toEntry();
|
|
||||||
originalCheckmarks.remove(rep);
|
|
||||||
|
|
||||||
record = getByTimestamp(today);
|
|
||||||
assertNull(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private EntryRecord getByTimestamp(Timestamp timestamp)
|
|
||||||
{
|
|
||||||
String query = "where habit = ? and timestamp = ?";
|
|
||||||
String params[] = {
|
|
||||||
Long.toString(habit.getId()), Long.toString(timestamp.getUnixTime())
|
|
||||||
};
|
|
||||||
|
|
||||||
return repository.findFirst(query, params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -91,7 +91,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
|||||||
if(skipEnabled) nextValue = Entry.Companion.nextToggleValueWithSkip(currentValue);
|
if(skipEnabled) nextValue = Entry.Companion.nextToggleValueWithSkip(currentValue);
|
||||||
else nextValue = Entry.Companion.nextToggleValueWithoutSkip(currentValue);
|
else nextValue = Entry.Companion.nextToggleValueWithoutSkip(currentValue);
|
||||||
|
|
||||||
habit.getOriginalEntries().setValue(timestamp, currentValue);
|
habit.getOriginalEntries().add(new Entry(timestamp, currentValue));
|
||||||
behavior.onToggleRepetition(habit, timestamp);
|
behavior.onToggleRepetition(habit, timestamp);
|
||||||
verify(preferences).isSkipEnabled();
|
verify(preferences).isSkipEnabled();
|
||||||
verify(commandRunner).execute(
|
verify(commandRunner).execute(
|
||||||
@@ -106,7 +106,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
|||||||
public void testOnIncrement()
|
public void testOnIncrement()
|
||||||
{
|
{
|
||||||
habit = fixtures.createNumericalHabit();
|
habit = fixtures.createNumericalHabit();
|
||||||
habit.getOriginalEntries().setValue(timestamp, 500);
|
habit.getOriginalEntries().add(new Entry(timestamp, 500));
|
||||||
|
|
||||||
behavior.onIncrement(habit, timestamp, 100);
|
behavior.onIncrement(habit, timestamp, 100);
|
||||||
verify(commandRunner).execute(
|
verify(commandRunner).execute(
|
||||||
@@ -120,7 +120,7 @@ public class WidgetBehaviorTest extends BaseUnitTest
|
|||||||
public void testOnDecrement()
|
public void testOnDecrement()
|
||||||
{
|
{
|
||||||
habit = fixtures.createNumericalHabit();
|
habit = fixtures.createNumericalHabit();
|
||||||
habit.getOriginalEntries().setValue(timestamp, 500);
|
habit.getOriginalEntries().add(new Entry(timestamp, 500));
|
||||||
|
|
||||||
behavior.onDecrement(habit, timestamp, 100);
|
behavior.onDecrement(habit, timestamp, 100);
|
||||||
verify(commandRunner).execute(
|
verify(commandRunner).execute(
|
||||||
|
|||||||
Reference in New Issue
Block a user