Convert uhabits-core (jvmTest)

pull/709/head
Quentin Hibon 5 years ago
parent 0f828cbd3a
commit ac6df47818

@ -56,7 +56,7 @@ interface Database {
val file: File?
interface ProcessCallback {
fun interface ProcessCallback {
fun process(cursor: Cursor)
}
}

@ -1,170 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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;
import androidx.annotation.*;
import org.apache.commons.io.*;
import org.isoron.uhabits.core.commands.*;
import org.isoron.uhabits.core.database.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.models.Timestamp;
import org.isoron.uhabits.core.models.memory.*;
import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.core.test.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import org.junit.runner.*;
import org.mockito.junit.*;
import java.io.*;
import java.nio.file.Paths;
import java.sql.*;
import java.util.*;
import static org.isoron.uhabits.core.ConstantsKt.*;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class BaseUnitTest
{
// 8:00am, January 25th, 2015 (UTC)
protected static final long FIXED_LOCAL_TIME = 1422172800000L;
protected HabitList habitList;
protected HabitFixtures fixtures;
protected ModelFactory modelFactory;
protected SingleThreadTaskRunner taskRunner;
protected CommandRunner commandRunner;
protected DatabaseOpener databaseOpener = new DatabaseOpener()
{
@Override
public Database open(@NonNull File file)
{
try
{
return new JdbcDatabase(DriverManager.getConnection(
String.format("jdbc:sqlite:%s", file.getAbsolutePath())));
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
}
};
@Before
public void setUp() throws Exception
{
DateUtils.setFixedLocalTime(FIXED_LOCAL_TIME);
DateUtils.setStartDayOffset(0, 0);
modelFactory = new MemoryModelFactory();
habitList = spy(modelFactory.buildHabitList());
fixtures = new HabitFixtures(modelFactory, habitList);
taskRunner = new SingleThreadTaskRunner();
commandRunner = new CommandRunner(taskRunner);
}
@After
public void tearDown() throws Exception
{
validateMockitoUsage();
DateUtils.setFixedLocalTime(null);
DateUtils.setStartDayOffset(0, 0);
}
public long unixTime(int year, int month, int day)
{
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
cal.set(year, month, day, 0, 0, 0);
return cal.getTimeInMillis();
}
public long unixTime(int year, int month, int day, int hour, int minute)
{
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
cal.set(year, month, day, hour, minute);
return cal.getTimeInMillis();
}
public Timestamp timestamp(int year, int month, int day) {
return new Timestamp(unixTime(year, month, day));
}
@Test
public void nothing()
{
}
public static Database buildMemoryDatabase()
{
try
{
Database db = new JdbcDatabase(
DriverManager.getConnection("jdbc:sqlite::memory:"));
db.execute("pragma user_version=8;");
MigrationHelper helper = new MigrationHelper(db);
helper.migrateTo(DATABASE_VERSION);
return db;
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
}
protected void copyAssetToFile(String assetPath, File dst)
throws IOException
{
IOUtils.copy(openAsset(assetPath), new FileOutputStream(dst));
}
@NonNull
protected InputStream openAsset(String assetPath) throws IOException
{
InputStream in = getClass().getResourceAsStream(assetPath);
if (in != null) return in;
String pwd = Paths.get(".").toAbsolutePath().normalize().toString();
String fullPath = pwd + "/assets/test/" + assetPath;
File file = new File(fullPath);
if (file.exists() && file.canRead()) in = new FileInputStream(file);
if (in != null) return in;
throw new IllegalStateException("asset not found: " + fullPath);
}
protected Database openDatabaseResource(String path) throws IOException
{
InputStream original = openAsset(path);
File tmpDbFile = File.createTempFile("database", ".db");
tmpDbFile.deleteOnExit();
IOUtils.copy(original, new FileOutputStream(tmpDbFile));
return databaseOpener.open(tmpDbFile);
}
}

@ -0,0 +1,159 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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
import org.apache.commons.io.IOUtils
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.database.Database
import org.isoron.uhabits.core.database.DatabaseOpener
import org.isoron.uhabits.core.database.JdbcDatabase
import org.isoron.uhabits.core.database.MigrationHelper
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.models.memory.MemoryModelFactory
import org.isoron.uhabits.core.tasks.SingleThreadTaskRunner
import org.isoron.uhabits.core.test.HabitFixtures
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendar
import org.isoron.uhabits.core.utils.DateUtils.Companion.setFixedLocalTime
import org.isoron.uhabits.core.utils.DateUtils.Companion.setStartDayOffset
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnitRunner
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.nio.file.Paths
import java.sql.DriverManager
import java.sql.SQLException
@RunWith(MockitoJUnitRunner::class)
open class BaseUnitTest {
protected open lateinit var habitList: HabitList
protected lateinit var fixtures: HabitFixtures
protected lateinit var modelFactory: ModelFactory
protected lateinit var taskRunner: SingleThreadTaskRunner
protected open lateinit var commandRunner: CommandRunner
protected var databaseOpener: DatabaseOpener = object : DatabaseOpener {
override fun open(file: File): Database {
return try {
JdbcDatabase(
DriverManager.getConnection(
String.format(
"jdbc:sqlite:%s",
file.absolutePath
)
)
)
} catch (e: SQLException) {
throw RuntimeException(e)
}
}
}
@Before
@Throws(Exception::class)
open fun setUp() {
setFixedLocalTime(FIXED_LOCAL_TIME)
setStartDayOffset(0, 0)
val memoryModelFactory = MemoryModelFactory()
habitList = Mockito.spy(memoryModelFactory.buildHabitList())
fixtures = HabitFixtures(memoryModelFactory, habitList)
modelFactory = memoryModelFactory
taskRunner = SingleThreadTaskRunner()
commandRunner = CommandRunner(taskRunner)
}
@After
@Throws(Exception::class)
open fun tearDown() {
Mockito.validateMockitoUsage()
setFixedLocalTime(null)
setStartDayOffset(0, 0)
}
fun unixTime(year: Int, month: Int, day: Int): Long {
val cal = getStartOfTodayCalendar()
cal.set(year, month, day, 0, 0, 0)
return cal.timeInMillis
}
open fun unixTime(year: Int, month: Int, day: Int, hour: Int, minute: Int): Long {
val cal = getStartOfTodayCalendar()
cal.set(year, month, day, hour, minute)
return cal.timeInMillis
}
fun timestamp(year: Int, month: Int, day: Int): Timestamp {
return Timestamp(unixTime(year, month, day))
}
@Test
fun nothing() {
}
@Throws(IOException::class)
protected fun copyAssetToFile(assetPath: String, dst: File?) {
IOUtils.copy(openAsset(assetPath), FileOutputStream(dst!!))
}
@Throws(IOException::class)
protected fun openAsset(assetPath: String): InputStream {
var inputStream = javaClass.getResourceAsStream(assetPath)
if (inputStream != null) return inputStream
val pwd = Paths.get(".").toAbsolutePath().normalize().toString()
val fullPath = "$pwd/assets/test/$assetPath"
val file = File(fullPath)
if (file.exists() && file.canRead()) inputStream = FileInputStream(file)
if (inputStream != null) return inputStream
throw IllegalStateException("asset not found: $fullPath")
}
@Throws(IOException::class)
protected fun openDatabaseResource(path: String): Database {
val original = openAsset(path)
val tmpDbFile = File.createTempFile("database", ".db")
tmpDbFile.deleteOnExit()
IOUtils.copy(original, FileOutputStream(tmpDbFile))
return databaseOpener.open(tmpDbFile)
}
companion object {
// 8:00am, January 25th, 2015 (UTC)
const val FIXED_LOCAL_TIME = 1422172800000L
fun buildMemoryDatabase(): Database {
return try {
val db: Database = JdbcDatabase(
DriverManager.getConnection("jdbc:sqlite::memory:")
)
db.execute("pragma user_version=8;")
val helper = MigrationHelper(db)
helper.migrateTo(DATABASE_VERSION)
db
} catch (e: SQLException) {
throw RuntimeException(e)
}
}
}
}

@ -16,43 +16,31 @@
* 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.commands;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import java.util.*;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
public class ArchiveHabitsCommandTest extends BaseUnitTest
{
private ArchiveHabitsCommand command;
private Habit habit;
@Override
package org.isoron.uhabits.core.commands
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.junit.Before
import org.junit.Test
class ArchiveHabitsCommandTest : BaseUnitTest() {
private var command: ArchiveHabitsCommand? = null
private var habit: Habit? = null
@Before
public void setUp() throws Exception
{
super.setUp();
habit = fixtures.createShortHabit();
habitList.add(habit);
command = new ArchiveHabitsCommand(habitList,
Collections.singletonList(habit));
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit = fixtures.createShortHabit()
habitList.add(habit!!)
command = ArchiveHabitsCommand(habitList, listOf(habit!!))
}
@Test
public void testExecute()
{
assertFalse(habit.isArchived());
command.run();
assertTrue(habit.isArchived());
fun testExecute() {
assertFalse(habit!!.isArchived)
command!!.run()
assertTrue(habit!!.isArchived)
}
}

@ -1,76 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import java.util.*;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
public class ChangeHabitColorCommandTest extends BaseUnitTest
{
private ChangeHabitColorCommand command;
private LinkedList<Habit> selected;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
selected = new LinkedList<>();
for (int i = 0; i < 3; i++)
{
Habit habit = fixtures.createShortHabit();
habit.setColor(new PaletteColor(i + 1));
selected.add(habit);
habitList.add(habit);
}
command = new ChangeHabitColorCommand(habitList, selected, new PaletteColor(0));
}
@Test
public void testExecute()
{
checkOriginalColors();
command.run();
checkNewColors();
}
private void checkNewColors()
{
for (Habit h : selected)
assertThat(h.getColor(), equalTo(new PaletteColor(0)));
}
private void checkOriginalColors()
{
int k = 0;
for (Habit h : selected)
assertThat(h.getColor(), equalTo(new PaletteColor(++k)));
}
}

@ -0,0 +1,69 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.junit.Before
import org.junit.Test
import java.util.LinkedList
class ChangeHabitColorCommandTest : BaseUnitTest() {
private lateinit var command: ChangeHabitColorCommand
private lateinit var selected: LinkedList<Habit>
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
selected = LinkedList()
for (i in 0..2) {
val habit = fixtures.createShortHabit()
habit.color = PaletteColor(i + 1)
selected.add(habit)
habitList.add(habit)
}
command = ChangeHabitColorCommand(habitList, selected, PaletteColor(0))
}
@Test
fun testExecute() {
checkOriginalColors()
command.run()
checkNewColors()
}
private fun checkNewColors() {
for (habit in selected) {
assertThat(habit.color, CoreMatchers.equalTo(PaletteColor(0)))
}
}
private fun checkOriginalColors() {
var k = 0
for (habit in selected)
assertThat(
habit.color,
CoreMatchers.equalTo(PaletteColor(++k))
)
}
}

@ -1,58 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.*;
public class CreateHabitCommandTest extends BaseUnitTest
{
private CreateHabitCommand command;
private Habit model;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
model = fixtures.createEmptyHabit();
model.setName("New habit");
model.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
command = new CreateHabitCommand(modelFactory, habitList, model);
}
@Test
public void testExecute()
{
assertTrue(habitList.isEmpty());
command.run();
assertThat(habitList.size(), equalTo(1));
Habit habit = habitList.getByPosition(0);
assertThat(habit.getName(), equalTo(model.getName()));
}
}

@ -0,0 +1,58 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands
import junit.framework.Assert.assertTrue
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList
import org.junit.Before
import org.junit.Test
class CreateHabitCommandTest : BaseUnitTest() {
private lateinit var command: CreateHabitCommand
private lateinit var model: Habit
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
model = fixtures.createEmptyHabit()
model.name = "New habit"
model.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
command = CreateHabitCommand(modelFactory, habitList, model)
}
@Test
fun testExecute() {
assertTrue(habitList.isEmpty)
command.run()
assertThat(habitList.size(), CoreMatchers.equalTo(1))
val habit = habitList.getByPosition(0)
assertThat(
habit.name,
CoreMatchers.equalTo(
model.name
)
)
}
}

@ -1,62 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import static org.isoron.uhabits.core.models.Entry.*;
import static org.junit.Assert.*;
public class CreateRepetitionCommandTest extends BaseUnitTest
{
private CreateRepetitionCommand command;
private Habit habit;
private Timestamp today;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
habit = fixtures.createShortHabit();
habitList.add(habit);
today = DateUtils.getToday();
command = new CreateRepetitionCommand(habitList, habit, today, 100);
}
@Test
public void testExecute()
{
EntryList entries = habit.getOriginalEntries();
Entry entry = entries.get(today);
assertEquals(YES_MANUAL, entry.getValue());
command.run();
entry = entries.get(today);
assertEquals(100, entry.getValue());
}
}

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands
import junit.framework.Assert.assertEquals
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.junit.Before
import org.junit.Test
class CreateRepetitionCommandTest : BaseUnitTest() {
private var command: CreateRepetitionCommand? = null
private var habit: Habit? = null
private var today: Timestamp? = null
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit = fixtures.createShortHabit()
habitList.add(habit!!)
today = getToday()
command = CreateRepetitionCommand(habitList, habit!!, today!!, 100)
}
@Test
fun testExecute() {
val entries = habit!!.originalEntries
var entry = entries.get(today!!)
assertEquals(Entry.YES_MANUAL, entry.value)
command!!.run()
entry = entries.get(today!!)
assertEquals(100, entry.value.toLong())
}
}

@ -1,73 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import org.junit.rules.*;
import java.util.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
public class DeleteHabitsCommandTest extends BaseUnitTest
{
private DeleteHabitsCommand command;
private LinkedList<Habit> selected;
@Rule
public ExpectedException thrown = ExpectedException.none();
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
selected = new LinkedList<>();
// Habits that should be deleted
for (int i = 0; i < 3; i++)
{
Habit habit = fixtures.createShortHabit();
habitList.add(habit);
selected.add(habit);
}
// Extra habit that should not be deleted
Habit extraHabit = fixtures.createShortHabit();
extraHabit.setName("extra");
habitList.add(extraHabit);
command = new DeleteHabitsCommand(habitList, selected);
}
@Test
public void testExecute()
{
assertThat(habitList.size(), equalTo(4));
command.run();
assertThat(habitList.size(), equalTo(1));
assertThat(habitList.getByPosition(0).getName(), equalTo("extra"));
}
}

@ -0,0 +1,64 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import java.util.LinkedList
class DeleteHabitsCommandTest : BaseUnitTest() {
private lateinit var command: DeleteHabitsCommand
private lateinit var selected: LinkedList<Habit>
@get:Rule
var thrown = ExpectedException.none()!!
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
selected = LinkedList()
// Habits that should be deleted
for (i in 0..2) {
val habit = fixtures.createShortHabit()
habitList.add(habit)
selected.add(habit)
}
// Extra habit that should not be deleted
val extraHabit = fixtures.createShortHabit()
extraHabit.name = "extra"
habitList.add(extraHabit)
command = DeleteHabitsCommand(habitList, selected)
}
@Test
fun testExecute() {
assertThat(habitList.size(), CoreMatchers.equalTo(4))
command.run()
assertThat(habitList.size(), CoreMatchers.equalTo(1))
assertThat(habitList.getByPosition(0).name, CoreMatchers.equalTo("extra"))
}
}

@ -1,72 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
public class EditHabitCommandTest extends BaseUnitTest
{
private EditHabitCommand command;
private Habit habit;
private Habit modified;
private Timestamp today;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
habit = fixtures.createShortHabit();
habit.setName("original");
habit.setFrequency(Frequency.DAILY);
habit.recompute();
habitList.add(habit);
modified = fixtures.createEmptyHabit();
modified.copyFrom(habit);
modified.setName("modified");
habitList.add(modified);
today = DateUtils.getTodayWithOffset();
}
@Test
public void testExecute()
{
command = new EditHabitCommand(habitList, habit.getId(), modified);
double originalScore = habit.getScores().get(today).getValue();
assertThat(habit.getName(), equalTo("original"));
command.run();
assertThat(habit.getName(), equalTo("modified"));
assertThat(habit.getScores().get(today).getValue(), equalTo(originalScore));
}
}

@ -0,0 +1,61 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.commands
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Frequency
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset
import org.junit.Before
import org.junit.Test
class EditHabitCommandTest : BaseUnitTest() {
private lateinit var command: EditHabitCommand
private lateinit var habit: Habit
private lateinit var modified: Habit
private lateinit var today: Timestamp
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit = fixtures.createShortHabit()
habit.name = "original"
habit.frequency = Frequency.DAILY
habit.recompute()
habitList.add(habit)
modified = fixtures.createEmptyHabit()
modified.copyFrom(habit)
modified.name = "modified"
habitList.add(modified)
today = getTodayWithOffset()
}
@Test
fun testExecute() {
command = EditHabitCommand(habitList, habit.id!!, modified)
val originalScore = habit.scores[today].value
assertThat(habit.name, equalTo("original"))
command.run()
assertThat(habit.name, equalTo("modified"))
assertThat(habit.scores[today].value, equalTo(originalScore))
}
}

@ -16,43 +16,33 @@
* 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.commands
package org.isoron.uhabits.core.commands;
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.junit.Before
import org.junit.Test
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
class UnarchiveHabitsCommandTest : BaseUnitTest() {
private lateinit var command: UnarchiveHabitsCommand
private lateinit var habit: Habit
import java.util.*;
import static org.junit.Assert.*;
public class UnarchiveHabitsCommandTest extends BaseUnitTest
{
private UnarchiveHabitsCommand command;
private Habit habit;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
habit = fixtures.createShortHabit();
habit.setArchived(true);
habitList.add(habit);
command = new UnarchiveHabitsCommand(habitList, Collections
.singletonList
(habit));
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit = fixtures.createShortHabit()
habit.isArchived = true
habitList.add(habit)
command = UnarchiveHabitsCommand(habitList, listOf(habit))
}
@Test
public void testExecuteUndoRedo()
{
assertTrue(habit.isArchived());
command.run();
assertFalse(habit.isArchived());
fun testExecuteUndoRedo() {
assertTrue(habit.isArchived)
command.run()
assertFalse(habit.isArchived)
}
}

@ -40,7 +40,7 @@ public class RepositoryTest extends BaseUnitTest
public void setUp() throws Exception
{
super.setUp();
this.db = buildMemoryDatabase();
this.db = BaseUnitTest.Companion.buildMemoryDatabase();
repository = new Repository<>(ThingRecord.class, db);
db.execute("drop table if exists tests");

@ -1,162 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.database.migrations;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.database.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.models.sqlite.*;
import org.isoron.uhabits.core.test.*;
import org.junit.*;
import org.junit.rules.*;
import static junit.framework.TestCase.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
public class Version22Test extends BaseUnitTest
{
@Rule
public ExpectedException exception = ExpectedException.none();
private Database db;
private MigrationHelper helper;
@Override
public void setUp() throws Exception
{
super.setUp();
db = openDatabaseResource("/databases/021.db");
helper = new MigrationHelper(db);
modelFactory = new SQLModelFactory(db);
habitList = modelFactory.buildHabitList();
fixtures = new HabitFixtures(modelFactory, habitList);
}
@Test
public void testKeepValidReps() throws Exception
{
db.query("select count(*) from repetitions",
(c) -> assertThat(c.getInt(0), equalTo(3)));
helper.migrateTo(22);
db.query("select count(*) from repetitions",
(c) -> assertThat(c.getInt(0), equalTo(3)));
}
@Test
public void testRemoveRepsWithInvalidId() throws Exception
{
db.execute("insert into Repetitions(habit, timestamp, value) " +
"values (99999, 100, 2)");
db.query("select count(*) from repetitions where habit = 99999",
(c) -> assertThat(c.getInt(0), equalTo(1)));
helper.migrateTo(22);
db.query("select count(*) from repetitions where habit = 99999",
(c) -> assertThat(c.getInt(0), equalTo(0)));
}
@Test
public void testDisallowNewRepsWithInvalidRef() throws Exception
{
helper.migrateTo(22);
exception.expectMessage(containsString("SQLITE_CONSTRAINT"));
db.execute("insert into Repetitions(habit, timestamp, value) " +
"values (99999, 100, 2)");
}
@Test
public void testRemoveRepetitionsWithNullTimestamp() throws Exception
{
db.execute("insert into repetitions(habit, value) values (0, 2)");
db.query("select count(*) from repetitions where timestamp is null",
(c) -> assertThat(c.getInt(0), equalTo(1)));
helper.migrateTo(22);
db.query("select count(*) from repetitions where timestamp is null",
(c) -> assertThat(c.getInt(0), equalTo(0)));
}
@Test
public void testDisallowNullTimestamp() throws Exception
{
helper.migrateTo(22);
exception.expectMessage(containsString("SQLITE_CONSTRAINT"));
db.execute("insert into Repetitions(habit, value) " + "values (0, 2)");
}
@Test
public void testRemoveRepetitionsWithNullHabit() throws Exception
{
db.execute("insert into repetitions(timestamp, value) values (0, 2)");
db.query("select count(*) from repetitions where habit is null",
(c) -> assertThat(c.getInt(0), equalTo(1)));
helper.migrateTo(22);
db.query("select count(*) from repetitions where habit is null",
(c) -> assertThat(c.getInt(0), equalTo(0)));
}
@Test
public void testDisallowNullHabit() throws Exception
{
helper.migrateTo(22);
exception.expectMessage(containsString("SQLITE_CONSTRAINT"));
db.execute(
"insert into Repetitions(timestamp, value) " + "values (5, 2)");
}
@Test
public void testRemoveDuplicateRepetitions() throws Exception
{
db.execute("insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 2)");
db.execute("insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 5)");
db.execute("insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 10)");
db.query(
"select count(*) from repetitions where timestamp=100 and habit=0",
(c) -> assertThat(c.getInt(0), equalTo(3)));
helper.migrateTo(22);
db.query(
"select count(*) from repetitions where timestamp=100 and habit=0",
(c) -> assertThat(c.getInt(0), equalTo(1)));
}
@Test
public void testDisallowNewDuplicateTimestamps() throws Exception
{
helper.migrateTo(22);
db.execute("insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 2)");
exception.expectMessage(containsString("SQLITE_CONSTRAINT"));
db.execute("insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 5)");
}
}

@ -0,0 +1,220 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.database.migrations
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers
import org.hamcrest.Matchers.equalTo
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.database.Cursor
import org.isoron.uhabits.core.database.Database
import org.isoron.uhabits.core.database.MigrationHelper
import org.isoron.uhabits.core.models.sqlite.SQLModelFactory
import org.isoron.uhabits.core.test.HabitFixtures
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
class Version22Test : BaseUnitTest() {
@get:Rule
var exception = ExpectedException.none()!!
private lateinit var db: Database
private lateinit var helper: MigrationHelper
@Throws(Exception::class)
override fun setUp() {
super.setUp()
db = openDatabaseResource("/databases/021.db")
helper = MigrationHelper(db)
modelFactory = SQLModelFactory(db)
habitList = (modelFactory as SQLModelFactory).buildHabitList()
fixtures = HabitFixtures(modelFactory, habitList)
}
@Test
@Throws(Exception::class)
fun testKeepValidReps() {
db.query(
"select count(*) from repetitions"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(3)
)
}
helper.migrateTo(22)
db.query(
"select count(*) from repetitions"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(3)
)
}
}
@Test
@Throws(Exception::class)
fun testRemoveRepsWithInvalidId() {
db.execute(
"insert into Repetitions(habit, timestamp, value) " +
"values (99999, 100, 2)"
)
db.query(
"select count(*) from repetitions where habit = 99999"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(1)
)
}
helper.migrateTo(22)
db.query(
"select count(*) from repetitions where habit = 99999"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(0)
)
}
}
@Test
@Throws(Exception::class)
fun testDisallowNewRepsWithInvalidRef() {
helper.migrateTo(22)
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
db.execute(
"insert into Repetitions(habit, timestamp, value) " +
"values (99999, 100, 2)"
)
}
@Test
@Throws(Exception::class)
fun testRemoveRepetitionsWithNullTimestamp() {
db.execute("insert into repetitions(habit, value) values (0, 2)")
db.query(
"select count(*) from repetitions where timestamp is null"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(1)
)
}
helper.migrateTo(22)
db.query(
"select count(*) from repetitions where timestamp is null"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(0)
)
}
}
@Test
@Throws(Exception::class)
fun testDisallowNullTimestamp() {
helper.migrateTo(22)
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
db.execute("insert into Repetitions(habit, value) " + "values (0, 2)")
}
@Test
@Throws(Exception::class)
fun testRemoveRepetitionsWithNullHabit() {
db.execute("insert into repetitions(timestamp, value) values (0, 2)")
db.query(
"select count(*) from repetitions where habit is null"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(1)
)
}
helper.migrateTo(22)
db.query(
"select count(*) from repetitions where habit is null"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(0)
)
}
}
@Test
@Throws(Exception::class)
fun testDisallowNullHabit() {
helper.migrateTo(22)
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
db.execute(
"insert into Repetitions(timestamp, value) " + "values (5, 2)"
)
}
@Test
@Throws(Exception::class)
fun testRemoveDuplicateRepetitions() {
db.execute(
"insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 2)"
)
db.execute(
"insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 5)"
)
db.execute(
"insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 10)"
)
db.query(
"select count(*) from repetitions where timestamp=100 and habit=0"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(3)
)
}
helper.migrateTo(22)
db.query(
"select count(*) from repetitions where timestamp=100 and habit=0"
) { c: Cursor ->
assertThat(
c.getInt(0),
equalTo(1)
)
}
}
@Test
@Throws(Exception::class)
fun testDisallowNewDuplicateTimestamps() {
helper.migrateTo(22)
db.execute(
"insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 2)"
)
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
db.execute(
"insert into repetitions(habit, timestamp, value)" +
"values (0, 100, 5)"
)
}
}

@ -20,7 +20,7 @@
package org.isoron.uhabits.core.database.migrations
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.database.Database
import org.isoron.uhabits.core.database.MigrationHelper
@ -39,7 +39,7 @@ class Version23Test : BaseUnitTest() {
db = openDatabaseResource("/databases/022.db")
helper = MigrationHelper(db)
modelFactory = SQLModelFactory(db)
habitList = modelFactory.buildHabitList()
habitList = (modelFactory as SQLModelFactory).buildHabitList()
fixtures = HabitFixtures(modelFactory, habitList)
}
@ -66,7 +66,7 @@ class Version23Test : BaseUnitTest() {
for (i in 0 until descriptions.size) {
cursor.moveToNext()
MatcherAssert.assertThat(cursor.getString(0), equalTo(descriptions[i]))
assertThat(cursor.getString(0), equalTo(descriptions[i]))
}
}
@ -76,7 +76,7 @@ class Version23Test : BaseUnitTest() {
val cursor = db.query("select description from Habits")
while (cursor.moveToNext()) {
MatcherAssert.assertThat(cursor.getString(0), equalTo(""))
assertThat(cursor.getString(0), equalTo(""))
}
}
}

@ -1,138 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.io;
import org.apache.commons.io.*;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.zip.*;
import static org.junit.Assert.*;
public class HabitsCSVExporterTest extends BaseUnitTest
{
private File baseDir;
@Before
public void setUp() throws Exception
{
super.setUp();
habitList.add(fixtures.createShortHabit());
habitList.add(fixtures.createEmptyHabit());
baseDir = Files.createTempDirectory("csv").toFile();
assertNotNull(baseDir);
}
@Override
public void tearDown() throws Exception
{
FileUtils.deleteDirectory(baseDir);
super.tearDown();
}
@Test
public void testExportCSV() throws IOException
{
List<Habit> selected = new LinkedList<>();
for (Habit h : habitList) selected.add(h);
HabitsCSVExporter exporter =
new HabitsCSVExporter(habitList, selected, baseDir);
String filename = exporter.writeArchive();
assertAbsolutePathExists(filename);
File archive = new File(filename);
unzip(archive);
assertPathExists("Habits.csv");
assertPathExists("001 Meditate/Checkmarks.csv");
assertPathExists("001 Meditate/Scores.csv");
assertPathExists("002 Wake up early");
assertPathExists("002 Wake up early/Checkmarks.csv");
assertPathExists("002 Wake up early/Scores.csv");
assertPathExists("Checkmarks.csv");
assertPathExists("Scores.csv");
}
private void unzip(File file) throws IOException
{
ZipFile zip = new ZipFile(file);
Enumeration<? extends ZipEntry> e = zip.entries();
while (e.hasMoreElements())
{
ZipEntry entry = e.nextElement();
InputStream stream = zip.getInputStream(entry);
String outputFilename =
String.format("%s/%s", baseDir.getAbsolutePath(),
entry.getName());
File out = new File(outputFilename);
File parent = out.getParentFile();
if (parent != null) parent.mkdirs();
IOUtils.copy(stream, new FileOutputStream(out));
}
zip.close();
}
// @Test
// public void test_writeCSV() throws IOException
// {
// Habit habit = fixtures.createShortHabit();
//
// String expectedCSV =
// "2015-01-25,0.2557\n" +
// "2015-01-24,0.2226\n" +
// "2015-01-23,0.1991\n" +
// "2015-01-22,0.1746\n" +
// "2015-01-21,0.1379\n" +
// "2015-01-20,0.0995\n" +
// "2015-01-19,0.0706\n" +
// "2015-01-18,0.0515\n" +
// "2015-01-17,0.0315\n" +
// "2015-01-16,0.0107\n";
//
// StringWriter writer = new StringWriter();
// habit.getScores().writeCSV(writer);
//
// assertThat(writer.toString(), equalTo(expectedCSV));
// }
private void assertPathExists(String s)
{
assertAbsolutePathExists(
String.format("%s/%s", baseDir.getAbsolutePath(), s));
}
private void assertAbsolutePathExists(String s)
{
File file = new File(s);
assertTrue(
String.format("File %s should exist", file.getAbsolutePath()),
file.exists());
}
}

@ -0,0 +1,109 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.io
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
import org.apache.commons.io.FileUtils
import org.apache.commons.io.IOUtils
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.junit.Before
import org.junit.Test
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.nio.file.Files
import java.util.LinkedList
import java.util.zip.ZipFile
class HabitsCSVExporterTest : BaseUnitTest() {
private var baseDir: File? = null
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habitList.add(fixtures.createShortHabit())
habitList.add(fixtures.createEmptyHabit())
baseDir = Files.createTempDirectory("csv").toFile()
assertNotNull(baseDir)
}
@Throws(Exception::class)
override fun tearDown() {
FileUtils.deleteDirectory(baseDir)
super.tearDown()
}
@Test
@Throws(IOException::class)
fun testExportCSV() {
val selected: MutableList<Habit> = LinkedList()
for (h in habitList) selected.add(h)
val exporter = HabitsCSVExporter(
habitList,
selected,
baseDir!!
)
val filename = exporter.writeArchive()
assertAbsolutePathExists(filename)
val archive = File(filename)
unzip(archive)
assertPathExists("Habits.csv")
assertPathExists("001 Meditate/Checkmarks.csv")
assertPathExists("001 Meditate/Scores.csv")
assertPathExists("002 Wake up early")
assertPathExists("002 Wake up early/Checkmarks.csv")
assertPathExists("002 Wake up early/Scores.csv")
assertPathExists("Checkmarks.csv")
assertPathExists("Scores.csv")
}
@Throws(IOException::class)
private fun unzip(file: File) {
val zip = ZipFile(file)
val e = zip.entries()
while (e.hasMoreElements()) {
val entry = e.nextElement()
val stream = zip.getInputStream(entry)
val outputFilename = String.format(
"%s/%s",
baseDir!!.absolutePath,
entry.name
)
val out = File(outputFilename)
val parent = out.parentFile
parent?.mkdirs()
IOUtils.copy(stream, FileOutputStream(out))
}
zip.close()
}
private fun assertPathExists(s: String) {
assertAbsolutePathExists(String.format("%s/%s", baseDir!!.absolutePath, s))
}
private fun assertAbsolutePathExists(s: String) {
val file = File(s)
assertTrue(
String.format("File %s should exist", file.absolutePath),
file.exists()
)
}
}

@ -1,147 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.io;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import java.io.*;
import java.util.*;
import static junit.framework.TestCase.assertFalse;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.*;
import static org.isoron.uhabits.core.models.Entry.*;
import static org.isoron.uhabits.core.models.Frequency.*;
import static org.junit.Assert.assertTrue;
public class ImportTest extends BaseUnitTest
{
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
DateUtils.setFixedLocalTime(null);
}
@Test
public void testHabitBullCSV() throws IOException
{
importFromFile("habitbull.csv");
assertThat(habitList.size(), equalTo(4));
Habit habit = habitList.getByPosition(0);
assertThat(habit.getName(), equalTo("Breed dragons"));
assertThat(habit.getDescription(), equalTo("with love and fire"));
assertThat(habit.getFrequency(), equalTo(Frequency.DAILY));
assertTrue(isChecked(habit, 2016, 3, 18));
assertTrue(isChecked(habit, 2016, 3, 19));
assertFalse(isChecked(habit, 2016, 3, 20));
}
@Test
public void testLoopDB() throws IOException
{
importFromFile("loop.db");
assertThat(habitList.size(), equalTo(9));
Habit habit = habitList.getByPosition(0);
assertThat(habit.getName(), equalTo("Wake up early"));
assertThat(habit.getFrequency(), equalTo(THREE_TIMES_PER_WEEK));
assertTrue(isChecked(habit, 2016, 3, 14));
assertTrue(isChecked(habit, 2016, 3, 16));
assertFalse(isChecked(habit, 2016, 3, 17));
}
@Test
public void testRewireDB() throws IOException
{
importFromFile("rewire.db");
assertThat(habitList.size(), equalTo(3));
Habit habit = habitList.getByPosition(1);
assertThat(habit.getName(), equalTo("Wake up early"));
assertThat(habit.getFrequency(), equalTo(THREE_TIMES_PER_WEEK));
assertFalse(habit.hasReminder());
assertFalse(isChecked(habit, 2015, 12, 31));
assertTrue(isChecked(habit, 2016, 1, 18));
assertTrue(isChecked(habit, 2016, 1, 28));
assertFalse(isChecked(habit, 2016, 3, 10));
habit = habitList.getByPosition(2);
assertThat(habit.getName(), equalTo("brush teeth"));
assertThat(habit.getFrequency(), equalTo(THREE_TIMES_PER_WEEK));
assertThat(habit.hasReminder(), equalTo(true));
Reminder reminder = habit.getReminder();
assertThat(reminder.getHour(), equalTo(8));
assertThat(reminder.getMinute(), equalTo(0));
boolean[] reminderDays = { false, true, true, true, true, true, false };
assertThat(reminder.getDays().toArray(), equalTo(reminderDays));
}
@Test
public void testTickmateDB() throws IOException
{
importFromFile("tickmate.db");
assertThat(habitList.size(), equalTo(3));
Habit h = habitList.getByPosition(2);
assertThat(h.getName(), equalTo("Vegan"));
assertTrue(isChecked(h, 2016, 1, 24));
assertTrue(isChecked(h, 2016, 2, 5));
assertTrue(isChecked(h, 2016, 3, 18));
assertFalse(isChecked(h, 2016, 3, 14));
}
private boolean isChecked(Habit h, int year, int month, int day)
{
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
date.set(year, month - 1, day);
Timestamp timestamp = new Timestamp(date);
return h.getOriginalEntries().get(timestamp).getValue() == YES_MANUAL;
}
private void importFromFile(String assetFilename) throws IOException
{
File file = File.createTempFile("asset", "");
copyAssetToFile(assetFilename, file);
assertTrue(file.exists());
assertTrue(file.canRead());
GenericImporter importer = new GenericImporter(
new LoopDBImporter(habitList, modelFactory, databaseOpener, commandRunner, new StandardLogging()),
new RewireDBImporter(habitList, modelFactory, databaseOpener),
new TickmateDBImporter(habitList, modelFactory, databaseOpener),
new HabitBullCSVImporter(habitList, modelFactory));
assertTrue(importer.canHandle(file));
importer.importHabitsFromFile(file);
file.delete();
}
}

@ -0,0 +1,138 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.io
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Frequency
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendar
import org.isoron.uhabits.core.utils.DateUtils.Companion.setFixedLocalTime
import org.junit.Before
import org.junit.Test
import java.io.File
import java.io.IOException
class ImportTest : BaseUnitTest() {
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
setFixedLocalTime(null)
}
@Test
@Throws(IOException::class)
fun testHabitBullCSV() {
importFromFile("habitbull.csv")
assertThat(habitList.size(), IsEqual.equalTo(4))
val habit = habitList.getByPosition(0)
assertThat(habit.name, IsEqual.equalTo("Breed dragons"))
assertThat(habit.description, IsEqual.equalTo("with love and fire"))
assertThat(habit.frequency, IsEqual.equalTo(Frequency.DAILY))
assertTrue(isChecked(habit, 2016, 3, 18))
assertTrue(isChecked(habit, 2016, 3, 19))
assertFalse(isChecked(habit, 2016, 3, 20))
}
@Test
@Throws(IOException::class)
fun testLoopDB() {
importFromFile("loop.db")
assertThat(habitList.size(), IsEqual.equalTo(9))
val habit = habitList.getByPosition(0)
assertThat(habit.name, IsEqual.equalTo("Wake up early"))
assertThat(habit.frequency, IsEqual.equalTo(Frequency.THREE_TIMES_PER_WEEK))
assertTrue(isChecked(habit, 2016, 3, 14))
assertTrue(isChecked(habit, 2016, 3, 16))
assertFalse(isChecked(habit, 2016, 3, 17))
}
@Test
@Throws(IOException::class)
fun testRewireDB() {
importFromFile("rewire.db")
assertThat(habitList.size(), IsEqual.equalTo(3))
var habit = habitList.getByPosition(1)
assertThat(habit.name, IsEqual.equalTo("Wake up early"))
assertThat(habit.frequency, IsEqual.equalTo(Frequency.THREE_TIMES_PER_WEEK))
assertFalse(habit.hasReminder())
assertFalse(isChecked(habit, 2015, 12, 31))
assertTrue(isChecked(habit, 2016, 1, 18))
assertTrue(isChecked(habit, 2016, 1, 28))
assertFalse(isChecked(habit, 2016, 3, 10))
habit = habitList.getByPosition(2)
assertThat(habit.name, IsEqual.equalTo("brush teeth"))
assertThat(habit.frequency, IsEqual.equalTo(Frequency.THREE_TIMES_PER_WEEK))
assertThat(habit.hasReminder(), IsEqual.equalTo(true))
val reminder = habit.reminder
assertThat(reminder!!.hour, IsEqual.equalTo(8))
assertThat(reminder.minute, IsEqual.equalTo(0))
val reminderDays = booleanArrayOf(false, true, true, true, true, true, false)
assertThat(reminder.days.toArray(), IsEqual.equalTo(reminderDays))
}
@Test
@Throws(IOException::class)
fun testTickmateDB() {
importFromFile("tickmate.db")
assertThat(habitList.size(), IsEqual.equalTo(3))
val h = habitList.getByPosition(2)
assertThat(h.name, IsEqual.equalTo("Vegan"))
assertTrue(isChecked(h, 2016, 1, 24))
assertTrue(isChecked(h, 2016, 2, 5))
assertTrue(isChecked(h, 2016, 3, 18))
assertFalse(isChecked(h, 2016, 3, 14))
}
private fun isChecked(h: Habit, year: Int, month: Int, day: Int): Boolean {
val date = getStartOfTodayCalendar()
date.set(year, month - 1, day)
val timestamp = Timestamp(date)
return h.originalEntries.get(timestamp).value == Entry.YES_MANUAL
}
@Throws(IOException::class)
private fun importFromFile(assetFilename: String) {
val file = File.createTempFile("asset", "")
copyAssetToFile(assetFilename, file)
assertTrue(file.exists())
assertTrue(file.canRead())
val importer = GenericImporter(
LoopDBImporter(
habitList,
modelFactory,
databaseOpener,
commandRunner,
StandardLogging()
),
RewireDBImporter(habitList, modelFactory, databaseOpener),
TickmateDBImporter(habitList, modelFactory, databaseOpener),
HabitBullCSVImporter(habitList, modelFactory)
)
assertTrue(importer.canHandle(file))
importer.importHabitsFromFile(file)
file.delete()
}
}

@ -381,5 +381,5 @@ class EntryListTest {
}
}
fun day(offset: Int) = DateUtils.getToday().minus(offset)
fun day(offset: Int) = DateUtils.getToday().minus(offset)!!
}

@ -1,318 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.junit.*;
import org.junit.rules.*;
import java.io.*;
import java.util.*;
import static java.lang.Math.*;
import static junit.framework.TestCase.assertFalse;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.isoron.uhabits.core.models.HabitList.Order.*;
import static org.junit.Assert.*;
@SuppressWarnings("JavaDoc")
public class HabitListTest extends BaseUnitTest
{
@Rule
public ExpectedException thrown = ExpectedException.none();
private ArrayList<Habit> habitsArray;
private HabitList activeHabits;
private HabitList reminderHabits;
@Override
public void setUp() throws Exception
{
super.setUp();
habitsArray = new ArrayList<>();
for (int i = 0; i < 10; i++)
{
Habit habit = fixtures.createEmptyHabit();
habitList.add(habit);
habitsArray.add(habit);
if (i % 3 == 0)
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
}
habitsArray.get(0).setArchived(true);
habitsArray.get(1).setArchived(true);
habitsArray.get(4).setArchived(true);
habitsArray.get(7).setArchived(true);
activeHabits = habitList.getFiltered(new HabitMatcherBuilder().build());
reminderHabits = habitList.getFiltered(new HabitMatcherBuilder()
.setArchivedAllowed(true)
.setReminderRequired(true)
.build());
}
@Test
public void testSize()
{
assertThat(habitList.size(), equalTo(10));
assertThat(activeHabits.size(), equalTo(6));
assertThat(reminderHabits.size(), equalTo(4));
}
@Test
public void testGetByPosition()
{
assertThat(habitList.getByPosition(0), equalTo(habitsArray.get(0)));
assertThat(habitList.getByPosition(3), equalTo(habitsArray.get(3)));
assertThat(habitList.getByPosition(9), equalTo(habitsArray.get(9)));
assertThat(activeHabits.getByPosition(0), equalTo(habitsArray.get(2)));
assertThat(reminderHabits.getByPosition(1),
equalTo(habitsArray.get(3)));
}
@Test
public void testGetById()
{
Habit habit1 = habitsArray.get(0);
Habit habit2 = habitList.getById(habit1.getId());
assertThat(habit1, equalTo(habit2));
}
@Test
public void testGetById_withInvalidId()
{
assertNull(habitList.getById(100L));
}
@Test
public void testOrdering()
{
Habit h1 = fixtures.createEmptyHabit();
h1.setName("A Habit");
h1.setColor(new PaletteColor(2));
h1.setPosition(1);
Habit h2 = fixtures.createEmptyHabit();
h2.setName("B Habit");
h2.setColor(new PaletteColor(2));
h2.setPosition(3);
Habit h3 = fixtures.createEmptyHabit();
h3.setName("C Habit");
h3.setColor(new PaletteColor(0));
h3.setPosition(0);
Habit h4 = fixtures.createEmptyHabit();
h4.setName("D Habit");
h4.setColor(new PaletteColor(1));
h4.setPosition(2);
HabitList list = modelFactory.buildHabitList();
list.add(h3);
list.add(h1);
list.add(h4);
list.add(h2);
list.setPrimaryOrder(BY_POSITION);
assertThat(list.getByPosition(0), equalTo(h3));
assertThat(list.getByPosition(1), equalTo(h1));
assertThat(list.getByPosition(2), equalTo(h4));
assertThat(list.getByPosition(3), equalTo(h2));
list.setPrimaryOrder(BY_NAME_DESC);
assertThat(list.getByPosition(0), equalTo(h4));
assertThat(list.getByPosition(1), equalTo(h3));
assertThat(list.getByPosition(2), equalTo(h2));
assertThat(list.getByPosition(3), equalTo(h1));
list.setPrimaryOrder(BY_NAME_ASC);
assertThat(list.getByPosition(0), equalTo(h1));
assertThat(list.getByPosition(1), equalTo(h2));
assertThat(list.getByPosition(2), equalTo(h3));
assertThat(list.getByPosition(3), equalTo(h4));
list.setPrimaryOrder(BY_NAME_ASC);
list.remove(h1);
list.add(h1);
assertThat(list.getByPosition(0), equalTo(h1));
list.setPrimaryOrder(BY_COLOR_ASC);
list.setSecondaryOrder(BY_NAME_ASC);
assertThat(list.getByPosition(0), equalTo(h3));
assertThat(list.getByPosition(1), equalTo(h4));
assertThat(list.getByPosition(2), equalTo(h1));
assertThat(list.getByPosition(3), equalTo(h2));
list.setPrimaryOrder(BY_COLOR_DESC);
list.setSecondaryOrder(BY_NAME_ASC);
assertThat(list.getByPosition(0), equalTo(h1));
assertThat(list.getByPosition(1), equalTo(h2));
assertThat(list.getByPosition(2), equalTo(h4));
assertThat(list.getByPosition(3), equalTo(h3));
list.setPrimaryOrder(BY_POSITION);
assertThat(list.getByPosition(0), equalTo(h3));
assertThat(list.getByPosition(1), equalTo(h1));
assertThat(list.getByPosition(2), equalTo(h4));
assertThat(list.getByPosition(3), equalTo(h2));
}
@Test
public void testReorder() {
int operations[][] = {
{ 5, 2 }, { 3, 7 }, { 4, 4 }, { 8, 3 }
};
int expectedSequence[][] = {
{ 0, 1, 5, 2, 3, 4, 6, 7, 8, 9 },
{ 0, 1, 5, 2, 4, 6, 7, 3, 8, 9 },
{ 0, 1, 5, 2, 4, 6, 7, 3, 8, 9 },
{ 0, 1, 5, 2, 4, 6, 7, 8, 3, 9 },
};
for (int i = 0; i < operations.length; i++)
{
Habit fromHabit = habitsArray.get(operations[i][0]);
Habit toHabit = habitsArray.get(operations[i][1]);
habitList.reorder(fromHabit, toHabit);
int actualSequence[] = new int[10];
for (int j = 0; j < 10; j++)
{
Habit h = habitList.getByPosition(j);
assertThat(h.getPosition(), equalTo(j));
actualSequence[j] = toIntExact(h.getId());
}
assertThat(actualSequence, equalTo(expectedSequence[i]));
}
assertThat(activeHabits.indexOf(habitsArray.get(5)), equalTo(0));
assertThat(activeHabits.indexOf(habitsArray.get(2)), equalTo(1));
}
@Test
public void testReorder_withInvalidArguments() throws Exception
{
Habit h1 = habitsArray.get(0);
Habit h2 = fixtures.createEmptyHabit();
thrown.expect(IllegalArgumentException.class);
habitList.reorder(h1, h2);
}
@Test
public void testOrder_inherit()
{
habitList.setPrimaryOrder(BY_COLOR_ASC);
HabitList filteredList = habitList.getFiltered(new HabitMatcherBuilder()
.setArchivedAllowed(false)
.setCompletedAllowed(false)
.build());
assertEquals(filteredList.getPrimaryOrder(), BY_COLOR_ASC);
}
@Test
public void testWriteCSV() throws IOException
{
HabitList list = modelFactory.buildHabitList();
Habit h1 = fixtures.createEmptyHabit();
h1.setName("Meditate");
h1.setQuestion("Did you meditate this morning?");
h1.setDescription("this is a test description");
h1.setFrequency(Frequency.DAILY);
h1.setColor(new PaletteColor(3));
Habit h2 = fixtures.createEmptyHabit();
h2.setName("Wake up early");
h2.setQuestion("Did you wake up before 6am?");
h2.setDescription("");
h2.setFrequency(new Frequency(2, 3));
h2.setColor(new PaletteColor(5));
list.add(h1);
list.add(h2);
String expectedCSV =
"Position,Name,Question,Description,NumRepetitions,Interval,Color\n" +
"001,Meditate,Did you meditate this morning?,this is a test description,1,1,#FF8F00\n" +
"002,Wake up early,Did you wake up before 6am?,,2,3,#AFB42B\n";
StringWriter writer = new StringWriter();
list.writeCSV(writer);
assertThat(writer.toString(), equalTo(expectedCSV));
}
@Test
public void testAdd() throws Exception
{
Habit h1 = fixtures.createEmptyHabit();
assertFalse(h1.isArchived());
assertNull(h1.getId());
assertThat(habitList.indexOf(h1), equalTo(-1));
habitList.add(h1);
assertNotNull(h1.getId());
assertThat(habitList.indexOf(h1), not(equalTo(-1)));
assertThat(activeHabits.indexOf(h1), not(equalTo(-1)));
}
@Test
public void testAdd_withFilteredList() throws Exception
{
thrown.expect(IllegalStateException.class);
activeHabits.add(fixtures.createEmptyHabit());
}
@Test
public void testRemove_onFilteredList() throws Exception
{
thrown.expect(IllegalStateException.class);
activeHabits.remove(fixtures.createEmptyHabit());
}
@Test
public void testReorder_onFilteredList() throws Exception
{
Habit h1 = fixtures.createEmptyHabit();
Habit h2 = fixtures.createEmptyHabit();
thrown.expect(IllegalStateException.class);
activeHabits.reorder(h1, h2);
}
@Test
public void testReorder_onSortedList() throws Exception
{
habitList.setPrimaryOrder(BY_SCORE_DESC);
Habit h1 = habitsArray.get(1);
Habit h2 = habitsArray.get(2);
thrown.expect(IllegalStateException.class);
habitList.reorder(h1, h2);
}
}

@ -0,0 +1,301 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertNull
import junit.framework.TestCase
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import java.io.IOException
import java.io.StringWriter
import java.util.ArrayList
class HabitListTest : BaseUnitTest() {
@get:Rule
var thrown = ExpectedException.none()!!
private lateinit var habitsArray: ArrayList<Habit>
private lateinit var activeHabits: HabitList
private lateinit var reminderHabits: HabitList
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habitsArray = ArrayList()
for (i in 0..9) {
val habit = fixtures.createEmptyHabit()
habitList.add(habit)
habitsArray.add(habit)
if (i % 3 == 0) habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
}
habitsArray[0].isArchived = true
habitsArray[1].isArchived = true
habitsArray[4].isArchived = true
habitsArray[7].isArchived = true
activeHabits = habitList.getFiltered(HabitMatcherBuilder().build())
reminderHabits = habitList.getFiltered(
HabitMatcherBuilder()
.setArchivedAllowed(true)
.setReminderRequired(true)
.build()
)
}
@Test
fun testSize() {
assertThat(habitList.size(), CoreMatchers.equalTo(10))
assertThat(activeHabits.size(), CoreMatchers.equalTo(6))
assertThat(reminderHabits.size(), CoreMatchers.equalTo(4))
}
@Test
fun testGetByPosition() {
assertThat(
habitList.getByPosition(0),
CoreMatchers.equalTo(
habitsArray[0]
)
)
assertThat(
habitList.getByPosition(3),
CoreMatchers.equalTo(
habitsArray[3]
)
)
assertThat(
habitList.getByPosition(9),
CoreMatchers.equalTo(
habitsArray[9]
)
)
assertThat(
activeHabits.getByPosition(0),
CoreMatchers.equalTo(
habitsArray[2]
)
)
assertThat(
reminderHabits.getByPosition(1),
CoreMatchers.equalTo(habitsArray[3])
)
}
@Test
fun testGetById() {
val habit1 = habitsArray[0]
val habit2 = habitList.getById(habit1.id!!)
assertThat(habit1, CoreMatchers.equalTo(habit2))
}
@Test
fun testGetById_withInvalidId() {
assertNull(habitList.getById(100L))
}
@Test
fun testOrdering() {
val h1 = fixtures.createEmptyHabit("A Habit", PaletteColor(2), 1)
val h2 = fixtures.createEmptyHabit("B Habit", PaletteColor(2), 3)
val h3 = fixtures.createEmptyHabit("C Habit", PaletteColor(0), 0)
val h4 = fixtures.createEmptyHabit("D Habit", PaletteColor(1), 2)
val list = modelFactory.buildHabitList().apply {
add(h3)
add(h1)
add(h4)
add(h2)
}
list.primaryOrder = HabitList.Order.BY_POSITION
assertThat(list.getByPosition(0), CoreMatchers.equalTo(h3))
assertThat(list.getByPosition(1), CoreMatchers.equalTo(h1))
assertThat(list.getByPosition(2), CoreMatchers.equalTo(h4))
assertThat(list.getByPosition(3), CoreMatchers.equalTo(h2))
list.primaryOrder = HabitList.Order.BY_NAME_DESC
assertThat(list.getByPosition(0), CoreMatchers.equalTo(h4))
assertThat(list.getByPosition(1), CoreMatchers.equalTo(h3))
assertThat(list.getByPosition(2), CoreMatchers.equalTo(h2))
assertThat(list.getByPosition(3), CoreMatchers.equalTo(h1))
list.primaryOrder = HabitList.Order.BY_NAME_ASC
assertThat(list.getByPosition(0), CoreMatchers.equalTo(h1))
assertThat(list.getByPosition(1), CoreMatchers.equalTo(h2))
assertThat(list.getByPosition(2), CoreMatchers.equalTo(h3))
assertThat(list.getByPosition(3), CoreMatchers.equalTo(h4))
list.primaryOrder = HabitList.Order.BY_NAME_ASC
list.remove(h1)
list.add(h1)
assertThat(list.getByPosition(0), CoreMatchers.equalTo(h1))
list.primaryOrder = HabitList.Order.BY_COLOR_ASC
list.secondaryOrder = HabitList.Order.BY_NAME_ASC
assertThat(list.getByPosition(0), CoreMatchers.equalTo(h3))
assertThat(list.getByPosition(1), CoreMatchers.equalTo(h4))
assertThat(list.getByPosition(2), CoreMatchers.equalTo(h1))
assertThat(list.getByPosition(3), CoreMatchers.equalTo(h2))
list.primaryOrder = HabitList.Order.BY_COLOR_DESC
list.secondaryOrder = HabitList.Order.BY_NAME_ASC
assertThat(list.getByPosition(0), CoreMatchers.equalTo(h1))
assertThat(list.getByPosition(1), CoreMatchers.equalTo(h2))
assertThat(list.getByPosition(2), CoreMatchers.equalTo(h4))
assertThat(list.getByPosition(3), CoreMatchers.equalTo(h3))
list.primaryOrder = HabitList.Order.BY_POSITION
assertThat(list.getByPosition(0), CoreMatchers.equalTo(h3))
assertThat(list.getByPosition(1), CoreMatchers.equalTo(h1))
assertThat(list.getByPosition(2), CoreMatchers.equalTo(h4))
assertThat(list.getByPosition(3), CoreMatchers.equalTo(h2))
}
@Test
fun testReorder() {
val operations =
arrayOf(intArrayOf(5, 2), intArrayOf(3, 7), intArrayOf(4, 4), intArrayOf(8, 3))
val expectedSequence = arrayOf(
intArrayOf(0, 1, 5, 2, 3, 4, 6, 7, 8, 9),
intArrayOf(0, 1, 5, 2, 4, 6, 7, 3, 8, 9),
intArrayOf(0, 1, 5, 2, 4, 6, 7, 3, 8, 9),
intArrayOf(0, 1, 5, 2, 4, 6, 7, 8, 3, 9)
)
for (i in operations.indices) {
val fromHabit = habitsArray[operations[i][0]]
val toHabit = habitsArray[operations[i][1]]
habitList.reorder(fromHabit, toHabit)
val actualSequence = IntArray(10)
for (j in 0..9) {
val habit = habitList.getByPosition(j)
assertThat(habit.position, CoreMatchers.equalTo(j))
actualSequence[j] = Math.toIntExact(habit.id!!)
}
assertThat(
actualSequence,
CoreMatchers.equalTo(
expectedSequence[i]
)
)
}
assertThat(activeHabits.indexOf(habitsArray[5]), CoreMatchers.equalTo(0))
assertThat(activeHabits.indexOf(habitsArray[2]), CoreMatchers.equalTo(1))
}
@Test
@Throws(Exception::class)
fun testReorder_withInvalidArguments() {
val h1 = habitsArray[0]
val h2 = fixtures.createEmptyHabit()
thrown.expect(IllegalArgumentException::class.java)
habitList.reorder(h1, h2)
}
@Test
fun testOrder_inherit() {
habitList.primaryOrder = HabitList.Order.BY_COLOR_ASC
val filteredList = habitList.getFiltered(
HabitMatcherBuilder()
.setArchivedAllowed(false)
.setCompletedAllowed(false)
.build()
)
assertEquals(filteredList.primaryOrder, HabitList.Order.BY_COLOR_ASC)
}
@Test
@Throws(IOException::class)
fun testWriteCSV() {
val list = modelFactory.buildHabitList()
val h1 = fixtures.createEmptyHabit()
h1.name = "Meditate"
h1.question = "Did you meditate this morning?"
h1.description = "this is a test description"
h1.frequency = Frequency.DAILY
h1.color = PaletteColor(3)
val h2 = fixtures.createEmptyHabit()
h2.name = "Wake up early"
h2.question = "Did you wake up before 6am?"
h2.description = ""
h2.frequency = Frequency(2, 3)
h2.color = PaletteColor(5)
list.add(h1)
list.add(h2)
val expectedCSV =
"""
Position,Name,Question,Description,NumRepetitions,Interval,Color
001,Meditate,Did you meditate this morning?,this is a test description,1,1,#FF8F00
002,Wake up early,Did you wake up before 6am?,,2,3,#AFB42B
""".trimIndent()
val writer = StringWriter()
list.writeCSV(writer)
assertThat(writer.toString(), CoreMatchers.equalTo(expectedCSV))
}
@Test
@Throws(Exception::class)
fun testAdd() {
val h1 = fixtures.createEmptyHabit()
TestCase.assertFalse(h1.isArchived)
assertNull(h1.id)
assertThat(habitList.indexOf(h1), CoreMatchers.equalTo(-1))
habitList.add(h1)
assertNotNull(h1.id)
assertThat(
habitList.indexOf(h1),
CoreMatchers.not(CoreMatchers.equalTo(-1))
)
assertThat(
activeHabits.indexOf(h1),
CoreMatchers.not(CoreMatchers.equalTo(-1))
)
}
@Test
@Throws(Exception::class)
fun testAdd_withFilteredList() {
thrown.expect(IllegalStateException::class.java)
activeHabits.add(fixtures.createEmptyHabit())
}
@Test
@Throws(Exception::class)
fun testRemove_onFilteredList() {
thrown.expect(IllegalStateException::class.java)
activeHabits.remove(fixtures.createEmptyHabit())
}
@Test
@Throws(Exception::class)
fun testReorder_onFilteredList() {
val h1 = fixtures.createEmptyHabit()
val h2 = fixtures.createEmptyHabit()
thrown.expect(IllegalStateException::class.java)
activeHabits.reorder(h1, h2)
}
@Test
@Throws(Exception::class)
fun testReorder_onSortedList() {
habitList.primaryOrder = HabitList.Order.BY_SCORE_DESC
val h1 = habitsArray[1]
val h2 = habitsArray[2]
thrown.expect(IllegalStateException::class.java)
habitList.reorder(h1, h2)
}
}

@ -1,136 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.junit.*;
import org.junit.rules.*;
import nl.jqno.equalsverifier.*;
import static org.hamcrest.CoreMatchers.*;
import static org.isoron.uhabits.core.utils.DateUtils.*;
import static org.junit.Assert.*;
public class HabitTest extends BaseUnitTest
{
@Rule
public final ExpectedException exception = ExpectedException.none();
@Override
public void setUp() throws Exception
{
super.setUp();
}
@Test
public void testUuidGeneration()
{
Habit habit1 = modelFactory.buildHabit();
Habit habit2 = modelFactory.buildHabit();
assertNotNull(habit1.getUuid());
assertNotNull(habit2.getUuid());
assertNotEquals(habit1.getUuid(), habit2.getUuid());
}
@Test
public void test_copyAttributes()
{
Habit model = modelFactory.buildHabit();
model.setArchived(true);
model.setColor(new PaletteColor(0));
model.setFrequency(new Frequency(10, 20));
model.setReminder(new Reminder(8, 30, new WeekdayList(1)));
Habit habit = modelFactory.buildHabit();
habit.copyFrom(model);
assertThat(habit.isArchived(), is(model.isArchived()));
assertThat(habit.getColor(), is(model.getColor()));
assertThat(habit.getFrequency(), equalTo(model.getFrequency()));
assertThat(habit.getReminder(), equalTo(model.getReminder()));
}
@Test
public void test_hasReminder()
{
Habit h = modelFactory.buildHabit();
assertThat(h.hasReminder(), is(false));
h.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
assertThat(h.hasReminder(), is(true));
}
@Test
public void test_isCompleted() throws Exception
{
Habit h = modelFactory.buildHabit();
assertFalse(h.isCompletedToday());
h.getOriginalEntries().add(new Entry(getToday(), Entry.YES_MANUAL));
h.recompute();
assertTrue(h.isCompletedToday());
}
@Test
public void test_isCompleted_numerical() throws Exception
{
Habit h = modelFactory.buildHabit();
h.setType(Habit.NUMBER_HABIT);
h.setTargetType(Habit.AT_LEAST);
h.setTargetValue(100.0);
assertFalse(h.isCompletedToday());
h.getOriginalEntries().add(new Entry(getToday(), 200_000));
h.recompute();
assertTrue(h.isCompletedToday());
h.getOriginalEntries().add(new Entry(getToday(), 100_000));
h.recompute();
assertTrue(h.isCompletedToday());
h.getOriginalEntries().add(new Entry(getToday(), 50_000));
h.recompute();
assertFalse(h.isCompletedToday());
h.setTargetType(Habit.AT_MOST);
h.getOriginalEntries().add(new Entry(getToday(), 200_000));
h.recompute();
assertFalse(h.isCompletedToday());
h.getOriginalEntries().add(new Entry(getToday(), 100_000));
h.recompute();
assertTrue(h.isCompletedToday());
h.getOriginalEntries().add(new Entry(getToday(), 50_000));
h.recompute();
assertTrue(h.isCompletedToday());
}
@Test
public void testURI() throws Exception
{
assertTrue(habitList.isEmpty());
Habit h = modelFactory.buildHabit();
habitList.add(h);
assertThat(h.getId(), equalTo(0L));
assertThat(h.getUriString(),
equalTo("content://org.isoron.uhabits/habit/0"));
}
}

@ -0,0 +1,125 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 junit.framework.Assert.assertFalse
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
import org.hamcrest.CoreMatchers
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
class HabitTest : BaseUnitTest() {
@get:Rule
val exception = ExpectedException.none()!!
@Throws(Exception::class)
override fun setUp() {
super.setUp()
}
@Test
fun testUuidGeneration() {
val (_, _, _, _, _, _, _, _, _, _, _, _, _, uuid) = modelFactory.buildHabit()
val (_, _, _, _, _, _, _, _, _, _, _, _, _, uuid1) = modelFactory.buildHabit()
assertNotNull(uuid)
assertNotNull(uuid1)
assertNotEquals(uuid, uuid1)
}
@Test
fun test_copyAttributes() {
val model = modelFactory.buildHabit()
model.isArchived = true
model.color = PaletteColor(0)
model.frequency = Frequency(10, 20)
model.reminder = Reminder(8, 30, WeekdayList(1))
val habit = modelFactory.buildHabit()
habit.copyFrom(model)
assertThat(habit.isArchived, CoreMatchers.`is`(model.isArchived))
assertThat(habit.color, CoreMatchers.`is`(model.color))
assertThat(habit.frequency, CoreMatchers.equalTo(model.frequency))
assertThat(habit.reminder, CoreMatchers.equalTo(model.reminder))
}
@Test
fun test_hasReminder() {
val h = modelFactory.buildHabit()
assertThat(h.hasReminder(), CoreMatchers.`is`(false))
h.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
assertThat(h.hasReminder(), CoreMatchers.`is`(true))
}
@Test
@Throws(Exception::class)
fun test_isCompleted() {
val h = modelFactory.buildHabit()
assertFalse(h.isCompletedToday())
h.originalEntries.add(Entry(getToday(), Entry.YES_MANUAL))
h.recompute()
assertTrue(h.isCompletedToday())
}
@Test
@Throws(Exception::class)
fun test_isCompleted_numerical() {
val h = modelFactory.buildHabit()
h.type = Habit.NUMBER_HABIT
h.targetType = Habit.AT_LEAST
h.targetValue = 100.0
assertFalse(h.isCompletedToday())
h.originalEntries.add(Entry(getToday(), 200000))
h.recompute()
assertTrue(h.isCompletedToday())
h.originalEntries.add(Entry(getToday(), 100000))
h.recompute()
assertTrue(h.isCompletedToday())
h.originalEntries.add(Entry(getToday(), 50000))
h.recompute()
assertFalse(h.isCompletedToday())
h.targetType = Habit.AT_MOST
h.originalEntries.add(Entry(getToday(), 200000))
h.recompute()
assertFalse(h.isCompletedToday())
h.originalEntries.add(Entry(getToday(), 100000))
h.recompute()
assertTrue(h.isCompletedToday())
h.originalEntries.add(Entry(getToday(), 50000))
h.recompute()
assertTrue(h.isCompletedToday())
}
@Test
@Throws(Exception::class)
fun testURI() {
assertTrue(habitList.isEmpty)
val h = modelFactory.buildHabit()
habitList.add(h)
assertThat(h.id, CoreMatchers.equalTo(0L))
assertThat(
h.uriString,
CoreMatchers.equalTo("content://org.isoron.uhabits/habit/0")
)
}
}

@ -1,294 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.core.IsEqual.*;
import static org.hamcrest.number.IsCloseTo.*;
import static org.hamcrest.number.OrderingComparison.*;
import static org.isoron.uhabits.core.models.Entry.*;
public class ScoreListTest extends BaseUnitTest
{
private static final double E = 1e-6;
private Habit habit;
private Timestamp today;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
today = DateUtils.getToday();
habit = fixtures.createEmptyHabit();
}
@Test
public void test_getValue()
{
check(0, 20);
double[] expectedValues = {
0.655747,
0.636894,
0.617008,
0.596033,
0.573910,
0.550574,
0.525961,
0.500000,
0.472617,
0.443734,
0.413270,
0.381137,
0.347244,
0.311495,
0.273788,
0.234017,
0.192067,
0.147820,
0.101149,
0.051922,
0.000000,
0.000000,
0.000000
};
checkScoreValues(expectedValues);
}
@Test
public void test_getValueWithSkip()
{
check(0, 20);
addSkip(5);
addSkip(10);
addSkip(11);
habit.recompute();
double expectedValues[] = {
0.596033,
0.573910,
0.550574,
0.525961,
0.500000,
0.472617,
0.472617,
0.443734,
0.413270,
0.381137,
0.347244,
0.347244,
0.347244,
0.311495,
0.273788,
0.234017,
0.192067,
0.147820,
0.101149,
0.051922,
0.000000,
0.000000,
0.000000
};
checkScoreValues(expectedValues);
}
@Test
public void test_getValueWithSkip2()
{
check(5);
addSkip(4);
habit.recompute();
double[] expectedValues = {
0.041949,
0.044247,
0.046670,
0.049226,
0.051922,
0.051922,
0.0
};
checkScoreValues(expectedValues);
}
@Test
public void test_imperfectNonDaily()
{
// If the habit should be performed 3 times per week and the user misses 1 repetition
// each week, score should converge to 66%.
habit.setFrequency(new Frequency(3, 7));
ArrayList<Integer> values = new ArrayList<>();
for (int k = 0; k < 100; k++)
{
values.add(YES_MANUAL);
values.add(YES_MANUAL);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
}
check(values);
assertThat(habit.getScores().get(today).getValue(), closeTo(2/3.0, E));
// Missing 2 repetitions out of 4 per week, the score should converge to 50%
habit.setFrequency(new Frequency(4, 7));
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), closeTo(0.5, E));
}
@Test
public void test_irregularNonDaily()
{
// If the user performs habit perfectly each week, but on different weekdays,
// score should still converge to 100%
habit.setFrequency(new Frequency(1, 7));
ArrayList<Integer> values = new ArrayList<>();
for (int k = 0; k < 100; k++)
{
// Week 0
values.add(YES_MANUAL);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
// Week 1
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(NO);
values.add(YES_MANUAL);
}
check(values);
assertThat(habit.getScores().get(today).getValue(), closeTo(1.0, 1e-3));
}
@Test
public void shouldAchieveHighScoreInReasonableTime()
{
// Daily habits should achieve at least 99% in 3 months
habit = fixtures.createEmptyHabit();
habit.setFrequency(Frequency.DAILY);
for (int i = 0; i < 90; i++) check(i);
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), greaterThan(0.99));
// Weekly habits should achieve at least 99% in 9 months
habit = fixtures.createEmptyHabit();
habit.setFrequency(Frequency.WEEKLY);
for (int i = 0; i < 39; i++) check(7 * i);
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), greaterThan(0.99));
// Monthly habits should achieve at least 99% in 18 months
habit.setFrequency(new Frequency(1, 30));
for (int i = 0; i < 18; i++) check(30 * i);
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), greaterThan(0.99));
}
@Test
public void test_recompute()
{
assertThat(habit.getScores().get(today).getValue(), closeTo(0.0, E));
check(0, 2);
assertThat(habit.getScores().get(today).getValue(), closeTo(0.101149, E));
habit.setFrequency(new Frequency(1, 2));
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), closeTo(0.054816, E));
}
@Test
public void test_addThenRemove()
{
Habit habit = fixtures.createEmptyHabit();
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), closeTo(0.0, E));
habit.getOriginalEntries().add(new Entry(today, YES_MANUAL));
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), closeTo(0.051922, E));
habit.getOriginalEntries().add(new Entry(today, UNKNOWN));
habit.recompute();
assertThat(habit.getScores().get(today).getValue(), closeTo(0.0, E));
}
private void check(final int offset)
{
EntryList entries = habit.getOriginalEntries();
entries.add(new Entry(today.minus(offset), YES_MANUAL));
}
private void check(final int from, final int to)
{
EntryList entries = habit.getOriginalEntries();
for (int i = from; i < to; i++)
entries.add(new Entry(today.minus(i), YES_MANUAL));
habit.recompute();
}
private void check(ArrayList<Integer> values)
{
EntryList entries = habit.getOriginalEntries();
for (int i = 0; i < values.size(); i++)
if (values.get(i) == YES_MANUAL)
entries.add(new Entry(today.minus(i), YES_MANUAL));
habit.recompute();
}
private void addSkip(final int day)
{
EntryList entries = habit.getOriginalEntries();
entries.add(new Entry(today.minus(day), Entry.SKIP));
}
private void checkScoreValues(double[] expectedValues)
{
Timestamp current = today;
ScoreList scores = habit.getScores();
for (double expectedValue : expectedValues)
{
assertThat(scores.get(current).getValue(), closeTo(expectedValue, E));
current = current.minus(1);
}
}
}

@ -0,0 +1,262 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.hamcrest.MatcherAssert.assertThat
import org.hamcrest.number.IsCloseTo
import org.hamcrest.number.OrderingComparison
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.junit.Before
import org.junit.Test
import java.util.ArrayList
class ScoreListTest : BaseUnitTest() {
private lateinit var habit: Habit
private lateinit var today: Timestamp
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
today = getToday()
habit = fixtures.createEmptyHabit()
}
@Test
fun test_getValue() {
check(0, 20)
val expectedValues = doubleArrayOf(
0.655747,
0.636894,
0.617008,
0.596033,
0.573910,
0.550574,
0.525961,
0.500000,
0.472617,
0.443734,
0.413270,
0.381137,
0.347244,
0.311495,
0.273788,
0.234017,
0.192067,
0.147820,
0.101149,
0.051922,
0.000000,
0.000000,
0.000000
)
checkScoreValues(expectedValues)
}
@Test
fun test_getValueWithSkip() {
check(0, 20)
addSkip(5)
addSkip(10)
addSkip(11)
habit.recompute()
val expectedValues = doubleArrayOf(
0.596033,
0.573910,
0.550574,
0.525961,
0.500000,
0.472617,
0.472617,
0.443734,
0.413270,
0.381137,
0.347244,
0.347244,
0.347244,
0.311495,
0.273788,
0.234017,
0.192067,
0.147820,
0.101149,
0.051922,
0.000000,
0.000000,
0.000000
)
checkScoreValues(expectedValues)
}
@Test
fun test_getValueWithSkip2() {
check(5)
addSkip(4)
habit.recompute()
val expectedValues = doubleArrayOf(
0.041949,
0.044247,
0.046670,
0.049226,
0.051922,
0.051922,
0.0
)
checkScoreValues(expectedValues)
}
@Test
fun test_imperfectNonDaily() {
// If the habit should be performed 3 times per week and the user misses 1 repetition
// each week, score should converge to 66%.
habit.frequency = Frequency(3, 7)
val values = ArrayList<Int>()
for (k in 0..99) {
values.add(Entry.YES_MANUAL)
values.add(Entry.YES_MANUAL)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
}
check(values)
assertThat(habit.scores[today].value, IsCloseTo.closeTo(2 / 3.0, E))
// Missing 2 repetitions out of 4 per week, the score should converge to 50%
habit.frequency = Frequency(4, 7)
habit.recompute()
assertThat(habit.scores[today].value, IsCloseTo.closeTo(0.5, E))
}
@Test
fun test_irregularNonDaily() {
// If the user performs habit perfectly each week, but on different weekdays,
// score should still converge to 100%
habit.frequency = Frequency(1, 7)
val values = ArrayList<Int>()
for (k in 0..99) {
// Week 0
values.add(Entry.YES_MANUAL)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
// Week 1
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.NO)
values.add(Entry.YES_MANUAL)
}
check(values)
assertThat(habit.scores[today].value, IsCloseTo.closeTo(1.0, 1e-3))
}
@Test
fun shouldAchieveHighScoreInReasonableTime() {
// Daily habits should achieve at least 99% in 3 months
habit = fixtures.createEmptyHabit()
habit.frequency = Frequency.DAILY
for (i in 0..89) check(i)
habit.recompute()
assertThat(habit.scores[today].value, OrderingComparison.greaterThan(0.99))
// Weekly habits should achieve at least 99% in 9 months
habit = fixtures.createEmptyHabit()
habit.frequency = Frequency.WEEKLY
for (i in 0..38) check(7 * i)
habit.recompute()
assertThat(habit.scores[today].value, OrderingComparison.greaterThan(0.99))
// Monthly habits should achieve at least 99% in 18 months
habit.frequency = Frequency(1, 30)
for (i in 0..17) check(30 * i)
habit.recompute()
assertThat(habit.scores[today].value, OrderingComparison.greaterThan(0.99))
}
@Test
fun test_recompute() {
assertThat(habit.scores[today].value, IsCloseTo.closeTo(0.0, E))
check(0, 2)
assertThat(habit.scores[today].value, IsCloseTo.closeTo(0.101149, E))
habit.frequency = Frequency(1, 2)
habit.recompute()
assertThat(habit.scores[today].value, IsCloseTo.closeTo(0.054816, E))
}
@Test
fun test_addThenRemove() {
val habit = fixtures.createEmptyHabit()
habit.recompute()
assertThat(habit.scores[today].value, IsCloseTo.closeTo(0.0, E))
habit.originalEntries.add(Entry(today, Entry.YES_MANUAL))
habit.recompute()
assertThat(habit.scores[today].value, IsCloseTo.closeTo(0.051922, E))
habit.originalEntries.add(Entry(today, Entry.UNKNOWN))
habit.recompute()
assertThat(habit.scores[today].value, IsCloseTo.closeTo(0.0, E))
}
private fun check(offset: Int) {
val entries = habit.originalEntries
entries.add(Entry(today.minus(offset), Entry.YES_MANUAL))
}
private fun check(from: Int, to: Int) {
val entries = habit.originalEntries
for (i in from until to) entries.add(Entry(today.minus(i), Entry.YES_MANUAL))
habit.recompute()
}
private fun check(values: ArrayList<Int>) {
val entries = habit.originalEntries
for (i in values.indices) if (values[i] == Entry.YES_MANUAL) entries.add(
Entry(
today.minus(i),
Entry.YES_MANUAL
)
)
habit.recompute()
}
private fun addSkip(day: Int) {
val entries = habit.originalEntries
entries.add(Entry(today.minus(day), Entry.SKIP))
}
private fun checkScoreValues(expectedValues: DoubleArray) {
var current = today
val scores = habit.scores
for (expectedValue in expectedValues) {
assertThat(scores[current].value, IsCloseTo.closeTo(expectedValue, E))
current = current.minus(1)
}
}
companion object {
private const val E = 1e-6
}
}

@ -1,71 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.junit.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.core.IsEqual.*;
import static org.hamcrest.number.IsCloseTo.*;
import static org.isoron.uhabits.core.models.Score.*;
public class ScoreTest extends BaseUnitTest
{
private static final double E = 1e-6;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
}
@Test
public void test_compute_withDailyHabit()
{
int check = 1;
double freq = 1.0;
assertThat(compute(freq, 0, check), closeTo(0.051922, E));
assertThat(compute(freq, 0.5, check), closeTo(0.525961, E));
assertThat(compute(freq, 0.75, check), closeTo(0.762981, E));
check = 0;
assertThat(compute(freq, 0, check), closeTo(0, E));
assertThat(compute(freq, 0.5, check), closeTo(0.474039, E));
assertThat(compute(freq, 0.75, check), closeTo(0.711058, E));
}
@Test
public void test_compute_withNonDailyHabit()
{
int check = 1;
double freq = 1 / 3.0;
assertThat(compute(freq, 0, check), closeTo(0.030314, E));
assertThat(compute(freq, 0.5, check), closeTo(0.515157, E));
assertThat(compute(freq, 0.75, check), closeTo(0.757578, E));
check = 0;
assertThat(compute(freq, 0, check), closeTo(0.0, E));
assertThat(compute(freq, 0.5, check), closeTo(0.484842, E));
assertThat(compute(freq, 0.75, check), closeTo(0.727263, E));
}
}

@ -0,0 +1,94 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.hamcrest.MatcherAssert.assertThat
import org.hamcrest.number.IsCloseTo
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Score.Companion.compute
import org.junit.Before
import org.junit.Test
class ScoreTest : BaseUnitTest() {
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
}
@Test
fun test_compute_withDailyHabit() {
var check = 1
val freq = 1.0
assertThat(
compute(freq, 0.0, check.toDouble()),
IsCloseTo.closeTo(0.051922, E)
)
assertThat(
compute(freq, 0.5, check.toDouble()),
IsCloseTo.closeTo(0.525961, E)
)
assertThat(
compute(freq, 0.75, check.toDouble()),
IsCloseTo.closeTo(0.762981, E)
)
check = 0
assertThat(compute(freq, 0.0, check.toDouble()), IsCloseTo.closeTo(0.0, E))
assertThat(
compute(freq, 0.5, check.toDouble()),
IsCloseTo.closeTo(0.474039, E)
)
assertThat(
compute(freq, 0.75, check.toDouble()),
IsCloseTo.closeTo(0.711058, E)
)
}
@Test
fun test_compute_withNonDailyHabit() {
var check = 1
val freq = 1 / 3.0
assertThat(
compute(freq, 0.0, check.toDouble()),
IsCloseTo.closeTo(0.030314, E)
)
assertThat(
compute(freq, 0.5, check.toDouble()),
IsCloseTo.closeTo(0.515157, E)
)
assertThat(
compute(freq, 0.75, check.toDouble()),
IsCloseTo.closeTo(0.757578, E)
)
check = 0
assertThat(compute(freq, 0.0, check.toDouble()), IsCloseTo.closeTo(0.0, E))
assertThat(
compute(freq, 0.5, check.toDouble()),
IsCloseTo.closeTo(0.484842, E)
)
assertThat(
compute(freq, 0.75, check.toDouble()),
IsCloseTo.closeTo(0.727263, E)
)
}
companion object {
private const val E = 1e-6
}
}

@ -1,81 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.util.*;
import static junit.framework.TestCase.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.core.IsEqual.*;
import static org.mockito.Mockito.*;
public class StreakListTest extends BaseUnitTest
{
private Habit habit;
private StreakList streaks;
private Timestamp today;
@Override
public void setUp() throws Exception
{
super.setUp();
habit = fixtures.createLongHabit();
habit.setFrequency(Frequency.DAILY);
habit.recompute();
streaks = habit.getStreaks();
today = DateUtils.getToday();
}
@Test
public void testGetBest() throws Exception
{
List<Streak> best = streaks.getBest(4);
assertThat(best.size(), equalTo(4));
assertThat(best.get(0).getLength(), equalTo(4));
assertThat(best.get(1).getLength(), equalTo(3));
assertThat(best.get(2).getLength(), equalTo(5));
assertThat(best.get(3).getLength(), equalTo(6));
best = streaks.getBest(2);
assertThat(best.size(), equalTo(2));
assertThat(best.get(0).getLength(), equalTo(5));
assertThat(best.get(1).getLength(), equalTo(6));
}
@Test
public void testGetBest_withUnknowns()
{
habit.getOriginalEntries().clear();
habit.getOriginalEntries().add(new Entry(today, Entry.YES_MANUAL));
habit.getOriginalEntries().add(new Entry(today.minus(5), Entry.NO));
habit.recompute();
List<Streak> best = streaks.getBest(5);
assertThat(best.size(), equalTo(1));
assertThat(best.get(0).getLength(), equalTo(1));
}
}

@ -0,0 +1,67 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.junit.Test
class StreakListTest : BaseUnitTest() {
private lateinit var habit: Habit
private var streaks: StreakList? = null
private var today: Timestamp? = null
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit = fixtures.createLongHabit()
habit.frequency = Frequency.DAILY
habit.recompute()
streaks = habit.streaks
today = getToday()
}
@Test
@Throws(Exception::class)
fun testGetBest() {
var best = streaks!!.getBest(4)
assertThat(best.size, IsEqual.equalTo(4))
assertThat(best[0].length, IsEqual.equalTo(4))
assertThat(best[1].length, IsEqual.equalTo(3))
assertThat(best[2].length, IsEqual.equalTo(5))
assertThat(best[3].length, IsEqual.equalTo(6))
best = streaks!!.getBest(2)
assertThat(best.size, IsEqual.equalTo(2))
assertThat(best[0].length, IsEqual.equalTo(5))
assertThat(best[1].length, IsEqual.equalTo(6))
}
@Test
fun testGetBest_withUnknowns() {
habit.originalEntries.clear()
habit.originalEntries.add(Entry(today!!, Entry.YES_MANUAL))
habit.originalEntries.add(Entry(today!!.minus(5), Entry.NO))
habit.recompute()
val best = streaks!!.getBest(5)
assertThat(best.size, IsEqual.equalTo(1))
assertThat(best[0].length, IsEqual.equalTo(1))
}
}

@ -1,73 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 static junit.framework.TestCase.assertFalse;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertTrue;
public class TimestampTest extends BaseUnitTest
{
@Test
public void testCompare() throws Exception
{
Timestamp t1 = DateUtils.getToday();
Timestamp t2 = t1.minus(1);
Timestamp t3 = t1.plus(3);
assertThat(t1.compareTo(t2), greaterThan(0));
assertThat(t1.compareTo(t1), equalTo(0));
assertThat(t1.compareTo(t3), lessThan(0));
assertTrue(t1.isNewerThan(t2));
assertFalse(t1.isNewerThan(t1));
assertFalse(t2.isNewerThan(t1));
assertTrue(t2.isOlderThan(t1));
assertFalse(t1.isOlderThan(t2));
}
@Test
public void testDaysUntil() throws Exception
{
Timestamp t = DateUtils.getToday();
assertThat(t.daysUntil(t), equalTo(0));
assertThat(t.daysUntil(t.plus(1)), equalTo(1));
assertThat(t.daysUntil(t.plus(3)), equalTo(3));
assertThat(t.daysUntil(t.plus(300)), equalTo(300));
assertThat(t.daysUntil(t.minus(1)), equalTo(-1));
assertThat(t.daysUntil(t.minus(3)), equalTo(-3));
assertThat(t.daysUntil(t.minus(300)), equalTo(-300));
}
@Test
public void testInexact() throws Exception
{
Timestamp t = new Timestamp(1578054764000L);
assertThat(t.getUnixTime(), equalTo(1578009600000L));
}
}

@ -0,0 +1,67 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 junit.framework.Assert.assertTrue
import junit.framework.TestCase
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.hamcrest.Matchers.greaterThan
import org.hamcrest.Matchers.lessThan
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.junit.Test
class TimestampTest : BaseUnitTest() {
@Test
@Throws(Exception::class)
fun testCompare() {
val t1 = getToday()
val t2 = t1.minus(1)
val t3 = t1.plus(3)
assertThat(t1.compareTo(t2), greaterThan(0))
assertThat(t1.compareTo(t1), equalTo(0))
assertThat(t1.compareTo(t3), lessThan(0))
assertTrue(t1.isNewerThan(t2))
TestCase.assertFalse(t1.isNewerThan(t1))
TestCase.assertFalse(t2.isNewerThan(t1))
assertTrue(t2.isOlderThan(t1))
TestCase.assertFalse(t1.isOlderThan(t2))
}
@Test
@Throws(Exception::class)
fun testDaysUntil() {
val t = getToday()
assertThat(t.daysUntil(t), equalTo(0))
assertThat(t.daysUntil(t.plus(1)), equalTo(1))
assertThat(t.daysUntil(t.plus(3)), equalTo(3))
assertThat(t.daysUntil(t.plus(300)), equalTo(300))
assertThat(t.daysUntil(t.minus(1)), equalTo(-1))
assertThat(t.daysUntil(t.minus(3)), equalTo(-3))
assertThat(t.daysUntil(t.minus(300)), equalTo(-300))
}
@Test
@Throws(Exception::class)
fun testInexact() {
val t = Timestamp(1578054764000L)
assertThat(t.unixTime, equalTo(1578009600000L))
}
}

@ -1,56 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.*;
public class WeekdayListTest extends BaseUnitTest
{
@Test
public void test()
{
int daysInt = 124;
boolean[] daysArray = new boolean[]{
false, false, true, true, true, true, true
};
WeekdayList list = new WeekdayList(daysArray);
assertThat(list.toArray(), equalTo(daysArray));
assertThat(list.toInteger(), equalTo(daysInt));
list = new WeekdayList(daysInt);
assertThat(list.toArray(), equalTo(daysArray));
assertThat(list.toInteger(), equalTo(daysInt));
}
@Test
public void testEmpty()
{
WeekdayList list = new WeekdayList(0);
assertTrue(list.isEmpty());
assertFalse(WeekdayList.EVERY_DAY.isEmpty());
}
}

@ -0,0 +1,55 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.junit.Test
class WeekdayListTest : BaseUnitTest() {
@Test
fun test() {
val daysInt = 124
val daysArray = booleanArrayOf(
false,
false,
true,
true,
true,
true,
true
)
var list = WeekdayList(daysArray)
assertThat(list.toArray(), IsEqual.equalTo(daysArray))
assertThat(list.toInteger(), IsEqual.equalTo(daysInt))
list = WeekdayList(daysInt)
assertThat(list.toArray(), IsEqual.equalTo(daysArray))
assertThat(list.toInteger(), IsEqual.equalTo(daysInt))
}
@Test
fun testEmpty() {
val list = WeekdayList(0)
assertTrue(list.isEmpty)
assertFalse(WeekdayList.EVERY_DAY.isEmpty)
}
}

@ -22,7 +22,7 @@ package org.isoron.uhabits.core.models.sqlite
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertNull
import org.isoron.uhabits.core.BaseUnitTest.buildMemoryDatabase
import org.isoron.uhabits.core.BaseUnitTest.Companion.buildMemoryDatabase
import org.isoron.uhabits.core.database.Repository
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN

@ -1,223 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 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.junit.*;
import org.junit.rules.*;
import java.util.*;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class SQLiteHabitListTest extends BaseUnitTest
{
@Rule
public ExpectedException exception = ExpectedException.none();
private SQLiteHabitList habitList;
private Repository<HabitRecord> repository;
private ModelObservable.Listener listener;
private ArrayList<Habit> habitsArray;
private HabitList activeHabits;
private HabitList reminderHabits;
@Override
public void setUp() throws Exception
{
super.setUp();
Database db = buildMemoryDatabase();
modelFactory = new SQLModelFactory(db);
habitList = new SQLiteHabitList(modelFactory);
fixtures = new HabitFixtures(modelFactory, habitList);
repository = new Repository<>(HabitRecord.class, db);
habitsArray = new ArrayList<>();
for (int i = 0; i < 10; i++)
{
Habit habit = fixtures.createEmptyHabit();
habit.setName("habit " + (i+1));
habitList.update(habit);
habitsArray.add(habit);
if (i % 3 == 0)
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
}
habitsArray.get(0).setArchived(true);
habitsArray.get(1).setArchived(true);
habitsArray.get(4).setArchived(true);
habitsArray.get(7).setArchived(true);
habitList.update(habitsArray);
activeHabits = habitList.getFiltered(new HabitMatcherBuilder().build());
reminderHabits = habitList.getFiltered(new HabitMatcherBuilder()
.setArchivedAllowed(true)
.setReminderRequired(true)
.build());
listener = mock(ModelObservable.Listener.class);
habitList.getObservable().addListener(listener);
}
@Override
public void tearDown() throws Exception
{
habitList.getObservable().removeListener(listener);
super.tearDown();
}
@Test
public void testAdd_withDuplicate()
{
Habit habit = modelFactory.buildHabit();
habitList.add(habit);
verify(listener).onModelChange();
exception.expect(IllegalArgumentException.class);
habitList.add(habit);
}
@Test
public void testAdd_withId()
{
Habit habit = modelFactory.buildHabit();
habit.setName("Hello world with id");
habit.setId(12300L);
habitList.add(habit);
assertThat(habit.getId(), equalTo(12300L));
HabitRecord record = repository.find(12300L);
assertNotNull(record);
assertThat(record.name, equalTo(habit.getName()));
}
@Test
public void testAdd_withoutId()
{
Habit habit = modelFactory.buildHabit();
habit.setName("Hello world");
assertNull(habit.getId());
habitList.add(habit);
assertNotNull(habit.getId());
HabitRecord record = repository.find(habit.getId());
assertNotNull(record);
assertThat(record.name, equalTo(habit.getName()));
}
@Test
public void testSize()
{
assertThat(habitList.size(), equalTo(10));
}
@Test
public void testGetById()
{
Habit h1 = habitList.getById(1);
assertNotNull(h1);
assertThat(h1.getName(), equalTo("habit 1"));
Habit h2 = habitList.getById(2);
assertNotNull(h2);
assertThat(h2, equalTo(h2));
}
@Test
public void testGetById_withInvalid()
{
long invalidId = 9183792001L;
Habit h1 = habitList.getById(invalidId);
assertNull(h1);
}
@Test
public void testGetByPosition()
{
Habit h = habitList.getByPosition(4);
assertNotNull(h);
assertThat(h.getName(), equalTo("habit 5"));
}
@Test
public void testIndexOf()
{
Habit h1 = habitList.getByPosition(5);
assertNotNull(h1);
assertThat(habitList.indexOf(h1), equalTo(5));
Habit h2 = modelFactory.buildHabit();
assertThat(habitList.indexOf(h2), equalTo(-1));
h2.setId(1000L);
assertThat(habitList.indexOf(h2), equalTo(-1));
}
@Test
public void testRemove() throws Exception
{
Habit h = habitList.getById(2);
habitList.remove(h);
assertThat(habitList.indexOf(h), equalTo(-1));
HabitRecord rec = repository.find(2L);
assertNull(rec);
rec = repository.find(3L);
assertNotNull(rec);
assertThat(rec.position, equalTo(1));
}
@Test
public void testReorder()
{
Habit habit3 = habitList.getById(3);
Habit habit4 = habitList.getById(4);
assertNotNull(habit3);
assertNotNull(habit4);
habitList.reorder(habit4, habit3);
HabitRecord record3 = repository.find(3L);
assertNotNull(record3);
assertThat(record3.position, equalTo(3));
HabitRecord record4 = repository.find(4L);
assertNotNull(record4);
assertThat(record4.position, equalTo(2));
}
}

@ -0,0 +1,193 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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 junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertNull
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.database.Database
import org.isoron.uhabits.core.database.Repository
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.HabitMatcherBuilder
import org.isoron.uhabits.core.models.ModelObservable
import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList
import org.isoron.uhabits.core.models.sqlite.records.HabitRecord
import org.isoron.uhabits.core.test.HabitFixtures
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.mockito.Mockito
import java.util.ArrayList
class SQLiteHabitListTest : BaseUnitTest() {
@get:Rule
var exception = ExpectedException.none()!!
private lateinit var repository: Repository<HabitRecord>
private lateinit var listener: ModelObservable.Listener
private lateinit var habitsArray: ArrayList<Habit>
private lateinit var activeHabits: HabitList
private lateinit var reminderHabits: HabitList
@Throws(Exception::class)
override fun setUp() {
super.setUp()
val db: Database = buildMemoryDatabase()
modelFactory = SQLModelFactory(db)
habitList = SQLiteHabitList(modelFactory)
fixtures = HabitFixtures(modelFactory, habitList)
repository = Repository(
HabitRecord::class.java,
db
)
habitsArray = ArrayList()
for (i in 0..9) {
val habit = fixtures.createEmptyHabit()
habit.name = "habit " + (i + 1)
habitList.update(habit)
habitsArray.add(habit)
if (i % 3 == 0) habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
}
habitsArray[0].isArchived = true
habitsArray[1].isArchived = true
habitsArray[4].isArchived = true
habitsArray[7].isArchived = true
habitList.update(habitsArray)
activeHabits = habitList.getFiltered(HabitMatcherBuilder().build())
reminderHabits = habitList.getFiltered(
HabitMatcherBuilder()
.setArchivedAllowed(true)
.setReminderRequired(true)
.build()
)
listener = Mockito.mock(ModelObservable.Listener::class.java)
habitList.observable.addListener(listener)
}
@Throws(Exception::class)
override fun tearDown() {
habitList.observable.removeListener(listener)
super.tearDown()
}
@Test
fun testAdd_withDuplicate() {
val habit = modelFactory.buildHabit()
habitList.add(habit)
Mockito.verify(listener)!!.onModelChange()
exception.expect(IllegalArgumentException::class.java)
habitList.add(habit)
}
@Test
fun testAdd_withId() {
val habit = modelFactory.buildHabit()
habit.name = "Hello world with id"
habit.id = 12300L
habitList.add(habit)
assertThat(habit.id, CoreMatchers.equalTo(12300L))
val record = repository.find(12300L)
assertNotNull(record)
assertThat(record!!.name, CoreMatchers.equalTo(habit.name))
}
@Test
fun testAdd_withoutId() {
val habit = modelFactory.buildHabit()
habit.name = "Hello world"
assertNull(habit.id)
habitList.add(habit)
assertNotNull(habit.id)
val record = repository.find(
habit.id!!
)
assertNotNull(record)
assertThat(record!!.name, CoreMatchers.equalTo(habit.name))
}
@Test
fun testSize() {
assertThat(habitList.size(), CoreMatchers.equalTo(10))
}
@Test
fun testGetById() {
val h1 = habitList.getById(1)
assertNotNull(h1)
assertThat(h1!!.name, CoreMatchers.equalTo("habit 1"))
val h2 = habitList.getById(2)
assertNotNull(h2)
assertThat(h2, CoreMatchers.equalTo(h2))
}
@Test
fun testGetById_withInvalid() {
val invalidId = 9183792001L
val h1 = habitList.getById(invalidId)
assertNull(h1)
}
@Test
fun testGetByPosition() {
val h = habitList.getByPosition(4)
assertNotNull(h)
assertThat(h.name, CoreMatchers.equalTo("habit 5"))
}
@Test
fun testIndexOf() {
val h1 = habitList.getByPosition(5)
assertNotNull(h1)
assertThat(habitList.indexOf(h1), CoreMatchers.equalTo(5))
val h2 = modelFactory.buildHabit()
assertThat(habitList.indexOf(h2), CoreMatchers.equalTo(-1))
h2.id = 1000L
assertThat(habitList.indexOf(h2), CoreMatchers.equalTo(-1))
}
@Test
@Throws(Exception::class)
fun testRemove() {
val h = habitList.getById(2)
habitList.remove(h!!)
assertThat(habitList.indexOf(h), CoreMatchers.equalTo(-1))
var rec = repository.find(2L)
assertNull(rec)
rec = repository.find(3L)
assertNotNull(rec)
assertThat(rec!!.position, CoreMatchers.equalTo(1))
}
@Test
fun testReorder() {
val habit3 = habitList.getById(3)
val habit4 = habitList.getById(4)
assertNotNull(habit3)
assertNotNull(habit4)
habitList.reorder(habit4!!, habit3!!)
val record3 = repository.find(3L)
assertNotNull(record3)
assertThat(record3!!.position, CoreMatchers.equalTo(3))
val record4 = repository.find(4L)
assertNotNull(record4)
assertThat(record4!!.position, CoreMatchers.equalTo(2))
}
}

@ -16,24 +16,22 @@
* 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.records
package org.isoron.uhabits.core.models.sqlite.records;
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Timestamp
import org.junit.Test
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
public class EntryRecordTest extends BaseUnitTest
{
class EntryRecordTest : BaseUnitTest() {
@Test
public void testRecord() throws Exception
{
Entry check = new Entry(Timestamp.ZERO.plus(100), 50);
EntryRecord record = new EntryRecord();
record.copyFrom(check);
assertThat(check, equalTo(record.toEntry()));
@Throws(Exception::class)
fun testRecord() {
val check = Entry(Timestamp.ZERO.plus(100), 50)
val record = EntryRecord()
record.copyFrom(check)
assertThat(check, IsEqual.equalTo(record.toEntry()))
}
}

@ -1,79 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.records;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.core.IsEqual.*;
public class HabitRecordTest extends BaseUnitTest
{
@Test
public void testCopyRestore1()
{
Habit original = modelFactory.buildHabit();
original.setName("Hello world");
original.setQuestion("Did you greet the world today?");
original.setColor(new PaletteColor(1));
original.setArchived(true);
original.setFrequency(Frequency.THREE_TIMES_PER_WEEK);
original.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
original.setId(1000L);
original.setPosition(20);
HabitRecord record = new HabitRecord();
record.copyFrom(original);
Habit duplicate = modelFactory.buildHabit();
record.copyTo(duplicate);
assertThat(original, equalTo(duplicate));
}
@Test
public void testCopyRestore2()
{
Habit original = modelFactory.buildHabit();
original.setName("Hello world");
original.setQuestion("Did you greet the world today?");
original.setColor(new PaletteColor(5));
original.setArchived(false);
original.setFrequency(Frequency.DAILY);
original.setReminder(null);
original.setId(1L);
original.setPosition(15);
original.setType(Habit.NUMBER_HABIT);
original.setTargetValue(100);
original.setTargetType(Habit.AT_LEAST);
original.setUnit("miles");
HabitRecord record = new HabitRecord();
record.copyFrom(original);
Habit duplicate = modelFactory.buildHabit();
record.copyTo(duplicate);
assertThat(original, equalTo(duplicate));
}
}

@ -0,0 +1,71 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.records
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Frequency
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList
import org.junit.Test
class HabitRecordTest : BaseUnitTest() {
@Test
fun testCopyRestore1() {
val original = modelFactory.buildHabit()
original.name = "Hello world"
original.question = "Did you greet the world today?"
original.color = PaletteColor(1)
original.isArchived = true
original.frequency = Frequency.THREE_TIMES_PER_WEEK
original.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
original.id = 1000L
original.position = 20
val record = HabitRecord()
record.copyFrom(original)
val duplicate = modelFactory.buildHabit()
record.copyTo(duplicate)
assertThat(original, IsEqual.equalTo(duplicate))
}
@Test
fun testCopyRestore2() {
val original = modelFactory.buildHabit()
original.name = "Hello world"
original.question = "Did you greet the world today?"
original.color = PaletteColor(5)
original.isArchived = false
original.frequency = Frequency.DAILY
original.reminder = null
original.id = 1L
original.position = 15
original.type = Habit.NUMBER_HABIT
original.targetValue = 100.0
original.targetType = Habit.AT_LEAST
original.unit = "miles"
val record = HabitRecord()
record.copyFrom(original)
val duplicate = modelFactory.buildHabit()
record.copyTo(duplicate)
assertThat(original, IsEqual.equalTo(duplicate))
}
}

@ -1,186 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.preferences;
import androidx.annotation.*;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.ui.*;
import org.junit.*;
import org.mockito.*;
import java.io.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
public class PreferencesTest extends BaseUnitTest
{
@NonNull
private Preferences prefs;
@Mock
private Preferences.Listener listener;
private PropertiesStorage storage;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
File file = File.createTempFile("prefs", ".properties");
file.deleteOnExit();
storage = new PropertiesStorage(file);
prefs = new Preferences(storage);
prefs.addListener(listener);
}
@Test
public void testClear() throws Exception
{
prefs.setDefaultHabitColor(99);
prefs.clear();
assertThat(prefs.getDefaultHabitColor(0), equalTo(0));
}
@Test
public void testHabitColor() throws Exception
{
assertThat(prefs.getDefaultHabitColor(999), equalTo(999));
prefs.setDefaultHabitColor(10);
assertThat(prefs.getDefaultHabitColor(999), equalTo(10));
}
@Test
public void testDefaultOrder() throws Exception
{
assertThat(prefs.getDefaultPrimaryOrder(), equalTo(HabitList.Order.BY_POSITION));
prefs.setDefaultPrimaryOrder(HabitList.Order.BY_SCORE_DESC);
assertThat(prefs.getDefaultPrimaryOrder(), equalTo(HabitList.Order.BY_SCORE_DESC));
storage.putString("pref_default_order", "BOGUS");
assertThat(prefs.getDefaultPrimaryOrder(), equalTo(HabitList.Order.BY_POSITION));
assertThat(storage.getString("pref_default_order", ""), equalTo("BY_POSITION"));
}
@Test
public void testScoreCardSpinnerPosition() throws Exception
{
assertThat(prefs.getScoreCardSpinnerPosition(), equalTo(1));
prefs.setScoreCardSpinnerPosition(4);
assertThat(prefs.getScoreCardSpinnerPosition(), equalTo(4));
storage.putInt("pref_score_view_interval", 9000);
assertThat(prefs.getScoreCardSpinnerPosition(), equalTo(4));
}
@Test
public void testLastHint() throws Exception
{
assertThat(prefs.getLastHintNumber(), equalTo(-1));
assertNull(prefs.getLastHintTimestamp());
prefs.updateLastHint(34, Timestamp.ZERO.plus(100));
assertThat(prefs.getLastHintNumber(), equalTo(34));
assertThat(prefs.getLastHintTimestamp(), equalTo(Timestamp.ZERO.plus(100)));
}
@Test
public void testTheme() throws Exception
{
assertThat(prefs.getTheme(), equalTo(ThemeSwitcher.THEME_AUTOMATIC));
prefs.setTheme(ThemeSwitcher.THEME_DARK);
assertThat(prefs.getTheme(), equalTo(ThemeSwitcher.THEME_DARK));
assertFalse(prefs.isPureBlackEnabled());
prefs.setPureBlackEnabled(true);
assertTrue(prefs.isPureBlackEnabled());
}
@Test
public void testNotifications() throws Exception
{
assertFalse(prefs.shouldMakeNotificationsSticky());
prefs.setNotificationsSticky(true);
assertTrue(prefs.shouldMakeNotificationsSticky());
assertFalse(prefs.shouldMakeNotificationsLed());
prefs.setNotificationsLed(true);
assertTrue(prefs.shouldMakeNotificationsLed());
assertThat(prefs.getSnoozeInterval(), equalTo(15L));
prefs.setSnoozeInterval(30);
assertThat(prefs.getSnoozeInterval(), equalTo(30L));
}
@Test
public void testAppVersionAndLaunch() throws Exception
{
assertThat(prefs.getLastAppVersion(), equalTo(0));
prefs.setLastAppVersion(23);
assertThat(prefs.getLastAppVersion(), equalTo(23));
assertTrue(prefs.isFirstRun());
prefs.setFirstRun(false);
assertFalse(prefs.isFirstRun());
assertThat(prefs.getLaunchCount(), equalTo(0));
prefs.incrementLaunchCount();
assertThat(prefs.getLaunchCount(), equalTo(1));
}
@Test
public void testCheckmarks() throws Exception
{
assertFalse(prefs.isCheckmarkSequenceReversed());
prefs.setCheckmarkSequenceReversed(true);
assertTrue(prefs.isCheckmarkSequenceReversed());
assertFalse(prefs.isShortToggleEnabled());
prefs.setShortToggleEnabled(true);
assertTrue(prefs.isShortToggleEnabled());
}
@Test
public void testDeveloper() throws Exception
{
assertFalse(prefs.isDeveloper());
prefs.setDeveloper(true);
assertTrue(prefs.isDeveloper());
}
@Test
public void testFiltering() throws Exception
{
assertFalse(prefs.getShowArchived());
assertTrue(prefs.getShowCompleted());
prefs.setShowArchived(true);
prefs.setShowCompleted(false);
assertTrue(prefs.getShowArchived());
assertFalse(prefs.getShowCompleted());
}
}

@ -0,0 +1,180 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.preferences
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertNull
import junit.framework.Assert.assertTrue
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.ui.ThemeSwitcher
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import java.io.File
class PreferencesTest : BaseUnitTest() {
private lateinit var prefs: Preferences
@Mock
private val listener: Preferences.Listener? = null
private var storage: PropertiesStorage? = null
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
val file = File.createTempFile("prefs", ".properties")
file.deleteOnExit()
storage = PropertiesStorage(file)
prefs = Preferences(storage!!)
prefs.addListener(listener)
}
@Test
@Throws(Exception::class)
fun testClear() {
prefs.setDefaultHabitColor(99)
prefs.clear()
assertThat(prefs.getDefaultHabitColor(0), IsEqual.equalTo(0))
}
@Test
@Throws(Exception::class)
fun testHabitColor() {
assertThat(prefs.getDefaultHabitColor(999), IsEqual.equalTo(999))
prefs.setDefaultHabitColor(10)
assertThat(prefs.getDefaultHabitColor(999), IsEqual.equalTo(10))
}
@Test
@Throws(Exception::class)
fun testDefaultOrder() {
assertThat(
prefs.defaultPrimaryOrder,
IsEqual.equalTo(HabitList.Order.BY_POSITION)
)
prefs.defaultPrimaryOrder = HabitList.Order.BY_SCORE_DESC
assertThat(
prefs.defaultPrimaryOrder,
IsEqual.equalTo(HabitList.Order.BY_SCORE_DESC)
)
storage!!.putString("pref_default_order", "BOGUS")
assertThat(
prefs.defaultPrimaryOrder,
IsEqual.equalTo(HabitList.Order.BY_POSITION)
)
assertThat(
storage!!.getString("pref_default_order", ""),
IsEqual.equalTo("BY_POSITION")
)
}
@Test
@Throws(Exception::class)
fun testScoreCardSpinnerPosition() {
assertThat(prefs.scoreCardSpinnerPosition, IsEqual.equalTo(1))
prefs.scoreCardSpinnerPosition = 4
assertThat(prefs.scoreCardSpinnerPosition, IsEqual.equalTo(4))
storage!!.putInt("pref_score_view_interval", 9000)
assertThat(prefs.scoreCardSpinnerPosition, IsEqual.equalTo(4))
}
@Test
@Throws(Exception::class)
fun testLastHint() {
assertThat(prefs.lastHintNumber, IsEqual.equalTo(-1))
assertNull(prefs.lastHintTimestamp)
prefs.updateLastHint(34, Timestamp.ZERO.plus(100))
assertThat(prefs.lastHintNumber, IsEqual.equalTo(34))
assertThat(prefs.lastHintTimestamp, IsEqual.equalTo(Timestamp.ZERO.plus(100)))
}
@Test
@Throws(Exception::class)
fun testTheme() {
assertThat(prefs.theme, IsEqual.equalTo(ThemeSwitcher.THEME_AUTOMATIC))
prefs.theme = ThemeSwitcher.THEME_DARK
assertThat(prefs.theme, IsEqual.equalTo(ThemeSwitcher.THEME_DARK))
assertFalse(prefs.isPureBlackEnabled)
prefs.isPureBlackEnabled = true
assertTrue(prefs.isPureBlackEnabled)
}
@Test
@Throws(Exception::class)
fun testNotifications() {
assertFalse(prefs.shouldMakeNotificationsSticky())
prefs.setNotificationsSticky(true)
assertTrue(prefs.shouldMakeNotificationsSticky())
assertFalse(prefs.shouldMakeNotificationsLed())
prefs.setNotificationsLed(true)
assertTrue(prefs.shouldMakeNotificationsLed())
assertThat(prefs.snoozeInterval, IsEqual.equalTo(15L))
prefs.setSnoozeInterval(30)
assertThat(prefs.snoozeInterval, IsEqual.equalTo(30L))
}
@Test
@Throws(Exception::class)
fun testAppVersionAndLaunch() {
assertThat(prefs.lastAppVersion, IsEqual.equalTo(0))
prefs.lastAppVersion = 23
assertThat(prefs.lastAppVersion, IsEqual.equalTo(23))
assertTrue(prefs.isFirstRun)
prefs.isFirstRun = false
assertFalse(prefs.isFirstRun)
assertThat(prefs.launchCount, IsEqual.equalTo(0))
prefs.incrementLaunchCount()
assertThat(prefs.launchCount, IsEqual.equalTo(1))
}
@Test
@Throws(Exception::class)
fun testCheckmarks() {
assertFalse(prefs.isCheckmarkSequenceReversed)
prefs.isCheckmarkSequenceReversed = true
assertTrue(prefs.isCheckmarkSequenceReversed)
assertFalse(prefs.isShortToggleEnabled)
prefs.isShortToggleEnabled = true
assertTrue(prefs.isShortToggleEnabled)
}
@Test
@Throws(Exception::class)
fun testDeveloper() {
assertFalse(prefs.isDeveloper)
prefs.isDeveloper = true
assertTrue(prefs.isDeveloper)
}
@Test
@Throws(Exception::class)
fun testFiltering() {
assertFalse(prefs.showArchived)
assertTrue(prefs.showCompleted)
prefs.showArchived = true
prefs.showCompleted = false
assertTrue(prefs.showArchived)
assertFalse(prefs.showCompleted)
}
}

@ -1,119 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.preferences;
import org.isoron.uhabits.core.*;
import org.junit.*;
import java.io.*;
import java.util.*;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertTrue;
public class PropertiesStorageTest extends BaseUnitTest
{
private PropertiesStorage storage;
private File file;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
file = File.createTempFile("test", ".properties");
file.deleteOnExit();
storage = new PropertiesStorage(file);
}
@Test
public void testPutGetRemove() throws Exception
{
storage.putBoolean("booleanKey", true);
assertTrue(storage.getBoolean("booleanKey", false));
assertFalse(storage.getBoolean("random", false));
storage.putInt("intKey", 64);
assertThat(storage.getInt("intKey", 200), equalTo(64));
assertThat(storage.getInt("random", 200), equalTo(200));
storage.putLong("longKey", 64L);
assertThat(storage.getLong("intKey", 200L), equalTo(64L));
assertThat(storage.getLong("random", 200L), equalTo(200L));
storage.putString("stringKey", "Hello");
assertThat(storage.getString("stringKey", ""), equalTo("Hello"));
assertThat(storage.getString("random", ""), equalTo(""));
storage.remove("stringKey");
assertThat(storage.getString("stringKey", ""), equalTo(""));
storage.clear();
assertThat(storage.getLong("intKey", 200L), equalTo(200L));
assertFalse(storage.getBoolean("booleanKey", false));
}
@Test
public void testPersistence() throws Exception
{
storage.putBoolean("booleanKey", true);
storage.putInt("intKey", 64);
storage.putLong("longKey", 64L);
storage.putString("stringKey", "Hello");
PropertiesStorage storage2 = new PropertiesStorage(file);
assertTrue(storage2.getBoolean("booleanKey", false));
assertThat(storage2.getInt("intKey", 200), equalTo(64));
assertThat(storage2.getLong("intKey", 200L), equalTo(64L));
assertThat(storage2.getString("stringKey", ""), equalTo("Hello"));
}
@Test
public void testLongArray() throws Exception
{
long[] expected1 = new long[]{1L, 2L, 3L, 5L};
long[] expected2 = new long[]{1L};
long[] expected3 = new long[]{};
long[] expected4 = new long[]{};
storage.putLongArray("key1", expected1);
storage.putLongArray("key2", expected2);
storage.putLongArray("key3", expected3);
long[] actual1 = storage.getLongArray("key1", new long[]{});
long[] actual2 = storage.getLongArray("key2", new long[]{});
long[] actual3 = storage.getLongArray("key3", new long[]{});
long[] actual4 = storage.getLongArray("invalidKey", new long[]{});
assertTrue(Arrays.equals(actual1, expected1));
assertTrue(Arrays.equals(actual2, expected2));
assertTrue(Arrays.equals(actual3, expected3));
assertTrue(Arrays.equals(actual4, expected4));
assertEquals("1,2,3,5", storage.getString("key1", ""));
assertEquals(1, storage.getLong("key2", -1));
}
}

@ -0,0 +1,103 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.preferences
import junit.framework.Assert.assertTrue
import junit.framework.TestCase
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.junit.Before
import org.junit.Test
import java.io.File
import java.util.Arrays
class PropertiesStorageTest : BaseUnitTest() {
private var storage: PropertiesStorage? = null
private lateinit var file: File
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
file = File.createTempFile("test", ".properties")
file.deleteOnExit()
storage = PropertiesStorage(file)
}
@Test
@Throws(Exception::class)
fun testPutGetRemove() {
storage!!.putBoolean("booleanKey", true)
assertTrue(storage!!.getBoolean("booleanKey", false))
TestCase.assertFalse(storage!!.getBoolean("random", false))
storage!!.putInt("intKey", 64)
assertThat(storage!!.getInt("intKey", 200), IsEqual.equalTo(64))
assertThat(storage!!.getInt("random", 200), IsEqual.equalTo(200))
storage!!.putLong("longKey", 64L)
assertThat(storage!!.getLong("intKey", 200L), IsEqual.equalTo(64L))
assertThat(storage!!.getLong("random", 200L), IsEqual.equalTo(200L))
storage!!.putString("stringKey", "Hello")
assertThat(storage!!.getString("stringKey", ""), IsEqual.equalTo("Hello"))
assertThat(storage!!.getString("random", ""), IsEqual.equalTo(""))
storage!!.remove("stringKey")
assertThat(storage!!.getString("stringKey", ""), IsEqual.equalTo(""))
storage!!.clear()
assertThat(storage!!.getLong("intKey", 200L), IsEqual.equalTo(200L))
TestCase.assertFalse(storage!!.getBoolean("booleanKey", false))
}
@Test
@Throws(Exception::class)
fun testPersistence() {
storage!!.putBoolean("booleanKey", true)
storage!!.putInt("intKey", 64)
storage!!.putLong("longKey", 64L)
storage!!.putString("stringKey", "Hello")
val storage2 = PropertiesStorage(
file
)
assertTrue(storage2.getBoolean("booleanKey", false))
assertThat(storage2.getInt("intKey", 200), IsEqual.equalTo(64))
assertThat(storage2.getLong("intKey", 200L), IsEqual.equalTo(64L))
assertThat(storage2.getString("stringKey", ""), IsEqual.equalTo("Hello"))
}
@Test
@Throws(Exception::class)
fun testLongArray() {
val expected1 = longArrayOf(1L, 2L, 3L, 5L)
val expected2 = longArrayOf(1L)
val expected3 = longArrayOf()
val expected4 = longArrayOf()
storage!!.putLongArray("key1", expected1)
storage!!.putLongArray("key2", expected2)
storage!!.putLongArray("key3", expected3)
val actual1 = storage!!.getLongArray("key1", longArrayOf())
val actual2 = storage!!.getLongArray("key2", longArrayOf())
val actual3 = storage!!.getLongArray("key3", longArrayOf())
val actual4 = storage!!.getLongArray("invalidKey", longArrayOf())
assertTrue(Arrays.equals(actual1, expected1))
assertTrue(Arrays.equals(actual2, expected2))
assertTrue(Arrays.equals(actual3, expected3))
assertTrue(Arrays.equals(actual4, expected4))
TestCase.assertEquals("1,2,3,5", storage!!.getString("key1", ""))
TestCase.assertEquals(1, storage!!.getLong("key2", -1))
}
}

@ -1,171 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.reminders;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import org.junit.runner.*;
import org.mockito.*;
import org.mockito.junit.*;
import java.util.*;
import static org.isoron.uhabits.core.utils.DateUtils.applyTimezone;
import static org.isoron.uhabits.core.utils.DateUtils.removeTimezone;
import static org.isoron.uhabits.core.utils.DateUtils.setFixedLocalTime;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ReminderSchedulerTest extends BaseUnitTest
{
private final long habitId = 10L;
private Habit habit;
private ReminderScheduler reminderScheduler;
@Mock
private ReminderScheduler.SystemScheduler sys;
@Mock
private WidgetPreferences widgetPreferences;
@Before
@Override
public void setUp() throws Exception
{
super.setUp();
habit = fixtures.createEmptyHabit();
habit.setId(habitId);
reminderScheduler =
new ReminderScheduler(commandRunner, habitList, sys, widgetPreferences);
DateUtils.setFixedTimeZone(TimeZone.getTimeZone("GMT-4"));
}
@Test
public void testScheduleAll()
{
long now = unixTime(2015, 1, 26, 13, 0);
setFixedLocalTime(now);
Habit h1 = fixtures.createEmptyHabit();
Habit h2 = fixtures.createEmptyHabit();
Habit h3 = fixtures.createEmptyHabit();
h1.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
h2.setReminder(new Reminder(18, 30, WeekdayList.EVERY_DAY));
h3.setReminder(null);
habitList.add(h1);
habitList.add(h2);
habitList.add(h3);
reminderScheduler.scheduleAll();
verify(sys).scheduleShowReminder(eq(unixTime(2015, 1, 27, 12, 30)),
eq(h1), anyLong());
verify(sys).scheduleShowReminder(eq(unixTime(2015, 1, 26, 22, 30)),
eq(h2), anyLong());
}
@Test
public void testSchedule_atSpecificTime()
{
long atTime = unixTime(2015, 1, 30, 11, 30);
long expectedCheckmarkTime = unixTime(2015, 1, 30, 0, 0);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
scheduleAndVerify(atTime, expectedCheckmarkTime, atTime);
}
@Test
public void testSchedule_withSnooze()
{
long now = removeTimezone(unixTime(2015, 1, 1, 15, 0));
setFixedLocalTime(now);
long snoozeTimeInFuture = unixTime(2015, 1, 1, 21, 0);
long snoozeTimeInPast = unixTime(2015, 1, 1, 7, 0);
long regularReminderTime = applyTimezone(unixTime(2015, 1, 2, 8, 30));
long todayCheckmarkTime = unixTime(2015, 1, 1, 0, 0);
long tomorrowCheckmarkTime = unixTime(2015, 1, 2, 0, 0);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
when(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInFuture);
reminderScheduler.schedule(habit);
verify(sys).scheduleShowReminder(snoozeTimeInFuture, habit, todayCheckmarkTime);
when(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInPast);
reminderScheduler.schedule(habit);
verify(sys).scheduleShowReminder(regularReminderTime, habit, tomorrowCheckmarkTime);
}
@Test
public void testSchedule_laterToday()
{
long now = unixTime(2015, 1, 26, 6, 30);
setFixedLocalTime(now);
long expectedCheckmarkTime = unixTime(2015, 1, 26, 0, 0);
long expectedReminderTime = unixTime(2015, 1, 26, 12, 30);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime);
}
@Test
public void testSchedule_tomorrow()
{
long now = unixTime(2015, 1, 26, 13, 0);
setFixedLocalTime(now);
long expectedCheckmarkTime = unixTime(2015, 1, 27, 0, 0);
long expectedReminderTime = unixTime(2015, 1, 27, 12, 30);
habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime);
}
@Test
public void testSchedule_withoutReminder()
{
reminderScheduler.schedule(habit);
}
public long unixTime(int year, int month, int day, int hour, int minute)
{
Calendar cal = DateUtils.getStartOfTodayCalendar();
cal.set(year, month, day, hour, minute);
return cal.getTimeInMillis();
}
private void scheduleAndVerify(Long atTime,
long expectedCheckmarkTime,
long expectedReminderTime)
{
if(atTime == null) reminderScheduler.schedule(habit);
else reminderScheduler.scheduleAtTime(habit, atTime);
verify(sys).scheduleShowReminder(expectedReminderTime, habit,
expectedCheckmarkTime);
}
}

@ -0,0 +1,161 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.reminders
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList
import org.isoron.uhabits.core.preferences.WidgetPreferences
import org.isoron.uhabits.core.utils.DateUtils.Companion.applyTimezone
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendar
import org.isoron.uhabits.core.utils.DateUtils.Companion.removeTimezone
import org.isoron.uhabits.core.utils.DateUtils.Companion.setFixedLocalTime
import org.isoron.uhabits.core.utils.DateUtils.Companion.setFixedTimeZone
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnitRunner
import java.util.Calendar
import java.util.TimeZone
@RunWith(MockitoJUnitRunner::class)
class ReminderSchedulerTest : BaseUnitTest() {
private val habitId = 10L
private var habit: Habit? = null
private var reminderScheduler: ReminderScheduler? = null
@Mock
private val sys: ReminderScheduler.SystemScheduler? = null
@Mock
private val widgetPreferences: WidgetPreferences? = null
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit = fixtures.createEmptyHabit()
habit!!.id = habitId
reminderScheduler =
ReminderScheduler(commandRunner, habitList, sys!!, widgetPreferences!!)
setFixedTimeZone(TimeZone.getTimeZone("GMT-4"))
}
@Test
fun testScheduleAll() {
val now = unixTime(2015, 1, 26, 13, 0)
setFixedLocalTime(now)
val h1 = fixtures.createEmptyHabit()
val h2 = fixtures.createEmptyHabit()
val h3 = fixtures.createEmptyHabit()
h1.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
h2.reminder = Reminder(18, 30, WeekdayList.EVERY_DAY)
h3.reminder = null
habitList.add(h1)
habitList.add(h2)
habitList.add(h3)
reminderScheduler!!.scheduleAll()
Mockito.verify(sys)!!.scheduleShowReminder(
ArgumentMatchers.eq(unixTime(2015, 1, 27, 12, 30)),
ArgumentMatchers.eq(h1),
ArgumentMatchers.anyLong()
)
Mockito.verify(sys)!!.scheduleShowReminder(
ArgumentMatchers.eq(unixTime(2015, 1, 26, 22, 30)),
ArgumentMatchers.eq(h2),
ArgumentMatchers.anyLong()
)
}
@Test
fun testSchedule_atSpecificTime() {
val atTime = unixTime(2015, 1, 30, 11, 30)
val expectedCheckmarkTime = unixTime(2015, 1, 30, 0, 0)
habit!!.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
scheduleAndVerify(atTime, expectedCheckmarkTime, atTime)
}
@Test
fun testSchedule_withSnooze() {
val now = removeTimezone(unixTime(2015, 1, 1, 15, 0))
setFixedLocalTime(now)
val snoozeTimeInFuture = unixTime(2015, 1, 1, 21, 0)
val snoozeTimeInPast = unixTime(2015, 1, 1, 7, 0)
val regularReminderTime = applyTimezone(unixTime(2015, 1, 2, 8, 30))
val todayCheckmarkTime = unixTime(2015, 1, 1, 0, 0)
val tomorrowCheckmarkTime = unixTime(2015, 1, 2, 0, 0)
habit!!.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
Mockito.`when`(widgetPreferences!!.getSnoozeTime(habitId)).thenReturn(snoozeTimeInFuture)
reminderScheduler!!.schedule(habit!!)
Mockito.verify(sys)!!.scheduleShowReminder(snoozeTimeInFuture, habit, todayCheckmarkTime)
Mockito.`when`(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInPast)
reminderScheduler!!.schedule(habit!!)
Mockito.verify(sys)!!.scheduleShowReminder(regularReminderTime, habit, tomorrowCheckmarkTime)
}
@Test
fun testSchedule_laterToday() {
val now = unixTime(2015, 1, 26, 6, 30)
setFixedLocalTime(now)
val expectedCheckmarkTime = unixTime(2015, 1, 26, 0, 0)
val expectedReminderTime = unixTime(2015, 1, 26, 12, 30)
habit!!.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime)
}
@Test
fun testSchedule_tomorrow() {
val now = unixTime(2015, 1, 26, 13, 0)
setFixedLocalTime(now)
val expectedCheckmarkTime = unixTime(2015, 1, 27, 0, 0)
val expectedReminderTime = unixTime(2015, 1, 27, 12, 30)
habit!!.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime)
}
@Test
fun testSchedule_withoutReminder() {
reminderScheduler!!.schedule(habit!!)
}
override fun unixTime(year: Int, month: Int, day: Int, hour: Int, minute: Int): Long {
val cal: Calendar = getStartOfTodayCalendar()
cal[year, month, day, hour] = minute
return cal.timeInMillis
}
private fun scheduleAndVerify(
atTime: Long?,
expectedCheckmarkTime: Long,
expectedReminderTime: Long
) {
if (atTime == null) reminderScheduler!!.schedule(habit!!) else reminderScheduler!!.scheduleAtTime(
habit!!,
atTime
)
Mockito.verify(sys)!!.scheduleShowReminder(
expectedReminderTime,
habit,
expectedCheckmarkTime
)
}
}

@ -1,56 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.tasks;
import org.isoron.uhabits.core.*;
import org.junit.*;
import org.junit.runner.*;
import org.junit.runners.*;
import org.mockito.*;
import static org.mockito.Mockito.*;
@RunWith(JUnit4.class)
public class SingleThreadTaskRunnerTest extends BaseUnitTest
{
private SingleThreadTaskRunner runner;
private Task task;
@Override
public void setUp() throws Exception
{
super.setUp();
runner = new SingleThreadTaskRunner();
task = mock(Task.class);
}
@Test
public void test()
{
runner.execute(task);
InOrder inOrder = inOrder(task);
inOrder.verify(task).onAttached(runner);
inOrder.verify(task).onPreExecute();
inOrder.verify(task).doInBackground();
inOrder.verify(task).onPostExecute();
}
}

@ -0,0 +1,47 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.tasks
import org.isoron.uhabits.core.BaseUnitTest
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mockito
@RunWith(JUnit4::class)
class SingleThreadTaskRunnerTest : BaseUnitTest() {
private var runner: SingleThreadTaskRunner? = null
private lateinit var task: Task
@Throws(Exception::class)
override fun setUp() {
super.setUp()
runner = SingleThreadTaskRunner()
task = Mockito.mock(Task::class.java)
}
@Test
fun test() {
runner!!.execute(task)
val inOrder = Mockito.inOrder(task)
inOrder.verify(task).onAttached(runner!!)
inOrder.verify(task).onPreExecute()
inOrder.verify(task).doInBackground()
inOrder.verify(task).onPostExecute()
}
}

@ -1,188 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.commands.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import java.util.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.core.IsEqual.*;
import static org.mockito.Mockito.*;
public class HabitCardListCacheTest extends BaseUnitTest
{
private HabitCardListCache cache;
private HabitCardListCache.Listener listener;
Timestamp today = DateUtils.getToday();
@Override
public void setUp() throws Exception
{
super.setUp();
habitList.removeAll();
for (int i = 0; i < 10; i++)
{
if (i == 3) habitList.add(fixtures.createLongHabit());
else habitList.add(fixtures.createShortHabit());
}
cache = new HabitCardListCache(habitList, commandRunner, taskRunner);
cache.setCheckmarkCount(10);
cache.refreshAllHabits();
cache.onAttached();
listener = mock(HabitCardListCache.Listener.class);
cache.setListener(listener);
}
@Override
public void tearDown()
{
cache.onDetached();
}
@Test
public void testCommandListener_all()
{
assertThat(cache.getHabitCount(), equalTo(10));
Habit h = habitList.getByPosition(0);
commandRunner.run(
new DeleteHabitsCommand(habitList, Collections.singletonList(h))
);
verify(listener).onItemRemoved(0);
verify(listener).onRefreshFinished();
assertThat(cache.getHabitCount(), equalTo(9));
}
@Test
public void testCommandListener_single()
{
Habit h2 = habitList.getByPosition(2);
commandRunner.run(new CreateRepetitionCommand(habitList, h2, today, Entry.NO));
verify(listener).onItemChanged(2);
verify(listener).onRefreshFinished();
verifyNoMoreInteractions(listener);
}
@Test
public void testGet()
{
assertThat(cache.getHabitCount(), equalTo(10));
Habit h = habitList.getByPosition(3);
Assert.assertNotNull(h.getId());
double score = h.getScores().get(today).getValue();
assertThat(cache.getHabitByPosition(3), equalTo(h));
assertThat(cache.getScore(h.getId()), equalTo(score));
int[] actualCheckmarks = cache.getCheckmarks(h.getId());
int[] expectedCheckmarks = ArrayUtils.toPrimitive(h.getComputedEntries()
.getByInterval(today.minus(9), today)
.stream()
.map(Entry::getValue)
.toArray(Integer[]::new));
assertThat(actualCheckmarks, equalTo(expectedCheckmarks));
}
@Test
public void testRemoval()
{
removeHabitAt(0);
removeHabitAt(3);
cache.refreshAllHabits();
verify(listener).onItemRemoved(0);
verify(listener).onItemRemoved(3);
verify(listener).onRefreshFinished();
assertThat(cache.getHabitCount(), equalTo(8));
}
@Test
public void testRefreshWithNoChanges()
{
cache.refreshAllHabits();
verify(listener).onRefreshFinished();
verifyNoMoreInteractions(listener);
}
@Test
public void testReorder_onCache()
{
Habit h2 = cache.getHabitByPosition(2);
Habit h3 = cache.getHabitByPosition(3);
Habit h7 = cache.getHabitByPosition(7);
cache.reorder(2, 7);
assertThat(cache.getHabitByPosition(2), equalTo(h3));
assertThat(cache.getHabitByPosition(7), equalTo(h2));
assertThat(cache.getHabitByPosition(6), equalTo(h7));
verify(listener).onItemMoved(2, 7);
verifyNoMoreInteractions(listener);
}
@Test
public void testReorder_onList()
{
Habit h2 = habitList.getByPosition(2);
Habit h3 = habitList.getByPosition(3);
Habit h7 = habitList.getByPosition(7);
assertThat(cache.getHabitByPosition(2), equalTo(h2));
assertThat(cache.getHabitByPosition(7), equalTo(h7));
reset(listener);
habitList.reorder(h2, h7);
cache.refreshAllHabits();
assertThat(cache.getHabitByPosition(2), equalTo(h3));
assertThat(cache.getHabitByPosition(7), equalTo(h2));
assertThat(cache.getHabitByPosition(6), equalTo(h7));
verify(listener).onItemMoved(3, 2);
verify(listener).onItemMoved(4, 3);
verify(listener).onItemMoved(5, 4);
verify(listener).onItemMoved(6, 5);
verify(listener).onItemMoved(7, 6);
verify(listener).onRefreshFinished();
verifyNoMoreInteractions(listener);
}
protected void removeHabitAt(int position)
{
Habit h = habitList.getByPosition(position);
Assert.assertNotNull(h);
habitList.remove(h);
}
}

@ -0,0 +1,154 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list
import junit.framework.Assert.assertNotNull
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
import org.isoron.uhabits.core.commands.DeleteHabitsCommand
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.junit.Test
import org.mockito.Mockito
class HabitCardListCacheTest : BaseUnitTest() {
private var cache: HabitCardListCache? = null
private var listener: HabitCardListCache.Listener? = null
var today = getToday()
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habitList.removeAll()
for (i in 0..9) {
if (i == 3) habitList.add(fixtures.createLongHabit()) else habitList.add(fixtures.createShortHabit())
}
cache = HabitCardListCache(habitList, commandRunner, taskRunner)
cache!!.setCheckmarkCount(10)
cache!!.refreshAllHabits()
cache!!.onAttached()
listener = Mockito.mock(
HabitCardListCache.Listener::class.java
)
cache!!.setListener(listener!!)
}
override fun tearDown() {
cache!!.onDetached()
}
@Test
fun testCommandListener_all() {
assertThat(cache!!.habitCount, IsEqual.equalTo(10))
val h = habitList.getByPosition(0)
commandRunner.run(
DeleteHabitsCommand(habitList, listOf(h))
)
Mockito.verify(listener)!!.onItemRemoved(0)
Mockito.verify(listener)!!.onRefreshFinished()
assertThat(cache!!.habitCount, IsEqual.equalTo(9))
}
@Test
fun testCommandListener_single() {
val h2 = habitList.getByPosition(2)
commandRunner.run(CreateRepetitionCommand(habitList, h2, today, Entry.NO))
Mockito.verify(listener)!!.onItemChanged(2)
Mockito.verify(listener)!!.onRefreshFinished()
Mockito.verifyNoMoreInteractions(listener)
}
@Test
fun testGet() {
assertThat(cache!!.habitCount, IsEqual.equalTo(10))
val h = habitList.getByPosition(3)
assertNotNull(h.id)
val score = h.scores[today].value
assertThat(cache!!.getHabitByPosition(3), IsEqual.equalTo(h))
assertThat(cache!!.getScore(h.id!!), IsEqual.equalTo(score))
val actualCheckmarks = cache!!.getCheckmarks(h.id!!)
val expectedCheckmarks = h
.computedEntries
.getByInterval(today.minus(9), today)
.map { it.value }.toIntArray()
assertThat(actualCheckmarks, IsEqual.equalTo(expectedCheckmarks))
}
@Test
fun testRemoval() {
removeHabitAt(0)
removeHabitAt(3)
cache!!.refreshAllHabits()
Mockito.verify(listener)!!.onItemRemoved(0)
Mockito.verify(listener)!!.onItemRemoved(3)
Mockito.verify(listener)!!.onRefreshFinished()
assertThat(cache!!.habitCount, IsEqual.equalTo(8))
}
@Test
fun testRefreshWithNoChanges() {
cache!!.refreshAllHabits()
Mockito.verify(listener)!!.onRefreshFinished()
Mockito.verifyNoMoreInteractions(listener)
}
@Test
fun testReorder_onCache() {
val h2 = cache!!.getHabitByPosition(2)
val h3 = cache!!.getHabitByPosition(3)
val h7 = cache!!.getHabitByPosition(7)
cache!!.reorder(2, 7)
assertThat(cache!!.getHabitByPosition(2), IsEqual.equalTo(h3))
assertThat(cache!!.getHabitByPosition(7), IsEqual.equalTo(h2))
assertThat(cache!!.getHabitByPosition(6), IsEqual.equalTo(h7))
Mockito.verify(listener)!!.onItemMoved(2, 7)
Mockito.verifyNoMoreInteractions(listener)
}
@Test
fun testReorder_onList() {
val h2 = habitList.getByPosition(2)
val h3 = habitList.getByPosition(3)
val h7 = habitList.getByPosition(7)
assertThat(cache!!.getHabitByPosition(2), IsEqual.equalTo(h2))
assertThat(cache!!.getHabitByPosition(7), IsEqual.equalTo(h7))
Mockito.reset(listener)
habitList.reorder(h2, h7)
cache!!.refreshAllHabits()
assertThat(cache!!.getHabitByPosition(2), IsEqual.equalTo(h3))
assertThat(cache!!.getHabitByPosition(7), IsEqual.equalTo(h2))
assertThat(cache!!.getHabitByPosition(6), IsEqual.equalTo(h7))
Mockito.verify(listener)!!.onItemMoved(3, 2)
Mockito.verify(listener)!!.onItemMoved(4, 3)
Mockito.verify(listener)!!.onItemMoved(5, 4)
Mockito.verify(listener)!!.onItemMoved(6, 5)
Mockito.verify(listener)!!.onItemMoved(7, 6)
Mockito.verify(listener)!!.onRefreshFinished()
Mockito.verifyNoMoreInteractions(listener)
}
private fun removeHabitAt(position: Int) {
val h = habitList.getByPosition(position)
assertNotNull(h)
habitList.remove(h)
}
}

@ -1,80 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import org.mockito.*;
import static junit.framework.TestCase.assertFalse;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
public class HintListTest extends BaseUnitTest
{
private HintList hintList;
private String[] hints;
@Mock
private Preferences prefs;
private Timestamp today;
private Timestamp yesterday;
@Override
public void setUp() throws Exception
{
super.setUp();
today = DateUtils.getToday();
yesterday = today.minus(1);
hints = new String[]{ "hint1", "hint2", "hint3" };
hintList = new HintList(prefs, hints);
}
@Test
public void pop() throws Exception
{
when(prefs.getLastHintNumber()).thenReturn(-1);
assertThat(hintList.pop(), equalTo("hint1"));
verify(prefs).updateLastHint(0, today);
when(prefs.getLastHintNumber()).thenReturn(2);
assertNull(hintList.pop());
}
@Test
public void shouldShow() throws Exception
{
when(prefs.getLastHintTimestamp()).thenReturn(today);
assertFalse(hintList.shouldShow());
when(prefs.getLastHintTimestamp()).thenReturn(yesterday);
assertTrue(hintList.shouldShow());
}
}

@ -0,0 +1,70 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list
import junit.framework.Assert.assertNull
import junit.framework.Assert.assertTrue
import junit.framework.TestCase
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito
class HintListTest : BaseUnitTest() {
private var hintList: HintList? = null
private lateinit var hints: Array<String>
@Mock
private val prefs: Preferences? = null
private var today: Timestamp? = null
private var yesterday: Timestamp? = null
@Throws(Exception::class)
override fun setUp() {
super.setUp()
today = getToday()
yesterday = today!!.minus(1)
hints = arrayOf("hint1", "hint2", "hint3")
hintList = HintList(prefs!!, hints)
}
@Test
@Throws(Exception::class)
fun pop() {
Mockito.`when`(prefs!!.lastHintNumber).thenReturn(-1)
assertThat(hintList!!.pop(), equalTo("hint1"))
Mockito.verify(prefs).updateLastHint(0, today)
Mockito.`when`(prefs.lastHintNumber).thenReturn(2)
assertNull(hintList!!.pop())
}
@Test
@Throws(Exception::class)
fun shouldShow() {
Mockito.`when`(prefs!!.lastHintTimestamp).thenReturn(today)
TestCase.assertFalse(hintList!!.shouldShow())
Mockito.`when`(prefs.lastHintTimestamp).thenReturn(yesterday)
assertTrue(hintList!!.shouldShow())
}
}

@ -1,181 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import org.mockito.*;
import java.io.*;
import static java.nio.file.Files.createTempDirectory;
import static org.apache.commons.io.FileUtils.deleteDirectory;
import static org.apache.commons.io.FileUtils.listFiles;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior.Message.COULD_NOT_EXPORT;
import static org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior.Message.COULD_NOT_GENERATE_BUG_REPORT;
import static org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior.Message.DATABASE_REPAIRED;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class ListHabitsBehaviorTest extends BaseUnitTest
{
@Mock
private ListHabitsBehavior.DirFinder dirFinder;
@Mock
private Preferences prefs;
private ListHabitsBehavior behavior;
@Mock
private ListHabitsBehavior.Screen screen;
private Habit habit1, habit2;
@Captor
ArgumentCaptor<ListHabitsBehavior.NumberPickerCallback> picker;
@Mock
private ListHabitsBehavior.BugReporter bugReporter;
@Override
@Before
public void setUp() throws Exception
{
super.setUp();
habit1 = fixtures.createShortHabit();
habit2 = fixtures.createNumericalHabit();
habitList.add(habit1);
habitList.add(habit2);
clearInvocations(habitList);
behavior = new ListHabitsBehavior(habitList, dirFinder, taskRunner, screen,
commandRunner, prefs, bugReporter);
}
@Test
public void testOnEdit()
{
behavior.onEdit(habit2, DateUtils.getToday());
verify(screen).showNumberPicker(eq(0.1), eq("miles"), picker.capture());
picker.getValue().onNumberPicked(100);
Timestamp today = DateUtils.getTodayWithOffset();
assertThat(habit2.getComputedEntries().get(today).getValue(), equalTo(100000));
}
@Test
public void testOnExportCSV() throws Exception
{
File outputDir = createTempDirectory("CSV").toFile();
when(dirFinder.getCSVOutputDir()).thenReturn(outputDir);
behavior.onExportCSV();
verify(screen).showSendFileScreen(any());
assertThat(listFiles(outputDir, null, false).size(), equalTo(1));
deleteDirectory(outputDir);
}
@Test
public void testOnExportCSV_fail() throws Exception
{
File outputDir = createTempDirectory("CSV").toFile();
outputDir.setWritable(false);
when(dirFinder.getCSVOutputDir()).thenReturn(outputDir);
behavior.onExportCSV();
verify(screen).showMessage(COULD_NOT_EXPORT);
assertTrue(outputDir.delete());
}
@Test
public void testOnHabitClick()
{
behavior.onClickHabit(habit1);
verify(screen).showHabitScreen(habit1);
}
@Test
public void testOnHabitReorder()
{
Habit from = habit1;
Habit to = habit2;
behavior.onReorderHabit(from, to);
verify(habitList).reorder(from, to);
}
@Test
public void testOnRepairDB()
{
behavior.onRepairDB();
verify(habitList).repair();
verify(screen).showMessage(DATABASE_REPAIRED);
}
@Test
public void testOnSendBugReport() throws IOException
{
when(bugReporter.getBugReport()).thenReturn("hello");
behavior.onSendBugReport();
verify(bugReporter).dumpBugReportToFile();
verify(screen).showSendBugReportToDeveloperScreen("hello");
when(bugReporter.getBugReport()).thenThrow(new IOException());
behavior.onSendBugReport();
verify(screen).showMessage(COULD_NOT_GENERATE_BUG_REPORT);
}
@Test
public void testOnStartup_firstLaunch()
{
Timestamp today = DateUtils.getToday();
when(prefs.isFirstRun()).thenReturn(true);
behavior.onStartup();
verify(prefs).setFirstRun(false);
verify(prefs).updateLastHint(-1, today);
verify(screen).showIntroScreen();
}
@Test
public void testOnStartup_notFirstLaunch()
{
when(prefs.isFirstRun()).thenReturn(false);
behavior.onStartup();
verify(prefs).incrementLaunchCount();
}
@Test
public void testOnToggle()
{
assertTrue(habit1.isCompletedToday());
behavior.onToggle(habit1, DateUtils.getToday(), Entry.NO);
assertFalse(habit1.isCompletedToday());
}
}

@ -0,0 +1,181 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.apache.commons.io.FileUtils
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
import java.io.IOException
import java.nio.file.Files
class ListHabitsBehaviorTest : BaseUnitTest() {
@Mock
private val dirFinder: ListHabitsBehavior.DirFinder? = null
@Mock
private val prefs: Preferences? = null
private var behavior: ListHabitsBehavior? = null
@Mock
private val screen: ListHabitsBehavior.Screen? = null
private var habit1: Habit? = null
private var habit2: Habit? = null
@Captor
var picker: ArgumentCaptor<ListHabitsBehavior.NumberPickerCallback>? = null
@Mock
private val bugReporter: ListHabitsBehavior.BugReporter? = null
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit1 = fixtures.createShortHabit()
habit2 = fixtures.createNumericalHabit()
habitList.add(habit1!!)
habitList.add(habit2!!)
Mockito.clearInvocations(habitList)
behavior = ListHabitsBehavior(
habitList,
dirFinder!!,
taskRunner,
screen!!,
commandRunner,
prefs!!,
bugReporter!!
)
}
@Test
fun testOnEdit() {
behavior!!.onEdit(habit2!!, getToday())
Mockito.verify(screen)!!.showNumberPicker(
ArgumentMatchers.eq(0.1),
ArgumentMatchers.eq("miles"),
picker!!.capture()
)
picker!!.value.onNumberPicked(100.0)
val today = getTodayWithOffset()
assertThat(
habit2!!.computedEntries.get(today).value,
CoreMatchers.equalTo(100000)
)
}
@Test
@Throws(Exception::class)
fun testOnExportCSV() {
val outputDir = Files.createTempDirectory("CSV").toFile()
Mockito.`when`(dirFinder!!.csvOutputDir).thenReturn(outputDir)
behavior!!.onExportCSV()
Mockito.verify(screen)!!.showSendFileScreen(ArgumentMatchers.any())
assertThat(
FileUtils.listFiles(outputDir, null, false).size,
CoreMatchers.equalTo(1)
)
FileUtils.deleteDirectory(outputDir)
}
@Test
@Throws(Exception::class)
fun testOnExportCSV_fail() {
val outputDir = Files.createTempDirectory("CSV").toFile()
outputDir.setWritable(false)
Mockito.`when`(dirFinder!!.csvOutputDir).thenReturn(outputDir)
behavior!!.onExportCSV()
Mockito.verify(screen)!!.showMessage(ListHabitsBehavior.Message.COULD_NOT_EXPORT)
assertTrue(outputDir.delete())
}
@Test
fun testOnHabitClick() {
behavior!!.onClickHabit(habit1!!)
Mockito.verify(screen)!!.showHabitScreen(
habit1!!
)
}
@Test
fun testOnHabitReorder() {
val from = habit1
val to = habit2
behavior!!.onReorderHabit(from!!, to!!)
Mockito.verify(habitList)!!.reorder(from, to)
}
@Test
fun testOnRepairDB() {
behavior!!.onRepairDB()
Mockito.verify(habitList)!!.repair()
Mockito.verify(screen)!!.showMessage(ListHabitsBehavior.Message.DATABASE_REPAIRED)
}
@Test
@Throws(IOException::class)
fun testOnSendBugReport() {
Mockito.`when`(bugReporter!!.bugReport).thenReturn("hello")
behavior!!.onSendBugReport()
Mockito.verify(bugReporter).dumpBugReportToFile()
Mockito.verify(screen)!!.showSendBugReportToDeveloperScreen("hello")
Mockito.`when`(bugReporter.bugReport).thenThrow(IOException())
behavior!!.onSendBugReport()
Mockito.verify(screen)!!
.showMessage(ListHabitsBehavior.Message.COULD_NOT_GENERATE_BUG_REPORT)
}
@Test
fun testOnStartup_firstLaunch() {
val today = getToday()
Mockito.`when`(prefs!!.isFirstRun).thenReturn(true)
behavior!!.onStartup()
Mockito.verify(prefs).isFirstRun = false
Mockito.verify(prefs).updateLastHint(-1, today)
Mockito.verify(screen)!!.showIntroScreen()
}
@Test
fun testOnStartup_notFirstLaunch() {
Mockito.`when`(prefs!!.isFirstRun).thenReturn(false)
behavior!!.onStartup()
Mockito.verify(prefs).incrementLaunchCount()
}
@Test
fun testOnToggle() {
assertTrue(habit1!!.isCompletedToday())
behavior!!.onToggle(habit1!!, getToday(), Entry.NO)
assertFalse(habit1!!.isCompletedToday())
}
}

@ -1,217 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.*;
import org.junit.*;
import org.mockito.*;
import static junit.framework.TestCase.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.isoron.uhabits.core.models.HabitList.Order.*;
import static org.mockito.Mockito.*;
public class ListHabitsMenuBehaviorTest extends BaseUnitTest
{
private ListHabitsMenuBehavior behavior;
@Mock
private ListHabitsMenuBehavior.Screen screen;
@Mock
private ListHabitsMenuBehavior.Adapter adapter;
@Mock
private Preferences prefs;
@Mock
private ThemeSwitcher themeSwitcher;
@Captor
private ArgumentCaptor<HabitMatcher> matcherCaptor;
@Captor
private ArgumentCaptor<HabitList.Order> orderCaptor;
@Captor
private ArgumentCaptor<HabitList.Order> secondaryOrderCaptor;
@Override
public void setUp() throws Exception
{
super.setUp();
behavior =
new ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher);
clearInvocations(adapter);
}
@Test
public void testInitialFilter()
{
when(prefs.getShowArchived()).thenReturn(true);
when(prefs.getShowCompleted()).thenReturn(true);
behavior =
new ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher);
verify(adapter).setFilter(matcherCaptor.capture());
verify(adapter).refresh();
verifyNoMoreInteractions(adapter);
clearInvocations(adapter);
assertTrue(matcherCaptor.getValue().isArchivedAllowed());
assertTrue(matcherCaptor.getValue().isCompletedAllowed());
when(prefs.getShowArchived()).thenReturn(false);
when(prefs.getShowCompleted()).thenReturn(false);
behavior =
new ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher);
verify(adapter).setFilter(matcherCaptor.capture());
verify(adapter).refresh();
verifyNoMoreInteractions(adapter);
assertFalse(matcherCaptor.getValue().isArchivedAllowed());
assertFalse(matcherCaptor.getValue().isCompletedAllowed());
}
// @Test
// public void testOnCreateHabit()
// {
// behavior.onCreateHabit();
// verify(screen).showCreateHabitScreen();
// }
@Test
public void testOnSortByColor()
{
behavior.onSortByColor();
verify(adapter).setPrimaryOrder(orderCaptor.capture());
assertThat(orderCaptor.getValue(), equalTo(BY_COLOR_ASC));
}
@Test
public void testOnSortManually()
{
behavior.onSortByManually();
verify(adapter).setPrimaryOrder(orderCaptor.capture());
assertThat(orderCaptor.getValue(), equalTo(BY_POSITION));
}
@Test
public void testOnSortScore()
{
behavior.onSortByScore();
verify(adapter).setPrimaryOrder(orderCaptor.capture());
assertThat(orderCaptor.getValue(), equalTo(BY_SCORE_DESC));
}
@Test
public void testOnSortName()
{
behavior.onSortByName();
verify(adapter).setPrimaryOrder(orderCaptor.capture());
assertThat(orderCaptor.getValue(), equalTo(BY_NAME_ASC));
}
@Test
public void testOnSortStatus()
{
when(adapter.getPrimaryOrder()).thenReturn(BY_NAME_ASC);
behavior.onSortByStatus();
verify(adapter).setPrimaryOrder(orderCaptor.capture());
verify(adapter).setSecondaryOrder(secondaryOrderCaptor.capture());
assertThat(orderCaptor.getValue(), equalTo(BY_STATUS_ASC));
assertThat(secondaryOrderCaptor.getValue(), equalTo(BY_NAME_ASC));
}
@Test
public void testOnSortStatusToggle()
{
when(adapter.getPrimaryOrder()).thenReturn(BY_STATUS_ASC);
behavior.onSortByStatus();
verify(adapter).setPrimaryOrder(orderCaptor.capture());
verify(adapter, never()).setSecondaryOrder(any());
assertThat(orderCaptor.getValue(), equalTo(BY_STATUS_DESC));
}
@Test
public void testOnToggleShowArchived()
{
behavior.onToggleShowArchived();
verify(adapter).setFilter(matcherCaptor.capture());
assertTrue(matcherCaptor.getValue().isArchivedAllowed());
clearInvocations(adapter);
behavior.onToggleShowArchived();
verify(adapter).setFilter(matcherCaptor.capture());
assertFalse(matcherCaptor.getValue().isArchivedAllowed());
}
@Test
public void testOnToggleShowCompleted()
{
behavior.onToggleShowCompleted();
verify(adapter).setFilter(matcherCaptor.capture());
assertTrue(matcherCaptor.getValue().isCompletedAllowed());
clearInvocations(adapter);
behavior.onToggleShowCompleted();
verify(adapter).setFilter(matcherCaptor.capture());
assertFalse(matcherCaptor.getValue().isCompletedAllowed());
}
@Test
public void testOnViewAbout()
{
behavior.onViewAbout();
verify(screen).showAboutScreen();
}
@Test
public void testOnViewFAQ()
{
behavior.onViewFAQ();
verify(screen).showFAQScreen();
}
@Test
public void testOnViewSettings()
{
behavior.onViewSettings();
verify(screen).showSettingsScreen();
}
@Test
public void testOnToggleNightMode()
{
behavior.onToggleNightMode();
verify(themeSwitcher).toggleNightMode();
verify(screen).applyTheme();
}
}

@ -0,0 +1,222 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list
import junit.framework.TestCase
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.HabitMatcher
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.ThemeSwitcher
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
class ListHabitsMenuBehaviorTest : BaseUnitTest() {
private var behavior: ListHabitsMenuBehavior? = null
@Mock
private val screen: ListHabitsMenuBehavior.Screen? = null
@Mock
private val adapter: ListHabitsMenuBehavior.Adapter? = null
@Mock
private val prefs: Preferences? = null
@Mock
private val themeSwitcher: ThemeSwitcher? = null
@Captor
private val matcherCaptor: ArgumentCaptor<HabitMatcher>? = null
@Captor
private val orderCaptor: ArgumentCaptor<HabitList.Order>? = null
@Captor
private val secondaryOrderCaptor: ArgumentCaptor<HabitList.Order>? = null
@Throws(Exception::class)
override fun setUp() {
super.setUp()
behavior = ListHabitsMenuBehavior(screen!!, adapter!!, prefs!!, themeSwitcher!!)
Mockito.clearInvocations(adapter)
}
@Test
fun testInitialFilter() {
Mockito.`when`(prefs!!.showArchived).thenReturn(true)
Mockito.`when`(prefs.showCompleted).thenReturn(true)
behavior = ListHabitsMenuBehavior(screen!!, adapter!!, prefs, themeSwitcher!!)
Mockito.verify(adapter).setFilter(
matcherCaptor!!.capture()
)
Mockito.verify(adapter).refresh()
Mockito.verifyNoMoreInteractions(adapter)
Mockito.clearInvocations(adapter)
TestCase.assertTrue(matcherCaptor.value.isArchivedAllowed)
TestCase.assertTrue(matcherCaptor.value.isCompletedAllowed)
Mockito.`when`(prefs.showArchived).thenReturn(false)
Mockito.`when`(prefs.showCompleted).thenReturn(false)
behavior = ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher)
Mockito.verify(adapter).setFilter(
matcherCaptor.capture()
)
Mockito.verify(adapter).refresh()
Mockito.verifyNoMoreInteractions(adapter)
TestCase.assertFalse(matcherCaptor.value.isArchivedAllowed)
TestCase.assertFalse(matcherCaptor.value.isCompletedAllowed)
}
// @Test
// public void testOnCreateHabit()
// {
// behavior.onCreateHabit();
// verify(screen).showCreateHabitScreen();
// }
@Test
fun testOnSortByColor() {
behavior!!.onSortByColor()
Mockito.verify(adapter)!!.primaryOrder = orderCaptor!!.capture()
assertThat(
orderCaptor.value,
equalTo(HabitList.Order.BY_COLOR_ASC)
)
}
@Test
fun testOnSortManually() {
behavior!!.onSortByManually()
Mockito.verify(adapter)!!.primaryOrder = orderCaptor!!.capture()
assertThat(
orderCaptor.value,
equalTo(HabitList.Order.BY_POSITION)
)
}
@Test
fun testOnSortScore() {
behavior!!.onSortByScore()
Mockito.verify(adapter)!!.primaryOrder = orderCaptor!!.capture()
assertThat(
orderCaptor.value,
equalTo(HabitList.Order.BY_SCORE_DESC)
)
}
@Test
fun testOnSortName() {
behavior!!.onSortByName()
Mockito.verify(adapter)!!.primaryOrder = orderCaptor!!.capture()
assertThat(
orderCaptor.value,
equalTo(HabitList.Order.BY_NAME_ASC)
)
}
@Test
fun testOnSortStatus() {
Mockito.`when`(adapter!!.primaryOrder).thenReturn(HabitList.Order.BY_NAME_ASC)
behavior!!.onSortByStatus()
Mockito.verify(adapter).primaryOrder = orderCaptor!!.capture()
Mockito.verify(adapter).setSecondaryOrder(
secondaryOrderCaptor!!.capture()
)
assertThat(
orderCaptor.value,
equalTo(HabitList.Order.BY_STATUS_ASC)
)
assertThat(
secondaryOrderCaptor.value,
equalTo(HabitList.Order.BY_NAME_ASC)
)
}
@Test
fun testOnSortStatusToggle() {
Mockito.`when`(adapter!!.primaryOrder).thenReturn(HabitList.Order.BY_STATUS_ASC)
behavior!!.onSortByStatus()
Mockito.verify(adapter).primaryOrder = orderCaptor!!.capture()
Mockito.verify(adapter, Mockito.never()).setSecondaryOrder(ArgumentMatchers.any())
assertThat(
orderCaptor.value,
equalTo(HabitList.Order.BY_STATUS_DESC)
)
}
@Test
fun testOnToggleShowArchived() {
behavior!!.onToggleShowArchived()
Mockito.verify(adapter)!!.setFilter(
matcherCaptor!!.capture()
)
TestCase.assertTrue(matcherCaptor.value.isArchivedAllowed)
Mockito.clearInvocations(adapter)
behavior!!.onToggleShowArchived()
Mockito.verify(adapter)!!.setFilter(
matcherCaptor.capture()
)
TestCase.assertFalse(matcherCaptor.value.isArchivedAllowed)
}
@Test
fun testOnToggleShowCompleted() {
behavior!!.onToggleShowCompleted()
Mockito.verify(adapter)!!.setFilter(
matcherCaptor!!.capture()
)
TestCase.assertTrue(matcherCaptor.value.isCompletedAllowed)
Mockito.clearInvocations(adapter)
behavior!!.onToggleShowCompleted()
Mockito.verify(adapter)!!.setFilter(
matcherCaptor.capture()
)
TestCase.assertFalse(matcherCaptor.value.isCompletedAllowed)
}
@Test
fun testOnViewAbout() {
behavior!!.onViewAbout()
Mockito.verify(screen)!!.showAboutScreen()
}
@Test
fun testOnViewFAQ() {
behavior!!.onViewFAQ()
Mockito.verify(screen)!!.showFAQScreen()
}
@Test
fun testOnViewSettings() {
behavior!!.onViewSettings()
Mockito.verify(screen)!!.showSettingsScreen()
}
@Test
fun testOnToggleNightMode() {
behavior!!.onToggleNightMode()
Mockito.verify(themeSwitcher)!!.toggleNightMode()
Mockito.verify(screen)!!.applyTheme()
}
}

@ -1,159 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.ui.callbacks.*;
import org.junit.*;
import org.mockito.*;
import java.util.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;
import static junit.framework.TestCase.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.*;
public class ListHabitsSelectionMenuBehaviorTest extends BaseUnitTest
{
@Mock
private ListHabitsSelectionMenuBehavior.Screen screen;
@Mock
private ListHabitsSelectionMenuBehavior.Adapter adapter;
private ListHabitsSelectionMenuBehavior behavior;
private Habit habit1, habit2, habit3;
@Captor
private ArgumentCaptor<OnColorPickedCallback> colorPickerCallback;
@Captor
private ArgumentCaptor<OnConfirmedCallback> deleteCallback;
@Test
public void canArchive() throws Exception
{
when(adapter.getSelected()).thenReturn(asList(habit1, habit2));
assertFalse(behavior.canArchive());
when(adapter.getSelected()).thenReturn(asList(habit2, habit3));
assertTrue(behavior.canArchive());
}
@Test
public void canEdit() throws Exception
{
when(adapter.getSelected()).thenReturn(singletonList(habit1));
assertTrue(behavior.canEdit());
when(adapter.getSelected()).thenReturn(asList(habit1, habit2));
assertFalse(behavior.canEdit());
}
@Test
public void canUnarchive() throws Exception
{
when(adapter.getSelected()).thenReturn(asList(habit1, habit2));
assertFalse(behavior.canUnarchive());
when(adapter.getSelected()).thenReturn(singletonList(habit1));
assertTrue(behavior.canUnarchive());
}
@Test
public void onArchiveHabits() throws Exception
{
assertFalse(habit2.isArchived());
when(adapter.getSelected()).thenReturn(singletonList(habit2));
behavior.onArchiveHabits();
assertTrue(habit2.isArchived());
}
@Test
public void onChangeColor() throws Exception
{
assertThat(habit1.getColor(), equalTo(new PaletteColor(8)));
assertThat(habit2.getColor(), equalTo(new PaletteColor(8)));
when(adapter.getSelected()).thenReturn(asList(habit1, habit2));
behavior.onChangeColor();
verify(screen).showColorPicker(eq(new PaletteColor(8)), colorPickerCallback.capture());
colorPickerCallback.getValue().onColorPicked(new PaletteColor(30));
assertThat(habit1.getColor(), equalTo(new PaletteColor(30)));
}
@Test
public void onDeleteHabits() throws Exception
{
Long id = habit1.getId();
assertNotNull(id);
assertNotNull(habitList.getById(id));
when(adapter.getSelected()).thenReturn(singletonList(habit1));
behavior.onDeleteHabits();
verify(screen).showDeleteConfirmationScreen(deleteCallback.capture(), eq(1));
deleteCallback.getValue().onConfirmed();
assertNull(habitList.getById(id));
}
@Test
public void onEditHabits() throws Exception
{
List<Habit> selected = asList(habit1, habit2);
when(adapter.getSelected()).thenReturn(selected);
behavior.onEditHabits();
verify(screen).showEditHabitsScreen(selected);
}
@Test
public void onUnarchiveHabits() throws Exception
{
assertTrue(habit1.isArchived());
when(adapter.getSelected()).thenReturn(singletonList(habit1));
behavior.onUnarchiveHabits();
assertFalse(habit1.isArchived());
}
@Override
public void setUp() throws Exception
{
super.setUp();
habit1 = fixtures.createShortHabit();
habit1.setArchived(true);
habit2 = fixtures.createShortHabit();
habit3 = fixtures.createShortHabit();
habitList.add(habit1);
habitList.add(habit2);
habitList.add(habit3);
behavior =
new ListHabitsSelectionMenuBehavior(habitList, screen, adapter,
commandRunner);
}
}

@ -0,0 +1,153 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.list
import junit.framework.TestCase
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.ui.callbacks.OnColorPickedCallback
import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
@Mock
private val screen: ListHabitsSelectionMenuBehavior.Screen? = null
@Mock
private val adapter: ListHabitsSelectionMenuBehavior.Adapter? = null
private var behavior: ListHabitsSelectionMenuBehavior? = null
private var habit1: Habit? = null
private var habit2: Habit? = null
private var habit3: Habit? = null
@Captor
private val colorPickerCallback: ArgumentCaptor<OnColorPickedCallback>? = null
@Captor
private val deleteCallback: ArgumentCaptor<OnConfirmedCallback>? = null
@Test
@Throws(Exception::class)
fun canArchive() {
Mockito.`when`(adapter!!.selected).thenReturn(listOf(habit1, habit2))
TestCase.assertFalse(behavior!!.canArchive())
Mockito.`when`(adapter.selected).thenReturn(listOf(habit2, habit3))
TestCase.assertTrue(behavior!!.canArchive())
}
@Test
@Throws(Exception::class)
fun canEdit() {
Mockito.`when`(adapter!!.selected).thenReturn(listOf(habit1))
TestCase.assertTrue(behavior!!.canEdit())
Mockito.`when`(adapter.selected).thenReturn(listOf(habit1, habit2))
TestCase.assertFalse(behavior!!.canEdit())
}
@Test
@Throws(Exception::class)
fun canUnarchive() {
Mockito.`when`(adapter!!.selected).thenReturn(listOf(habit1, habit2))
TestCase.assertFalse(behavior!!.canUnarchive())
Mockito.`when`(adapter.selected).thenReturn(listOf(habit1))
TestCase.assertTrue(behavior!!.canUnarchive())
}
@Test
@Throws(Exception::class)
fun onArchiveHabits() {
TestCase.assertFalse(habit2!!.isArchived)
Mockito.`when`(adapter!!.selected).thenReturn(listOf(habit2))
behavior!!.onArchiveHabits()
TestCase.assertTrue(habit2!!.isArchived)
}
@Test
@Throws(Exception::class)
fun onChangeColor() {
assertThat(habit1!!.color, equalTo(PaletteColor(8)))
assertThat(habit2!!.color, equalTo(PaletteColor(8)))
Mockito.`when`(adapter!!.selected).thenReturn(listOf(habit1, habit2))
behavior!!.onChangeColor()
Mockito.verify(screen)!!
.showColorPicker(ArgumentMatchers.eq(PaletteColor(8)), colorPickerCallback!!.capture())
colorPickerCallback.value.onColorPicked(PaletteColor(30))
assertThat(habit1!!.color, equalTo(PaletteColor(30)))
}
@Test
@Throws(Exception::class)
fun onDeleteHabits() {
val id = habit1!!.id
TestCase.assertNotNull(id)
TestCase.assertNotNull(habitList.getById(id!!))
Mockito.`when`(adapter!!.selected).thenReturn(listOf(habit1))
behavior!!.onDeleteHabits()
Mockito.verify(screen)!!.showDeleteConfirmationScreen(
deleteCallback!!.capture(),
ArgumentMatchers.eq(1)
)
deleteCallback.value.onConfirmed()
TestCase.assertNull(habitList.getById(id))
}
@Test
@Throws(Exception::class)
fun onEditHabits() {
val selected: List<Habit> = listOf(habit1!!, habit2!!)
Mockito.`when`(adapter!!.selected).thenReturn(selected)
behavior!!.onEditHabits()
Mockito.verify(screen)!!.showEditHabitsScreen(selected)
}
@Test
@Throws(Exception::class)
fun onUnarchiveHabits() {
TestCase.assertTrue(habit1!!.isArchived)
Mockito.`when`(adapter!!.selected).thenReturn(listOf(habit1))
behavior!!.onUnarchiveHabits()
TestCase.assertFalse(habit1!!.isArchived)
}
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit1 = fixtures.createShortHabit()
habit1!!.isArchived = true
habit2 = fixtures.createShortHabit()
habit3 = fixtures.createShortHabit()
habitList.add(habit1!!)
habitList.add(habit2!!)
habitList.add(habit3!!)
behavior = ListHabitsSelectionMenuBehavior(
habitList,
screen!!,
adapter!!,
commandRunner
)
}
}

@ -1,71 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.show;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import java.io.*;
import static java.nio.file.Files.*;
import static org.apache.commons.io.FileUtils.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
public class ShowHabitMenuPresenterTest extends BaseUnitTest
{
private ShowHabitMenuPresenter.System system;
private ShowHabitMenuPresenter.Screen screen;
private Habit habit;
private ShowHabitMenuPresenter menu;
@Override
public void setUp() throws Exception
{
super.setUp();
system = mock(ShowHabitMenuPresenter.System.class);
screen = mock(ShowHabitMenuPresenter.Screen.class);
habit = fixtures.createShortHabit();
menu = new ShowHabitMenuPresenter(commandRunner, habit, habitList, screen, system, taskRunner);
}
@Test
public void testOnEditHabit()
{
menu.onEditHabit();
verify(screen).showEditHabitScreen(habit);
}
@Test
public void testOnExport() throws Exception
{
File outputDir = createTempDirectory("CSV").toFile();
when(system.getCSVOutputDir()).thenReturn(outputDir);
menu.onExportCSV();
assertThat(listFiles(outputDir, null, false).size(), equalTo(1));
deleteDirectory(outputDir);
}
}

@ -0,0 +1,66 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.screens.habits.show
import org.apache.commons.io.FileUtils
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.junit.Test
import org.mockito.Mockito
import java.nio.file.Files
class ShowHabitMenuPresenterTest : BaseUnitTest() {
private lateinit var system: ShowHabitMenuPresenter.System
private lateinit var screen: ShowHabitMenuPresenter.Screen
private lateinit var habit: Habit
private lateinit var menu: ShowHabitMenuPresenter
@Throws(Exception::class)
override fun setUp() {
super.setUp()
system = Mockito.mock(ShowHabitMenuPresenter.System::class.java)
screen = Mockito.mock(ShowHabitMenuPresenter.Screen::class.java)
habit = fixtures.createShortHabit()
menu = ShowHabitMenuPresenter(
commandRunner,
habit,
habitList,
screen,
system,
taskRunner
)
}
@Test
fun testOnEditHabit() {
menu.onEditHabit()
Mockito.verify(screen)!!.showEditHabitScreen(habit)
}
@Test
@Throws(Exception::class)
fun testOnExport() {
val outputDir = Files.createTempDirectory("CSV").toFile()
Mockito.`when`(system.getCSVOutputDir()).thenReturn(outputDir)
menu.onExportCSV()
assertThat(FileUtils.listFiles(outputDir, null, false).size, CoreMatchers.equalTo(1))
FileUtils.deleteDirectory(outputDir)
}
}

@ -29,11 +29,11 @@ import java.util.Locale
class BarChartTest {
val base = "views/BarChart"
val today = LocalDate(2015, 1, 25)
val fmt = JavaLocalDateFormatter(Locale.US)
private val fmt = JavaLocalDateFormatter(Locale.US)
val theme = LightTheme()
val component = BarChart(theme, fmt)
val axis = (0..100).map { today.minus(it) }
val series1 = listOf(200.0, 0.0, 150.0, 137.0, 0.0, 0.0, 500.0, 30.0, 100.0, 0.0, 300.0)
private val axis = (0..100).map { today.minus(it) }
private val series1 = listOf(200.0, 0.0, 150.0, 137.0, 0.0, 0.0, 500.0, 30.0, 100.0, 0.0, 300.0)
init {
component.axis = axis

@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.components
package org.isoron.uhabits.core.ui.views
import kotlinx.coroutines.runBlocking
import org.isoron.platform.gui.assertRenders
@ -26,15 +26,10 @@ import org.isoron.platform.time.DayOfWeek.SUNDAY
import org.isoron.platform.time.JavaLocalDateFormatter
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.ui.views.DarkTheme
import org.isoron.uhabits.core.ui.views.HistoryChart
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.DIMMED
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.HATCHED
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.OFF
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.ON
import org.isoron.uhabits.core.ui.views.LightTheme
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
import org.isoron.uhabits.core.ui.views.WidgetTheme
import org.junit.Test
import org.mockito.Mockito.mock
import org.mockito.Mockito.reset
@ -45,7 +40,7 @@ import java.util.Locale
class HistoryChartTest {
val base = "views/HistoryChart"
val dateClickedListener = mock(OnDateClickedListener::class.java)
private val dateClickedListener = mock(OnDateClickedListener::class.java)!!
val view = HistoryChart(
today = LocalDate(2015, 1, 25),

@ -1,136 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.widgets;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.commands.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import java.util.*;
import static org.isoron.uhabits.core.models.Entry.*;
import static org.mockito.Mockito.*;
public class WidgetBehaviorTest extends BaseUnitTest
{
private NotificationTray notificationTray;
private CommandRunner commandRunner;
private Preferences preferences;
private WidgetBehavior behavior;
private Habit habit;
private Timestamp today;
@Before
@Override
public void setUp() throws Exception
{
super.setUp();
habit = fixtures.createEmptyHabit();
commandRunner = mock(CommandRunner.class);
notificationTray = mock(NotificationTray.class);
preferences = mock(Preferences.class);
behavior = new WidgetBehavior(habitList, commandRunner, notificationTray, preferences);
today = DateUtils.getTodayWithOffset();
}
@Test
public void testOnAddRepetition()
{
behavior.onAddRepetition(habit, today);
verify(commandRunner).run(
new CreateRepetitionCommand(habitList, habit, today, YES_MANUAL)
);
verify(notificationTray).cancel(habit);
verifyZeroInteractions(preferences);
}
@Test
public void testOnRemoveRepetition()
{
behavior.onRemoveRepetition(habit, today);
verify(commandRunner).run(
new CreateRepetitionCommand(habitList, habit, today, NO)
);
verify(notificationTray).cancel(habit);
verifyZeroInteractions(preferences);
}
@Test
public void testOnToggleRepetition()
{
for (boolean skipEnabled : Arrays.asList(true, false))
for (int currentValue : Arrays.asList(NO, YES_MANUAL, YES_AUTO, SKIP))
{
when(preferences.isSkipEnabled()).thenReturn(skipEnabled);
int nextValue;
if(skipEnabled) nextValue = Entry.Companion.nextToggleValueWithSkip(currentValue);
else nextValue = Entry.Companion.nextToggleValueWithoutSkip(currentValue);
habit.getOriginalEntries().add(new Entry(today, currentValue));
behavior.onToggleRepetition(habit, today);
verify(preferences).isSkipEnabled();
verify(commandRunner).run(
new CreateRepetitionCommand(habitList, habit, today, nextValue)
);
verify(notificationTray).cancel(habit);
reset(preferences, commandRunner, notificationTray);
}
}
@Test
public void testOnIncrement()
{
habit = fixtures.createNumericalHabit();
habit.getOriginalEntries().add(new Entry(today, 500));
habit.recompute();
behavior.onIncrement(habit, today, 100);
verify(commandRunner).run(
new CreateRepetitionCommand(habitList, habit, today, 600)
);
verify(notificationTray).cancel(habit);
verifyZeroInteractions(preferences);
}
@Test
public void testOnDecrement()
{
habit = fixtures.createNumericalHabit();
habit.getOriginalEntries().add(new Entry(today, 500));
habit.recompute();
behavior.onDecrement(habit, today, 100);
verify(commandRunner).run(
new CreateRepetitionCommand(habitList, habit, today, 400)
);
verify(notificationTray).cancel(habit);
verifyZeroInteractions(preferences);
}
}

@ -0,0 +1,126 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.ui.widgets
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Entry.Companion.nextToggleValueWithSkip
import org.isoron.uhabits.core.models.Entry.Companion.nextToggleValueWithoutSkip
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.NotificationTray
import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
class WidgetBehaviorTest : BaseUnitTest() {
private lateinit var notificationTray: NotificationTray
private lateinit var preferences: Preferences
private lateinit var behavior: WidgetBehavior
private var habit: Habit? = null
private var today: Timestamp? = null
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
habit = fixtures.createEmptyHabit()
commandRunner = Mockito.mock(CommandRunner::class.java)
notificationTray = Mockito.mock(NotificationTray::class.java)
preferences = Mockito.mock(Preferences::class.java)
behavior = WidgetBehavior(habitList, commandRunner, notificationTray, preferences)
today = getTodayWithOffset()
}
@Test
fun testOnAddRepetition() {
behavior.onAddRepetition(habit!!, today)
Mockito.verify(commandRunner)!!.run(
CreateRepetitionCommand(habitList, habit!!, today!!, Entry.YES_MANUAL)
)
Mockito.verify(notificationTray)!!.cancel(habit!!)
Mockito.verifyZeroInteractions(preferences)
}
@Test
fun testOnRemoveRepetition() {
behavior.onRemoveRepetition(habit!!, today)
Mockito.verify(commandRunner)!!.run(
CreateRepetitionCommand(habitList, habit!!, today!!, Entry.NO)
)
Mockito.verify(notificationTray)!!.cancel(habit!!)
Mockito.verifyZeroInteractions(preferences)
}
@Test
fun testOnToggleRepetition() {
for (skipEnabled in listOf(true, false)) for (
currentValue in listOf(
Entry.NO,
Entry.YES_MANUAL,
Entry.YES_AUTO,
Entry.SKIP
)
) {
Mockito.`when`(preferences.isSkipEnabled).thenReturn(skipEnabled)
val nextValue: Int = if (skipEnabled) nextToggleValueWithSkip(currentValue) else nextToggleValueWithoutSkip(
currentValue
)
habit!!.originalEntries.add(Entry(today!!, currentValue))
behavior.onToggleRepetition(habit!!, today)
Mockito.verify(preferences)!!.isSkipEnabled
Mockito.verify(commandRunner)!!.run(
CreateRepetitionCommand(habitList, habit!!, today!!, nextValue)
)
Mockito.verify(notificationTray)!!.cancel(
habit!!
)
Mockito.reset(preferences, commandRunner, notificationTray)
}
}
@Test
fun testOnIncrement() {
habit = fixtures.createNumericalHabit()
habit!!.originalEntries.add(Entry(today!!, 500))
habit!!.recompute()
behavior.onIncrement(habit!!, today!!, 100)
Mockito.verify(commandRunner)!!.run(
CreateRepetitionCommand(habitList, habit!!, today!!, 600)
)
Mockito.verify(notificationTray)!!.cancel(habit!!)
Mockito.verifyZeroInteractions(preferences)
}
@Test
fun testOnDecrement() {
habit = fixtures.createNumericalHabit()
habit!!.originalEntries.add(Entry(today!!, 500))
habit!!.recompute()
behavior.onDecrement(habit!!, today!!, 100)
Mockito.verify(commandRunner)!!.run(
CreateRepetitionCommand(habitList, habit!!, today!!, 400)
)
Mockito.verify(notificationTray)!!.cancel(habit!!)
Mockito.verifyZeroInteractions(preferences)
}
}

@ -1,286 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.utils;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.junit.*;
import java.util.*;
import static java.util.Calendar.*;
import static junit.framework.Assert.assertEquals;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
import static org.isoron.uhabits.core.utils.DateUtils.*;
public class DateUtilsTest extends BaseUnitTest
{
int firstWeekday = SUNDAY;
@Before
@Override
public void setUp() throws Exception
{
super.setUp();
DateUtils.setFixedLocale(Locale.US);
}
@Test
public void testFormatHeaderDate()
{
long timestamp = unixTime(2015, DECEMBER, 31);
GregorianCalendar date = new Timestamp(timestamp).toCalendar();
String formatted = DateUtils.formatHeaderDate(date);
assertThat(formatted, equalTo("Thu\n31"));
}
@Test
public void testTruncate_dayOfWeek()
{
DateUtils.TruncateField field = DateUtils.TruncateField.WEEK_NUMBER;
long expected = unixTime(2015, Calendar.JANUARY, 11);
long t0 = unixTime(2015, Calendar.JANUARY, 11);
long t1 = unixTime(2015, Calendar.JANUARY, 16);
long t2 = unixTime(2015, Calendar.JANUARY, 17);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2015, Calendar.JANUARY, 18);
t0 = unixTime(2015, Calendar.JANUARY, 18);
t1 = unixTime(2015, Calendar.JANUARY, 19);
t2 = unixTime(2015, Calendar.JANUARY, 24);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
firstWeekday = WEDNESDAY;
expected = unixTime(2015, Calendar.JANUARY, 7);
t0 = unixTime(2015, Calendar.JANUARY, 7);
t1 = unixTime(2015, Calendar.JANUARY, 9);
t2 = unixTime(2015, Calendar.JANUARY, 13);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
}
@Test
public void testTruncate_month()
{
long expected = unixTime(2016, Calendar.JUNE, 1);
long t0 = unixTime(2016, Calendar.JUNE, 1);
long t1 = unixTime(2016, Calendar.JUNE, 15);
long t2 = unixTime(2016, Calendar.JUNE, 20);
DateUtils.TruncateField field = DateUtils.TruncateField.MONTH;
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2016, DECEMBER, 1);
t0 = unixTime(2016, DECEMBER, 1);
t1 = unixTime(2016, DECEMBER, 15);
t2 = unixTime(2016, DECEMBER, 31);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
}
@Test
public void testTruncate_quarter()
{
DateUtils.TruncateField field = DateUtils.TruncateField.QUARTER;
long expected = unixTime(2016, JANUARY, 1);
long t0 = unixTime(2016, JANUARY, 20);
long t1 = unixTime(2016, FEBRUARY, 15);
long t2 = unixTime(2016, MARCH, 30);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2016, APRIL, 1);
t0 = unixTime(2016, APRIL, 1);
t1 = unixTime(2016, MAY, 30);
t2 = unixTime(2016, JUNE, 20);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
}
@Test
public void testTruncate_year()
{
DateUtils.TruncateField field = DateUtils.TruncateField.YEAR;
long expected = unixTime(2016, JANUARY, 1);
long t0 = unixTime(2016, JANUARY, 1);
long t1 = unixTime(2016, FEBRUARY, 25);
long t2 = unixTime(2016, DECEMBER, 31);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2017, JANUARY, 1);
t0 = unixTime(2017, JANUARY, 1);
t1 = unixTime(2017, MAY, 30);
t2 = unixTime(2017, DECEMBER, 31);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
}
@Test
public void testMillisecondsUntilTomorrow() throws Exception
{
DateUtils.setFixedTimeZone(TimeZone.getTimeZone("GMT"));
DateUtils.setFixedLocalTime(unixTime(2017, JANUARY, 1, 23, 59));
assertThat(DateUtils.millisecondsUntilTomorrowWithOffset(), equalTo(MINUTE_LENGTH));
DateUtils.setFixedLocalTime(unixTime(2017, JANUARY, 1, 20, 0));
assertThat(DateUtils.millisecondsUntilTomorrowWithOffset(), equalTo(4 * HOUR_LENGTH));
DateUtils.setStartDayOffset(3, 30);
DateUtils.setFixedLocalTime(unixTime(2017, JANUARY, 1, 23, 59));
assertThat(DateUtils.millisecondsUntilTomorrowWithOffset(), equalTo(3 * HOUR_LENGTH + 31 * MINUTE_LENGTH));
DateUtils.setFixedLocalTime(unixTime(2017, JANUARY, 2, 1, 0));
assertThat(DateUtils.millisecondsUntilTomorrowWithOffset(), equalTo(2 * HOUR_LENGTH + 30 * MINUTE_LENGTH));
}
@Test
public void testGetTodayWithOffset() throws Exception
{
assertThat(DateUtils.getTodayWithOffset(), equalTo(new Timestamp(FIXED_LOCAL_TIME)));
DateUtils.setStartDayOffset(9, 0);
assertThat(
DateUtils.getTodayWithOffset(),
equalTo(new Timestamp(FIXED_LOCAL_TIME - DAY_LENGTH)));
}
@Test
public void testGetStartOfDayWithOffset() throws Exception
{
long timestamp = unixTime(2020, SEPTEMBER, 3);
assertThat(
DateUtils.getStartOfDayWithOffset(timestamp + HOUR_LENGTH),
equalTo(timestamp));
DateUtils.setStartDayOffset(3, 30);
assertThat(
DateUtils.getStartOfDayWithOffset(timestamp + 3 * HOUR_LENGTH + 29 * MINUTE_LENGTH),
equalTo(timestamp - DAY_LENGTH));
}
@Test
public void test_applyTimezone()
{
DateUtils.setFixedTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
assertEquals(applyTimezone(unixTime(2017, JULY, 30, 18, 0)), (unixTime(2017, JULY, 30, 8, 0)));
assertEquals(applyTimezone(unixTime(2017, SEPTEMBER, 30, 0, 0)), (unixTime(2017, SEPTEMBER, 29, 14, 0)));
assertEquals(applyTimezone(unixTime(2017, SEPTEMBER, 30, 10, 0)), (unixTime(2017, SEPTEMBER, 30, 0, 0)));
assertEquals(applyTimezone(unixTime(2017, SEPTEMBER, 30, 11, 0)), (unixTime(2017, SEPTEMBER, 30, 1, 0)));
assertEquals(applyTimezone(unixTime(2017, SEPTEMBER, 30, 12, 0)), (unixTime(2017, SEPTEMBER, 30, 2, 0)));
assertEquals(applyTimezone(unixTime(2017, SEPTEMBER, 30, 13, 0)), (unixTime(2017, SEPTEMBER, 30, 3, 0)));
assertEquals(applyTimezone(unixTime(2017, SEPTEMBER, 30, 22, 0)), (unixTime(2017, SEPTEMBER, 30, 12, 0)));
assertEquals(applyTimezone(unixTime(2017, SEPTEMBER, 30, 23, 0)), (unixTime(2017, SEPTEMBER, 30, 13, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 0, 0)), (unixTime(2017, SEPTEMBER, 30, 14, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 1, 0)), (unixTime(2017, SEPTEMBER, 30, 15, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 1, 59)), (unixTime(2017, SEPTEMBER, 30, 15, 59)));
// DST begins
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 3, 0)), (unixTime(2017, SEPTEMBER, 30, 16, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 4, 0)), (unixTime(2017, SEPTEMBER, 30, 17, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 5, 0)), (unixTime(2017, SEPTEMBER, 30, 18, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 11, 0)), (unixTime(2017, OCTOBER, 1, 0, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 12, 0)), (unixTime(2017, OCTOBER, 1, 1, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 13, 0)), (unixTime(2017, OCTOBER, 1, 2, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 14, 0)), (unixTime(2017, OCTOBER, 1, 3, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 15, 0)), (unixTime(2017, OCTOBER, 1, 4, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 1, 19, 0)), (unixTime(2017, OCTOBER, 1, 8, 0)));
assertEquals(applyTimezone(unixTime(2017, OCTOBER, 2, 19, 0)), (unixTime(2017, OCTOBER, 2, 8, 0)));
assertEquals(applyTimezone(unixTime(2017, NOVEMBER, 30, 19, 0)), (unixTime(2017, NOVEMBER, 30, 8, 0)));
assertEquals(applyTimezone(unixTime(2018, MARCH, 31, 0, 0)), (unixTime(2018, MARCH, 30, 13, 0)));
assertEquals(applyTimezone(unixTime(2018, MARCH, 31, 12, 0)), (unixTime(2018, MARCH, 31, 1, 0)));
assertEquals(applyTimezone(unixTime(2018, MARCH, 31, 18, 0)), (unixTime(2018, MARCH, 31, 7, 0)));
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 0, 0)), (unixTime(2018, MARCH, 31, 13, 0)));
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 1, 0)), (unixTime(2018, MARCH, 31, 14, 0)));
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 1, 59)), (unixTime(2018, MARCH, 31, 14, 59)));
// DST ends
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 2, 0)), (unixTime(2018, MARCH, 31, 16, 0)));
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 3, 0)), (unixTime(2018, MARCH, 31, 17, 0)));
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 4, 0)), (unixTime(2018, MARCH, 31, 18, 0)));
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 10, 0)), (unixTime(2018, APRIL, 1, 0, 0)));
assertEquals(applyTimezone(unixTime(2018, APRIL, 1, 18, 0)), (unixTime(2018, APRIL, 1, 8, 0)));
}
@Test
public void test_removeTimezone()
{
DateUtils.setFixedTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
assertEquals(removeTimezone(unixTime(2017, JULY, 30, 8, 0)), (unixTime(2017, JULY, 30, 18, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 29, 14, 0)), (unixTime(2017, SEPTEMBER, 30, 0, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 0, 0)), (unixTime(2017, SEPTEMBER, 30, 10, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 1, 0)), (unixTime(2017, SEPTEMBER, 30, 11, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 2, 0)), (unixTime(2017, SEPTEMBER, 30, 12, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 3, 0)), (unixTime(2017, SEPTEMBER, 30, 13, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 12, 0)), (unixTime(2017, SEPTEMBER, 30, 22, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 13, 0)), (unixTime(2017, SEPTEMBER, 30, 23, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 14, 0)), (unixTime(2017, OCTOBER, 1, 0, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 15, 0)), (unixTime(2017, OCTOBER, 1, 1, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 15, 59)), (unixTime(2017, OCTOBER, 1, 1, 59)));
// DST begins
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 16, 0)), (unixTime(2017, OCTOBER, 1, 3, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 17, 0)), (unixTime(2017, OCTOBER, 1, 4, 0)));
assertEquals(removeTimezone(unixTime(2017, SEPTEMBER, 30, 18, 0)), (unixTime(2017, OCTOBER, 1, 5, 0)));
assertEquals(removeTimezone(unixTime(2017, OCTOBER, 1, 0, 0)), (unixTime(2017, OCTOBER, 1, 11, 0)));
assertEquals(removeTimezone(unixTime(2017, OCTOBER, 1, 1, 0)), (unixTime(2017, OCTOBER, 1, 12, 0)));
assertEquals(removeTimezone(unixTime(2017, OCTOBER, 1, 2, 0)), (unixTime(2017, OCTOBER, 1, 13, 0)));
assertEquals(removeTimezone(unixTime(2017, OCTOBER, 1, 3, 0)), (unixTime(2017, OCTOBER, 1, 14, 0)));
assertEquals(removeTimezone(unixTime(2017, OCTOBER, 1, 4, 0)), (unixTime(2017, OCTOBER, 1, 15, 0)));
assertEquals(removeTimezone(unixTime(2017, OCTOBER, 1, 8, 0)), (unixTime(2017, OCTOBER, 1, 19, 0)));
assertEquals(removeTimezone(unixTime(2017, OCTOBER, 2, 8, 0)), (unixTime(2017, OCTOBER, 2, 19, 0)));
assertEquals(removeTimezone(unixTime(2017, NOVEMBER, 30, 8, 0)), (unixTime(2017, NOVEMBER, 30, 19, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 30, 13, 0)), (unixTime(2018, MARCH, 31, 0, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 1, 0)), (unixTime(2018, MARCH, 31, 12, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 7, 0)), (unixTime(2018, MARCH, 31, 18, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 13, 0)), (unixTime(2018, APRIL, 1, 0, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 14, 0)), (unixTime(2018, APRIL, 1, 1, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 14, 59)), (unixTime(2018, APRIL, 1, 1, 59)));
// DST ends
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 16, 0)), (unixTime(2018, APRIL, 1, 2, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 17, 0)), (unixTime(2018, APRIL, 1, 3, 0)));
assertEquals(removeTimezone(unixTime(2018, MARCH, 31, 18, 0)), (unixTime(2018, APRIL, 1, 4, 0)));
assertEquals(removeTimezone(unixTime(2018, APRIL, 1, 0, 0)), (unixTime(2018, APRIL, 1, 10, 0)));
assertEquals(removeTimezone(unixTime(2018, APRIL, 1, 8, 0)), (unixTime(2018, APRIL, 1, 18, 0)));
}
}

@ -0,0 +1,479 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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.utils
import junit.framework.Assert.assertEquals
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.utils.DateUtils.Companion.applyTimezone
import org.isoron.uhabits.core.utils.DateUtils.Companion.formatHeaderDate
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfDayWithOffset
import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset
import org.isoron.uhabits.core.utils.DateUtils.Companion.millisecondsUntilTomorrowWithOffset
import org.isoron.uhabits.core.utils.DateUtils.Companion.removeTimezone
import org.isoron.uhabits.core.utils.DateUtils.Companion.setFixedLocalTime
import org.isoron.uhabits.core.utils.DateUtils.Companion.setFixedLocale
import org.isoron.uhabits.core.utils.DateUtils.Companion.setFixedTimeZone
import org.isoron.uhabits.core.utils.DateUtils.Companion.setStartDayOffset
import org.isoron.uhabits.core.utils.DateUtils.Companion.truncate
import org.junit.Before
import org.junit.Test
import java.util.Calendar
import java.util.Locale
import java.util.TimeZone
class DateUtilsTest : BaseUnitTest() {
var firstWeekday = Calendar.SUNDAY
@Before
@Throws(Exception::class)
override fun setUp() {
super.setUp()
setFixedLocale(Locale.US)
}
@Test
fun testFormatHeaderDate() {
val timestamp = unixTime(2015, Calendar.DECEMBER, 31)
val date = Timestamp(timestamp).toCalendar()
val formatted = formatHeaderDate(date)
assertThat(formatted, CoreMatchers.equalTo("Thu\n31"))
}
@Test
fun testTruncate_dayOfWeek() {
val field = DateUtils.TruncateField.WEEK_NUMBER
var expected = unixTime(2015, Calendar.JANUARY, 11)
var t0 = unixTime(2015, Calendar.JANUARY, 11)
var t1 = unixTime(2015, Calendar.JANUARY, 16)
var t2 = unixTime(2015, Calendar.JANUARY, 17)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
expected = unixTime(2015, Calendar.JANUARY, 18)
t0 = unixTime(2015, Calendar.JANUARY, 18)
t1 = unixTime(2015, Calendar.JANUARY, 19)
t2 = unixTime(2015, Calendar.JANUARY, 24)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
firstWeekday = Calendar.WEDNESDAY
expected = unixTime(2015, Calendar.JANUARY, 7)
t0 = unixTime(2015, Calendar.JANUARY, 7)
t1 = unixTime(2015, Calendar.JANUARY, 9)
t2 = unixTime(2015, Calendar.JANUARY, 13)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
}
@Test
fun testTruncate_month() {
var expected = unixTime(2016, Calendar.JUNE, 1)
var t0 = unixTime(2016, Calendar.JUNE, 1)
var t1 = unixTime(2016, Calendar.JUNE, 15)
var t2 = unixTime(2016, Calendar.JUNE, 20)
val field = DateUtils.TruncateField.MONTH
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
expected = unixTime(2016, Calendar.DECEMBER, 1)
t0 = unixTime(2016, Calendar.DECEMBER, 1)
t1 = unixTime(2016, Calendar.DECEMBER, 15)
t2 = unixTime(2016, Calendar.DECEMBER, 31)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
}
@Test
fun testTruncate_quarter() {
val field = DateUtils.TruncateField.QUARTER
var expected = unixTime(2016, Calendar.JANUARY, 1)
var t0 = unixTime(2016, Calendar.JANUARY, 20)
var t1 = unixTime(2016, Calendar.FEBRUARY, 15)
var t2 = unixTime(2016, Calendar.MARCH, 30)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
expected = unixTime(2016, Calendar.APRIL, 1)
t0 = unixTime(2016, Calendar.APRIL, 1)
t1 = unixTime(2016, Calendar.MAY, 30)
t2 = unixTime(2016, Calendar.JUNE, 20)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
}
@Test
fun testTruncate_year() {
val field = DateUtils.TruncateField.YEAR
var expected = unixTime(2016, Calendar.JANUARY, 1)
var t0 = unixTime(2016, Calendar.JANUARY, 1)
var t1 = unixTime(2016, Calendar.FEBRUARY, 25)
var t2 = unixTime(2016, Calendar.DECEMBER, 31)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
expected = unixTime(2017, Calendar.JANUARY, 1)
t0 = unixTime(2017, Calendar.JANUARY, 1)
t1 = unixTime(2017, Calendar.MAY, 30)
t2 = unixTime(2017, Calendar.DECEMBER, 31)
assertThat(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected))
assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected))
}
@Test
@Throws(Exception::class)
fun testMillisecondsUntilTomorrow() {
setFixedTimeZone(TimeZone.getTimeZone("GMT"))
setFixedLocalTime(unixTime(2017, Calendar.JANUARY, 1, 23, 59))
assertThat(
millisecondsUntilTomorrowWithOffset(),
CoreMatchers.equalTo(
DateUtils.MINUTE_LENGTH
)
)
setFixedLocalTime(unixTime(2017, Calendar.JANUARY, 1, 20, 0))
assertThat(
millisecondsUntilTomorrowWithOffset(),
CoreMatchers.equalTo(4 * DateUtils.HOUR_LENGTH)
)
setStartDayOffset(3, 30)
setFixedLocalTime(unixTime(2017, Calendar.JANUARY, 1, 23, 59))
assertThat(
millisecondsUntilTomorrowWithOffset(),
CoreMatchers.equalTo(3 * DateUtils.HOUR_LENGTH + 31 * DateUtils.MINUTE_LENGTH)
)
setFixedLocalTime(unixTime(2017, Calendar.JANUARY, 2, 1, 0))
assertThat(
millisecondsUntilTomorrowWithOffset(),
CoreMatchers.equalTo(2 * DateUtils.HOUR_LENGTH + 30 * DateUtils.MINUTE_LENGTH)
)
}
@Test
@Throws(Exception::class)
fun testGetTodayWithOffset() {
assertThat(
getTodayWithOffset(),
CoreMatchers.equalTo(Timestamp(FIXED_LOCAL_TIME))
)
setStartDayOffset(9, 0)
assertThat(
getTodayWithOffset(),
CoreMatchers.equalTo(Timestamp(FIXED_LOCAL_TIME - DateUtils.DAY_LENGTH))
)
}
@Test
@Throws(Exception::class)
fun testGetStartOfDayWithOffset() {
val timestamp = unixTime(2020, Calendar.SEPTEMBER, 3)
assertThat(
getStartOfDayWithOffset(timestamp + DateUtils.HOUR_LENGTH),
CoreMatchers.equalTo(timestamp)
)
setStartDayOffset(3, 30)
assertThat(
getStartOfDayWithOffset(timestamp + 3 * DateUtils.HOUR_LENGTH + 29 * DateUtils.MINUTE_LENGTH),
CoreMatchers.equalTo(timestamp - DateUtils.DAY_LENGTH)
)
}
@Test
fun test_applyTimezone() {
setFixedTimeZone(TimeZone.getTimeZone("Australia/Sydney"))
assertEquals(
applyTimezone(unixTime(2017, Calendar.JULY, 30, 18, 0)),
unixTime(2017, Calendar.JULY, 30, 8, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 0, 0)),
unixTime(2017, Calendar.SEPTEMBER, 29, 14, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 10, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 0, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 11, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 1, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 12, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 2, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 13, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 3, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 22, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 12, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 23, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 13, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 0, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 14, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 1, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 15, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 1, 59)),
unixTime(2017, Calendar.SEPTEMBER, 30, 15, 59)
)
// DST begins
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 3, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 16, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 4, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 17, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 5, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 18, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 11, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 0, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 12, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 1, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 13, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 2, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 14, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 3, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 15, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 4, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 1, 19, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 8, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.OCTOBER, 2, 19, 0)),
unixTime(2017, Calendar.OCTOBER, 2, 8, 0)
)
assertEquals(
applyTimezone(unixTime(2017, Calendar.NOVEMBER, 30, 19, 0)),
unixTime(2017, Calendar.NOVEMBER, 30, 8, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.MARCH, 31, 0, 0)),
unixTime(2018, Calendar.MARCH, 30, 13, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.MARCH, 31, 12, 0)),
unixTime(2018, Calendar.MARCH, 31, 1, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.MARCH, 31, 18, 0)),
unixTime(2018, Calendar.MARCH, 31, 7, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 0, 0)),
unixTime(2018, Calendar.MARCH, 31, 13, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 1, 0)),
unixTime(2018, Calendar.MARCH, 31, 14, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 1, 59)),
unixTime(2018, Calendar.MARCH, 31, 14, 59)
)
// DST ends
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 2, 0)),
unixTime(2018, Calendar.MARCH, 31, 16, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 3, 0)),
unixTime(2018, Calendar.MARCH, 31, 17, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 4, 0)),
unixTime(2018, Calendar.MARCH, 31, 18, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 10, 0)),
unixTime(2018, Calendar.APRIL, 1, 0, 0)
)
assertEquals(
applyTimezone(unixTime(2018, Calendar.APRIL, 1, 18, 0)),
unixTime(2018, Calendar.APRIL, 1, 8, 0)
)
}
@Test
fun test_removeTimezone() {
setFixedTimeZone(TimeZone.getTimeZone("Australia/Sydney"))
assertEquals(
removeTimezone(unixTime(2017, Calendar.JULY, 30, 8, 0)),
unixTime(2017, Calendar.JULY, 30, 18, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 29, 14, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 0, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 0, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 10, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 1, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 11, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 2, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 12, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 3, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 13, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 12, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 22, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 13, 0)),
unixTime(2017, Calendar.SEPTEMBER, 30, 23, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 14, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 0, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 15, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 1, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 15, 59)),
unixTime(2017, Calendar.OCTOBER, 1, 1, 59)
)
// DST begins
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 16, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 3, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 17, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 4, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.SEPTEMBER, 30, 18, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 5, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.OCTOBER, 1, 0, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 11, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.OCTOBER, 1, 1, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 12, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.OCTOBER, 1, 2, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 13, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.OCTOBER, 1, 3, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 14, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.OCTOBER, 1, 4, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 15, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.OCTOBER, 1, 8, 0)),
unixTime(2017, Calendar.OCTOBER, 1, 19, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.OCTOBER, 2, 8, 0)),
unixTime(2017, Calendar.OCTOBER, 2, 19, 0)
)
assertEquals(
removeTimezone(unixTime(2017, Calendar.NOVEMBER, 30, 8, 0)),
unixTime(2017, Calendar.NOVEMBER, 30, 19, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 30, 13, 0)),
unixTime(2018, Calendar.MARCH, 31, 0, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 1, 0)),
unixTime(2018, Calendar.MARCH, 31, 12, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 7, 0)),
unixTime(2018, Calendar.MARCH, 31, 18, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 13, 0)),
unixTime(2018, Calendar.APRIL, 1, 0, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 14, 0)),
unixTime(2018, Calendar.APRIL, 1, 1, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 14, 59)),
unixTime(2018, Calendar.APRIL, 1, 1, 59)
)
// DST ends
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 16, 0)),
unixTime(2018, Calendar.APRIL, 1, 2, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 17, 0)),
unixTime(2018, Calendar.APRIL, 1, 3, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.MARCH, 31, 18, 0)),
unixTime(2018, Calendar.APRIL, 1, 4, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.APRIL, 1, 0, 0)),
unixTime(2018, Calendar.APRIL, 1, 10, 0)
)
assertEquals(
removeTimezone(unixTime(2018, Calendar.APRIL, 1, 8, 0)),
unixTime(2018, Calendar.APRIL, 1, 18, 0)
)
}
}
Loading…
Cancel
Save