From b6223c3805266243242760ec8b11a6fed7025045 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Mon, 18 Jan 2021 02:30:52 +0100 Subject: [PATCH 01/15] Fix outdated javadocs --- .../java/com/android/datetimepicker/date/DatePickerDialog.java | 2 +- .../java/com/android/datetimepicker/date/DayPickerView.java | 2 +- .../com/android/datetimepicker/time/RadialPickerLayout.java | 2 +- .../java/com/android/datetimepicker/time/TimePickerDialog.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/uhabits-android/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java b/uhabits-android/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java index 229b8df2e..4392fe496 100644 --- a/uhabits-android/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java +++ b/uhabits-android/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java @@ -114,7 +114,7 @@ public class DatePickerDialog extends DialogFragment implements public interface OnDateSetListener { /** - * @param view The view associated with this listener. + * @param dialog The dialog associated with this listener. * @param year The year that was set. * @param monthOfYear The month that was set (0-11) for compatibility * with {@link java.util.Calendar}. diff --git a/uhabits-android/src/main/java/com/android/datetimepicker/date/DayPickerView.java b/uhabits-android/src/main/java/com/android/datetimepicker/date/DayPickerView.java index 8d39e6f99..05348fe8c 100644 --- a/uhabits-android/src/main/java/com/android/datetimepicker/date/DayPickerView.java +++ b/uhabits-android/src/main/java/com/android/datetimepicker/date/DayPickerView.java @@ -167,7 +167,7 @@ public abstract class DayPickerView extends ListView implements OnScrollListener * the list will not be scrolled unless forceScroll is true. This time may * optionally be highlighted as selected as well. * - * @param time The time to move to + * @param day The day to move to * @param animate Whether to scroll to the given time or just redraw at the * new location * @param setSelected Whether to set the given time as selected diff --git a/uhabits-android/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java b/uhabits-android/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java index b877b8fdb..bb6be1300 100644 --- a/uhabits-android/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java +++ b/uhabits-android/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java @@ -392,7 +392,7 @@ public class RadialPickerLayout extends FrameLayout implements OnTouchListener { * Returns mapping of any input degrees (0 to 360) to one of 12 visible output degrees (all * multiples of 30), where the input will be "snapped" to the closest visible degrees. * @param degrees The input degrees - * @param forceAboveOrBelow The output may be forced to either the higher or lower step, or may + * @param forceHigherOrLower The output may be forced to either the higher or lower step, or may * be allowed to snap to whichever is closer. Use 1 to force strictly higher, -1 to force * strictly lower, and 0 to snap to the closer one. * @return output degrees, will be a multiple of 30 diff --git a/uhabits-android/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java b/uhabits-android/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java index 93c4d3ba1..0dc48ea6e 100644 --- a/uhabits-android/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java +++ b/uhabits-android/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java @@ -720,7 +720,7 @@ public class TimePickerDialog extends AppCompatDialogFragment implements OnValue /** * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time. * - * @param changeDisplays If true, update the displays with the relevant time. + * @param updateDisplays If true, update the displays with the relevant time. */ private void finishKbMode(boolean updateDisplays) { From a69490a23a9042fd223795f180e058788cad7428 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Sun, 17 Jan 2021 15:59:45 +0100 Subject: [PATCH 02/15] Update kotlin version --- uhabits-server/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uhabits-server/gradle.properties b/uhabits-server/gradle.properties index f7235a299..b7300cbf9 100644 --- a/uhabits-server/gradle.properties +++ b/uhabits-server/gradle.properties @@ -19,5 +19,5 @@ ktor_version=1.4.1 kotlin.code.style=official -kotlin_version=1.4.10 +kotlin_version=1.4.21 logback_version=1.2.1 From bbe39f85234f3e62cede915785d69668e69e7da4 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Mon, 18 Jan 2021 02:29:32 +0100 Subject: [PATCH 03/15] Replace appendln with appendLine --- .../org/isoron/uhabits/AndroidBugReporter.kt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/AndroidBugReporter.kt b/uhabits-android/src/main/java/org/isoron/uhabits/AndroidBugReporter.kt index fdc2b1a74..7dbee9c5b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/AndroidBugReporter.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/AndroidBugReporter.kt @@ -68,7 +68,7 @@ open class AndroidBugReporter @Inject constructor(@AppContext private val contex if (log.size > maxLineCount) log.removeFirst() } for (l in log) { - builder.appendln(l) + builder.appendLine(l) } return builder.toString() } @@ -99,18 +99,18 @@ open class AndroidBugReporter @Inject constructor(@AppContext private val contex private fun getDeviceInfo(): String { val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager return buildString { - appendln("App Version Name: ${BuildConfig.VERSION_NAME}") - appendln("App Version Code: ${BuildConfig.VERSION_CODE}") - appendln("OS Version: ${System.getProperty("os.version")} (${Build.VERSION.INCREMENTAL})") - appendln("OS API Level: ${Build.VERSION.SDK_INT}") - appendln("Device: ${Build.DEVICE}") - appendln("Model (Product): ${Build.MODEL} (${Build.PRODUCT})") - appendln("Manufacturer: ${Build.MANUFACTURER}") - appendln("Other tags: ${Build.TAGS}") - appendln("Screen Width: ${wm.defaultDisplay.width}") - appendln("Screen Height: ${wm.defaultDisplay.height}") - appendln("External storage state: ${Environment.getExternalStorageState()}") - appendln() + appendLine("App Version Name: ${BuildConfig.VERSION_NAME}") + appendLine("App Version Code: ${BuildConfig.VERSION_CODE}") + appendLine("OS Version: ${System.getProperty("os.version")} (${Build.VERSION.INCREMENTAL})") + appendLine("OS API Level: ${Build.VERSION.SDK_INT}") + appendLine("Device: ${Build.DEVICE}") + appendLine("Model (Product): ${Build.MODEL} (${Build.PRODUCT})") + appendLine("Manufacturer: ${Build.MANUFACTURER}") + appendLine("Other tags: ${Build.TAGS}") + appendLine("Screen Width: ${wm.defaultDisplay.width}") + appendLine("Screen Height: ${wm.defaultDisplay.height}") + appendLine("External storage state: ${Environment.getExternalStorageState()}") + appendLine() } } } From a2a8dc4489f82dd2e3857d37a9ce880fc70fbf9d Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 18:54:25 +0100 Subject: [PATCH 04/15] Mention git pre-commit hook in GUIDELINES.md --- docs/GUIDELINES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/GUIDELINES.md b/docs/GUIDELINES.md index 0658f4147..c24b375cb 100644 --- a/docs/GUIDELINES.md +++ b/docs/GUIDELINES.md @@ -49,7 +49,7 @@ Further resources: ## Code Style -For Kotlin, we follow [ktlint](https://ktlint.github.io/) style with default settings. This code style is enforced by our automated build pipeline. To make sure that IntelliJ and Android Studio are configured according to ktlint, run `./gradlew ktlintApplyToIdea`. To check that all code is properly formatted, run `./gradlew ktlintCheck`. See more details in [ktlint-gradle](https://github.com/jlleitschuh/ktlint-gradle). +For Kotlin, we follow [ktlint](https://ktlint.github.io/) style with default settings. This code style is enforced by our automated build pipeline. To make sure that IntelliJ and Android Studio are configured according to ktlint, run `./gradlew ktlintApplyToIdea`. To check that all code is properly formatted, run `./gradlew ktlintCheck`. You can install a Git pre-commit hook to ensure that the code is properly formatted when you commit using `./gradlew addKtlintFormatGitPreCommitHook`. See more details in [ktlint-gradle](https://github.com/jlleitschuh/ktlint-gradle). For legacy Java code, we don't have strict guidelines. Please follow a code style similar to the file you are modifying. Note that new classes should be written in Kotlin. Pull requests converting existing Java code to Kotlin are also welcome. From 714771fbc363b79fefa36ba3ea15534392f52a92 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 15:19:32 +0100 Subject: [PATCH 05/15] Convert org.isoron.uhabits.activities.common.dialogs --- ...PickerDialog.java => ColorPickerDialog.kt} | 24 ++-- .../dialogs/ColorPickerDialogFactory.java | 53 --------- .../dialogs/ColorPickerDialogFactory.kt | 45 ++++++++ ...leteDialog.java => ConfirmDeleteDialog.kt} | 53 ++++----- .../common/dialogs/ConfirmSyncKeyDialog.java | 50 -------- .../common/dialogs/ConfirmSyncKeyDialog.kt | 45 ++++++++ .../common/dialogs/WeekdayPickerDialog.java | 107 ------------------ .../common/dialogs/WeekdayPickerDialog.kt | 94 +++++++++++++++ .../habits/edit/EditHabitActivity.kt | 3 +- 9 files changed, 220 insertions(+), 254 deletions(-) rename uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/{ColorPickerDialog.java => ColorPickerDialog.kt} (62%) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.kt rename uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/{ConfirmDeleteDialog.java => ConfirmDeleteDialog.kt} (52%) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.kt delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialog.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialog.kt similarity index 62% rename from uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialog.java rename to uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialog.kt index a36cac195..cf6248600 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialog.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialog.kt @@ -16,24 +16,20 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.activities.common.dialogs -package org.isoron.uhabits.activities.common.dialogs; - -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.ui.callbacks.*; -import org.isoron.uhabits.utils.*; +import com.android.colorpicker.ColorPickerDialog +import org.isoron.uhabits.core.ui.callbacks.OnColorPickedCallback +import org.isoron.uhabits.utils.toPaletteColor /** * Dialog that allows the user to choose a color. */ -public class ColorPickerDialog extends com.android.colorpicker.ColorPickerDialog -{ - public void setListener(OnColorPickedCallback callback) - { - super.setOnColorSelectedListener(c -> - { - PaletteColor pc = PaletteUtilsKt.toPaletteColor(c, getContext()); - callback.onColorPicked(pc); - }); +class ColorPickerDialog : ColorPickerDialog() { + fun setListener(callback: OnColorPickedCallback) { + super.setOnColorSelectedListener { c: Int -> + val pc = c.toPaletteColor(context!!) + callback.onColorPicked(pc) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.java deleted file mode 100644 index d06272d63..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.common.dialogs; - -import android.content.*; - -import org.isoron.uhabits.R; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.inject.*; -import org.isoron.uhabits.utils.*; - -import javax.inject.*; - -@ActivityScope -public class ColorPickerDialogFactory -{ - private final Context context; - - @Inject - public ColorPickerDialogFactory(@ActivityContext Context context) - { - this.context = context; - } - - public ColorPickerDialog create(PaletteColor color) - { - ColorPickerDialog dialog = new ColorPickerDialog(); - StyledResources res = new StyledResources(context); - int androidColor = PaletteUtilsKt.toThemedAndroidColor(color, context); - - dialog.initialize(R.string.color_picker_default_title, res.getPalette(), - androidColor, 4, com.android.colorpicker.ColorPickerDialog.SIZE_SMALL); - - return dialog; - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.kt new file mode 100644 index 000000000..ac393d506 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ColorPickerDialogFactory.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.activities.common.dialogs + +import android.content.Context +import org.isoron.uhabits.R +import org.isoron.uhabits.core.models.PaletteColor +import org.isoron.uhabits.inject.ActivityContext +import org.isoron.uhabits.inject.ActivityScope +import org.isoron.uhabits.utils.StyledResources +import org.isoron.uhabits.utils.toThemedAndroidColor +import javax.inject.Inject + +@ActivityScope +class ColorPickerDialogFactory @Inject constructor(@param:ActivityContext private val context: Context) { + fun create(color: PaletteColor): ColorPickerDialog { + val dialog = ColorPickerDialog() + val res = StyledResources(context) + val androidColor = color.toThemedAndroidColor(context) + dialog.initialize( + R.string.color_picker_default_title, + res.getPalette(), + androidColor, + 4, + com.android.colorpicker.ColorPickerDialog.SIZE_SMALL + ) + return dialog + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmDeleteDialog.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmDeleteDialog.kt similarity index 52% rename from uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmDeleteDialog.java rename to uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmDeleteDialog.kt index 7309f27d5..bac6180b2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmDeleteDialog.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmDeleteDialog.kt @@ -16,39 +16,34 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.activities.common.dialogs -package org.isoron.uhabits.activities.common.dialogs; - -import android.content.*; -import android.content.res.*; - -import androidx.annotation.*; -import androidx.appcompat.app.*; - -import org.isoron.uhabits.R; -import org.isoron.uhabits.core.ui.callbacks.*; -import org.isoron.uhabits.inject.*; +import android.content.Context +import android.content.DialogInterface +import androidx.appcompat.app.AlertDialog +import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback +import org.isoron.uhabits.inject.ActivityContext /** * Dialog that asks the user confirmation before executing a delete operation. */ -public class ConfirmDeleteDialog extends AlertDialog -{ - public ConfirmDeleteDialog(@ActivityContext Context context, - @NonNull OnConfirmedCallback callback, - int quantity) - { - super(context); - Resources res = context.getResources(); - setTitle(res.getQuantityString(R.plurals.delete_habits_title, quantity)); - setMessage(res.getQuantityString(R.plurals.delete_habits_message, quantity)); - setButton(BUTTON_POSITIVE, - res.getString(R.string.yes), - (dialog, which) -> callback.onConfirmed() - ); - setButton(BUTTON_NEGATIVE, - res.getString(R.string.no), - (dialog, which) -> { } - ); +class ConfirmDeleteDialog( + @ActivityContext context: Context, + callback: OnConfirmedCallback, + quantity: Int +) : AlertDialog(context) { + init { + val res = context.resources + setTitle(res.getQuantityString(R.plurals.delete_habits_title, quantity)) + setMessage(res.getQuantityString(R.plurals.delete_habits_message, quantity)) + setButton( + BUTTON_POSITIVE, + res.getString(R.string.yes) + ) { dialog: DialogInterface?, which: Int -> callback.onConfirmed() } + setButton( + BUTTON_NEGATIVE, + res.getString(R.string.no) + ) { dialog: DialogInterface?, which: Int -> } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.java deleted file mode 100644 index 337823e5f..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.common.dialogs; - -import android.content.*; -import android.content.res.*; - -import androidx.annotation.*; -import androidx.appcompat.app.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.ui.callbacks.*; -import org.isoron.uhabits.inject.*; - -public class ConfirmSyncKeyDialog extends AlertDialog -{ - public ConfirmSyncKeyDialog(@ActivityContext Context context, - @NonNull OnConfirmedCallback callback) - { - super(context); - setTitle(R.string.device_sync); - Resources res = context.getResources(); - setMessage(res.getString(R.string.sync_confirm)); - setButton(BUTTON_POSITIVE, - res.getString(R.string.yes), - (dialog, which) -> callback.onConfirmed() - ); - setButton(BUTTON_NEGATIVE, - res.getString(R.string.no), - (dialog, which) -> { } - ); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.kt new file mode 100644 index 000000000..b50ed50be --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/ConfirmSyncKeyDialog.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.activities.common.dialogs + +import android.content.Context +import android.content.DialogInterface +import androidx.appcompat.app.AlertDialog +import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback +import org.isoron.uhabits.inject.ActivityContext + +class ConfirmSyncKeyDialog( + @ActivityContext context: Context, + callback: OnConfirmedCallback +) : AlertDialog(context) { + init { + setTitle(R.string.device_sync) + val res = context.resources + setMessage(res.getString(R.string.sync_confirm)) + setButton( + BUTTON_POSITIVE, + res.getString(R.string.yes) + ) { dialog: DialogInterface?, which: Int -> callback.onConfirmed() } + setButton( + BUTTON_NEGATIVE, + res.getString(R.string.no) + ) { dialog: DialogInterface?, which: Int -> } + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java deleted file mode 100644 index 4d40cc386..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.common.dialogs; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatDialogFragment; - -import org.isoron.uhabits.R; -import org.isoron.uhabits.core.models.WeekdayList; -import org.isoron.uhabits.core.utils.DateUtils; - -import java.util.Calendar; - -/** - * Dialog that allows the user to pick one or more days of the week. - */ -public class WeekdayPickerDialog extends AppCompatDialogFragment implements - DialogInterface.OnMultiChoiceClickListener, - DialogInterface.OnClickListener -{ - private static final String KEY_SELECTED_DAYS = "selectedDays"; - private boolean[] selectedDays; - - private OnWeekdaysPickedListener listener; - - @Override - public void onClick(DialogInterface dialog, int which, boolean isChecked) - { - selectedDays[which] = isChecked; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if(savedInstanceState != null){ - selectedDays = savedInstanceState.getBooleanArray(KEY_SELECTED_DAYS); - } - } - - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBooleanArray(KEY_SELECTED_DAYS, selectedDays); - } - - @Override - public void onClick(DialogInterface dialog, int which) - { - if (listener != null) - listener.onWeekdaysSet(new WeekdayList(selectedDays)); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) - { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder - .setTitle(R.string.select_weekdays) - .setMultiChoiceItems(DateUtils.getLongWeekdayNames(Calendar.SATURDAY), - selectedDays, - this) - .setPositiveButton(android.R.string.yes, this) - .setNegativeButton(android.R.string.cancel, (dialog, which) -> { - dismiss(); - }); - - return builder.create(); - } - - public void setListener(OnWeekdaysPickedListener listener) - { - this.listener = listener; - } - - public void setSelectedDays(WeekdayList days) - { - this.selectedDays = days.toArray(); - } - - public interface OnWeekdaysPickedListener - { - void onWeekdaysSet(WeekdayList days); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.kt new file mode 100644 index 000000000..6e1f8cf28 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/WeekdayPickerDialog.kt @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.activities.common.dialogs + +import android.app.Dialog +import android.content.DialogInterface +import android.content.DialogInterface.OnMultiChoiceClickListener +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatDialogFragment +import org.isoron.uhabits.R +import org.isoron.uhabits.core.models.WeekdayList +import org.isoron.uhabits.core.utils.DateUtils +import java.util.Calendar + +/** + * Dialog that allows the user to pick one or more days of the week. + */ +class WeekdayPickerDialog : + AppCompatDialogFragment(), + OnMultiChoiceClickListener, + DialogInterface.OnClickListener { + private var selectedDays: BooleanArray? = null + private var listener: OnWeekdaysPickedListener? = null + override fun onClick(dialog: DialogInterface, which: Int, isChecked: Boolean) { + selectedDays!![which] = isChecked + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (savedInstanceState != null) { + selectedDays = savedInstanceState.getBooleanArray(KEY_SELECTED_DAYS) + } + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putBooleanArray(KEY_SELECTED_DAYS, selectedDays) + } + + override fun onClick(dialog: DialogInterface, which: Int) { + if (listener != null) listener!!.onWeekdaysSet(WeekdayList(selectedDays)) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val builder = AlertDialog.Builder( + activity!! + ) + builder + .setTitle(R.string.select_weekdays) + .setMultiChoiceItems( + DateUtils.getLongWeekdayNames(Calendar.SATURDAY), + selectedDays, + this + ) + .setPositiveButton(android.R.string.yes, this) + .setNegativeButton( + android.R.string.cancel + ) { _: DialogInterface?, _: Int -> dismiss() } + return builder.create() + } + + fun setListener(listener: OnWeekdaysPickedListener?) { + this.listener = listener + } + + fun setSelectedDays(days: WeekdayList) { + selectedDays = days.toArray() + } + + fun interface OnWeekdaysPickedListener { + fun onWeekdaysSet(days: WeekdayList) + } + + companion object { + private const val KEY_SELECTED_DAYS = "selectedDays" + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt index 5e7aab70a..80adad0c7 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt @@ -197,7 +197,8 @@ class EditHabitActivity : AppCompatActivity() { binding.reminderDatePicker.setOnClickListener { val dialog = WeekdayPickerDialog() - dialog.setListener { days -> + + dialog.setListener { days: WeekdayList -> reminderDays = days if (reminderDays.isEmpty) reminderDays = WeekdayList.EVERY_DAY populateReminder() From 8165b5417fc9d213b66cd8352c5116dd94f043e3 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 15:35:30 +0100 Subject: [PATCH 06/15] Convert HabitCardListAdapter --- .../list/views/HabitCardListAdapter.java | 350 ------------------ .../habits/list/views/HabitCardListAdapter.kt | 263 +++++++++++++ 2 files changed, 263 insertions(+), 350 deletions(-) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.java deleted file mode 100644 index 38f1932f7..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.habits.list.views; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import android.view.*; - -import androidx.recyclerview.widget.RecyclerView; - -import org.isoron.uhabits.activities.habits.list.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.core.ui.screens.habits.list.*; -import org.isoron.uhabits.core.utils.*; -import org.isoron.uhabits.inject.*; - -import java.util.*; - -import javax.inject.*; - -/** - * Provides data that backs a {@link HabitCardListView}. - *

- * The data if fetched and cached by a {@link HabitCardListCache}. This adapter - * also holds a list of items that have been selected. - */ -@ActivityScope -public class HabitCardListAdapter - extends RecyclerView.Adapter implements - HabitCardListCache.Listener, - MidnightTimer.MidnightListener, - ListHabitsMenuBehavior.Adapter, - ListHabitsSelectionMenuBehavior.Adapter -{ - @NonNull - private ModelObservable observable; - - @Nullable - private HabitCardListView listView; - - @NonNull - private final LinkedList selected; - - @NonNull - private final HabitCardListCache cache; - - @NonNull - private Preferences preferences; - - private final MidnightTimer midnightTimer; - - @Inject - public HabitCardListAdapter(@NonNull HabitCardListCache cache, - @NonNull Preferences preferences, - @NonNull MidnightTimer midnightTimer) - { - this.preferences = preferences; - this.selected = new LinkedList<>(); - this.observable = new ModelObservable(); - this.cache = cache; - - this.midnightTimer = midnightTimer; - - cache.setListener(this); - cache.setCheckmarkCount( - ListHabitsRootViewKt.MAX_CHECKMARK_COUNT); - cache.setSecondaryOrder(preferences.getDefaultSecondaryOrder()); - cache.setPrimaryOrder(preferences.getDefaultPrimaryOrder()); - - setHasStableIds(true); - } - - @Override - public void atMidnight() - { - cache.refreshAllHabits(); - } - - public void cancelRefresh() - { - cache.cancelTasks(); - } - - /** - * Sets all items as not selected. - */ - @Override - public void clearSelection() - { - selected.clear(); - notifyDataSetChanged(); - observable.notifyListeners(); - } - - /** - * Returns the item that occupies a certain position on the list - * - * @param position position of the item - * @return the item at given position or null if position is invalid - */ - @Deprecated - @Nullable - public Habit getItem(int position) - { - return cache.getHabitByPosition(position); - } - - @Override - public int getItemCount() - { - return cache.getHabitCount(); - } - - @Override - public long getItemId(int position) - { - return getItem(position).getId(); - } - - @NonNull - public ModelObservable getObservable() - { - return observable; - } - - @Override - @NonNull - public List getSelected() - { - return new LinkedList<>(selected); - } - - /** - * Returns whether list of selected items is empty. - * - * @return true if selection is empty, false otherwise - */ - public boolean isSelectionEmpty() - { - return selected.isEmpty(); - } - - public boolean isSortable() - { - return cache.getPrimaryOrder() == HabitList.Order.BY_POSITION; - } - - /** - * Notify the adapter that it has been attached to a ListView. - */ - public void onAttached() - { - cache.onAttached(); - midnightTimer.addListener(this); - } - - @Override - public void onBindViewHolder(@Nullable HabitCardViewHolder holder, - int position) - { - if (holder == null) return; - if (listView == null) return; - - Habit habit = cache.getHabitByPosition(position); - double score = cache.getScore(habit.getId()); - int checkmarks[] = cache.getCheckmarks(habit.getId()); - boolean selected = this.selected.contains(habit); - - listView.bindCardView(holder, habit, score, checkmarks, selected); - } - - @Override - public void onViewAttachedToWindow(@Nullable HabitCardViewHolder holder) - { - if (listView == null) return; - listView.attachCardView(holder); - } - - @Override - public void onViewDetachedFromWindow(@Nullable HabitCardViewHolder holder) - { - if (listView == null) return; - listView.detachCardView(holder); - } - - @Override - public HabitCardViewHolder onCreateViewHolder(ViewGroup parent, - int viewType) - { - if (listView == null) return null; - View view = listView.createHabitCardView(); - return new HabitCardViewHolder(view); - } - - /** - * Notify the adapter that it has been detached from a ListView. - */ - public void onDetached() - { - cache.onDetached(); - midnightTimer.removeListener(this); - } - - @Override - public void onItemChanged(int position) - { - notifyItemChanged(position); - observable.notifyListeners(); - } - - @Override - public void onItemInserted(int position) - { - notifyItemInserted(position); - observable.notifyListeners(); - } - - @Override - public void onItemMoved(int fromPosition, int toPosition) - { - notifyItemMoved(fromPosition, toPosition); - observable.notifyListeners(); - } - - @Override - public void onItemRemoved(int position) - { - notifyItemRemoved(position); - observable.notifyListeners(); - } - - @Override - public void onRefreshFinished() - { - observable.notifyListeners(); - } - - /** - * Removes a list of habits from the adapter. - *

- * Note that this only has effect on the adapter cache. The database is not - * modified, and the change is lost when the cache is refreshed. This method - * is useful for making the ListView more responsive: while we wait for the - * database operation to finish, the cache can be modified to reflect the - * changes immediately. - * - * @param habits list of habits to be removed - */ - @Override - public void performRemove(List habits) - { - for (Habit h : habits) - cache.remove(h.getId()); - } - - /** - * Changes the order of habits on the adapter. - *

- * Note that this only has effect on the adapter cache. The database is not - * modified, and the change is lost when the cache is refreshed. This method - * is useful for making the ListView more responsive: while we wait for the - * database operation to finish, the cache can be modified to reflect the - * changes immediately. - * - * @param from the habit that should be moved - * @param to the habit that currently occupies the desired position - */ - public void performReorder(int from, int to) - { - cache.reorder(from, to); - } - - @Override - public void refresh() - { - cache.refreshAllHabits(); - } - - @Override - public void setFilter(HabitMatcher matcher) - { - cache.setFilter(matcher); - } - - /** - * Sets the HabitCardListView that this adapter will provide data for. - *

- * This object will be used to generated new HabitCardViews, upon demand. - * - * @param listView the HabitCardListView associated with this adapter - */ - public void setListView(@Nullable HabitCardListView listView) - { - this.listView = listView; - } - - @Override - public void setPrimaryOrder(HabitList.Order order) - { - cache.setPrimaryOrder(order); - preferences.setDefaultPrimaryOrder(order); - } - - @Override - public void setSecondaryOrder(HabitList.Order order) { - cache.setSecondaryOrder(order); - preferences.setDefaultSecondaryOrder(order); - } - - @Override - public HabitList.Order getPrimaryOrder() - { - return cache.getPrimaryOrder(); - } - - /** - * Selects or deselects the item at a given position. - * - * @param position position of the item to be toggled - */ - public void toggleSelection(int position) - { - Habit h = getItem(position); - if (h == null) return; - - int k = selected.indexOf(h); - if (k < 0) selected.add(h); - else selected.remove(h); - notifyDataSetChanged(); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt new file mode 100644 index 000000000..8dae13f2d --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.activities.habits.list.views + +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import org.isoron.uhabits.activities.habits.list.MAX_CHECKMARK_COUNT +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.HabitList +import org.isoron.uhabits.core.models.HabitMatcher +import org.isoron.uhabits.core.models.ModelObservable +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.ui.screens.habits.list.HabitCardListCache +import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsMenuBehavior +import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsSelectionMenuBehavior +import org.isoron.uhabits.core.utils.MidnightTimer +import org.isoron.uhabits.inject.ActivityScope +import java.util.LinkedList +import javax.inject.Inject + +/** + * Provides data that backs a [HabitCardListView]. + * + * + * The data if fetched and cached by a [HabitCardListCache]. This adapter + * also holds a list of items that have been selected. + */ +@ActivityScope +class HabitCardListAdapter @Inject constructor( + private val cache: HabitCardListCache, + private val preferences: Preferences, + private val midnightTimer: MidnightTimer +) : RecyclerView.Adapter(), + HabitCardListCache.Listener, + MidnightTimer.MidnightListener, + ListHabitsMenuBehavior.Adapter, + ListHabitsSelectionMenuBehavior.Adapter { + val observable: ModelObservable = ModelObservable() + private var listView: HabitCardListView? = null + private val selected: LinkedList = LinkedList() + override fun atMidnight() { + cache.refreshAllHabits() + } + + fun cancelRefresh() { + cache.cancelTasks() + } + + /** + * Sets all items as not selected. + */ + override fun clearSelection() { + selected.clear() + notifyDataSetChanged() + observable.notifyListeners() + } + + /** + * Returns the item that occupies a certain position on the list + * + * @param position position of the item + * @return the item at given position or null if position is invalid + */ + @Deprecated("") + fun getItem(position: Int): Habit? { + return cache.getHabitByPosition(position) + } + + override fun getItemCount(): Int { + return cache.habitCount + } + + override fun getItemId(position: Int): Long { + return getItem(position)!!.id!! + } + + override fun getSelected(): List { + return LinkedList(selected) + } + + /** + * Returns whether list of selected items is empty. + * + * @return true if selection is empty, false otherwise + */ + val isSelectionEmpty: Boolean + get() = selected.isEmpty() + val isSortable: Boolean + get() = cache.primaryOrder == HabitList.Order.BY_POSITION + + /** + * Notify the adapter that it has been attached to a ListView. + */ + fun onAttached() { + cache.onAttached() + midnightTimer.addListener(this) + } + + override fun onBindViewHolder( + holder: HabitCardViewHolder, + position: Int + ) { + if (listView == null) return + val habit = cache.getHabitByPosition(position) + val score = cache.getScore(habit!!.id!!) + val checkmarks = cache.getCheckmarks(habit.id!!) + val selected = selected.contains(habit) + listView!!.bindCardView(holder, habit, score, checkmarks, selected) + } + + override fun onViewAttachedToWindow(holder: HabitCardViewHolder) { + listView!!.attachCardView(holder) + } + + override fun onViewDetachedFromWindow(holder: HabitCardViewHolder) { + listView!!.detachCardView(holder) + } + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): HabitCardViewHolder { + val view = listView!!.createHabitCardView() + return HabitCardViewHolder(view) + } + + /** + * Notify the adapter that it has been detached from a ListView. + */ + fun onDetached() { + cache.onDetached() + midnightTimer.removeListener(this) + } + + override fun onItemChanged(position: Int) { + notifyItemChanged(position) + observable.notifyListeners() + } + + override fun onItemInserted(position: Int) { + notifyItemInserted(position) + observable.notifyListeners() + } + + override fun onItemMoved(fromPosition: Int, toPosition: Int) { + notifyItemMoved(fromPosition, toPosition) + observable.notifyListeners() + } + + override fun onItemRemoved(position: Int) { + notifyItemRemoved(position) + observable.notifyListeners() + } + + override fun onRefreshFinished() { + observable.notifyListeners() + } + + /** + * Removes a list of habits from the adapter. + * + * + * Note that this only has effect on the adapter cache. The database is not + * modified, and the change is lost when the cache is refreshed. This method + * is useful for making the ListView more responsive: while we wait for the + * database operation to finish, the cache can be modified to reflect the + * changes immediately. + * + * @param habits list of habits to be removed + */ + override fun performRemove(habits: List) { + for (habit in habits) cache.remove(habit.id!!) + } + + /** + * Changes the order of habits on the adapter. + * + * + * Note that this only has effect on the adapter cache. The database is not + * modified, and the change is lost when the cache is refreshed. This method + * is useful for making the ListView more responsive: while we wait for the + * database operation to finish, the cache can be modified to reflect the + * changes immediately. + * + * @param from the habit that should be moved + * @param to the habit that currently occupies the desired position + */ + fun performReorder(from: Int, to: Int) { + cache.reorder(from, to) + } + + override fun refresh() { + cache.refreshAllHabits() + } + + override fun setFilter(matcher: HabitMatcher) { + cache.setFilter(matcher) + } + + /** + * Sets the HabitCardListView that this adapter will provide data for. + * + * + * This object will be used to generated new HabitCardViews, upon demand. + * + * @param listView the HabitCardListView associated with this adapter + */ + fun setListView(listView: HabitCardListView?) { + this.listView = listView + } + + override fun setPrimaryOrder(order: HabitList.Order) { + cache.primaryOrder = order + preferences.defaultPrimaryOrder = order + } + + override fun setSecondaryOrder(order: HabitList.Order) { + cache.secondaryOrder = order + preferences.defaultSecondaryOrder = order + } + + override fun getPrimaryOrder(): HabitList.Order { + return cache.primaryOrder + } + + /** + * Selects or deselects the item at a given position. + * + * @param position position of the item to be toggled + */ + fun toggleSelection(position: Int) { + val h = getItem(position) ?: return + val k = selected.indexOf(h) + if (k < 0) selected.add(h) else selected.remove(h) + notifyDataSetChanged() + } + + init { + cache.setListener(this) + cache.setCheckmarkCount( + MAX_CHECKMARK_COUNT + ) + cache.secondaryOrder = preferences.defaultSecondaryOrder + cache.primaryOrder = preferences.defaultPrimaryOrder + setHasStableIds(true) + } +} From e9816a22a3583f6c0de14d75d7522d65f17dda87 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 15:39:44 +0100 Subject: [PATCH 07/15] Convert SettingsFragment --- .../activities/settings/SettingsActivity.java | 0 .../activities/settings/SettingsFragment.java | 236 ------------------ .../activities/settings/SettingsFragment.kt | 201 +++++++++++++++ 3 files changed, 201 insertions(+), 236 deletions(-) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsActivity.java delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsActivity.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsActivity.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java deleted file mode 100644 index a913c19af..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.settings; - -import android.app.backup.*; -import android.content.*; -import android.net.*; -import android.os.*; -import android.provider.*; -import android.util.*; - -import androidx.annotation.*; -import androidx.preference.*; - -import org.isoron.uhabits.R; -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.core.ui.*; -import org.isoron.uhabits.core.utils.*; -import org.isoron.uhabits.intents.*; -import org.isoron.uhabits.notifications.*; -import org.isoron.uhabits.widgets.*; - -import java.util.*; - -import static android.media.RingtoneManager.*; -import static android.os.Build.VERSION.*; -import static org.isoron.uhabits.activities.habits.list.ListHabitsScreenKt.*; - -public class SettingsFragment extends PreferenceFragmentCompat - implements SharedPreferences.OnSharedPreferenceChangeListener -{ - private static int RINGTONE_REQUEST_CODE = 1; - - private SharedPreferences sharedPrefs; - - private RingtoneManager ringtoneManager; - - @NonNull - private Preferences prefs; - - @Nullable - private WidgetUpdater widgetUpdater; - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) - { - if (requestCode == RINGTONE_REQUEST_CODE) - { - ringtoneManager.update(data); - updateRingtoneDescription(); - return; - } - - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.preferences); - - Context appContext = getContext().getApplicationContext(); - if (appContext instanceof HabitsApplication) - { - HabitsApplication app = (HabitsApplication) appContext; - prefs = app.getComponent().getPreferences(); - widgetUpdater = app.getComponent().getWidgetUpdater(); - } - - setResultOnPreferenceClick("importData", RESULT_IMPORT_DATA); - setResultOnPreferenceClick("exportCSV", RESULT_EXPORT_CSV); - setResultOnPreferenceClick("exportDB", RESULT_EXPORT_DB); - setResultOnPreferenceClick("repairDB", RESULT_REPAIR_DB); - setResultOnPreferenceClick("bugReport", RESULT_BUG_REPORT); - - } - - @Override - public void onCreatePreferences(Bundle bundle, String s) - { - // NOP - } - - @Override - public void onPause() - { - sharedPrefs.unregisterOnSharedPreferenceChangeListener(this); - super.onPause(); - } - - @Override - public boolean onPreferenceTreeClick(Preference preference) - { - String key = preference.getKey(); - if (key == null) return false; - - if (key.equals("reminderSound")) - { - showRingtonePicker(); - return true; - } - else if (key.equals("reminderCustomize")) - { - if (SDK_INT < Build.VERSION_CODES.O) return true; - AndroidNotificationTray.Companion.createAndroidNotificationChannel(getContext()); - Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); - intent.putExtra(Settings.EXTRA_APP_PACKAGE, getContext().getPackageName()); - intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationTray.REMINDERS_CHANNEL_ID); - startActivity(intent); - return true; - } - else if (key.equals("pref_sync_enabled_dummy")) - { - if (prefs.isSyncEnabled()) - { - prefs.disableSync(); - } - else - { - Context context = getActivity(); - context.startActivity(new IntentFactory().startSyncActivity(context)); - } - } - - return super.onPreferenceTreeClick(preference); - } - - @Override - public void onResume() - { - super.onResume(); - this.ringtoneManager = new RingtoneManager(getActivity()); - - sharedPrefs = getPreferenceManager().getSharedPreferences(); - sharedPrefs.registerOnSharedPreferenceChangeListener(this); - - if (!prefs.isDeveloper()) - { - PreferenceCategory devCategory = - (PreferenceCategory) findPreference("devCategory"); - devCategory.setVisible(false); - } - - updateWeekdayPreference(); - updateSyncPreferences(); - - // Temporarily disable this; we now always ask - findPreference("reminderSound").setVisible(false); - findPreference("pref_snooze_interval").setVisible(false); - } - - private void updateSyncPreferences() - { - findPreference("pref_sync_display").setVisible(prefs.isSyncEnabled()); - ((CheckBoxPreference) findPreference("pref_sync_enabled_dummy")).setChecked(prefs.isSyncEnabled()); - } - - private void updateWeekdayPreference() - { - ListPreference weekdayPref = (ListPreference) findPreference("pref_first_weekday"); - int currentFirstWeekday = prefs.getFirstWeekday().getDaysSinceSunday() + 1; - String[] dayNames = DateUtils.getLongWeekdayNames(Calendar.SATURDAY); - String[] dayValues = {"7", "1", "2", "3", "4", "5", "6"}; - weekdayPref.setEntries(dayNames); - weekdayPref.setEntryValues(dayValues); - weekdayPref.setDefaultValue(Integer.toString(currentFirstWeekday)); - weekdayPref.setSummary(dayNames[currentFirstWeekday % 7]); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) - { - if (key.equals("pref_widget_opacity") && widgetUpdater != null) - { - Log.d("SettingsFragment", "updating widgets"); - widgetUpdater.updateWidgets(); - } - - BackupManager.dataChanged("org.isoron.uhabits"); - updateWeekdayPreference(); - updateSyncPreferences(); - } - - private void setResultOnPreferenceClick(String key, final int result) - { - Preference pref = findPreference(key); - pref.setOnPreferenceClickListener(preference -> - { - getActivity().setResult(result); - getActivity().finish(); - return true; - }); - } - - private void showRingtonePicker() - { - Uri existingRingtoneUri = ringtoneManager.getURI(); - Uri defaultRingtoneUri = Settings.System.DEFAULT_NOTIFICATION_URI; - - Intent intent = new Intent(ACTION_RINGTONE_PICKER); - intent.putExtra(EXTRA_RINGTONE_TYPE, TYPE_NOTIFICATION); - intent.putExtra(EXTRA_RINGTONE_SHOW_DEFAULT, true); - intent.putExtra(EXTRA_RINGTONE_SHOW_SILENT, true); - intent.putExtra(EXTRA_RINGTONE_DEFAULT_URI, defaultRingtoneUri); - intent.putExtra(EXTRA_RINGTONE_EXISTING_URI, existingRingtoneUri); - startActivityForResult(intent, RINGTONE_REQUEST_CODE); - } - - private void updateRingtoneDescription() - { - String ringtoneName = ringtoneManager.getName(); - if (ringtoneName == null) return; - Preference ringtonePreference = findPreference("reminderSound"); - ringtonePreference.setSummary(ringtoneName); - } -} \ No newline at end of file diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt new file mode 100644 index 000000000..38418e1b5 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.activities.settings + +import android.app.backup.BackupManager +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.content.SharedPreferences.OnSharedPreferenceChangeListener +import android.os.Build +import android.os.Build.VERSION +import android.os.Bundle +import android.provider.Settings +import android.util.Log +import androidx.preference.CheckBoxPreference +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceFragmentCompat +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.R +import org.isoron.uhabits.activities.habits.list.RESULT_BUG_REPORT +import org.isoron.uhabits.activities.habits.list.RESULT_EXPORT_CSV +import org.isoron.uhabits.activities.habits.list.RESULT_EXPORT_DB +import org.isoron.uhabits.activities.habits.list.RESULT_IMPORT_DATA +import org.isoron.uhabits.activities.habits.list.RESULT_REPAIR_DB +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.ui.NotificationTray +import org.isoron.uhabits.core.utils.DateUtils.Companion.getLongWeekdayNames +import org.isoron.uhabits.intents.IntentFactory +import org.isoron.uhabits.notifications.AndroidNotificationTray.Companion.createAndroidNotificationChannel +import org.isoron.uhabits.notifications.RingtoneManager +import org.isoron.uhabits.widgets.WidgetUpdater +import java.util.Calendar + +class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListener { + private var sharedPrefs: SharedPreferences? = null + private var ringtoneManager: RingtoneManager? = null + private lateinit var prefs: Preferences + private var widgetUpdater: WidgetUpdater? = null + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (requestCode == RINGTONE_REQUEST_CODE) { + ringtoneManager!!.update(data) + updateRingtoneDescription() + return + } + super.onActivityResult(requestCode, resultCode, data) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addPreferencesFromResource(R.xml.preferences) + val appContext = context!!.applicationContext + if (appContext is HabitsApplication) { + prefs = appContext.component.preferences + widgetUpdater = appContext.component.widgetUpdater + } + setResultOnPreferenceClick("importData", RESULT_IMPORT_DATA) + setResultOnPreferenceClick("exportCSV", RESULT_EXPORT_CSV) + setResultOnPreferenceClick("exportDB", RESULT_EXPORT_DB) + setResultOnPreferenceClick("repairDB", RESULT_REPAIR_DB) + setResultOnPreferenceClick("bugReport", RESULT_BUG_REPORT) + } + + override fun onCreatePreferences(bundle: Bundle, s: String) { + // NOP + } + + override fun onPause() { + sharedPrefs!!.unregisterOnSharedPreferenceChangeListener(this) + super.onPause() + } + + override fun onPreferenceTreeClick(preference: Preference): Boolean { + val key = preference.key ?: return false + if (key == "reminderSound") { + showRingtonePicker() + return true + } else if (key == "reminderCustomize") { + if (VERSION.SDK_INT < Build.VERSION_CODES.O) return true + createAndroidNotificationChannel(context!!) + val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) + intent.putExtra(Settings.EXTRA_APP_PACKAGE, context!!.packageName) + intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationTray.REMINDERS_CHANNEL_ID) + startActivity(intent) + return true + } else if (key == "pref_sync_enabled_dummy") { + if (prefs.isSyncEnabled) { + prefs.disableSync() + } else { + val context: Context? = activity + context!!.startActivity(IntentFactory().startSyncActivity(context)) + } + } + return super.onPreferenceTreeClick(preference) + } + + override fun onResume() { + super.onResume() + ringtoneManager = RingtoneManager(activity!!) + sharedPrefs = preferenceManager.sharedPreferences + sharedPrefs!!.registerOnSharedPreferenceChangeListener(this) + if (!prefs.isDeveloper) { + val devCategory = findPreference("devCategory") as PreferenceCategory + devCategory.isVisible = false + } + updateWeekdayPreference() + updateSyncPreferences() + + // Temporarily disable this; we now always ask + findPreference("reminderSound").isVisible = false + findPreference("pref_snooze_interval").isVisible = false + } + + private fun updateSyncPreferences() { + findPreference("pref_sync_display").isVisible = prefs.isSyncEnabled + (findPreference("pref_sync_enabled_dummy") as CheckBoxPreference).isChecked = + prefs.isSyncEnabled + } + + private fun updateWeekdayPreference() { + val weekdayPref = findPreference("pref_first_weekday") as ListPreference + val currentFirstWeekday = prefs.firstWeekday.daysSinceSunday + 1 + val dayNames = getLongWeekdayNames(Calendar.SATURDAY) + val dayValues = arrayOf("7", "1", "2", "3", "4", "5", "6") + weekdayPref.entries = dayNames + weekdayPref.entryValues = dayValues + weekdayPref.setDefaultValue(currentFirstWeekday.toString()) + weekdayPref.summary = dayNames[currentFirstWeekday % 7] + } + + override fun onSharedPreferenceChanged( + sharedPreferences: SharedPreferences, + key: String + ) { + if (key == "pref_widget_opacity" && widgetUpdater != null) { + Log.d("SettingsFragment", "updating widgets") + widgetUpdater!!.updateWidgets() + } + BackupManager.dataChanged("org.isoron.uhabits") + updateWeekdayPreference() + updateSyncPreferences() + } + + private fun setResultOnPreferenceClick(key: String, result: Int) { + val pref = findPreference(key) + pref.onPreferenceClickListener = + Preference.OnPreferenceClickListener { + activity!!.setResult(result) + activity!!.finish() + true + } + } + + private fun showRingtonePicker() { + val existingRingtoneUri = ringtoneManager!!.getURI() + val defaultRingtoneUri = Settings.System.DEFAULT_NOTIFICATION_URI + val intent = Intent(android.media.RingtoneManager.ACTION_RINGTONE_PICKER) + intent.putExtra( + android.media.RingtoneManager.EXTRA_RINGTONE_TYPE, + android.media.RingtoneManager.TYPE_NOTIFICATION + ) + intent.putExtra(android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true) + intent.putExtra(android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true) + intent.putExtra( + android.media.RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, + defaultRingtoneUri + ) + intent.putExtra( + android.media.RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, + existingRingtoneUri + ) + startActivityForResult(intent, RINGTONE_REQUEST_CODE) + } + + private fun updateRingtoneDescription() { + val ringtoneName = ringtoneManager!!.getName() ?: return + val ringtonePreference = findPreference("reminderSound") + ringtonePreference.summary = ringtoneName + } + + companion object { + private const val RINGTONE_REQUEST_CODE = 1 + } +} From 11831a2b24cb318098e33da63ade0c4527f0cab8 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 15:50:10 +0100 Subject: [PATCH 08/15] Convert org.isoron.uhabits.inject --- ...xtModule.java => ActivityContextModule.kt} | 30 ++----- ...ContextModule.java => AppContextModule.kt} | 32 ++----- .../inject/HabitsApplicationComponent.java | 88 ------------------- .../inject/HabitsApplicationComponent.kt | 68 ++++++++++++++ 4 files changed, 85 insertions(+), 133 deletions(-) rename uhabits-android/src/main/java/org/isoron/uhabits/inject/{AppContextModule.java => ActivityContextModule.kt} (67%) rename uhabits-android/src/main/java/org/isoron/uhabits/inject/{ActivityContextModule.java => AppContextModule.kt} (67%) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.java b/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.kt similarity index 67% rename from uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.java rename to uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.kt index 307cac9af..89efc00af 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.kt @@ -16,28 +16,14 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.inject -package org.isoron.uhabits.inject; - -import android.content.Context; - -import dagger.Module; -import dagger.Provides; +import android.content.Context +import dagger.Module +import dagger.Provides @Module -public class AppContextModule -{ - private final Context context; - - public AppContextModule(@AppContext Context context) - { - this.context = context; - } - - @Provides - @AppContext - Context getContext() - { - return context; - } -} +class ActivityContextModule( + @get:Provides + @get:ActivityContext val context: Context +) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.java b/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.kt similarity index 67% rename from uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.java rename to uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.kt index 919a0622d..74b433ea2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.kt @@ -16,29 +16,15 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.inject -package org.isoron.uhabits.inject; - - -import android.content.Context; - -import dagger.Module; -import dagger.Provides; +import android.content.Context +import dagger.Module +import dagger.Provides @Module -public class ActivityContextModule -{ - private Context context; - - public ActivityContextModule(Context context) - { - this.context = context; - } - - @Provides - @ActivityContext - public Context getContext() - { - return context; - } -} +class AppContextModule( + @get:Provides + @get:AppContext + @param:AppContext val context: Context +) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.java b/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.java deleted file mode 100644 index dd4d27504..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.inject; - -import android.content.*; - -import org.isoron.uhabits.core.*; -import org.isoron.uhabits.core.commands.*; -import org.isoron.uhabits.core.io.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.core.reminders.*; -import org.isoron.uhabits.core.sync.*; -import org.isoron.uhabits.core.tasks.*; -import org.isoron.uhabits.core.ui.*; -import org.isoron.uhabits.core.ui.screens.habits.list.*; -import org.isoron.uhabits.core.utils.*; -import org.isoron.uhabits.intents.*; -import org.isoron.uhabits.receivers.*; -import org.isoron.uhabits.tasks.*; -import org.isoron.uhabits.widgets.*; - -import dagger.*; - -@AppScope -@Component(modules = { - AppContextModule.class, - HabitsModule.class, - AndroidTaskRunner.class, -}) -public interface HabitsApplicationComponent -{ - CommandRunner getCommandRunner(); - - @AppContext - Context getContext(); - - GenericImporter getGenericImporter(); - - HabitCardListCache getHabitCardListCache(); - - HabitList getHabitList(); - - IntentFactory getIntentFactory(); - - IntentParser getIntentParser(); - - Logging getLogging(); - - MidnightTimer getMidnightTimer(); - - ModelFactory getModelFactory(); - - NotificationTray getNotificationTray(); - - PendingIntentFactory getPendingIntentFactory(); - - Preferences getPreferences(); - - ReminderScheduler getReminderScheduler(); - - ReminderController getReminderController(); - - TaskRunner getTaskRunner(); - - WidgetPreferences getWidgetPreferences(); - - WidgetUpdater getWidgetUpdater(); - - SyncManager getSyncManager(); -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.kt b/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.kt new file mode 100644 index 000000000..49bb8d67f --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsApplicationComponent.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.inject + +import android.content.Context +import dagger.Component +import org.isoron.uhabits.core.AppScope +import org.isoron.uhabits.core.commands.CommandRunner +import org.isoron.uhabits.core.io.GenericImporter +import org.isoron.uhabits.core.io.Logging +import org.isoron.uhabits.core.models.HabitList +import org.isoron.uhabits.core.models.ModelFactory +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.preferences.WidgetPreferences +import org.isoron.uhabits.core.reminders.ReminderScheduler +import org.isoron.uhabits.core.sync.SyncManager +import org.isoron.uhabits.core.tasks.TaskRunner +import org.isoron.uhabits.core.ui.NotificationTray +import org.isoron.uhabits.core.ui.screens.habits.list.HabitCardListCache +import org.isoron.uhabits.core.utils.MidnightTimer +import org.isoron.uhabits.intents.IntentFactory +import org.isoron.uhabits.intents.IntentParser +import org.isoron.uhabits.intents.PendingIntentFactory +import org.isoron.uhabits.receivers.ReminderController +import org.isoron.uhabits.tasks.AndroidTaskRunner +import org.isoron.uhabits.widgets.WidgetUpdater + +@AppScope +@Component(modules = [AppContextModule::class, HabitsModule::class, AndroidTaskRunner::class]) +interface HabitsApplicationComponent { + val commandRunner: CommandRunner + + @get:AppContext + val context: Context + val genericImporter: GenericImporter + val habitCardListCache: HabitCardListCache + val habitList: HabitList + val intentFactory: IntentFactory + val intentParser: IntentParser + val logging: Logging + val midnightTimer: MidnightTimer + val modelFactory: ModelFactory + val notificationTray: NotificationTray + val pendingIntentFactory: PendingIntentFactory + val preferences: Preferences + val reminderScheduler: ReminderScheduler + val reminderController: ReminderController + val taskRunner: TaskRunner + val widgetPreferences: WidgetPreferences + val widgetUpdater: WidgetUpdater + val syncManager: SyncManager +} From eb8d39fbe33031c002cb22907dbcfe7d93bd7e1c Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 18:51:23 +0100 Subject: [PATCH 09/15] Convert org.isoron.uhabits.core.ui.widgets --- .../isoron/uhabits/widgets/BaseWidget.java | 214 ----------------- .../org/isoron/uhabits/widgets/BaseWidget.kt | 162 +++++++++++++ .../uhabits/widgets/BaseWidgetProvider.java | 206 ---------------- .../uhabits/widgets/BaseWidgetProvider.kt | 177 ++++++++++++++ .../isoron/uhabits/widgets/CheckmarkWidget.kt | 31 +-- .../org/isoron/uhabits/widgets/EmptyWidget.kt | 9 +- .../isoron/uhabits/widgets/FrequencyWidget.kt | 10 +- .../widgets/FrequencyWidgetProvider.kt | 2 +- .../isoron/uhabits/widgets/HistoryWidget.kt | 10 +- .../org/isoron/uhabits/widgets/ScoreWidget.kt | 10 +- .../org/isoron/uhabits/widgets/StackWidget.kt | 16 +- .../uhabits/widgets/StackWidgetService.java | 186 --------------- .../uhabits/widgets/StackWidgetService.kt | 162 +++++++++++++ .../uhabits/widgets/StackWidgetType.java | 117 --------- .../isoron/uhabits/widgets/StackWidgetType.kt | 79 ++++++ .../isoron/uhabits/widgets/StreakWidget.kt | 10 +- .../isoron/uhabits/widgets/TargetWidget.kt | 10 +- .../widgets/views/CheckmarkWidgetView.java | 225 ------------------ .../widgets/views/CheckmarkWidgetView.kt | 156 ++++++++++++ ...mptyWidgetView.java => EmptyWidgetView.kt} | 45 ++-- .../widgets/views/GraphWidgetView.java | 74 ------ .../uhabits/widgets/views/GraphWidgetView.kt | 51 ++++ .../widgets/views/HabitWidgetView.java | 121 ---------- .../uhabits/widgets/views/HabitWidgetView.kt | 104 ++++++++ 24 files changed, 965 insertions(+), 1222 deletions(-) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.kt delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt rename uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/{EmptyWidgetView.java => EmptyWidgetView.kt} (54%) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.kt delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.java deleted file mode 100644 index 8c35f6cbc..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.widgets; - -import android.app.*; -import android.content.*; -import android.graphics.*; -import android.view.*; -import android.widget.*; - -import androidx.annotation.NonNull; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.commands.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.intents.*; - -import static android.view.View.MeasureSpec.makeMeasureSpec; - -public abstract class BaseWidget -{ - private final int id; - - @NonNull - protected final WidgetPreferences widgetPrefs; - - @NonNull - protected final Preferences prefs; - - @NonNull - protected final PendingIntentFactory pendingIntentFactory; - - @NonNull - private final Context context; - - @NonNull - protected final CommandRunner commandRunner; - - @NonNull - private WidgetDimensions dimensions; - - public BaseWidget(@NonNull Context context, int id) - { - this.id = id; - this.context = context; - - HabitsApplication app = - (HabitsApplication) context.getApplicationContext(); - - widgetPrefs = app.getComponent().getWidgetPreferences(); - prefs = app.getComponent().getPreferences(); - commandRunner = app.getComponent().getCommandRunner(); - pendingIntentFactory = app.getComponent().getPendingIntentFactory(); - dimensions = new WidgetDimensions(getDefaultWidth(), getDefaultHeight(), - getDefaultWidth(), getDefaultHeight()); - } - - public void delete() - { - widgetPrefs.removeWidget(id); - } - - @NonNull - public Context getContext() - { - return context; - } - - public int getId() - { - return id; - } - - @NonNull - public RemoteViews getLandscapeRemoteViews() - { - return getRemoteViews(dimensions.getLandscapeWidth(), - dimensions.getLandscapeHeight()); - } - - public abstract PendingIntent getOnClickPendingIntent(Context context); - - @NonNull - public RemoteViews getPortraitRemoteViews() - { - return getRemoteViews(dimensions.getPortraitWidth(), - dimensions.getPortraitHeight()); - } - - public abstract void refreshData(View widgetView); - - public void setDimensions(@NonNull WidgetDimensions dimensions) - { - this.dimensions = dimensions; - } - - protected abstract View buildView(); - - protected abstract int getDefaultHeight(); - - protected abstract int getDefaultWidth(); - - private void adjustRemoteViewsPadding(RemoteViews remoteViews, - View view, - int width, - int height) - { - int imageWidth = view.getMeasuredWidth(); - int imageHeight = view.getMeasuredHeight(); - int p[] = calculatePadding(width, height, imageWidth, imageHeight); - remoteViews.setViewPadding(R.id.buttonOverlay, p[0], p[1], p[2], p[3]); - } - - private void buildRemoteViews(View view, - RemoteViews remoteViews, - int width, - int height) - { - Bitmap bitmap = getBitmapFromView(view); - remoteViews.setImageViewBitmap(R.id.imageView, bitmap); - - adjustRemoteViewsPadding(remoteViews, view, width, height); - - PendingIntent onClickIntent = getOnClickPendingIntent(context); - if (onClickIntent != null) - remoteViews.setOnClickPendingIntent(R.id.button, onClickIntent); - } - - private int[] calculatePadding(int entireWidth, - int entireHeight, - int imageWidth, - int imageHeight) - { - int w = (int) (((float) entireWidth - imageWidth) / 2); - int h = (int) (((float) entireHeight - imageHeight) / 2); - - return new int[]{w, h, w, h}; - } - - @NonNull - private Bitmap getBitmapFromView(View view) - { - view.invalidate(); - int width = view.getMeasuredWidth(); - int height = view.getMeasuredHeight(); - - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - view.draw(canvas); - return bitmap; - } - - @NonNull - protected RemoteViews getRemoteViews(int width, int height) - { - View view = buildView(); - measureView(view, width, height); - - refreshData(view); - - if (view.isLayoutRequested()) measureView(view, width, height); - - RemoteViews remoteViews = - new RemoteViews(context.getPackageName(), R.layout.widget_wrapper); - - buildRemoteViews(view, remoteViews, width, height); - - return remoteViews; - } - - private void measureView(View view, int width, int height) - { - LayoutInflater inflater = LayoutInflater.from(context); - View entireView = inflater.inflate(R.layout.widget_wrapper, null); - - int specWidth = makeMeasureSpec(width, View.MeasureSpec.EXACTLY); - int specHeight = makeMeasureSpec(height, View.MeasureSpec.EXACTLY); - - entireView.measure(specWidth, specHeight); - entireView.layout(0, 0, entireView.getMeasuredWidth(), - entireView.getMeasuredHeight()); - - View imageView = entireView.findViewById(R.id.imageView); - width = imageView.getMeasuredWidth(); - height = imageView.getMeasuredHeight(); - - specWidth = makeMeasureSpec(width, View.MeasureSpec.EXACTLY); - specHeight = makeMeasureSpec(height, View.MeasureSpec.EXACTLY); - - view.measure(specWidth, specHeight); - view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); - } - - protected int getPreferedBackgroundAlpha() { - return prefs.getWidgetOpacity(); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt new file mode 100644 index 000000000..aef9a3a4c --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.widgets + +import android.app.PendingIntent +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.view.LayoutInflater +import android.view.View +import android.view.View.MeasureSpec +import android.widget.RemoteViews +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.R +import org.isoron.uhabits.core.commands.CommandRunner +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.preferences.WidgetPreferences +import org.isoron.uhabits.intents.PendingIntentFactory + +abstract class BaseWidget(val context: Context, val id: Int) { + protected val widgetPrefs: WidgetPreferences + protected val prefs: Preferences + protected val pendingIntentFactory: PendingIntentFactory + protected val commandRunner: CommandRunner + private var dimensions: WidgetDimensions + fun delete() { + widgetPrefs.removeWidget(id) + } + + val landscapeRemoteViews: RemoteViews + get() = getRemoteViews( + dimensions.landscapeWidth, + dimensions.landscapeHeight + ) + + abstract fun getOnClickPendingIntent(context: Context): PendingIntent? + val portraitRemoteViews: RemoteViews + get() = getRemoteViews( + dimensions.portraitWidth, + dimensions.portraitHeight + ) + + abstract fun refreshData(widgetView: View) + fun setDimensions(dimensions: WidgetDimensions) { + this.dimensions = dimensions + } + + protected abstract fun buildView(): View? + protected abstract val defaultHeight: Int + protected abstract val defaultWidth: Int + private fun adjustRemoteViewsPadding( + remoteViews: RemoteViews, + view: View, + width: Int, + height: Int + ) { + val imageWidth = view.measuredWidth + val imageHeight = view.measuredHeight + val p = calculatePadding(width, height, imageWidth, imageHeight) + remoteViews.setViewPadding(R.id.buttonOverlay, p[0], p[1], p[2], p[3]) + } + + private fun buildRemoteViews( + view: View, + remoteViews: RemoteViews, + width: Int, + height: Int + ) { + val bitmap = getBitmapFromView(view) + remoteViews.setImageViewBitmap(R.id.imageView, bitmap) + adjustRemoteViewsPadding(remoteViews, view, width, height) + val onClickIntent = getOnClickPendingIntent(context) + if (onClickIntent != null) remoteViews.setOnClickPendingIntent(R.id.button, onClickIntent) + } + + private fun calculatePadding( + entireWidth: Int, + entireHeight: Int, + imageWidth: Int, + imageHeight: Int + ): IntArray { + val w = ((entireWidth.toFloat() - imageWidth) / 2).toInt() + val h = ((entireHeight.toFloat() - imageHeight) / 2).toInt() + return intArrayOf(w, h, w, h) + } + + private fun getBitmapFromView(view: View): Bitmap { + view.invalidate() + val width = view.measuredWidth + val height = view.measuredHeight + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + view.draw(canvas) + return bitmap + } + + protected open fun getRemoteViews(width: Int, height: Int): RemoteViews { + val view = buildView()!! + measureView(view, width, height) + refreshData(view) + if (view.isLayoutRequested) measureView(view, width, height) + val remoteViews = RemoteViews(context.packageName, R.layout.widget_wrapper) + buildRemoteViews(view, remoteViews, width, height) + return remoteViews + } + + private fun measureView(view: View, width: Int, height: Int) { + var width = width + var height = height + val inflater = LayoutInflater.from(context) + val entireView = inflater.inflate(R.layout.widget_wrapper, null) + var specWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY) + var specHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + entireView.measure(specWidth, specHeight) + entireView.layout( + 0, + 0, + entireView.measuredWidth, + entireView.measuredHeight + ) + val imageView = entireView.findViewById(R.id.imageView) + width = imageView.measuredWidth + height = imageView.measuredHeight + specWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY) + specHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + view.measure(specWidth, specHeight) + view.layout(0, 0, view.measuredWidth, view.measuredHeight) + } + + protected val preferedBackgroundAlpha: Int + protected get() = prefs.widgetOpacity + + init { + val app = context.applicationContext as HabitsApplication + widgetPrefs = app.component.widgetPreferences + prefs = app.component.preferences + commandRunner = app.component.commandRunner + pendingIntentFactory = app.component.pendingIntentFactory + dimensions = WidgetDimensions( + defaultWidth, + defaultHeight, + defaultWidth, + defaultHeight + ) + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java deleted file mode 100644 index 946a7e966..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.widgets; - -import android.appwidget.*; -import android.content.*; -import android.os.*; -import android.widget.*; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.preferences.*; - -import java.util.*; - -import static android.appwidget.AppWidgetManager.*; -import static org.isoron.uhabits.utils.InterfaceUtils.dpToPixels; - -public abstract class BaseWidgetProvider extends AppWidgetProvider -{ - private HabitList habits; - - private Preferences preferences; - - private WidgetPreferences widgetPrefs; - - public static void updateAppWidget(@NonNull AppWidgetManager manager, - @NonNull BaseWidget widget) - { - RemoteViews landscape = widget.getLandscapeRemoteViews(); - RemoteViews portrait = widget.getPortraitRemoteViews(); - RemoteViews views = new RemoteViews(landscape, portrait); - manager.updateAppWidget(widget.getId(), views); - } - - @NonNull - public WidgetDimensions getDimensionsFromOptions(@NonNull Context ctx, - @NonNull Bundle options) - { - int maxWidth = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH)); - int maxHeight = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT)); - int minWidth = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH)); - int minHeight = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT)); - - return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight); - } - - @Override - public void onAppWidgetOptionsChanged(@Nullable Context context, - @Nullable AppWidgetManager manager, - int widgetId, - @Nullable Bundle options) - { - try - { - if (context == null) throw new RuntimeException("context is null"); - if (manager == null) throw new RuntimeException("manager is null"); - if (options == null) throw new RuntimeException("options is null"); - updateDependencies(context); - - context.setTheme(R.style.WidgetTheme); - - BaseWidget widget = getWidgetFromId(context, widgetId); - WidgetDimensions dims = getDimensionsFromOptions(context, options); - widget.setDimensions(dims); - updateAppWidget(manager, widget); - } - catch (RuntimeException e) - { - drawErrorWidget(context, manager, widgetId, e); - e.printStackTrace(); - } - } - - @Override - public void onDeleted(@Nullable Context context, @Nullable int[] ids) - { - if (context == null) throw new RuntimeException("context is null"); - if (ids == null) throw new RuntimeException("ids is null"); - - updateDependencies(context); - - for (int id : ids) - { - try - { - BaseWidget widget = getWidgetFromId(context, id); - widget.delete(); - } - catch (HabitNotFoundException e) - { - e.printStackTrace(); - } - } - } - - @Override - public void onUpdate(@Nullable Context context, - @Nullable AppWidgetManager manager, - @Nullable int[] widgetIds) - { - if (context == null) throw new RuntimeException("context is null"); - if (manager == null) throw new RuntimeException("manager is null"); - if (widgetIds == null) throw new RuntimeException("widgetIds is null"); - updateDependencies(context); - context.setTheme(R.style.WidgetTheme); - - new Thread(() -> - { - Looper.prepare(); - for (int id : widgetIds) - update(context, manager, id); - }).start(); - } - - protected List getHabitsFromWidgetId(int widgetId) - { - long selectedIds[] = widgetPrefs.getHabitIdsFromWidgetId(widgetId); - ArrayList selectedHabits = new ArrayList<>(selectedIds.length); - for (long id : selectedIds) - { - Habit h = habits.getById(id); - if (h == null) throw new HabitNotFoundException(); - selectedHabits.add(h); - } - - return selectedHabits; - } - - @NonNull - protected abstract BaseWidget getWidgetFromId(@NonNull Context context, - int id); - - private void drawErrorWidget(Context context, - AppWidgetManager manager, - int widgetId, - RuntimeException e) - { - RemoteViews errorView = - new RemoteViews(context.getPackageName(), R.layout.widget_error); - - if (e instanceof HabitNotFoundException) - { - errorView.setCharSequence(R.id.label, "setText", - context.getString(R.string.habit_not_found)); - } - - manager.updateAppWidget(widgetId, errorView); - } - - private void update(@NonNull Context context, - @NonNull AppWidgetManager manager, - int widgetId) - { - try - { - BaseWidget widget = getWidgetFromId(context, widgetId); - Bundle options = manager.getAppWidgetOptions(widgetId); - widget.setDimensions(getDimensionsFromOptions(context, options)); - updateAppWidget(manager, widget); - } - catch (RuntimeException e) - { - drawErrorWidget(context, manager, widgetId, e); - e.printStackTrace(); - } - } - - private void updateDependencies(Context context) - { - HabitsApplication app = - (HabitsApplication) context.getApplicationContext(); - habits = app.getComponent().getHabitList(); - preferences = app.getComponent().getPreferences(); - widgetPrefs = app.getComponent().getWidgetPreferences(); - } - - public Preferences getPreferences() - { - return preferences; - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.kt new file mode 100644 index 000000000..1a41d0f4f --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.kt @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.widgets + +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.os.Bundle +import android.os.Looper +import android.widget.RemoteViews +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.R +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.HabitList +import org.isoron.uhabits.core.models.HabitNotFoundException +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.preferences.WidgetPreferences +import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels +import java.util.ArrayList + +abstract class BaseWidgetProvider : AppWidgetProvider() { + private lateinit var habits: HabitList + lateinit var preferences: Preferences + private set + private lateinit var widgetPrefs: WidgetPreferences + fun getDimensionsFromOptions( + ctx: Context, + options: Bundle + ): WidgetDimensions { + val maxWidth = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH).toFloat() + ).toInt() + val maxHeight = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT).toFloat() + ).toInt() + val minWidth = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH).toFloat() + ).toInt() + val minHeight = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT).toFloat() + ).toInt() + return WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight) + } + + override fun onAppWidgetOptionsChanged( + context: Context, + manager: AppWidgetManager, + widgetId: Int, + options: Bundle + ) { + try { + updateDependencies(context) + context.setTheme(R.style.WidgetTheme) + val widget = getWidgetFromId(context, widgetId) + val dims = getDimensionsFromOptions(context, options) + widget.setDimensions(dims) + updateAppWidget(manager, widget) + } catch (e: RuntimeException) { + drawErrorWidget(context, manager, widgetId, e) + e.printStackTrace() + } + } + + override fun onDeleted(context: Context?, ids: IntArray?) { + if (context == null) throw RuntimeException("context is null") + if (ids == null) throw RuntimeException("ids is null") + updateDependencies(context) + for (id in ids) { + try { + val widget = getWidgetFromId(context, id) + widget.delete() + } catch (e: HabitNotFoundException) { + e.printStackTrace() + } + } + } + + override fun onUpdate( + context: Context, + manager: AppWidgetManager, + widgetIds: IntArray + ) { + updateDependencies(context) + context.setTheme(R.style.WidgetTheme) + Thread { + Looper.prepare() + for (id in widgetIds) update(context, manager, id) + }.start() + } + + protected fun getHabitsFromWidgetId(widgetId: Int): List { + val selectedIds = widgetPrefs.getHabitIdsFromWidgetId(widgetId) + val selectedHabits = ArrayList(selectedIds.size) + for (id in selectedIds) { + val h = habits.getById(id) ?: throw HabitNotFoundException() + selectedHabits.add(h) + } + return selectedHabits + } + + protected abstract fun getWidgetFromId( + context: Context, + id: Int + ): BaseWidget + + private fun drawErrorWidget( + context: Context, + manager: AppWidgetManager, + widgetId: Int, + e: RuntimeException + ) { + val errorView = RemoteViews(context.packageName, R.layout.widget_error) + if (e is HabitNotFoundException) { + errorView.setCharSequence( + R.id.label, + "setText", + context.getString(R.string.habit_not_found) + ) + } + manager.updateAppWidget(widgetId, errorView) + } + + private fun update( + context: Context, + manager: AppWidgetManager, + widgetId: Int + ) { + try { + val widget = getWidgetFromId(context, widgetId) + val options = manager.getAppWidgetOptions(widgetId) + widget.setDimensions(getDimensionsFromOptions(context, options)) + updateAppWidget(manager, widget) + } catch (e: RuntimeException) { + drawErrorWidget(context, manager, widgetId, e) + e.printStackTrace() + } + } + + private fun updateDependencies(context: Context) { + val app = context.applicationContext as HabitsApplication + habits = app.component.habitList + preferences = app.component.preferences + widgetPrefs = app.component.widgetPreferences + } + + companion object { + fun updateAppWidget( + manager: AppWidgetManager, + widget: BaseWidget + ) { + val landscape = widget.landscapeRemoteViews + val portrait = widget.portraitRemoteViews + val views = RemoteViews(landscape, portrait) + manager.updateAppWidget(widget.id, views) + } + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt index a62bc910a..95d0394bf 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt @@ -21,7 +21,9 @@ package org.isoron.uhabits.widgets import android.app.PendingIntent import android.content.Context +import android.os.Build import android.view.View +import androidx.annotation.RequiresApi import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.utils.DateUtils @@ -31,10 +33,13 @@ import org.isoron.uhabits.widgets.views.CheckmarkWidgetView open class CheckmarkWidget( context: Context, widgetId: Int, - protected val habit: Habit + protected val habit: Habit, ) : BaseWidget(context, widgetId) { - override fun getOnClickPendingIntent(context: Context): PendingIntent { + override val defaultHeight: Int = 125 + override val defaultWidth: Int = 125 + + override fun getOnClickPendingIntent(context: Context): PendingIntent? { return if (habit.isNumerical) { pendingIntentFactory.setNumericalValue(context, habit, 10, null) } else { @@ -42,20 +47,21 @@ open class CheckmarkWidget( } } - override fun refreshData(v: View) { - (v as CheckmarkWidgetView).apply { + @RequiresApi(Build.VERSION_CODES.O) + override fun refreshData(widgetView: View) { + (widgetView as CheckmarkWidgetView).apply { val today = DateUtils.getTodayWithOffset() setBackgroundAlpha(preferedBackgroundAlpha) - setActiveColor(habit.color.toThemedAndroidColor(context)) - setName(habit.name) - setEntryValue(habit.computedEntries.get(today).value) + activeColor = habit.color.toThemedAndroidColor(context) + name = habit.name + entryValue = habit.computedEntries.get(today).value if (habit.isNumerical) { - setNumerical(true) - setEntryState(getNumericalEntryState()) + isNumerical = true + entryState = getNumericalEntryState() } else { - setEntryState(habit.computedEntries.get(today).value) + entryState = habit.computedEntries.get(today).value } - setPercentage(habit.scores.get(today).value.toFloat()) + percentage = habit.scores[today].value.toFloat() refresh() } } @@ -64,9 +70,6 @@ open class CheckmarkWidget( return CheckmarkWidgetView(context) } - override fun getDefaultHeight() = 125 - override fun getDefaultWidth() = 125 - private fun getNumericalEntryState(): Int { return if (habit.isCompletedToday()) { Entry.YES_MANUAL diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt index 2f95ee987..1e0c2bad5 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt @@ -19,18 +19,19 @@ package org.isoron.uhabits.widgets +import android.app.PendingIntent import android.content.Context import android.view.View import org.isoron.uhabits.widgets.views.EmptyWidgetView class EmptyWidget( context: Context, - widgetId: Int + widgetId: Int, ) : BaseWidget(context, widgetId) { + override val defaultHeight: Int = 200 + override val defaultWidth: Int = 200 - override fun getOnClickPendingIntent(context: Context) = null + override fun getOnClickPendingIntent(context: Context): PendingIntent? = null override fun refreshData(v: View) {} override fun buildView() = EmptyWidgetView(context) - override fun getDefaultHeight() = 200 - override fun getDefaultWidth() = 200 } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt index 09c969cab..568f98bc1 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt @@ -19,6 +19,7 @@ package org.isoron.uhabits.widgets +import android.app.PendingIntent import android.content.Context import android.view.View import org.isoron.uhabits.activities.common.views.FrequencyChart @@ -30,10 +31,12 @@ class FrequencyWidget( context: Context, widgetId: Int, private val habit: Habit, - private val firstWeekday: Int + private val firstWeekday: Int, ) : BaseWidget(context, widgetId) { + override val defaultHeight: Int = 200 + override val defaultWidth: Int = 200 - override fun getOnClickPendingIntent(context: Context) = + override fun getOnClickPendingIntent(context: Context): PendingIntent? = pendingIntentFactory.showHabit(habit) override fun refreshData(v: View) { @@ -50,7 +53,4 @@ class FrequencyWidget( override fun buildView() = GraphWidgetView(context, FrequencyChart(context)) - - override fun getDefaultHeight() = 200 - override fun getDefaultWidth() = 200 } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt index 907264c1c..6ff8cc250 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt @@ -28,7 +28,7 @@ class FrequencyWidgetProvider : BaseWidgetProvider() { context, id, habits[0], - preferences.firstWeekdayInt + preferences!!.firstWeekdayInt ) else return StackWidget(context, id, StackWidgetType.FREQUENCY, habits) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt index e39ff405b..e7c2800b9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt @@ -35,10 +35,13 @@ import java.util.Locale class HistoryWidget( context: Context, id: Int, - private val habit: Habit + private val habit: Habit, ) : BaseWidget(context, id) { - override fun getOnClickPendingIntent(context: Context): PendingIntent { + override val defaultHeight: Int = 250 + override val defaultWidth: Int = 250 + + override fun getOnClickPendingIntent(context: Context): PendingIntent? { return pendingIntentFactory.showHabit(habit) } @@ -72,7 +75,4 @@ class HistoryWidget( ).apply { setTitle(habit.name) } - - override fun getDefaultHeight() = 250 - override fun getDefaultWidth() = 250 } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt index ad2f970c5..46c5a432c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt @@ -19,6 +19,7 @@ package org.isoron.uhabits.widgets +import android.app.PendingIntent import android.content.Context import android.view.View import org.isoron.uhabits.activities.common.views.ScoreChart @@ -30,10 +31,12 @@ import org.isoron.uhabits.widgets.views.GraphWidgetView class ScoreWidget( context: Context, id: Int, - private val habit: Habit + private val habit: Habit, ) : BaseWidget(context, id) { + override val defaultHeight: Int = 300 + override val defaultWidth: Int = 300 - override fun getOnClickPendingIntent(context: Context) = + override fun getOnClickPendingIntent(context: Context): PendingIntent? = pendingIntentFactory.showHabit(habit) override fun refreshData(view: View) { @@ -57,7 +60,4 @@ class ScoreWidget( GraphWidgetView(context, ScoreChart(context)).apply { setTitle(habit.name) } - - override fun getDefaultHeight() = 300 - override fun getDefaultWidth() = 300 } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt index 51c4ef496..106fd2b2f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt @@ -19,6 +19,7 @@ package org.isoron.uhabits.widgets +import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.content.Context import android.content.Intent @@ -32,15 +33,22 @@ class StackWidget( context: Context, widgetId: Int, private val widgetType: StackWidgetType, - private val habits: List + private val habits: List, ) : BaseWidget(context, widgetId) { + override val defaultHeight: Int = 0 + override val defaultWidth: Int = 0 - override fun getOnClickPendingIntent(context: Context) = null + override fun getOnClickPendingIntent(context: Context): PendingIntent? = null override fun refreshData(v: View) { // unused } + override fun buildView(): View? { + // unused + return null + } + override fun getRemoteViews(width: Int, height: Int): RemoteViews { val manager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.packageName, StackWidgetType.getStackWidgetLayoutId(widgetType)) @@ -59,8 +67,4 @@ class StackWidget( ) return remoteViews } - - override fun buildView() = null // unused - override fun getDefaultHeight() = 0 // unused - override fun getDefaultWidth() = 0 // unused } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.java deleted file mode 100644 index d5b7fe110..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.widgets; - -import android.appwidget.*; -import android.content.*; -import android.os.*; -import android.util.Log; -import android.widget.*; - -import androidx.annotation.NonNull; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.core.utils.*; - -import java.util.*; - -import static android.appwidget.AppWidgetManager.*; -import static org.isoron.uhabits.utils.InterfaceUtils.dpToPixels; -import static org.isoron.uhabits.widgets.StackWidgetService.*; - -public class StackWidgetService extends RemoteViewsService -{ - public static final String WIDGET_TYPE = "WIDGET_TYPE"; - public static final String HABIT_IDS = "HABIT_IDS"; - - @Override - public RemoteViewsFactory onGetViewFactory(Intent intent) - { - return new StackRemoteViewsFactory(this.getApplicationContext(), intent); - } -} - -class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory -{ - private Context context; - private int widgetId; - private long[] habitIds; - private StackWidgetType widgetType; - private ArrayList remoteViews = new ArrayList<>(); - - public StackRemoteViewsFactory(Context context, Intent intent) - { - this.context = context; - widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID); - int widgetTypeValue = intent.getIntExtra(WIDGET_TYPE, -1); - String habitIdsStr = intent.getStringExtra(HABIT_IDS); - - if (widgetTypeValue < 0) throw new RuntimeException("invalid widget type"); - if (habitIdsStr == null) throw new RuntimeException("habitIdsStr is null"); - - widgetType = StackWidgetType.getWidgetTypeFromValue(widgetTypeValue); - habitIds = StringUtils.splitLongs(habitIdsStr); - } - - public void onCreate() - { - - } - - public void onDestroy() - { - - } - - public int getCount() - { - return habitIds.length; - } - - @NonNull - public WidgetDimensions getDimensionsFromOptions(@NonNull Context ctx, - @NonNull Bundle options) - { - int maxWidth = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH)); - int maxHeight = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT)); - int minWidth = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH)); - int minHeight = (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT)); - - return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight); - } - - public RemoteViews getViewAt(int position) - { - Log.i("StackRemoteViewsFactory", "getViewAt " + position); - if (position < 0 || position > remoteViews.size()) return null; - return remoteViews.get(position); - } - - @NonNull - private BaseWidget constructWidget(@NonNull Habit habit, - @NonNull Preferences prefs) - { - switch (widgetType) - { - case CHECKMARK: - return new CheckmarkWidget(context, widgetId, habit); - case FREQUENCY: - return new FrequencyWidget(context, widgetId, habit, prefs.getFirstWeekdayInt()); - case SCORE: - return new ScoreWidget(context, widgetId, habit); - case HISTORY: - return new HistoryWidget(context, widgetId, habit); - case STREAKS: - return new StreakWidget(context, widgetId, habit); - } - - throw new IllegalStateException(); - } - - public RemoteViews getLoadingView() - { - Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId); - EmptyWidget widget = new EmptyWidget(context, widgetId); - widget.setDimensions(getDimensionsFromOptions(context, options)); - RemoteViews landscapeViews = widget.getLandscapeRemoteViews(); - RemoteViews portraitViews = widget.getPortraitRemoteViews(); - return new RemoteViews(landscapeViews, portraitViews); - } - - public int getViewTypeCount() - { - return 1; - } - - public long getItemId(int position) - { - return habitIds[position]; - } - - public boolean hasStableIds() - { - return true; - } - - public void onDataSetChanged() - { - Log.i("StackRemoteViewsFactory", "onDataSetChanged started"); - - HabitsApplication app = (HabitsApplication) context.getApplicationContext(); - Preferences prefs = app.getComponent().getPreferences(); - HabitList habitList = app.getComponent().getHabitList(); - Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId); - ArrayList newRemoteViews = new ArrayList<>(); - - if (Looper.myLooper() == null) Looper.prepare(); - - for (long id : habitIds) - { - Habit h = habitList.getById(id); - if (h == null) throw new HabitNotFoundException(); - - BaseWidget widget = constructWidget(h, prefs); - widget.setDimensions(getDimensionsFromOptions(context, options)); - - RemoteViews landscapeViews = widget.getLandscapeRemoteViews(); - RemoteViews portraitViews = widget.getPortraitRemoteViews(); - newRemoteViews.add(new RemoteViews(landscapeViews, portraitViews)); - - Log.i("StackRemoteViewsFactory", "onDataSetChanged constructed widget " + id); - } - - remoteViews = newRemoteViews; - Log.i("StackRemoteViewsFactory", "onDataSetChanged ended"); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt new file mode 100644 index 000000000..a16bda608 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.widgets + +import android.appwidget.AppWidgetManager +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.Looper +import android.util.Log +import android.widget.RemoteViews +import android.widget.RemoteViewsService +import android.widget.RemoteViewsService.RemoteViewsFactory +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.HabitNotFoundException +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.utils.StringUtils.Companion.splitLongs +import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels +import java.util.ArrayList + +class StackWidgetService : RemoteViewsService() { + override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { + return StackRemoteViewsFactory(this.applicationContext, intent) + } + + companion object { + const val WIDGET_TYPE = "WIDGET_TYPE" + const val HABIT_IDS = "HABIT_IDS" + } +} + +internal class StackRemoteViewsFactory(private val context: Context, intent: Intent) : + RemoteViewsFactory { + private val widgetId: Int + private val habitIds: LongArray + private val widgetType: StackWidgetType? + private var remoteViews = ArrayList() + override fun onCreate() {} + override fun onDestroy() {} + override fun getCount(): Int { + return habitIds.size + } + + fun getDimensionsFromOptions( + ctx: Context, + options: Bundle + ): WidgetDimensions { + val maxWidth = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH).toFloat() + ).toInt() + val maxHeight = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT).toFloat() + ).toInt() + val minWidth = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH).toFloat() + ).toInt() + val minHeight = dpToPixels( + ctx, + options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT).toFloat() + ).toInt() + return WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight) + } + + override fun getViewAt(position: Int): RemoteViews? { + Log.i("StackRemoteViewsFactory", "getViewAt $position") + return if (position < 0 || position > remoteViews.size) null else remoteViews[position] + } + + private fun constructWidget( + habit: Habit, + prefs: Preferences + ): BaseWidget { + when (widgetType) { + StackWidgetType.CHECKMARK -> return CheckmarkWidget(context, widgetId, habit) + StackWidgetType.FREQUENCY -> return FrequencyWidget( + context, + widgetId, + habit, + prefs.firstWeekdayInt + ) + StackWidgetType.SCORE -> return ScoreWidget(context, widgetId, habit) + StackWidgetType.HISTORY -> return HistoryWidget(context, widgetId, habit) + StackWidgetType.STREAKS -> return StreakWidget(context, widgetId, habit) + } + throw IllegalStateException() + } + + override fun getLoadingView(): RemoteViews { + val options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId) + val widget = EmptyWidget(context, widgetId) + widget.setDimensions(getDimensionsFromOptions(context, options)) + val landscapeViews = widget.landscapeRemoteViews + val portraitViews = widget.portraitRemoteViews + return RemoteViews(landscapeViews, portraitViews) + } + + override fun getViewTypeCount(): Int { + return 1 + } + + override fun getItemId(position: Int): Long { + return habitIds[position] + } + + override fun hasStableIds(): Boolean { + return true + } + + override fun onDataSetChanged() { + Log.i("StackRemoteViewsFactory", "onDataSetChanged started") + val app = context.applicationContext as HabitsApplication + val prefs = app.component.preferences + val habitList = app.component.habitList + val options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId) + val newRemoteViews = ArrayList() + if (Looper.myLooper() == null) Looper.prepare() + for (id in habitIds) { + val h = habitList.getById(id) ?: throw HabitNotFoundException() + val widget = constructWidget(h, prefs) + widget.setDimensions(getDimensionsFromOptions(context, options)) + val landscapeViews = widget.landscapeRemoteViews + val portraitViews = widget.portraitRemoteViews + newRemoteViews.add(RemoteViews(landscapeViews, portraitViews)) + Log.i("StackRemoteViewsFactory", "onDataSetChanged constructed widget $id") + } + remoteViews = newRemoteViews + Log.i("StackRemoteViewsFactory", "onDataSetChanged ended") + } + + init { + widgetId = intent.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID + ) + val widgetTypeValue = intent.getIntExtra(StackWidgetService.WIDGET_TYPE, -1) + val habitIdsStr = intent.getStringExtra(StackWidgetService.HABIT_IDS) + if (widgetTypeValue < 0) throw RuntimeException("invalid widget type") + if (habitIdsStr == null) throw RuntimeException("habitIdsStr is null") + widgetType = StackWidgetType.Companion.getWidgetTypeFromValue(widgetTypeValue) + habitIds = splitLongs(habitIdsStr) + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.java deleted file mode 100644 index e686e2387..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.widgets; - -import org.isoron.uhabits.R; - -/** - * Created by victoryu on 11/3/17. - */ - -public enum StackWidgetType { - - CHECKMARK(0), - FREQUENCY(1), - SCORE(2), // habit strength widget - HISTORY(3), - STREAKS(4), - TARGET(5); - - private int value; - StackWidgetType(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - public static StackWidgetType getWidgetTypeFromValue(int value) { - if (CHECKMARK.getValue() == value) { - return CHECKMARK; - } else if (FREQUENCY.getValue() == value) { - return FREQUENCY; - } else if (SCORE.getValue() == value) { - return SCORE; - } else if (HISTORY.getValue() == value) { - return HISTORY; - } else if (STREAKS.getValue() == value) { - return STREAKS; - } else if (TARGET.getValue() == value) { - return TARGET; - } - return null; - } - - public static int getStackWidgetLayoutId(StackWidgetType type) { - switch (type) { - case CHECKMARK: - return R.layout.checkmark_stackview_widget; - case FREQUENCY: - return R.layout.frequency_stackview_widget; - case SCORE: - return R.layout.score_stackview_widget; - case HISTORY: - return R.layout.history_stackview_widget; - case STREAKS: - return R.layout.streak_stackview_widget; - case TARGET: - return R.layout.target_stackview_widget; - } - return 0; - } - - public static int getStackWidgetAdapterViewId(StackWidgetType type) { - switch (type) { - case CHECKMARK: - return R.id.checkmarkStackWidgetView; - case FREQUENCY: - return R.id.frequencyStackWidgetView; - case SCORE: - return R.id.scoreStackWidgetView; - case HISTORY: - return R.id.historyStackWidgetView; - case STREAKS: - return R.id.streakStackWidgetView; - case TARGET: - return R.id.targetStackWidgetView; - } - return 0; - } - - public static int getStackWidgetEmptyViewId(StackWidgetType type) { - switch (type) { - case CHECKMARK: - return R.id.checkmarkStackWidgetEmptyView; - case FREQUENCY: - return R.id.frequencyStackWidgetEmptyView; - case SCORE: - return R.id.scoreStackWidgetEmptyView; - case HISTORY: - return R.id.historyStackWidgetEmptyView; - case STREAKS: - return R.id.streakStackWidgetEmptyView; - case TARGET: - return R.id.targetStackWidgetEmptyView; - } - return 0; - } - -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt new file mode 100644 index 000000000..ca120142b --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.widgets + +import org.isoron.uhabits.R + +/** + * Created by victoryu on 11/3/17. + */ +enum class StackWidgetType(val value: Int) { + CHECKMARK(0), FREQUENCY(1), SCORE(2), // habit strength widget + HISTORY(3), STREAKS(4), TARGET(5); + + companion object { + fun getWidgetTypeFromValue(value: Int): StackWidgetType? { + return when { + CHECKMARK.value == value -> CHECKMARK + FREQUENCY.value == value -> FREQUENCY + SCORE.value == value -> SCORE + HISTORY.value == value -> HISTORY + STREAKS.value == value -> STREAKS + TARGET.value == value -> TARGET + else -> null + } + } + + fun getStackWidgetLayoutId(type: StackWidgetType?): Int { + when (type) { + CHECKMARK -> return R.layout.checkmark_stackview_widget + FREQUENCY -> return R.layout.frequency_stackview_widget + SCORE -> return R.layout.score_stackview_widget + HISTORY -> return R.layout.history_stackview_widget + STREAKS -> return R.layout.streak_stackview_widget + TARGET -> return R.layout.target_stackview_widget + } + return 0 + } + + fun getStackWidgetAdapterViewId(type: StackWidgetType?): Int { + when (type) { + CHECKMARK -> return R.id.checkmarkStackWidgetView + FREQUENCY -> return R.id.frequencyStackWidgetView + SCORE -> return R.id.scoreStackWidgetView + HISTORY -> return R.id.historyStackWidgetView + STREAKS -> return R.id.streakStackWidgetView + TARGET -> return R.id.targetStackWidgetView + } + return 0 + } + + fun getStackWidgetEmptyViewId(type: StackWidgetType?): Int { + when (type) { + CHECKMARK -> return R.id.checkmarkStackWidgetEmptyView + FREQUENCY -> return R.id.frequencyStackWidgetEmptyView + SCORE -> return R.id.scoreStackWidgetEmptyView + HISTORY -> return R.id.historyStackWidgetEmptyView + STREAKS -> return R.id.streakStackWidgetEmptyView + TARGET -> return R.id.targetStackWidgetEmptyView + } + return 0 + } + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt index 0a5658c09..fb2ee2866 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt @@ -19,6 +19,7 @@ package org.isoron.uhabits.widgets +import android.app.PendingIntent import android.content.Context import android.view.View import android.view.ViewGroup.LayoutParams @@ -31,10 +32,12 @@ import org.isoron.uhabits.widgets.views.GraphWidgetView class StreakWidget( context: Context, id: Int, - private val habit: Habit + private val habit: Habit, ) : BaseWidget(context, id) { + override val defaultHeight: Int = 200 + override val defaultWidth: Int = 200 - override fun getOnClickPendingIntent(context: Context) = + override fun getOnClickPendingIntent(context: Context): PendingIntent? = pendingIntentFactory.showHabit(habit) override fun refreshData(view: View) { @@ -53,7 +56,4 @@ class StreakWidget( layoutParams = LayoutParams(MATCH_PARENT, MATCH_PARENT) } } - - override fun getDefaultHeight() = 200 - override fun getDefaultWidth() = 200 } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt index bd1667b55..dcfbd8cc2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt @@ -19,6 +19,7 @@ package org.isoron.uhabits.widgets +import android.app.PendingIntent import android.content.Context import android.view.View import android.view.ViewGroup.LayoutParams @@ -34,10 +35,12 @@ import org.isoron.uhabits.widgets.views.GraphWidgetView class TargetWidget( context: Context, id: Int, - private val habit: Habit + private val habit: Habit, ) : BaseWidget(context, id) { + override val defaultHeight: Int = 200 + override val defaultWidth: Int = 200 - override fun getOnClickPendingIntent(context: Context) = + override fun getOnClickPendingIntent(context: Context): PendingIntent? = pendingIntentFactory.showHabit(habit) override fun refreshData(view: View) = runBlocking { @@ -58,7 +61,4 @@ class TargetWidget( layoutParams = LayoutParams(MATCH_PARENT, MATCH_PARENT) } } - - override fun getDefaultHeight() = 200 - override fun getDefaultWidth() = 200 } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java deleted file mode 100644 index 930bcdef3..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.widgets.views; - -import android.content.*; -import android.util.*; -import android.widget.*; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.activities.habits.list.views.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.activities.common.views.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.inject.*; -import org.isoron.uhabits.utils.*; - -import static org.isoron.uhabits.utils.InterfaceUtils.getDimension; - -public class CheckmarkWidgetView extends HabitWidgetView { - protected int activeColor; - - protected float percentage; - - @Nullable - protected String name; - - protected RingView ring; - - protected TextView label; - - protected int entryValue; - - protected int entryState; - - protected boolean isNumerical; - - private Preferences preferences; - - public CheckmarkWidgetView(Context context) - { - super(context); - init(); - } - - public CheckmarkWidgetView(Context context, AttributeSet attrs) - { - super(context, attrs); - init(); - } - - public void refresh() - { - if (backgroundPaint == null || frame == null || ring == null) return; - - StyledResources res = new StyledResources(getContext()); - - int bgColor; - int fgColor; - - switch (entryState) { - case Entry.YES_MANUAL: - case Entry.SKIP: - bgColor = activeColor; - fgColor = res.getColor(R.attr.highContrastReverseTextColor); - setShadowAlpha(0x4f); - backgroundPaint.setColor(bgColor); - frame.setBackgroundDrawable(background); - break; - - case Entry.YES_AUTO: - case Entry.NO: - case Entry.UNKNOWN: - default: - bgColor = res.getColor(R.attr.cardBgColor); - fgColor = res.getColor(R.attr.mediumContrastTextColor); - setShadowAlpha(0x00); - break; - } - - ring.setPercentage(percentage); - ring.setColor(fgColor); - ring.setBackgroundColor(bgColor); - ring.setText(getText()); - - label.setText(name); - label.setTextColor(fgColor); - - requestLayout(); - postInvalidate(); - } - - public void setEntryState(int entryState) - { - this.entryState = entryState; - } - - protected String getText() - { - if (isNumerical) return NumberButtonViewKt.toShortString(entryValue / 1000.0); - switch (entryState) { - case Entry.YES_MANUAL: - case Entry.YES_AUTO: - return getResources().getString(R.string.fa_check); - case Entry.SKIP: - return getResources().getString(R.string.fa_skipped); - case Entry.UNKNOWN: - { - if (preferences.areQuestionMarksEnabled()) - return getResources().getString(R.string.fa_question); - else - getResources().getString(R.string.fa_times); - } - case Entry.NO: - default: - return getResources().getString(R.string.fa_times); - } - } - - public void setActiveColor(int activeColor) - { - this.activeColor = activeColor; - } - - public void setEntryValue(int entryValue) - { - this.entryValue = entryValue; - } - - public void setName(@NonNull String name) - { - this.name = name; - } - - public void setPercentage(float percentage) - { - this.percentage = percentage; - } - - public void setNumerical(boolean isNumerical) - { - this.isNumerical = isNumerical; - } - - @Override - @NonNull - protected Integer getInnerLayoutId() - { - return R.layout.widget_checkmark; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) - { - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = MeasureSpec.getSize(heightMeasureSpec); - - float w = width; - float h = width * 1.25f; - float scale = Math.min(width / w, height / h); - - w *= scale; - h *= scale; - - if (h < getDimension(getContext(), R.dimen.checkmarkWidget_heightBreakpoint)) - ring.setVisibility(GONE); - else - ring.setVisibility(VISIBLE); - - widthMeasureSpec = - MeasureSpec.makeMeasureSpec((int) w, MeasureSpec.EXACTLY); - heightMeasureSpec = - MeasureSpec.makeMeasureSpec((int) h, MeasureSpec.EXACTLY); - - float textSize = 0.15f * h; - float maxTextSize = getDimension(getContext(), R.dimen.smallerTextSize); - textSize = Math.min(textSize, maxTextSize); - - label.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); - ring.setTextSize(textSize); - ring.setThickness(0.15f * textSize); - - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - - private void init() - { - HabitsApplicationComponent appComponent; - appComponent = ((HabitsApplication) getContext().getApplicationContext()).getComponent(); - preferences = appComponent.getPreferences(); - - ring = (RingView) findViewById(R.id.scoreRing); - label = (TextView) findViewById(R.id.label); - - if (ring != null) ring.setIsTransparencyEnabled(true); - - if (isInEditMode()) - { - percentage = 0.75f; - name = "Wake up early"; - activeColor = PaletteUtils.getAndroidTestColor(6); - entryValue = Entry.YES_MANUAL; - refresh(); - } - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt new file mode 100644 index 000000000..5caa04625 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.widgets.views + +import android.content.Context +import android.util.AttributeSet +import android.util.TypedValue +import android.view.View +import android.widget.TextView +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.R +import org.isoron.uhabits.activities.common.views.RingView +import org.isoron.uhabits.activities.habits.list.views.toShortString +import org.isoron.uhabits.core.models.Entry.Companion.NO +import org.isoron.uhabits.core.models.Entry.Companion.SKIP +import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN +import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO +import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.inject.HabitsApplicationComponent +import org.isoron.uhabits.utils.InterfaceUtils.getDimension +import org.isoron.uhabits.utils.PaletteUtils.getAndroidTestColor +import org.isoron.uhabits.utils.StyledResources + +class CheckmarkWidgetView : HabitWidgetView { + var activeColor: Int = 0 + + var percentage = 0f + var name: String? = null + protected lateinit var ring: RingView + protected lateinit var label: TextView + var entryValue = 0 + var entryState = 0 + var isNumerical = false + private var preferences: Preferences? = null + + constructor(context: Context?) : super(context) { + init() + } + + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { + init() + } + + fun refresh() { + if (backgroundPaint == null || frame == null) return + val res = StyledResources(context) + val bgColor: Int + val fgColor: Int + when (entryState) { + YES_MANUAL, SKIP -> { + bgColor = activeColor + fgColor = res.getColor(R.attr.highContrastReverseTextColor) + setShadowAlpha(0x4f) + backgroundPaint!!.color = bgColor + frame!!.setBackgroundDrawable(background) + } + YES_AUTO, NO, UNKNOWN -> { + bgColor = res.getColor(R.attr.cardBgColor) + fgColor = res.getColor(R.attr.mediumContrastTextColor) + setShadowAlpha(0x00) + } + else -> { + bgColor = res.getColor(R.attr.cardBgColor) + fgColor = res.getColor(R.attr.mediumContrastTextColor) + setShadowAlpha(0x00) + } + } + ring.percentage = percentage + ring.color = fgColor + ring.setBackgroundColor(bgColor) + ring.setText(text) + label.text = name + label.setTextColor(fgColor) + requestLayout() + postInvalidate() + } + + protected val text: String + get() = if (isNumerical) { + (entryValue / 1000.0).toShortString() + } else when (entryState) { + YES_MANUAL, YES_AUTO -> resources.getString(R.string.fa_check) + SKIP -> resources.getString(R.string.fa_skipped) + UNKNOWN -> { + run { + if (preferences!!.areQuestionMarksEnabled()) { + return resources.getString(R.string.fa_question) + } else { + resources.getString(R.string.fa_times) + } + } + resources.getString(R.string.fa_times) + } + NO -> resources.getString(R.string.fa_times) + else -> resources.getString(R.string.fa_times) + } + + override val innerLayoutId: Int + get() = R.layout.widget_checkmark + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + var widthMeasureSpec = widthMeasureSpec + var heightMeasureSpec = heightMeasureSpec + val width = MeasureSpec.getSize(widthMeasureSpec) + val height = MeasureSpec.getSize(heightMeasureSpec) + var w = width.toFloat() + var h = width * 1.25f + val scale = Math.min(width / w, height / h) + w *= scale + h *= scale + if (h < getDimension(context, R.dimen.checkmarkWidget_heightBreakpoint)) ring.visibility = + GONE else ring.visibility = VISIBLE + widthMeasureSpec = MeasureSpec.makeMeasureSpec(w.toInt(), MeasureSpec.EXACTLY) + heightMeasureSpec = MeasureSpec.makeMeasureSpec(h.toInt(), MeasureSpec.EXACTLY) + var textSize = 0.15f * h + val maxTextSize = getDimension(context, R.dimen.smallerTextSize) + textSize = Math.min(textSize, maxTextSize) + label.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + ring.setTextSize(textSize) + ring.setThickness(0.15f * textSize) + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + + private fun init() { + val appComponent: HabitsApplicationComponent + appComponent = (context.applicationContext as HabitsApplication).component + preferences = appComponent.preferences + ring = findViewById(R.id.scoreRing) as RingView + label = findViewById(R.id.label) as TextView + ring.setIsTransparencyEnabled(true) + if (isInEditMode) { + percentage = 0.75f + name = "Wake up early" + activeColor = getAndroidTestColor(6) + entryValue = YES_MANUAL + refresh() + } + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/EmptyWidgetView.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/EmptyWidgetView.kt similarity index 54% rename from uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/EmptyWidgetView.java rename to uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/EmptyWidgetView.kt index 83ff943fd..814302fc8 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/EmptyWidgetView.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/EmptyWidgetView.kt @@ -16,41 +16,28 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.widgets.views -package org.isoron.uhabits.widgets.views; +import android.content.Context +import android.view.View +import android.widget.TextView +import org.isoron.uhabits.R -import android.content.Context; -import androidx.annotation.NonNull; -import android.widget.TextView; - -import org.isoron.uhabits.R; - -public class EmptyWidgetView extends HabitWidgetView -{ - - private TextView title; - - public EmptyWidgetView(Context context) - { - super(context); - init(); +class EmptyWidgetView(context: Context?) : HabitWidgetView(context) { + private lateinit var title: TextView + fun setTitle(text: String?) { + title.text = text } - public void setTitle(String text) - { - title.setText(text); - } + override val innerLayoutId: Int + get() = R.layout.widget_graph - @Override - @NonNull - protected Integer getInnerLayoutId() - { - return R.layout.widget_graph; + private fun init() { + title = findViewById(R.id.title) as TextView + title.visibility = VISIBLE } - private void init() - { - title = (TextView) findViewById(R.id.title); - title.setVisibility(VISIBLE); + init { + init() } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.java deleted file mode 100644 index b574d9b56..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.widgets.views; - -import android.content.*; -import android.view.*; -import android.widget.*; - -import androidx.annotation.NonNull; - -import org.isoron.uhabits.*; - -public class GraphWidgetView extends HabitWidgetView -{ - - private final View dataView; - - private TextView title; - - public GraphWidgetView(Context context, View dataView) - { - super(context); - this.dataView = dataView; - init(); - } - - public View getDataView() - { - return dataView; - } - - public void setTitle(String text) - { - title.setText(text); - } - - @Override - @NonNull - protected Integer getInnerLayoutId() - { - return R.layout.widget_graph; - } - - private void init() - { - ViewGroup.LayoutParams params = - new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - dataView.setLayoutParams(params); - - ViewGroup innerFrame = (ViewGroup) findViewById(R.id.innerFrame); - innerFrame.addView(dataView); - - title = (TextView) findViewById(R.id.title); - title.setVisibility(VISIBLE); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.kt new file mode 100644 index 000000000..0f935bdf1 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/GraphWidgetView.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.widgets.views + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import org.isoron.uhabits.R + +class GraphWidgetView(context: Context?, val dataView: View) : HabitWidgetView(context) { + private lateinit var title: TextView + fun setTitle(text: String?) { + title.text = text + } + + override val innerLayoutId: Int + get() = R.layout.widget_graph + + private fun init() { + val params = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + dataView.layoutParams = params + val innerFrame = findViewById(R.id.innerFrame) as ViewGroup + innerFrame.addView(dataView) + title = findViewById(R.id.title) as TextView + title.visibility = VISIBLE + } + + init { + init() + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.java b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.java deleted file mode 100644 index 96f0285fc..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.widgets.views; - -import android.content.*; -import android.graphics.*; -import android.graphics.drawable.*; -import android.graphics.drawable.shapes.*; -import android.util.*; -import android.view.*; -import android.widget.*; - -import androidx.annotation.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.utils.*; - -import java.util.*; - -import static org.isoron.uhabits.utils.InterfaceUtils.*; - -public abstract class HabitWidgetView extends FrameLayout -{ - @Nullable - protected InsetDrawable background; - - @Nullable - protected Paint backgroundPaint; - - protected ViewGroup frame; - - private int shadowAlpha; - - private StyledResources res; - - private int backgroundAlpha; - - public HabitWidgetView(Context context) - { - super(context); - init(); - } - - public HabitWidgetView(Context context, AttributeSet attrs) - { - super(context, attrs); - init(); - } - - public void setShadowAlpha(int shadowAlpha) - { - this.shadowAlpha = shadowAlpha; - rebuildBackground(); - } - - public void setBackgroundAlpha(int backgroundAlpha) - { - this.backgroundAlpha = backgroundAlpha; - rebuildBackground(); - } - - protected abstract - @NonNull - Integer getInnerLayoutId(); - - public void rebuildBackground() - { - Context context = getContext(); - - int shadowRadius = (int) dpToPixels(context, 2); - int shadowOffset = (int) dpToPixels(context, 1); - int shadowColor = Color.argb(shadowAlpha, 0, 0, 0); - - float cornerRadius = dpToPixels(context, 5); - float[] radii = new float[8]; - Arrays.fill(radii, cornerRadius); - - RoundRectShape shape = new RoundRectShape(radii, null, null); - ShapeDrawable innerDrawable = new ShapeDrawable(shape); - - int insetLeftTop = Math.max(shadowRadius - shadowOffset, 0); - int insetRightBottom = shadowRadius + shadowOffset; - - background = - new InsetDrawable(innerDrawable, insetLeftTop, insetLeftTop, - insetRightBottom, insetRightBottom); - backgroundPaint = innerDrawable.getPaint(); - backgroundPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, - shadowColor); - backgroundPaint.setColor(res.getColor(R.attr.cardBgColor)); - backgroundPaint.setAlpha(backgroundAlpha); - - frame = (ViewGroup) findViewById(R.id.frame); - if (frame != null) frame.setBackground(background); - } - - private void init() - { - inflate(getContext(), getInnerLayoutId(), this); - res = new StyledResources(getContext()); - shadowAlpha = (int) (255 * res.getFloat(R.attr.widgetShadowAlpha)); - rebuildBackground(); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt new file mode 100644 index 000000000..d1465b56e --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.widgets.views + +import android.content.Context +import android.graphics.Color +import android.graphics.Paint +import android.graphics.drawable.InsetDrawable +import android.graphics.drawable.ShapeDrawable +import android.graphics.drawable.shapes.RoundRectShape +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import org.isoron.uhabits.R +import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels +import org.isoron.uhabits.utils.StyledResources +import java.util.Arrays + +abstract class HabitWidgetView : FrameLayout { + protected var background: InsetDrawable? = null + protected var backgroundPaint: Paint? = null + protected var frame: ViewGroup? = null + private var shadowAlpha = 0 + private var res: StyledResources? = null + private var backgroundAlpha = 0 + + constructor(context: Context?) : super(context!!) { + init() + } + + constructor(context: Context?, attrs: AttributeSet?) : super( + context!!, + attrs + ) { + init() + } + + fun setShadowAlpha(shadowAlpha: Int) { + this.shadowAlpha = shadowAlpha + rebuildBackground() + } + + fun setBackgroundAlpha(backgroundAlpha: Int) { + this.backgroundAlpha = backgroundAlpha + rebuildBackground() + } + + protected abstract val innerLayoutId: Int + fun rebuildBackground() { + val context = context + val shadowRadius = dpToPixels(context, 2f).toInt() + val shadowOffset = dpToPixels(context, 1f).toInt() + val shadowColor = Color.argb(shadowAlpha, 0, 0, 0) + val cornerRadius = dpToPixels(context, 5f) + val radii = FloatArray(8) + Arrays.fill(radii, cornerRadius) + val shape = RoundRectShape(radii, null, null) + val innerDrawable = ShapeDrawable(shape) + val insetLeftTop = Math.max(shadowRadius - shadowOffset, 0) + val insetRightBottom = shadowRadius + shadowOffset + background = InsetDrawable( + innerDrawable, + insetLeftTop, + insetLeftTop, + insetRightBottom, + insetRightBottom + ) + backgroundPaint = innerDrawable.paint + backgroundPaint?.setShadowLayer( + shadowRadius.toFloat(), + shadowOffset.toFloat(), + shadowOffset.toFloat(), + shadowColor + ) + backgroundPaint?.color = res!!.getColor(R.attr.cardBgColor) + backgroundPaint?.alpha = backgroundAlpha + frame = findViewById(R.id.frame) as ViewGroup + if (frame != null) frame!!.background = background + } + + private fun init() { + inflate(context, innerLayoutId, this) + res = StyledResources(context) + shadowAlpha = (255 * res!!.getFloat(R.attr.widgetShadowAlpha)).toInt() + rebuildBackground() + } +} From 0f828cbd3a92edad91caf6ef366f16550f07993e Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 22:07:19 +0100 Subject: [PATCH 10/15] Convert uhabits-android (test) --- .../isoron/uhabits/BaseAndroidJVMTest.java | 77 ------------------ .../org/isoron/uhabits/BaseAndroidJVMTest.kt | 64 +++++++++++++++ .../receivers/ReminderControllerTest.java | 79 ------------------- .../receivers/ReminderControllerTest.kt | 70 ++++++++++++++++ 4 files changed, 134 insertions(+), 156 deletions(-) delete mode 100644 uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.java create mode 100644 uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt delete mode 100644 uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java create mode 100644 uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.java b/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.java deleted file mode 100644 index ac41f26a3..000000000 --- a/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits; - -import org.isoron.uhabits.core.commands.*; -import org.isoron.uhabits.core.models.*; -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.util.*; - -import static org.mockito.Mockito.*; - -@RunWith(MockitoJUnitRunner.class) -public class BaseAndroidJVMTest -{ - protected HabitList habitList; - protected HabitFixtures fixtures; - protected MemoryModelFactory modelFactory; - protected SingleThreadTaskRunner taskRunner; - protected CommandRunner commandRunner; - - @Before - public void setUp() - { - long fixed_local_time = 1422172800000L; - 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() - { - DateUtils.setFixedLocalTime(null); - DateUtils.setStartDayOffset(0, 0); - } - - public long timestamp(int year, int month, int day) - { - GregorianCalendar cal = DateUtils.getStartOfTodayCalendar(); - cal.set(year, month, day); - return cal.getTimeInMillis(); - } - - @Test - public void nothing() - { - - } -} diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt b/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt new file mode 100644 index 000000000..41e7cf570 --- /dev/null +++ b/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits + +import org.isoron.uhabits.core.commands.CommandRunner +import org.isoron.uhabits.core.models.HabitList +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.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 + +@RunWith(MockitoJUnitRunner::class) +open class BaseAndroidJVMTest { + private lateinit var habitList: HabitList + protected lateinit var fixtures: HabitFixtures + private lateinit var modelFactory: MemoryModelFactory + private lateinit var taskRunner: SingleThreadTaskRunner + private lateinit var commandRunner: CommandRunner + + @Before + open fun setUp() { + val fixedLocalTime = 1422172800000L + setFixedLocalTime(fixedLocalTime) + setStartDayOffset(0, 0) + modelFactory = MemoryModelFactory() + habitList = Mockito.spy(modelFactory.buildHabitList()) + fixtures = HabitFixtures(modelFactory, habitList) + taskRunner = SingleThreadTaskRunner() + commandRunner = CommandRunner(taskRunner) + } + + @After + fun tearDown() { + setFixedLocalTime(null) + setStartDayOffset(0, 0) + } + + @Test + fun nothing() { + } +} diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java deleted file mode 100644 index f7a384392..000000000 --- a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.receivers; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.core.reminders.*; -import org.isoron.uhabits.core.ui.*; -import org.isoron.uhabits.core.utils.*; -import org.junit.*; - -import static org.mockito.Mockito.*; - -public class ReminderControllerTest extends BaseAndroidJVMTest -{ - - private ReminderController controller; - - private ReminderScheduler reminderScheduler; - - private NotificationTray notificationTray; - - private Preferences preferences; - - @Override - public void setUp() - { - super.setUp(); - - reminderScheduler = mock(ReminderScheduler.class); - notificationTray = mock(NotificationTray.class); - preferences = mock(Preferences.class); - - controller = new ReminderController(reminderScheduler, - notificationTray, preferences); - } - - @Test - public void testOnDismiss() throws Exception - { - verifyNoMoreInteractions(reminderScheduler); - verifyNoMoreInteractions(notificationTray); - verifyNoMoreInteractions(preferences); - } - - @Test - public void testOnShowReminder() throws Exception - { - Habit habit = mock(Habit.class); - controller.onShowReminder(habit, Timestamp.ZERO.plus(100), 456); - verify(notificationTray).show(habit, Timestamp.ZERO.plus(100), 456); - verify(reminderScheduler).scheduleAll(); - } - - @Test - public void testOnBootCompleted() throws Exception - { - controller.onBootCompleted(); - verify(reminderScheduler).scheduleAll(); - } -} \ No newline at end of file diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt new file mode 100644 index 000000000..df37441b9 --- /dev/null +++ b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.receivers + +import org.isoron.uhabits.BaseAndroidJVMTest +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.reminders.ReminderScheduler +import org.isoron.uhabits.core.ui.NotificationTray +import org.junit.Test +import org.mockito.Mockito + +class ReminderControllerTest : BaseAndroidJVMTest() { + private lateinit var controller: ReminderController + private lateinit var reminderScheduler: ReminderScheduler + private lateinit var notificationTray: NotificationTray + private lateinit var preferences: Preferences + override fun setUp() { + super.setUp() + reminderScheduler = Mockito.mock(ReminderScheduler::class.java) + notificationTray = Mockito.mock(NotificationTray::class.java) + preferences = Mockito.mock(Preferences::class.java) + controller = ReminderController( + reminderScheduler, + notificationTray, + preferences + ) + } + + @Test + @Throws(Exception::class) + fun testOnDismiss() { + Mockito.verifyNoMoreInteractions(reminderScheduler) + Mockito.verifyNoMoreInteractions(notificationTray) + Mockito.verifyNoMoreInteractions(preferences) + } + + @Test + @Throws(Exception::class) + fun testOnShowReminder() { + val habit = Mockito.mock(Habit::class.java) + controller.onShowReminder(habit, Timestamp.ZERO.plus(100), 456) + Mockito.verify(notificationTray).show(habit, Timestamp.ZERO.plus(100), 456) + Mockito.verify(reminderScheduler).scheduleAll() + } + + @Test + @Throws(Exception::class) + fun testOnBootCompleted() { + controller.onBootCompleted() + Mockito.verify(reminderScheduler).scheduleAll() + } +} From ac6df4781849870f8482dbc91edc7fe79787a2a9 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Thu, 14 Jan 2021 22:14:26 +0100 Subject: [PATCH 11/15] Convert uhabits-core (jvmTest) --- .../isoron/uhabits/core/database/Database.kt | 2 +- .../org/isoron/uhabits/core/BaseUnitTest.java | 170 ------- .../org/isoron/uhabits/core/BaseUnitTest.kt | 159 ++++++ ...dTest.java => ArchiveHabitsCommandTest.kt} | 56 +- .../commands/ChangeHabitColorCommandTest.java | 76 --- .../commands/ChangeHabitColorCommandTest.kt | 69 +++ .../core/commands/CreateHabitCommandTest.java | 58 --- .../core/commands/CreateHabitCommandTest.kt | 58 +++ .../commands/CreateRepetitionCommandTest.java | 62 --- .../commands/CreateRepetitionCommandTest.kt | 53 ++ .../commands/DeleteHabitsCommandTest.java | 73 --- .../core/commands/DeleteHabitsCommandTest.kt | 64 +++ .../core/commands/EditHabitCommandTest.java | 72 --- .../core/commands/EditHabitCommandTest.kt | 61 +++ ...est.java => UnarchiveHabitsCommandTest.kt} | 52 +- .../uhabits/core/database/RepositoryTest.java | 2 +- .../database/migrations/Version22Test.java | 162 ------ .../core/database/migrations/Version22Test.kt | 220 ++++++++ .../core/database/migrations/Version23Test.kt | 8 +- .../core/io/HabitsCSVExporterTest.java | 138 ----- .../uhabits/core/io/HabitsCSVExporterTest.kt | 109 ++++ .../isoron/uhabits/core/io/ImportTest.java | 147 ------ .../org/isoron/uhabits/core/io/ImportTest.kt | 138 +++++ .../uhabits/core/models/EntryListTest.kt | 2 +- .../uhabits/core/models/HabitListTest.java | 318 ------------ .../uhabits/core/models/HabitListTest.kt | 301 +++++++++++ .../isoron/uhabits/core/models/HabitTest.java | 136 ----- .../isoron/uhabits/core/models/HabitTest.kt | 125 +++++ .../uhabits/core/models/ScoreListTest.java | 294 ----------- .../uhabits/core/models/ScoreListTest.kt | 262 ++++++++++ .../isoron/uhabits/core/models/ScoreTest.java | 71 --- .../isoron/uhabits/core/models/ScoreTest.kt | 94 ++++ .../uhabits/core/models/StreakListTest.java | 81 --- .../uhabits/core/models/StreakListTest.kt | 67 +++ .../uhabits/core/models/TimestampTest.java | 73 --- .../uhabits/core/models/TimestampTest.kt | 67 +++ .../uhabits/core/models/WeekdayListTest.java | 56 -- .../uhabits/core/models/WeekdayListTest.kt | 55 ++ .../core/models/sqlite/SQLiteEntryListTest.kt | 2 +- .../models/sqlite/SQLiteHabitListTest.java | 223 -------- .../core/models/sqlite/SQLiteHabitListTest.kt | 193 +++++++ ...ntryRecordTest.java => EntryRecordTest.kt} | 30 +- .../sqlite/records/HabitRecordTest.java | 79 --- .../models/sqlite/records/HabitRecordTest.kt | 71 +++ .../core/preferences/PreferencesTest.java | 186 ------- .../core/preferences/PreferencesTest.kt | 180 +++++++ .../preferences/PropertiesStorageTest.java | 119 ----- .../core/preferences/PropertiesStorageTest.kt | 103 ++++ .../core/reminders/ReminderSchedulerTest.java | 171 ------- .../core/reminders/ReminderSchedulerTest.kt | 161 ++++++ .../tasks/SingleThreadTaskRunnerTest.java | 56 -- .../core/tasks/SingleThreadTaskRunnerTest.kt | 47 ++ .../habits/list/HabitCardListCacheTest.java | 188 ------- .../habits/list/HabitCardListCacheTest.kt | 154 ++++++ .../ui/screens/habits/list/HintListTest.java | 80 --- .../ui/screens/habits/list/HintListTest.kt | 70 +++ .../habits/list/ListHabitsBehaviorTest.java | 181 ------- .../habits/list/ListHabitsBehaviorTest.kt | 181 +++++++ .../list/ListHabitsMenuBehaviorTest.java | 217 -------- .../habits/list/ListHabitsMenuBehaviorTest.kt | 222 ++++++++ .../ListHabitsSelectionMenuBehaviorTest.java | 159 ------ .../ListHabitsSelectionMenuBehaviorTest.kt | 153 ++++++ .../show/ShowHabitMenuPresenterTest.java | 71 --- .../habits/show/ShowHabitMenuPresenterTest.kt | 66 +++ .../uhabits/core/ui/views/BarChartTest.kt | 6 +- .../uhabits/core/ui/views/HistoryChartTest.kt | 9 +- .../core/ui/widgets/WidgetBehaviorTest.java | 136 ----- .../core/ui/widgets/WidgetBehaviorTest.kt | 126 +++++ .../uhabits/core/utils/DateUtilsTest.java | 286 ----------- .../uhabits/core/utils/DateUtilsTest.kt | 479 ++++++++++++++++++ 70 files changed, 4178 insertions(+), 4238 deletions(-) delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt rename uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/{ArchiveHabitsCommandTest.java => ArchiveHabitsCommandTest.kt} (51%) delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.kt rename uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/{UnarchiveHabitsCommandTest.java => UnarchiveHabitsCommandTest.kt} (51%) delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt rename uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/{EntryRecordTest.java => EntryRecordTest.kt} (58%) delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt delete mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.java create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/Database.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/Database.kt index ea0bdf6ab..e3593868a 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/Database.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/Database.kt @@ -56,7 +56,7 @@ interface Database { val file: File? - interface ProcessCallback { + fun interface ProcessCallback { fun process(cursor: Cursor) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.java deleted file mode 100644 index 3447ad6b5..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt new file mode 100644 index 000000000..b14f2bc8f --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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) + } + } + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.kt similarity index 51% rename from uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.java rename to uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.kt index 219bcdf46..76fcc0d97 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.java +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.kt @@ -16,43 +16,31 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ - -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) } - } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.java deleted file mode 100644 index 2506f3f8c..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 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))); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt new file mode 100644 index 000000000..27823edb6 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + + @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)) + ) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.java deleted file mode 100644 index 0f77712ea..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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())); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt new file mode 100644 index 000000000..b92f549b2 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + ) + ) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java deleted file mode 100644 index 0ad5fdee4..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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()); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt new file mode 100644 index 000000000..2859ae52c --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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()) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.java deleted file mode 100644 index 97e5897b1..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 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")); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt new file mode 100644 index 000000000..d6c430139 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + + @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")) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.java deleted file mode 100644 index bef05430d..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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)); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.kt new file mode 100644 index 000000000..2ce4b8e86 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/EditHabitCommandTest.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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)) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/UnarchiveHabitsCommandTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/UnarchiveHabitsCommandTest.kt similarity index 51% rename from uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/UnarchiveHabitsCommandTest.java rename to uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/UnarchiveHabitsCommandTest.kt index 7756272a0..cf334e767 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/UnarchiveHabitsCommandTest.java +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/UnarchiveHabitsCommandTest.kt @@ -16,43 +16,33 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +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) } - } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/RepositoryTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/RepositoryTest.java index 31d09d398..232ad25ff 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/RepositoryTest.java +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/RepositoryTest.java @@ -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"); diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.java deleted file mode 100644 index 04567d131..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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)"); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt new file mode 100644 index 000000000..e3cbc19ce --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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)" + ) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version23Test.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version23Test.kt index c9bcbe90f..b68e96342 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version23Test.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version23Test.kt @@ -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("")) } } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.java deleted file mode 100644 index 8d32889bc..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 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 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()); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt new file mode 100644 index 000000000..17046505c --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 = 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() + ) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.java deleted file mode 100644 index 8bb89cd49..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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(); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt new file mode 100644 index 000000000..a44ed925f --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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() + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/EntryListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/EntryListTest.kt index 9c7de4bb3..744b21a62 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/EntryListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/EntryListTest.kt @@ -381,5 +381,5 @@ class EntryListTest { } } - fun day(offset: Int) = DateUtils.getToday().minus(offset) + fun day(offset: Int) = DateUtils.getToday().minus(offset)!! } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.java deleted file mode 100644 index 50a743849..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 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); - } -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt new file mode 100644 index 000000000..bce5119ac --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + 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) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.java deleted file mode 100644 index bf607808c..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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")); - } -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt new file mode 100644 index 000000000..933cd8c1d --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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") + ) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.java deleted file mode 100644 index 7c885da6f..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 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 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 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); - } - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.kt new file mode 100644 index 000000000..c96d2ce46 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreListTest.kt @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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() + 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() + 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) { + 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 + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.java deleted file mode 100644 index 49041cc2c..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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)); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt new file mode 100644 index 000000000..9e0baaddc --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.java deleted file mode 100644 index fce357bcb..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 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 best = streaks.getBest(5); - assertThat(best.size(), equalTo(1)); - assertThat(best.get(0).getLength(), equalTo(1)); - } -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt new file mode 100644 index 000000000..520ff81e7 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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)) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.java deleted file mode 100644 index f8e9130aa..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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)); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt new file mode 100644 index 000000000..826bf47a2 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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)) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.java deleted file mode 100644 index c0b2c7405..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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()); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt new file mode 100644 index 000000000..72e17cbd1 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt index 28f2aea03..74b8f2ada 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt @@ -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 diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.java deleted file mode 100644 index 87ee161c4..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 repository; - - private ModelObservable.Listener listener; - - private ArrayList 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)); - } - - -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt new file mode 100644 index 000000000..230da89a3 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + private lateinit var listener: ModelObservable.Listener + private lateinit var habitsArray: ArrayList + 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)) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.kt similarity index 58% rename from uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.java rename to uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.kt index da651c3a4..993a6f2ab 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.java +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.kt @@ -16,24 +16,22 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +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())) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java deleted file mode 100644 index 37581ce40..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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)); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt new file mode 100644 index 000000000..16bdb0e62 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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)) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.java deleted file mode 100644 index 3bab7abe5..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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()); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt new file mode 100644 index 000000000..a2f857200 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.java deleted file mode 100644 index 9df289bba..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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)); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt new file mode 100644 index 000000000..bc3045285 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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)) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.java deleted file mode 100644 index 08ae9010c..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt new file mode 100644 index 000000000..d9da1457e --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + ) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.java deleted file mode 100644 index 9a3266776..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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(); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt new file mode 100644 index 000000000..010c6f938 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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() + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java deleted file mode 100644 index e4d629f1f..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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); - } - -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt new file mode 100644 index 000000000..c44c825ad --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java deleted file mode 100644 index 7d8e06550..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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()); - } -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt new file mode 100644 index 000000000..b039c0e94 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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 + + @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()) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java deleted file mode 100644 index 38b572ed6..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 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()); - } - -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt new file mode 100644 index 000000000..a8aa04889 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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? = 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()) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.java deleted file mode 100644 index ec8603179..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 matcherCaptor; - - @Captor - private ArgumentCaptor orderCaptor; - - @Captor - private ArgumentCaptor 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(); - } -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt new file mode 100644 index 000000000..579d90349 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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? = null + + @Captor + private val orderCaptor: ArgumentCaptor? = null + + @Captor + private val secondaryOrderCaptor: ArgumentCaptor? = 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() + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.java deleted file mode 100644 index 86d5e913f..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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 colorPickerCallback; - - @Captor - private ArgumentCaptor 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 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); - } - -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt new file mode 100644 index 000000000..b5b2d626b --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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? = null + + @Captor + private val deleteCallback: ArgumentCaptor? = 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 = 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 + ) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.java deleted file mode 100644 index 07997521d..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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); - } -} \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt new file mode 100644 index 000000000..220f1db17 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt index c513b77d2..ff608a49b 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt @@ -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 diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt index ef5b9fb66..4a511c04b 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt @@ -17,7 +17,7 @@ * with this program. If not, see . */ -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), diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.java deleted file mode 100644 index f99554787..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt new file mode 100644 index 000000000..eb7ca2553 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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) + } +} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.java b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.java deleted file mode 100644 index 13f102d49..000000000 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.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))); - } -} diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt new file mode 100644 index 000000000..f651d1614 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.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) + ) + } +} From 25b25acc946c888ee138d22e60bb791f2ce7ed1a Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Fri, 15 Jan 2021 18:52:08 +0100 Subject: [PATCH 12/15] Convert org.isoron.uhabits.acceptance --- .../isoron/uhabits/acceptance/AboutTest.java | 56 ----- .../isoron/uhabits/acceptance/AboutTest.kt | 52 +++++ .../isoron/uhabits/acceptance/BackupTest.kt | 3 +- .../isoron/uhabits/acceptance/HabitsTest.java | 200 ------------------ .../isoron/uhabits/acceptance/HabitsTest.kt | 193 +++++++++++++++++ .../isoron/uhabits/acceptance/LinksTest.java | 71 ------- .../isoron/uhabits/acceptance/LinksTest.kt | 69 ++++++ .../isoron/uhabits/acceptance/WidgetTest.java | 55 ----- .../isoron/uhabits/acceptance/WidgetTest.kt | 52 +++++ .../uhabits/acceptance/steps/BackupSteps.kt | 2 +- .../uhabits/acceptance/steps/CommonSteps.java | 177 ---------------- .../uhabits/acceptance/steps/CommonSteps.kt | 157 ++++++++++++++ .../acceptance/steps/EditHabitSteps.java | 92 -------- .../acceptance/steps/EditHabitSteps.kt | 83 ++++++++ .../acceptance/steps/ListHabitsSteps.java | 161 -------------- .../acceptance/steps/ListHabitsSteps.kt | 123 +++++++++++ .../uhabits/acceptance/steps/WidgetSteps.java | 87 -------- .../uhabits/acceptance/steps/WidgetSteps.kt | 98 +++++++++ .../uhabits/core/test/HabitFixtures.java | 163 -------------- .../isoron/uhabits/core/test/HabitFixtures.kt | 143 +++++++++++++ 20 files changed, 973 insertions(+), 1064 deletions(-) delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.kt delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.kt delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.kt delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.kt delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.kt delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.kt delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt delete mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.java create mode 100644 uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt delete mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.java create mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.kt diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.java deleted file mode 100644 index 92f2971aa..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance; - -import androidx.test.filters.*; -import androidx.test.runner.*; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.isoron.uhabits.*; -import org.junit.*; -import org.junit.runner.*; - -import static org.isoron.uhabits.acceptance.steps.CommonSteps.*; -import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.*; -import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.*; - -@RunWith(AndroidJUnit4.class) -@LargeTest -public class AboutTest extends BaseUserInterfaceTest -{ - @Test - public void shouldDisplayAboutScreen() { - launchApp(); - clickMenu(ABOUT); - verifyDisplaysText("Loop Habit Tracker"); - verifyDisplaysText("Rate this app on Google Play"); - verifyDisplaysText("Developers"); - verifyDisplaysText("Translators"); - } - - @Test - public void shouldDisplayAboutScreenFromSettings() { - launchApp(); - clickMenu(SETTINGS); - clickText("About"); - verifyDisplaysText("Translators"); - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.kt new file mode 100644 index 000000000..ca54b609f --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/AboutTest.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import org.isoron.uhabits.BaseUserInterfaceTest +import org.isoron.uhabits.acceptance.steps.CommonSteps.launchApp +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplaysText +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.clickMenu +import org.isoron.uhabits.acceptance.steps.WidgetSteps.clickText +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@LargeTest +class AboutTest : BaseUserInterfaceTest() { + @Test + fun shouldDisplayAboutScreen() { + launchApp() + clickMenu(ListHabitsSteps.MenuItem.ABOUT) + verifyDisplaysText("Loop Habit Tracker") + verifyDisplaysText("Rate this app on Google Play") + verifyDisplaysText("Developers") + verifyDisplaysText("Translators") + } + + @Test + fun shouldDisplayAboutScreenFromSettings() { + launchApp() + clickMenu(ListHabitsSteps.MenuItem.SETTINGS) + clickText("About") + verifyDisplaysText("Translators") + } +} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/BackupTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/BackupTest.kt index e657598ae..9da6375e7 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/BackupTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/BackupTest.kt @@ -27,6 +27,7 @@ import org.isoron.uhabits.acceptance.steps.CommonSteps.longClickText import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplaysText import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDoesNotDisplayText import org.isoron.uhabits.acceptance.steps.ListHabitsSteps +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.clickMenu import org.isoron.uhabits.acceptance.steps.clearBackupFolder import org.isoron.uhabits.acceptance.steps.clearDownloadFolder import org.isoron.uhabits.acceptance.steps.copyBackupToDownloadFolder @@ -45,7 +46,7 @@ class BackupTest : BaseUserInterfaceTest() { copyBackupToDownloadFolder() longClickText("Wake up early") - ListHabitsSteps.clickMenu(ListHabitsSteps.MenuItem.DELETE) + clickMenu(ListHabitsSteps.MenuItem.DELETE) clickText("Yes") verifyDoesNotDisplayText("Wake up early") diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.java deleted file mode 100644 index a30a66d07..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance; - -import androidx.test.filters.*; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.isoron.uhabits.*; -import org.junit.*; -import org.junit.runner.*; - -import static org.isoron.uhabits.acceptance.steps.CommonSteps.Screen.*; -import static org.isoron.uhabits.acceptance.steps.CommonSteps.*; -import static org.isoron.uhabits.acceptance.steps.EditHabitSteps.*; -import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.*; -import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.*; - -@RunWith(AndroidJUnit4.class) -@LargeTest -public class HabitsTest extends BaseUserInterfaceTest -{ - @Test - public void shouldCreateHabit() throws Exception { - shouldCreateHabit("this is a test description"); - } - - @Test - public void shouldCreateHabitBlankDescription() throws Exception { - shouldCreateHabit(""); - } - - private void shouldCreateHabit(String description) throws Exception - { - launchApp(); - - verifyShowsScreen(LIST_HABITS); - clickMenu(ADD); - - verifyShowsScreen(SELECT_HABIT_TYPE); - clickText("Yes or No"); - - verifyShowsScreen(EDIT_HABIT); - String testName = "Hello world"; - typeName(testName); - typeQuestion("Did you say hello to the world today?"); - typeDescription(description); - pickFrequency(); - pickColor(5); - clickSave(); - - verifyShowsScreen(LIST_HABITS); - verifyDisplaysText(testName); - } - - @Test - public void shouldShowHabitStatistics() throws Exception - { - launchApp(); - verifyShowsScreen(LIST_HABITS); - clickText("Track time"); - - verifyShowsScreen(SHOW_HABIT); - verifyDisplayGraphs(); - } - - @Test - public void shouldDeleteHabit() throws Exception - { - launchApp(); - - verifyShowsScreen(LIST_HABITS); - longClickText("Track time"); - clickMenu(DELETE); - clickText("Yes"); - verifyDoesNotDisplayText("Track time"); - } - - @Test - public void shouldEditHabit() throws Exception { - shouldEditHabit("this is a test description"); - } - - @Test - public void shouldEditHabitBlankDescription() throws Exception { - shouldEditHabit(""); - } - - private void shouldEditHabit(String description) throws Exception - { - launchApp(); - - verifyShowsScreen(LIST_HABITS); - longClickText("Track time"); - clickMenu(EDIT); - - verifyShowsScreen(EDIT_HABIT); - typeName("Take a walk"); - typeQuestion("Did you take a walk today?"); - typeDescription(description); - clickSave(); - - verifyShowsScreen(LIST_HABITS); - verifyDisplaysTextInSequence("Wake up early", "Take a walk", "Meditate"); - verifyDoesNotDisplayText("Track time"); - } - - @Test - public void shouldEditHabit_fromStatisticsScreen() throws Exception - { - launchApp(); - - verifyShowsScreen(LIST_HABITS); - clickText("Track time"); - - verifyShowsScreen(SHOW_HABIT); - clickMenu(EDIT); - - verifyShowsScreen(EDIT_HABIT); - typeName("Take a walk"); - typeQuestion("Did you take a walk today?"); - pickColor(10); - clickSave(); - - verifyShowsScreen(SHOW_HABIT); - verifyDisplaysText("Take a walk"); - pressBack(); - - verifyShowsScreen(LIST_HABITS); - verifyDisplaysText("Take a walk"); - verifyDoesNotDisplayText("Track time"); - } - - @Test - public void shouldArchiveAndUnarchiveHabits() throws Exception - { - launchApp(); - - verifyShowsScreen(LIST_HABITS); - longClickText("Track time"); - clickMenu(ARCHIVE); - verifyDoesNotDisplayText("Track time"); - clickMenu(TOGGLE_ARCHIVED); - verifyDisplaysText("Track time"); - - longClickText("Track time"); - clickMenu(UNARCHIVE); - clickMenu(TOGGLE_ARCHIVED); - verifyDisplaysText("Track time"); - } - - @Test - public void shouldToggleCheckmarksAndUpdateScore() throws Exception - { - launchApp(); - verifyShowsScreen(LIST_HABITS); - longPressCheckmarks("Wake up early", 2); - clickText("Wake up early"); - - verifyShowsScreen(SHOW_HABIT); - verifyDisplaysText("10%"); - } - - @Test - public void shouldHideCompleted() throws Exception - { - launchApp(); - verifyShowsScreen(LIST_HABITS); - verifyDisplaysText("Track time"); - verifyDisplaysText("Wake up early"); - - clickMenu(TOGGLE_COMPLETED); - verifyDoesNotDisplayText("Track time"); - verifyDisplaysText("Wake up early"); - - longPressCheckmarks("Wake up early", 1); - verifyDoesNotDisplayText("Wake up early"); - - clickMenu(TOGGLE_COMPLETED); - verifyDisplaysText("Track time"); - verifyDisplaysText("Wake up early"); - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.kt new file mode 100644 index 000000000..c022175b7 --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/HabitsTest.kt @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import org.isoron.uhabits.BaseUserInterfaceTest +import org.isoron.uhabits.acceptance.steps.CommonSteps +import org.isoron.uhabits.acceptance.steps.CommonSteps.clickText +import org.isoron.uhabits.acceptance.steps.CommonSteps.launchApp +import org.isoron.uhabits.acceptance.steps.CommonSteps.longClickText +import org.isoron.uhabits.acceptance.steps.CommonSteps.pressBack +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplayGraphs +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplaysText +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplaysTextInSequence +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDoesNotDisplayText +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyShowsScreen +import org.isoron.uhabits.acceptance.steps.EditHabitSteps.clickSave +import org.isoron.uhabits.acceptance.steps.EditHabitSteps.pickColor +import org.isoron.uhabits.acceptance.steps.EditHabitSteps.pickFrequency +import org.isoron.uhabits.acceptance.steps.EditHabitSteps.typeDescription +import org.isoron.uhabits.acceptance.steps.EditHabitSteps.typeName +import org.isoron.uhabits.acceptance.steps.EditHabitSteps.typeQuestion +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.clickMenu +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.longPressCheckmarks +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@LargeTest +class HabitsTest : BaseUserInterfaceTest() { + @Test + @Throws(Exception::class) + fun shouldCreateHabit() { + shouldCreateHabit("this is a test description") + } + + @Test + @Throws(Exception::class) + fun shouldCreateHabitBlankDescription() { + shouldCreateHabit("") + } + + @Throws(Exception::class) + private fun shouldCreateHabit(description: String) { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + clickMenu(ListHabitsSteps.MenuItem.ADD) + verifyShowsScreen(CommonSteps.Screen.SELECT_HABIT_TYPE) + clickText("Yes or No") + verifyShowsScreen(CommonSteps.Screen.EDIT_HABIT) + val testName = "Hello world" + typeName(testName) + typeQuestion("Did you say hello to the world today?") + typeDescription(description) + pickFrequency() + pickColor(5) + clickSave() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + verifyDisplaysText(testName) + } + + @Test + @Throws(Exception::class) + fun shouldShowHabitStatistics() { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + clickText("Track time") + verifyShowsScreen(CommonSteps.Screen.SHOW_HABIT) + verifyDisplayGraphs() + } + + @Test + @Throws(Exception::class) + fun shouldDeleteHabit() { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + longClickText("Track time") + clickMenu(ListHabitsSteps.MenuItem.DELETE) + clickText("Yes") + verifyDoesNotDisplayText("Track time") + } + + @Test + @Throws(Exception::class) + fun shouldEditHabit() { + shouldEditHabit("this is a test description") + } + + @Test + @Throws(Exception::class) + fun shouldEditHabitBlankDescription() { + shouldEditHabit("") + } + + @Throws(Exception::class) + private fun shouldEditHabit(description: String) { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + longClickText("Track time") + clickMenu(ListHabitsSteps.MenuItem.EDIT) + verifyShowsScreen(CommonSteps.Screen.EDIT_HABIT) + typeName("Take a walk") + typeQuestion("Did you take a walk today?") + typeDescription(description) + clickSave() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + verifyDisplaysTextInSequence("Wake up early", "Take a walk", "Meditate") + verifyDoesNotDisplayText("Track time") + } + + @Test + @Throws(Exception::class) + fun shouldEditHabit_fromStatisticsScreen() { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + clickText("Track time") + verifyShowsScreen(CommonSteps.Screen.SHOW_HABIT) + clickMenu(ListHabitsSteps.MenuItem.EDIT) + verifyShowsScreen(CommonSteps.Screen.EDIT_HABIT) + typeName("Take a walk") + typeQuestion("Did you take a walk today?") + pickColor(10) + clickSave() + verifyShowsScreen(CommonSteps.Screen.SHOW_HABIT) + verifyDisplaysText("Take a walk") + pressBack() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + verifyDisplaysText("Take a walk") + verifyDoesNotDisplayText("Track time") + } + + @Test + @Throws(Exception::class) + fun shouldArchiveAndUnarchiveHabits() { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + longClickText("Track time") + clickMenu(ListHabitsSteps.MenuItem.ARCHIVE) + verifyDoesNotDisplayText("Track time") + clickMenu(ListHabitsSteps.MenuItem.TOGGLE_ARCHIVED) + verifyDisplaysText("Track time") + longClickText("Track time") + clickMenu(ListHabitsSteps.MenuItem.UNARCHIVE) + clickMenu(ListHabitsSteps.MenuItem.TOGGLE_ARCHIVED) + verifyDisplaysText("Track time") + } + + @Test + @Throws(Exception::class) + fun shouldToggleCheckmarksAndUpdateScore() { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + longPressCheckmarks("Wake up early", 2) + clickText("Wake up early") + verifyShowsScreen(CommonSteps.Screen.SHOW_HABIT) + verifyDisplaysText("10%") + } + + @Test + @Throws(Exception::class) + fun shouldHideCompleted() { + launchApp() + verifyShowsScreen(CommonSteps.Screen.LIST_HABITS) + verifyDisplaysText("Track time") + verifyDisplaysText("Wake up early") + clickMenu(ListHabitsSteps.MenuItem.TOGGLE_COMPLETED) + verifyDoesNotDisplayText("Track time") + verifyDisplaysText("Wake up early") + longPressCheckmarks("Wake up early", 1) + verifyDoesNotDisplayText("Wake up early") + clickMenu(ListHabitsSteps.MenuItem.TOGGLE_COMPLETED) + verifyDisplaysText("Track time") + verifyDisplaysText("Wake up early") + } +} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.java deleted file mode 100644 index 4af9c11b5..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance; - -import androidx.test.filters.*; -import androidx.test.runner.*; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.isoron.uhabits.*; -import org.junit.*; -import org.junit.runner.*; - -import static org.isoron.uhabits.acceptance.steps.CommonSteps.*; -import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.*; -import static org.isoron.uhabits.acceptance.steps.ListHabitsSteps.*; - -@RunWith(AndroidJUnit4.class) -@LargeTest -public class LinksTest extends BaseUserInterfaceTest -{ - @Test - public void shouldLinkToSourceCode() throws Exception - { - launchApp(); - clickMenu(ABOUT); - clickText("View source code at GitHub"); - verifyOpensWebsite("github.com"); - } - - @Test - public void shouldLinkToTranslationWebsite() throws Exception - { - launchApp(); - clickMenu(ABOUT); - clickText("Help translate this app"); - verifyOpensWebsite("translate.loophabits.org"); - } - - @Test - public void shouldLinkToHelp() throws Exception { - launchApp(); - clickMenu(HELP); - verifyOpensWebsite("github.com"); - } - - @Test - public void shouldLinkToHelpFromSettings() throws Exception { - launchApp(); - clickMenu(SETTINGS); - clickText("Help & FAQ"); - verifyOpensWebsite("github.com"); - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.kt new file mode 100644 index 000000000..b5e911519 --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/LinksTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import org.isoron.uhabits.BaseUserInterfaceTest +import org.isoron.uhabits.acceptance.steps.CommonSteps.launchApp +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyOpensWebsite +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps +import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.clickMenu +import org.isoron.uhabits.acceptance.steps.WidgetSteps.clickText +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@LargeTest +class LinksTest : BaseUserInterfaceTest() { + @Test + @Throws(Exception::class) + fun shouldLinkToSourceCode() { + launchApp() + clickMenu(ListHabitsSteps.MenuItem.ABOUT) + clickText("View source code at GitHub") + verifyOpensWebsite("github.com") + } + + @Test + @Throws(Exception::class) + fun shouldLinkToTranslationWebsite() { + launchApp() + clickMenu(ListHabitsSteps.MenuItem.ABOUT) + clickText("Help translate this app") + verifyOpensWebsite("translate.loophabits.org") + } + + @Test + @Throws(Exception::class) + fun shouldLinkToHelp() { + launchApp() + clickMenu(ListHabitsSteps.MenuItem.HELP) + verifyOpensWebsite("github.com") + } + + @Test + @Throws(Exception::class) + fun shouldLinkToHelpFromSettings() { + launchApp() + clickMenu(ListHabitsSteps.MenuItem.SETTINGS) + clickText("Help & FAQ") + verifyOpensWebsite("github.com") + } +} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.java deleted file mode 100644 index 5a8f4d0a5..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance; - -import androidx.test.filters.*; - -import org.isoron.uhabits.*; -import org.junit.*; - -import static org.isoron.uhabits.acceptance.steps.CommonSteps.*; -import static org.isoron.uhabits.acceptance.steps.WidgetSteps.*; -import static org.isoron.uhabits.acceptance.steps.WidgetSteps.clickText; - -@LargeTest -public class WidgetTest extends BaseUserInterfaceTest -{ - @Test - public void shouldCreateAndToggleCheckmarkWidget() throws Exception - { - dragCheckmarkWidgetToHomeScreen(); - Thread.sleep(3000); - clickText("Wake up early"); - clickText("Save"); - verifyCheckmarkWidgetIsShown(); - clickCheckmarkWidget(); - - launchApp(); - clickText("Wake up early"); - verifyDisplaysText("5%"); - - pressHome(); - clickCheckmarkWidget(); - - launchApp(); - clickText("Wake up early"); - verifyDisplaysText("0%"); - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.kt new file mode 100644 index 000000000..2ba898f29 --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/WidgetTest.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance + +import androidx.test.filters.LargeTest +import org.isoron.uhabits.BaseUserInterfaceTest +import org.isoron.uhabits.acceptance.steps.CommonSteps.launchApp +import org.isoron.uhabits.acceptance.steps.CommonSteps.pressHome +import org.isoron.uhabits.acceptance.steps.CommonSteps.verifyDisplaysText +import org.isoron.uhabits.acceptance.steps.WidgetSteps.clickCheckmarkWidget +import org.isoron.uhabits.acceptance.steps.WidgetSteps.clickText +import org.isoron.uhabits.acceptance.steps.WidgetSteps.dragCheckmarkWidgetToHomeScreen +import org.isoron.uhabits.acceptance.steps.WidgetSteps.verifyCheckmarkWidgetIsShown +import org.junit.Test + +@LargeTest +class WidgetTest : BaseUserInterfaceTest() { + @Test + @Throws(Exception::class) + fun shouldCreateAndToggleCheckmarkWidget() { + dragCheckmarkWidgetToHomeScreen() + Thread.sleep(3000) + clickText("Wake up early") + clickText("Save") + verifyCheckmarkWidgetIsShown() + clickCheckmarkWidget() + launchApp() + clickText("Wake up early") + verifyDisplaysText("5%") + pressHome() + clickCheckmarkWidget() + launchApp() + clickText("Wake up early") + verifyDisplaysText("0%") + } +} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/BackupSteps.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/BackupSteps.kt index 7fdc668d8..4e0a12ca2 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/BackupSteps.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/BackupSteps.kt @@ -20,8 +20,8 @@ package org.isoron.uhabits.acceptance.steps import androidx.test.uiautomator.UiSelector +import org.isoron.uhabits.BaseUserInterfaceTest.device import org.isoron.uhabits.acceptance.steps.CommonSteps.clickText -import org.isoron.uhabits.acceptance.steps.CommonSteps.device import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.SETTINGS import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.clickMenu diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.java deleted file mode 100644 index 82188510b..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance.steps; - -import android.view.*; - -import androidx.annotation.*; -import androidx.recyclerview.widget.*; -import androidx.test.espresso.*; -import androidx.test.espresso.contrib.*; -import androidx.test.uiautomator.*; - -import org.hamcrest.*; -import org.isoron.uhabits.*; -import org.isoron.uhabits.R; -import org.isoron.uhabits.activities.habits.list.*; - -import static android.os.Build.VERSION.*; -import static androidx.test.espresso.Espresso.*; -import static androidx.test.espresso.action.ViewActions.*; -import static androidx.test.espresso.assertion.PositionAssertions.*; -import static androidx.test.espresso.assertion.ViewAssertions.*; -import static androidx.test.espresso.matcher.ViewMatchers.*; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - -public class CommonSteps extends BaseUserInterfaceTest -{ - public static void pressBack() - { - device.pressBack(); - } - - public static void clickText(String text) - { - scrollToText(text); - onView(withText(text)).perform(click()); - } - - public static void clickText(@StringRes int id) - { - onView(withText(id)).perform(click()); - } - - public static void launchApp() - { - startActivity(ListHabitsActivity.class); - assertTrue( - device.wait(Until.hasObject(By.pkg("org.isoron.uhabits")), 5000)); - device.waitForIdle(); - } - - public static void longClickText(String text) - { - scrollToText(text); - onView(withText(text)).perform(longClick()); - } - - public static void pressHome() - { - device.pressHome(); - device.waitForIdle(); - } - - public static void scrollToText(String text) - { - try - { - if (device - .findObject(new UiSelector().className(RecyclerView.class)) - .exists()) - { - onView(instanceOf(RecyclerView.class)).perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText(text)))); - } - else - { - onView(withText(text)).perform(scrollTo()); - } - } - catch (PerformException e) - { - //ignored - } - } - - public static void verifyDisplayGraphs() - { - verifyDisplaysView("HistoryCard"); - verifyDisplaysView("ScoreCard"); - } - - public static void verifyDisplaysText(String text) - { - scrollToText(text); - onView(withText(text)).check(matches(isEnabled())); - } - - public static void verifyDisplaysTextInSequence(String... text) - { - verifyDisplaysText(text[0]); - for(int i = 1; i < text.length; i++) { - verifyDisplaysText(text[i]); - onView(withText(text[i])).check(isCompletelyBelow(withText(text[i-1]))); - } - } - - private static void verifyDisplaysView(String className) - { - onView(withClassName(endsWith(className))).check(matches(isEnabled())); - } - - public static void verifyDoesNotDisplayText(String text) - { - onView(withText(text)).check(doesNotExist()); - } - - public static void verifyOpensWebsite(String url) throws Exception - { - String browser_pkg = "org.chromium.webview_shell"; - if(SDK_INT <= 23) { - browser_pkg = "com.android.browser"; - } - assertTrue(device.wait(Until.hasObject(By.pkg(browser_pkg)), 5000)); - device.waitForIdle(); - assertTrue(device.findObject(new UiSelector().textContains(url)).exists()); - } - - public enum Screen - { - LIST_HABITS, SHOW_HABIT, EDIT_HABIT, SELECT_HABIT_TYPE - } - - public static void verifyShowsScreen(Screen screen) - { - switch(screen) - { - case LIST_HABITS: - onView(withClassName(endsWith("ListHabitsRootView"))) - .check(matches(isDisplayed())); - break; - - case SHOW_HABIT: - onView(withId(R.id.subtitleCard)).check(matches(isDisplayed())); - break; - - case EDIT_HABIT: - onView(withId(R.id.questionInput)).check(matches(isDisplayed())); - break; - - case SELECT_HABIT_TYPE: - onView(withText(R.string.yes_or_no_example)).check(matches(isDisplayed())); - break; - - default: - throw new IllegalStateException(); - } - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.kt new file mode 100644 index 000000000..4fa34d9cb --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/CommonSteps.kt @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance.steps + +import android.os.Build.VERSION +import androidx.annotation.StringRes +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso +import androidx.test.espresso.PerformException +import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.assertion.PositionAssertions +import androidx.test.espresso.assertion.ViewAssertions +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiSelector +import androidx.test.uiautomator.Until +import junit.framework.Assert.assertTrue +import org.hamcrest.CoreMatchers +import org.isoron.uhabits.BaseUserInterfaceTest +import org.isoron.uhabits.R +import org.isoron.uhabits.activities.habits.list.ListHabitsActivity + +object CommonSteps : BaseUserInterfaceTest() { + fun pressBack() { + device.pressBack() + } + + fun clickText(text: String?) { + scrollToText(text) + Espresso.onView(ViewMatchers.withText(text)).perform(ViewActions.click()) + } + + fun clickText(@StringRes id: Int) { + Espresso.onView(ViewMatchers.withText(id)).perform(ViewActions.click()) + } + + fun launchApp() { + startActivity(ListHabitsActivity::class.java) + assertTrue( + device.wait(Until.hasObject(By.pkg("org.isoron.uhabits")), 5000) + ) + device.waitForIdle() + } + + fun longClickText(text: String?) { + scrollToText(text) + Espresso.onView(ViewMatchers.withText(text)).perform(ViewActions.longClick()) + } + + fun pressHome() { + device.pressHome() + device.waitForIdle() + } + + fun scrollToText(text: String?) { + try { + if (device + .findObject(UiSelector().className(RecyclerView::class.java)) + .exists() + ) { + Espresso.onView(CoreMatchers.instanceOf(RecyclerView::class.java)).perform( + RecyclerViewActions.scrollTo( + ViewMatchers.hasDescendant(ViewMatchers.withText(text)) + ) + ) + } else { + Espresso.onView(ViewMatchers.withText(text)).perform(ViewActions.scrollTo()) + } + } catch (e: PerformException) { + // ignored + } + } + + fun verifyDisplayGraphs() { + verifyDisplaysView("HistoryCard") + verifyDisplaysView("ScoreCard") + } + + fun verifyDisplaysText(text: String?) { + scrollToText(text) + Espresso.onView(ViewMatchers.withText(text)) + .check(ViewAssertions.matches(ViewMatchers.isEnabled())) + } + + fun verifyDisplaysTextInSequence(vararg text: String?) { + verifyDisplaysText(text[0]) + for (i in 1 until text.size) { + verifyDisplaysText(text[i]) + Espresso.onView(ViewMatchers.withText(text[i])).check( + PositionAssertions.isCompletelyBelow( + ViewMatchers.withText( + text[i - 1] + ) + ) + ) + } + } + + private fun verifyDisplaysView(className: String) { + Espresso.onView(ViewMatchers.withClassName(CoreMatchers.endsWith(className))) + .check(ViewAssertions.matches(ViewMatchers.isEnabled())) + } + + fun verifyDoesNotDisplayText(text: String?) { + Espresso.onView(ViewMatchers.withText(text)).check(ViewAssertions.doesNotExist()) + } + + @Throws(Exception::class) + fun verifyOpensWebsite(url: String?) { + var browserPkg = "org.chromium.webview_shell" + if (VERSION.SDK_INT <= 23) { + browserPkg = "com.android.browser" + } + assertTrue(device.wait(Until.hasObject(By.pkg(browserPkg)), 5000)) + device.waitForIdle() + assertTrue(device.findObject(UiSelector().textContains(url)).exists()) + } + + fun verifyShowsScreen(screen: Screen?) { + when (screen) { + Screen.LIST_HABITS -> + Espresso.onView(ViewMatchers.withClassName(CoreMatchers.endsWith("ListHabitsRootView"))) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + Screen.SHOW_HABIT -> + Espresso.onView(ViewMatchers.withId(R.id.subtitleCard)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + Screen.EDIT_HABIT -> + Espresso.onView(ViewMatchers.withId(R.id.questionInput)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + Screen.SELECT_HABIT_TYPE -> + Espresso.onView(ViewMatchers.withText(R.string.yes_or_no_example)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + else -> throw IllegalStateException() + } + } + + enum class Screen { + LIST_HABITS, SHOW_HABIT, EDIT_HABIT, SELECT_HABIT_TYPE + } +} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.java deleted file mode 100644 index 3abbf1830..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance.steps; - -import androidx.test.uiautomator.*; - -import org.isoron.uhabits.*; - -import static androidx.test.espresso.Espresso.*; -import static androidx.test.espresso.action.ViewActions.*; -import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; -import static androidx.test.espresso.matcher.ViewMatchers.*; -import static org.isoron.uhabits.BaseUserInterfaceTest.*; - -public class EditHabitSteps -{ - public static void clickSave() - { - onView(withId(R.id.buttonSave)).perform(click()); - } - - public static void pickFrequency() - { - onView(withId(R.id.boolean_frequency_picker)).perform(click()); - onView(withText("SAVE")).perform(click()); - } - - public static void pickColor(int color) - { - onView(withId(R.id.colorButton)).perform(click()); - device.findObject(By.descStartsWith(String.format("Color %d", color))).click(); - } - - public static void typeName(String name) - { - typeTextWithId(R.id.nameInput, name); - } - - public static void typeQuestion(String name) - { - typeTextWithId(R.id.questionInput, name); - } - - public static void typeDescription(String description) - { - typeTextWithId(R.id.notesInput, description); - } - - public static void setReminder() - { - onView(withId(R.id.reminderTimePicker)).perform(click()); - onView(withId(R.id.done_button)).perform(click()); - } - - public static void clickReminderDays() - { - onView(withId(R.id.reminderDatePicker)).perform(click()); - } - - public static void unselectAllDays() - { - onView(withText("Saturday")).perform(click()); - onView(withText("Sunday")).perform(click()); - onView(withText("Monday")).perform(click()); - onView(withText("Tuesday")).perform(click()); - onView(withText("Wednesday")).perform(click()); - onView(withText("Thursday")).perform(click()); - onView(withText("Friday")).perform(click()); - } - - private static void typeTextWithId(int id, String name) - { - onView(withId(id)).perform(clearText(), typeText(name), closeSoftKeyboard()); - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.kt new file mode 100644 index 000000000..05dfc586e --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/EditHabitSteps.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance.steps + +import androidx.test.espresso.Espresso +import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.uiautomator.By +import org.isoron.uhabits.BaseUserInterfaceTest +import org.isoron.uhabits.R + +object EditHabitSteps { + fun clickSave() { + Espresso.onView(ViewMatchers.withId(R.id.buttonSave)).perform(ViewActions.click()) + } + + fun pickFrequency() { + Espresso.onView(ViewMatchers.withId(R.id.boolean_frequency_picker)) + .perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText("SAVE")).perform(ViewActions.click()) + } + + fun pickColor(color: Int) { + Espresso.onView(ViewMatchers.withId(R.id.colorButton)).perform(ViewActions.click()) + BaseUserInterfaceTest.device.findObject(By.descStartsWith(String.format("Color %d", color))) + .click() + } + + fun typeName(name: String) { + typeTextWithId(R.id.nameInput, name) + } + + fun typeQuestion(name: String) { + typeTextWithId(R.id.questionInput, name) + } + + fun typeDescription(description: String) { + typeTextWithId(R.id.notesInput, description) + } + + fun setReminder() { + Espresso.onView(ViewMatchers.withId(R.id.reminderTimePicker)).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withId(R.id.done_button)).perform(ViewActions.click()) + } + + fun clickReminderDays() { + Espresso.onView(ViewMatchers.withId(R.id.reminderDatePicker)).perform(ViewActions.click()) + } + + fun unselectAllDays() { + Espresso.onView(ViewMatchers.withText("Saturday")).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText("Sunday")).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText("Monday")).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText("Tuesday")).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText("Wednesday")).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText("Thursday")).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText("Friday")).perform(ViewActions.click()) + } + + private fun typeTextWithId(id: Int, name: String) { + Espresso.onView(ViewMatchers.withId(id)).perform( + ViewActions.clearText(), + ViewActions.typeText(name), + ViewActions.closeSoftKeyboard() + ) + } +} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.java deleted file mode 100644 index 73f0b2066..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance.steps; - -import androidx.test.espresso.*; -import android.view.*; - -import org.hamcrest.*; -import org.isoron.uhabits.R; -import org.isoron.uhabits.activities.habits.list.views.*; - -import java.util.*; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; -import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; -import static androidx.test.espresso.matcher.ViewMatchers.withClassName; -import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withParent; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.CoreMatchers.*; -import static org.isoron.uhabits.BaseUserInterfaceTest.device; -import static org.isoron.uhabits.acceptance.steps.CommonSteps.clickText; - -public abstract class ListHabitsSteps -{ - public static void clickMenu(MenuItem item) - { - switch (item) - { - case ABOUT: - clickTextInsideOverflowMenu(R.string.about); - break; - - case HELP: - clickTextInsideOverflowMenu(R.string.help); - break; - - case SETTINGS: - clickTextInsideOverflowMenu(R.string.settings); - break; - - case ADD: - clickViewWithId(R.id.actionCreateHabit); - break; - - case EDIT: - clickViewWithId(R.id.action_edit_habit); - break; - - case DELETE: - clickTextInsideOverflowMenu(R.string.delete); - break; - - case ARCHIVE: - clickTextInsideOverflowMenu(R.string.archive); - break; - - case UNARCHIVE: - clickTextInsideOverflowMenu(R.string.unarchive); - break; - - case TOGGLE_ARCHIVED: - clickViewWithId(R.id.action_filter); - clickText(R.string.hide_archived); - break; - - case TOGGLE_COMPLETED: - clickViewWithId(R.id.action_filter); - clickText(R.string.hide_completed); - break; - } - } - - private static void clickTextInsideOverflowMenu(int id) { - onView(allOf(withContentDescription("More options"), withParent(withParent(withClassName(endsWith("Toolbar")))))).perform(click()); - onView(withText(id)).perform(click()); - } - - private static void clickViewWithId(int id) - { - onView(withId(id)).perform(click()); - } - - private static ViewAction longClickDescendantWithClass(Class cls, int count) - { - return new ViewAction() - { - - @Override - public Matcher getConstraints() - { - return isEnabled(); - } - - @Override - public String getDescription() - { - return "perform on children"; - } - - @Override - public void perform(UiController uiController, View view) - { - LinkedList stack = new LinkedList<>(); - if (view instanceof ViewGroup) stack.push((ViewGroup) view); - int countRemaining = count; - - while (!stack.isEmpty()) - { - ViewGroup vg = stack.pop(); - for (int i = 0; i < vg.getChildCount(); i++) - { - View v = vg.getChildAt(i); - if (v instanceof ViewGroup) stack.push((ViewGroup) v); - if (cls.isInstance(v) && countRemaining > 0) - { - v.performLongClick(); - uiController.loopMainThreadUntilIdle(); - countRemaining--; - } - } - } - } - }; - } - - public static void longPressCheckmarks(String habit, int count) - { - CommonSteps.scrollToText(habit); - onView(allOf(hasDescendant(withText(habit)), - withClassName(endsWith("HabitCardView")))).perform( - longClickDescendantWithClass(CheckmarkButtonView.class, count)); - device.waitForIdle(); - } - - public enum MenuItem - { - ABOUT, HELP, SETTINGS, EDIT, DELETE, ARCHIVE, TOGGLE_ARCHIVED, - UNARCHIVE, TOGGLE_COMPLETED, ADD - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt new file mode 100644 index 000000000..1f2816b2c --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance.steps + +import android.view.View +import android.view.ViewGroup +import androidx.test.espresso.Espresso +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction +import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.matcher.ViewMatchers +import org.hamcrest.CoreMatchers +import org.hamcrest.Matcher +import org.isoron.uhabits.BaseUserInterfaceTest +import org.isoron.uhabits.R +import org.isoron.uhabits.activities.habits.list.views.CheckmarkButtonView +import java.util.LinkedList + +object ListHabitsSteps { + fun clickMenu(item: MenuItem?) { + when (item) { + MenuItem.ABOUT -> clickTextInsideOverflowMenu(R.string.about) + MenuItem.HELP -> clickTextInsideOverflowMenu(R.string.help) + MenuItem.SETTINGS -> clickTextInsideOverflowMenu(R.string.settings) + MenuItem.ADD -> clickViewWithId(R.id.actionCreateHabit) + MenuItem.EDIT -> clickViewWithId(R.id.action_edit_habit) + MenuItem.DELETE -> clickTextInsideOverflowMenu(R.string.delete) + MenuItem.ARCHIVE -> clickTextInsideOverflowMenu(R.string.archive) + MenuItem.UNARCHIVE -> clickTextInsideOverflowMenu(R.string.unarchive) + MenuItem.TOGGLE_ARCHIVED -> { + clickViewWithId(R.id.action_filter) + CommonSteps.clickText(R.string.hide_archived) + } + MenuItem.TOGGLE_COMPLETED -> { + clickViewWithId(R.id.action_filter) + CommonSteps.clickText(R.string.hide_completed) + } + } + } + + private fun clickTextInsideOverflowMenu(id: Int) { + Espresso.onView( + CoreMatchers.allOf( + ViewMatchers.withContentDescription("More options"), + ViewMatchers.withParent( + ViewMatchers.withParent( + ViewMatchers.withClassName( + CoreMatchers.endsWith("Toolbar") + ) + ) + ) + ) + ).perform(ViewActions.click()) + Espresso.onView(ViewMatchers.withText(id)).perform(ViewActions.click()) + } + + private fun clickViewWithId(id: Int) { + Espresso.onView(ViewMatchers.withId(id)).perform(ViewActions.click()) + } + + private fun longClickDescendantWithClass(cls: Class<*>, count: Int): ViewAction { + return object : ViewAction { + override fun getConstraints(): Matcher { + return ViewMatchers.isEnabled() + } + + override fun getDescription(): String { + return "perform on children" + } + + override fun perform(uiController: UiController, view: View) { + val stack = LinkedList() + if (view is ViewGroup) stack.push(view) + var countRemaining = count + while (!stack.isEmpty()) { + val vg = stack.pop() + for (i in 0 until vg.childCount) { + val v = vg.getChildAt(i) + if (v is ViewGroup) stack.push(v) + if (cls.isInstance(v) && countRemaining > 0) { + v.performLongClick() + uiController.loopMainThreadUntilIdle() + countRemaining-- + } + } + } + } + } + } + + fun longPressCheckmarks(habit: String?, count: Int) { + CommonSteps.scrollToText(habit) + Espresso.onView( + CoreMatchers.allOf( + ViewMatchers.hasDescendant(ViewMatchers.withText(habit)), + ViewMatchers.withClassName(CoreMatchers.endsWith("HabitCardView")) + ) + ).perform( + longClickDescendantWithClass(CheckmarkButtonView::class.java, count) + ) + BaseUserInterfaceTest.device.waitForIdle() + } + + enum class MenuItem { + ABOUT, HELP, SETTINGS, EDIT, DELETE, ARCHIVE, TOGGLE_ARCHIVED, UNARCHIVE, TOGGLE_COMPLETED, ADD + } +} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.java deleted file mode 100644 index caae50a0a..000000000 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.acceptance.steps; - -import androidx.test.uiautomator.*; - -import static android.os.Build.VERSION.SDK_INT; -import static org.junit.Assert.*; -import static org.isoron.uhabits.BaseUserInterfaceTest.*; - -public class WidgetSteps { - public static void clickCheckmarkWidget() throws Exception { - String view_id = "org.isoron.uhabits:id/imageView"; - device.findObject(new UiSelector().resourceId(view_id)).click(); - } - - public static void clickText(String s) throws Exception { - UiObject object = device.findObject(new UiSelector().text(s)); - if (!object.waitForExists(1000)) { - object = device.findObject(new UiSelector().text(s.toUpperCase())); - } - object.click(); - } - - public static void dragCheckmarkWidgetToHomeScreen() throws Exception { - openWidgetScreen(); - dragWidgetToHomeScreen(); - } - - private static void dragWidgetToHomeScreen() throws Exception { - int height = device.getDisplayHeight(); - int width = device.getDisplayWidth(); - device.findObject(new UiSelector().text("Checkmark")) - .dragTo(width / 2, height / 2, 40); - } - - private static void openWidgetScreen() throws Exception { - int h = device.getDisplayHeight(); - int w = device.getDisplayWidth(); - if (SDK_INT <= 21) { - device.pressHome(); - device.waitForIdle(); - device.findObject(new UiSelector().description("Apps")).click(); - device.findObject(new UiSelector().description("Apps")).click(); - device.findObject(new UiSelector().description("Widgets")).click(); - } else { - String list_id = "com.android.launcher3:id/widgets_list_view"; - device.pressHome(); - device.waitForIdle(); - device.drag(w / 2, h / 2, w / 2, h / 2, 8); - UiObject button = device.findObject(new UiSelector().text("WIDGETS")); - if(!button.waitForExists(1000)) { - button = device.findObject(new UiSelector().text("Widgets")); - } - button.click(); - if (SDK_INT >= 28) { - new UiScrollable(new UiSelector().resourceId(list_id)) - .scrollForward(); - } - new UiScrollable(new UiSelector().resourceId(list_id)) - .scrollIntoView(new UiSelector().text("Checkmark")); - } - } - - public static void verifyCheckmarkWidgetIsShown() throws Exception { - String view_id = "org.isoron.uhabits:id/imageView"; - assertTrue(device.findObject(new UiSelector().resourceId(view_id)).exists()); - assertFalse(device.findObject(new UiSelector().textStartsWith("Habit deleted")).exists()); - } -} diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt new file mode 100644 index 000000000..624720684 --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.acceptance.steps + +import android.os.Build.VERSION +import androidx.test.uiautomator.UiScrollable +import androidx.test.uiautomator.UiSelector +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.isoron.uhabits.BaseUserInterfaceTest + +object WidgetSteps { + @Throws(Exception::class) + fun clickCheckmarkWidget() { + val view_id = "org.isoron.uhabits:id/imageView" + BaseUserInterfaceTest.device.findObject(UiSelector().resourceId(view_id)).click() + } + + @Throws(Exception::class) + fun clickText(s: String) { + var textObject = BaseUserInterfaceTest.device.findObject(UiSelector().text(s)) + if (!textObject.waitForExists(1000)) { + textObject = BaseUserInterfaceTest.device.findObject(UiSelector().text(s.toUpperCase())) + } + textObject.click() + } + + @Throws(Exception::class) + fun dragCheckmarkWidgetToHomeScreen() { + openWidgetScreen() + dragWidgetToHomeScreen() + } + + @Throws(Exception::class) + private fun dragWidgetToHomeScreen() { + val height = BaseUserInterfaceTest.device.displayHeight + val width = BaseUserInterfaceTest.device.displayWidth + BaseUserInterfaceTest.device.findObject(UiSelector().text("Checkmark")) + .dragTo(width / 2, height / 2, 40) + } + + @Throws(Exception::class) + private fun openWidgetScreen() { + val h = BaseUserInterfaceTest.device.displayHeight + val w = BaseUserInterfaceTest.device.displayWidth + if (VERSION.SDK_INT <= 21) { + BaseUserInterfaceTest.device.pressHome() + BaseUserInterfaceTest.device.waitForIdle() + BaseUserInterfaceTest.device.findObject(UiSelector().description("Apps")).click() + BaseUserInterfaceTest.device.findObject(UiSelector().description("Apps")).click() + BaseUserInterfaceTest.device.findObject(UiSelector().description("Widgets")).click() + } else { + val list_id = "com.android.launcher3:id/widgets_list_view" + BaseUserInterfaceTest.device.pressHome() + BaseUserInterfaceTest.device.waitForIdle() + BaseUserInterfaceTest.device.drag(w / 2, h / 2, w / 2, h / 2, 8) + var button = BaseUserInterfaceTest.device.findObject(UiSelector().text("WIDGETS")) + if (!button.waitForExists(1000)) { + button = BaseUserInterfaceTest.device.findObject(UiSelector().text("Widgets")) + } + button.click() + if (VERSION.SDK_INT >= 28) { + UiScrollable(UiSelector().resourceId(list_id)) + .scrollForward() + } + UiScrollable(UiSelector().resourceId(list_id)) + .scrollIntoView(UiSelector().text("Checkmark")) + } + } + + @Throws(Exception::class) + fun verifyCheckmarkWidgetIsShown() { + val viewId = "org.isoron.uhabits:id/imageView" + assertTrue( + BaseUserInterfaceTest.device.findObject(UiSelector().resourceId(viewId)).exists() + ) + assertFalse( + BaseUserInterfaceTest.device.findObject(UiSelector().textStartsWith("Habit deleted")) + .exists() + ) + } +} diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.java b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.java deleted file mode 100644 index 512642761..000000000 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.test; - -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.models.sqlite.*; -import org.isoron.uhabits.core.utils.*; - -import static org.isoron.uhabits.core.models.Entry.*; - -public class HabitFixtures -{ - public boolean NON_DAILY_HABIT_CHECKS[] = { - true, false, false, true, true, true, false, false, true, true - }; - - private final ModelFactory modelFactory; - - private HabitList habitList; - - public HabitFixtures(ModelFactory modelFactory, HabitList habitList) - { - this.modelFactory = modelFactory; - this.habitList = habitList; - } - - public Habit createEmptyHabit() - { - Habit habit = modelFactory.buildHabit(); - habit.setName("Meditate"); - habit.setQuestion("Did you meditate this morning?"); - habit.setColor(new PaletteColor(3)); - habit.setFrequency(Frequency.DAILY); - saveIfSQLite(habit); - - return habit; - } - - public Habit createLongHabit() - { - Habit habit = createEmptyHabit(); - habit.setFrequency(new Frequency(3, 7)); - habit.setColor(new PaletteColor(4)); - - Timestamp today = DateUtils.getToday(); - int marks[] = {0, 1, 3, 5, 7, 8, 9, 10, 12, 14, 15, 17, 19, 20, 26, 27, - 28, 50, 51, 52, 53, 54, 58, 60, 63, 65, 70, 71, 72, 73, 74, 75, 80, - 81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120}; - - for (int mark : marks) - habit.getOriginalEntries().add(new Entry(today.minus(mark), YES_MANUAL)); - - habit.recompute(); - return habit; - } - - public Habit createNumericalHabit() - { - Habit habit = modelFactory.buildHabit(); - habit.setType(Habit.NUMBER_HABIT); - habit.setName("Run"); - habit.setQuestion("How many miles did you run today?"); - habit.setUnit("miles"); - habit.setTargetType(Habit.AT_LEAST); - habit.setTargetValue(2.0); - habit.setColor(new PaletteColor(1)); - saveIfSQLite(habit); - - Timestamp today = DateUtils.getToday(); - int times[] = {0, 1, 3, 5, 7, 8, 9, 10}; - int values[] = {100, 200, 300, 400, 500, 600, 700, 800}; - - for (int i = 0; i < times.length; i++) - { - Timestamp timestamp = today.minus(times[i]); - habit.getOriginalEntries().add(new Entry(timestamp, values[i])); - } - - habit.recompute(); - return habit; - } - - public Habit createLongNumericalHabit(Timestamp reference) - { - Habit habit = modelFactory.buildHabit(); - habit.setType(Habit.NUMBER_HABIT); - habit.setName("Walk"); - habit.setQuestion("How many steps did you walk today?"); - habit.setUnit("steps"); - habit.setTargetType(Habit.AT_LEAST); - habit.setTargetValue(100); - habit.setColor(new PaletteColor(1)); - saveIfSQLite(habit); - - int times[] = {0, 5, 9, 15, 17, 21, 23, 27, 28, 35, 41, 45, 47, 53, 56, 62, 70, 73, 78, - 83, 86, 94, 101, 106, 113, 114, 120, 126, 130, 133, 141, 143, 148, 151, 157, 164, - 166, 171, 173, 176, 179, 183, 191, 259, 264, 268, 270, 275, 282, 284, 289, 295, - 302, 306, 310, 315, 323, 325, 328, 335, 343, 349, 351, 353, 357, 359, 360, 367, - 372, 376, 380, 385, 393, 400, 404, 412, 415, 418, 422, 425, 433, 437, 444, 449, - 455, 460, 462, 465, 470, 471, 479, 481, 485, 489, 494, 495, 500, 501, 503, 507}; - - int values[] = {230, 306, 148, 281, 134, 285, 104, 158, 325, 236, 303, 210, 118, 124, - 301, 201, 156, 376, 347, 367, 396, 134, 160, 381, 155, 354, 231, 134, 164, 354, - 236, 398, 199, 221, 208, 397, 253, 276, 214, 341, 299, 221, 353, 250, 341, 168, - 374, 205, 182, 217, 297, 321, 104, 237, 294, 110, 136, 229, 102, 271, 250, 294, - 158, 319, 379, 126, 282, 155, 288, 159, 215, 247, 207, 226, 244, 158, 371, 219, - 272, 228, 350, 153, 356, 279, 394, 202, 213, 214, 112, 248, 139, 245, 165, 256, - 370, 187, 208, 231, 341, 312}; - - for (int i = 0; i < times.length; i++) - { - Timestamp timestamp = reference.minus(times[i]); - habit.getOriginalEntries().add(new Entry(timestamp, values[i])); - } - - habit.recompute(); - return habit; - } - - public Habit createShortHabit() - { - Habit habit = modelFactory.buildHabit(); - habit.setName("Wake up early"); - habit.setQuestion("Did you wake up before 6am?"); - habit.setFrequency(new Frequency(2, 3)); - saveIfSQLite(habit); - - Timestamp timestamp = DateUtils.getToday(); - for (boolean c : NON_DAILY_HABIT_CHECKS) - { - int value = NO; - if (c) value = YES_MANUAL; - habit.getOriginalEntries().add(new Entry(timestamp, value)); - timestamp = timestamp.minus(1); - } - - habit.recompute(); - return habit; - } - - private void saveIfSQLite(Habit habit) - { - if (!(habit.getOriginalEntries() instanceof SQLiteEntryList)) return; - habitList.add(habit); - } -} diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.kt new file mode 100644 index 000000000..86eaa122e --- /dev/null +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/test/HabitFixtures.kt @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.core.test + +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.HabitList +import org.isoron.uhabits.core.models.ModelFactory +import org.isoron.uhabits.core.models.PaletteColor +import org.isoron.uhabits.core.models.Timestamp +import org.isoron.uhabits.core.models.sqlite.SQLiteEntryList +import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday + +class HabitFixtures(private val modelFactory: ModelFactory, private val habitList: HabitList) { + var NON_DAILY_HABIT_CHECKS = booleanArrayOf( + true, false, false, true, true, true, false, false, true, true + ) + + fun createEmptyHabit( + name: String = "Meditate", + color: PaletteColor = PaletteColor(3), + position: Int = 0 + ): Habit { + val habit = modelFactory.buildHabit() + habit.name = name + habit.question = "Did you meditate this morning?" + habit.color = color + habit.position = position + habit.frequency = Frequency.DAILY + saveIfSQLite(habit) + return habit + } + + fun createLongHabit(): Habit { + val habit = createEmptyHabit() + habit.frequency = Frequency(3, 7) + habit.color = PaletteColor(4) + val today = getToday() + val marks = intArrayOf( + 0, 1, 3, 5, 7, 8, 9, 10, 12, 14, 15, 17, 19, 20, 26, 27, + 28, 50, 51, 52, 53, 54, 58, 60, 63, 65, 70, 71, 72, 73, 74, 75, 80, + 81, 83, 89, 90, 91, 95, 102, 103, 108, 109, 120 + ) + for (mark in marks) habit.originalEntries.add(Entry(today.minus(mark), Entry.YES_MANUAL)) + habit.recompute() + return habit + } + + fun createNumericalHabit(): Habit { + val habit = modelFactory.buildHabit() + habit.type = Habit.NUMBER_HABIT + habit.name = "Run" + habit.question = "How many miles did you run today?" + habit.unit = "miles" + habit.targetType = Habit.AT_LEAST + habit.targetValue = 2.0 + habit.color = PaletteColor(1) + saveIfSQLite(habit) + val today = getToday() + val times = intArrayOf(0, 1, 3, 5, 7, 8, 9, 10) + val values = intArrayOf(100, 200, 300, 400, 500, 600, 700, 800) + for (i in times.indices) { + val timestamp = today.minus(times[i]) + habit.originalEntries.add(Entry(timestamp, values[i])) + } + habit.recompute() + return habit + } + + fun createLongNumericalHabit(reference: Timestamp): Habit { + val habit = modelFactory.buildHabit() + habit.type = Habit.NUMBER_HABIT + habit.name = "Walk" + habit.question = "How many steps did you walk today?" + habit.unit = "steps" + habit.targetType = Habit.AT_LEAST + habit.targetValue = 100.0 + habit.color = PaletteColor(1) + saveIfSQLite(habit) + val times = intArrayOf( + 0, 5, 9, 15, 17, 21, 23, 27, 28, 35, 41, 45, 47, 53, 56, 62, 70, 73, 78, + 83, 86, 94, 101, 106, 113, 114, 120, 126, 130, 133, 141, 143, 148, 151, 157, 164, + 166, 171, 173, 176, 179, 183, 191, 259, 264, 268, 270, 275, 282, 284, 289, 295, + 302, 306, 310, 315, 323, 325, 328, 335, 343, 349, 351, 353, 357, 359, 360, 367, + 372, 376, 380, 385, 393, 400, 404, 412, 415, 418, 422, 425, 433, 437, 444, 449, + 455, 460, 462, 465, 470, 471, 479, 481, 485, 489, 494, 495, 500, 501, 503, 507 + ) + val values = intArrayOf( + 230, 306, 148, 281, 134, 285, 104, 158, 325, 236, 303, 210, 118, 124, + 301, 201, 156, 376, 347, 367, 396, 134, 160, 381, 155, 354, 231, 134, 164, 354, + 236, 398, 199, 221, 208, 397, 253, 276, 214, 341, 299, 221, 353, 250, 341, 168, + 374, 205, 182, 217, 297, 321, 104, 237, 294, 110, 136, 229, 102, 271, 250, 294, + 158, 319, 379, 126, 282, 155, 288, 159, 215, 247, 207, 226, 244, 158, 371, 219, + 272, 228, 350, 153, 356, 279, 394, 202, 213, 214, 112, 248, 139, 245, 165, 256, + 370, 187, 208, 231, 341, 312 + ) + for (i in times.indices) { + val timestamp = reference.minus(times[i]) + habit.originalEntries.add(Entry(timestamp, values[i])) + } + habit.recompute() + return habit + } + + fun createShortHabit(): Habit { + val habit = modelFactory.buildHabit() + habit.name = "Wake up early" + habit.question = "Did you wake up before 6am?" + habit.frequency = Frequency(2, 3) + saveIfSQLite(habit) + var timestamp = getToday() + for (c in NON_DAILY_HABIT_CHECKS) { + var value = Entry.NO + if (c) value = Entry.YES_MANUAL + habit.originalEntries.add(Entry(timestamp, value)) + timestamp = timestamp.minus(1) + } + habit.recompute() + return habit + } + + private fun saveIfSQLite(habit: Habit) { + if (habit.originalEntries !is SQLiteEntryList) return + habitList.add(habit) + } +} From 97dcf98e2b1eca216bfdeedd0e787574392486d4 Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Fri, 15 Jan 2021 18:58:50 +0100 Subject: [PATCH 13/15] Convert org.isoron.uhabits.utils --- .../uhabits/utils/AttributeSetUtils.java | 93 ------------------- .../isoron/uhabits/utils/AttributeSetUtils.kt | 87 +++++++++++++++++ .../isoron/uhabits/utils/DatabaseUtils.java | 92 ------------------ .../org/isoron/uhabits/utils/DatabaseUtils.kt | 75 +++++++++++++++ .../{SystemUtils.java => SystemUtils.kt} | 34 +++---- 5 files changed, 176 insertions(+), 205 deletions(-) delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt delete mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.java create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt rename uhabits-android/src/main/java/org/isoron/uhabits/utils/{SystemUtils.java => SystemUtils.kt} (55%) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java b/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java deleted file mode 100644 index db66fd774..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.utils; - -import android.content.*; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.util.*; - -import org.jetbrains.annotations.*; - -public class AttributeSetUtils -{ - public static final String ISORON_NAMESPACE = "http://isoron.org/android"; - - @Nullable - public static String getAttribute(@NonNull Context context, - @NonNull AttributeSet attrs, - @NonNull String name, - @Nullable String defaultValue) - { - int resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0); - if (resId != 0) return context.getResources().getString(resId); - - String value = attrs.getAttributeValue(ISORON_NAMESPACE, name); - if (value != null) return value; - else return defaultValue; - } - - public static boolean getBooleanAttribute(@NonNull Context context, - @NonNull AttributeSet attrs, - @NonNull String name, - boolean defaultValue) - { - String boolText = getAttribute(context, attrs, name, null); - if (boolText != null) return Boolean.parseBoolean(boolText); - else return defaultValue; - } - - @Contract("_,_,_,!null -> !null") - public static Integer getColorAttribute(@NonNull Context context, - @NonNull AttributeSet attrs, - @NonNull String name, - @Nullable Integer defaultValue) - { - int resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0); - if (resId != 0) return context.getResources().getColor(resId); - else return defaultValue; - } - - public static float getFloatAttribute(@NonNull Context context, - @NonNull AttributeSet attrs, - @NonNull String name, - float defaultValue) - { - try - { - String number = getAttribute(context, attrs, name, null); - if (number != null) return Float.parseFloat(number); - else return defaultValue; - } catch(NumberFormatException e) { - return defaultValue; - } - } - - public static int getIntAttribute(@NonNull Context context, - @NonNull AttributeSet attrs, - @NonNull String name, - int defaultValue) - { - String number = getAttribute(context, attrs, name, null); - if (number != null) return Integer.parseInt(number); - else return defaultValue; - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt new file mode 100644 index 000000000..7ab5a1e34 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.utils + +import android.content.Context +import android.util.AttributeSet +import org.jetbrains.annotations.Contract + +object AttributeSetUtils { + const val ISORON_NAMESPACE = "http://isoron.org/android" + @JvmStatic + fun getAttribute( + context: Context, + attrs: AttributeSet, + name: String, + defaultValue: String? + ): String? { + val resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0) + if (resId != 0) return context.resources.getString(resId) + val value = attrs.getAttributeValue(ISORON_NAMESPACE, name) + return value ?: defaultValue + } + + @JvmStatic + fun getBooleanAttribute( + context: Context, + attrs: AttributeSet, + name: String, + defaultValue: Boolean + ): Boolean { + val boolText = getAttribute(context, attrs, name, null) + return if (boolText != null) java.lang.Boolean.parseBoolean(boolText) else defaultValue + } + + @JvmStatic + @Contract("_,_,_,!null -> !null") + fun getColorAttribute( + context: Context, + attrs: AttributeSet, + name: String, + defaultValue: Int? + ): Int? { + val resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0) + return if (resId != 0) context.resources.getColor(resId) else defaultValue + } + + @JvmStatic + fun getFloatAttribute( + context: Context, + attrs: AttributeSet, + name: String, + defaultValue: Float + ): Float { + return try { + val number = getAttribute(context, attrs, name, null) + number?.toFloat() ?: defaultValue + } catch (e: NumberFormatException) { + defaultValue + } + } + + fun getIntAttribute( + context: Context, + attrs: AttributeSet, + name: String, + defaultValue: Int + ): Int { + val number = getAttribute(context, attrs, name, null) + return number?.toInt() ?: defaultValue + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.java b/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.java deleted file mode 100644 index 78aa5a3e7..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.utils; - -import android.content.*; -import android.database.sqlite.*; -import android.util.*; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.utils.*; - -import java.io.*; -import java.text.*; - -import static org.isoron.uhabits.core.ConstantsKt.*; - -public abstract class DatabaseUtils -{ - @Nullable - private static HabitsDatabaseOpener opener = null; - - @NonNull - public static File getDatabaseFile(Context context) - { - String databaseFilename = getDatabaseFilename(); - String root = context.getFilesDir().getPath(); - - String format = "%s/../databases/%s"; - String filename = String.format(format, root, databaseFilename); - - return new File(filename); - } - - @NonNull - public static String getDatabaseFilename() - { - String databaseFilename = DATABASE_FILENAME; - if (HabitsApplication.Companion.isTestMode()) databaseFilename = "test.db"; - return databaseFilename; - } - - @SuppressWarnings("unchecked") - public static void initializeDatabase(Context context) - { - opener = new HabitsDatabaseOpener(context, getDatabaseFilename(), - DATABASE_VERSION); - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - public static String saveDatabaseCopy(Context context, File dir) - throws IOException - { - SimpleDateFormat dateFormat = DateFormats.getBackupDateFormat(); - String date = dateFormat.format(DateUtils.getLocalTime()); - String format = "%s/Loop Habits Backup %s.db"; - String filename = String.format(format, dir.getAbsolutePath(), date); - Log.i("DatabaseUtils", "Writing: " + filename); - - File db = getDatabaseFile(context); - File dbCopy = new File(filename); - FileUtilsKt.copyTo(db, dbCopy); - - return dbCopy.getAbsolutePath(); - } - - @NonNull - public static SQLiteDatabase openDatabase() - { - if (opener == null) throw new IllegalStateException(); - return opener.getWritableDatabase(); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt new file mode 100644 index 000000000..db25f279d --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.utils + +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.util.Log +import org.isoron.uhabits.HabitsApplication.Companion.isTestMode +import org.isoron.uhabits.HabitsDatabaseOpener +import org.isoron.uhabits.core.DATABASE_FILENAME +import org.isoron.uhabits.core.DATABASE_VERSION +import org.isoron.uhabits.core.utils.DateFormats.Companion.getBackupDateFormat +import org.isoron.uhabits.core.utils.DateUtils.Companion.getLocalTime +import java.io.File +import java.io.IOException +import java.text.SimpleDateFormat + +object DatabaseUtils { + private var opener: HabitsDatabaseOpener? = null + @JvmStatic + fun getDatabaseFile(context: Context): File { + val databaseFilename = databaseFilename + val root = context.filesDir.path + return File("$root/../databases/$databaseFilename") + } + + private val databaseFilename: String + get() { + var databaseFilename: String = DATABASE_FILENAME + if (isTestMode()) databaseFilename = "test.db" + return databaseFilename + } + + fun initializeDatabase(context: Context?) { + opener = HabitsDatabaseOpener( + context!!, + databaseFilename, + DATABASE_VERSION + ) + } + + @JvmStatic + @Throws(IOException::class) + fun saveDatabaseCopy(context: Context, dir: File): String { + val dateFormat: SimpleDateFormat = getBackupDateFormat() + val date = dateFormat.format(getLocalTime()) + val filename = "${dir.absolutePath}/Loop Habits Backup $date.db" + Log.i("DatabaseUtils", "Writing: $filename") + val db = getDatabaseFile(context) + val dbCopy = File(filename) + db.copyTo(dbCopy) + return dbCopy.absolutePath + } + + fun openDatabase(): SQLiteDatabase { + checkNotNull(opener) + return opener!!.writableDatabase + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/SystemUtils.java b/uhabits-android/src/main/java/org/isoron/uhabits/utils/SystemUtils.kt similarity index 55% rename from uhabits-android/src/main/java/org/isoron/uhabits/utils/SystemUtils.java rename to uhabits-android/src/main/java/org/isoron/uhabits/utils/SystemUtils.kt index d848a90eb..a7d805103 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/SystemUtils.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/SystemUtils.kt @@ -16,30 +16,24 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.utils -package org.isoron.uhabits.utils; +import android.app.Activity +import android.app.KeyguardManager +import android.content.Context +import android.os.Build +import android.view.WindowManager -import android.app.*; -import android.content.*; -import android.os.*; -import android.view.*; +object SystemUtils { + val isAndroidOOrLater: Boolean + get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O - -public class SystemUtils -{ - public static boolean isAndroidOOrLater() - { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; - } - - public static void unlockScreen(Activity activity) - { - if (isAndroidOOrLater()) { - KeyguardManager km = - (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); - km.requestDismissKeyguard(activity, null); + fun unlockScreen(activity: Activity) { + if (isAndroidOOrLater) { + val km = activity.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager + km.requestDismissKeyguard(activity, null) } else { - activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + activity.window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD) } } } From 9d0fbb9ea9729907dee21363c533c60b5b23756b Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Fri, 15 Jan 2021 19:12:33 +0100 Subject: [PATCH 14/15] Convert WeekdayList --- .../habits/show/views/SubtitleCardViewTest.kt | 2 +- .../uhabits/core/models/WeekdayList.java | 101 ------------------ .../isoron/uhabits/core/models/WeekdayList.kt | 83 ++++++++++++++ 3 files changed, 84 insertions(+), 102 deletions(-) delete mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.java create mode 100644 uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt index 6b0f1cd18..63c700404 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt @@ -26,7 +26,7 @@ import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Frequency import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.Reminder -import org.isoron.uhabits.core.models.WeekdayList.EVERY_DAY +import org.isoron.uhabits.core.models.WeekdayList.Companion.EVERY_DAY import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardState import org.junit.Before import org.junit.Test diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.java b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.java deleted file mode 100644 index a8fbf2aed..000000000 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.models; - -import org.apache.commons.lang3.builder.*; - -import java.util.*; - -import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle; - -public final class WeekdayList -{ - public static final WeekdayList EVERY_DAY = new WeekdayList(127); - - private final boolean[] weekdays; - - public WeekdayList(int packedList) - { - weekdays = new boolean[7]; - - int current = 1; - for (int i = 0; i < 7; i++) - { - if ((packedList & current) != 0) weekdays[i] = true; - current = current << 1; - } - } - - public WeekdayList(boolean weekdays[]) - { - this.weekdays = Arrays.copyOf(weekdays, 7); - } - - public boolean isEmpty() - { - for (boolean d : weekdays) if (d) return false; - return true; - } - - public boolean[] toArray() - { - return Arrays.copyOf(weekdays, 7); - } - - public int toInteger() - { - int packedList = 0; - int current = 1; - - for (int i = 0; i < 7; i++) - { - if (weekdays[i]) packedList |= current; - current = current << 1; - } - - return packedList; - } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - - if (o == null || getClass() != o.getClass()) return false; - - WeekdayList that = (WeekdayList) o; - - return new EqualsBuilder().append(weekdays, that.weekdays).isEquals(); - } - - @Override - public int hashCode() - { - return new HashCodeBuilder(17, 37).append(weekdays).toHashCode(); - } - - @Override - public String toString() - { - return new ToStringBuilder(this, defaultToStringStyle()) - .append("weekdays", weekdays) - .toString(); - } -} diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt new file mode 100644 index 000000000..d598d5d78 --- /dev/null +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.core.models + +import org.apache.commons.lang3.builder.EqualsBuilder +import org.apache.commons.lang3.builder.HashCodeBuilder +import org.apache.commons.lang3.builder.ToStringBuilder +import org.isoron.uhabits.core.utils.StringUtils.Companion.defaultToStringStyle +import java.util.Arrays + +class WeekdayList { + private val weekdays: BooleanArray + + constructor(packedList: Int) { + weekdays = BooleanArray(7) + var current = 1 + for (i in 0..6) { + if (packedList and current != 0) weekdays[i] = true + current = current shl 1 + } + } + + constructor(weekdays: BooleanArray?) { + this.weekdays = Arrays.copyOf(weekdays, 7) + } + + val isEmpty: Boolean + get() { + for (d in weekdays) if (d) return false + return true + } + + fun toArray(): BooleanArray { + return Arrays.copyOf(weekdays, 7) + } + + fun toInteger(): Int { + var packedList = 0 + var current = 1 + for (i in 0..6) { + if (weekdays[i]) packedList = packedList or current + current = current shl 1 + } + return packedList + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || javaClass != other.javaClass) return false + val that = other as WeekdayList + return EqualsBuilder().append(weekdays, that.weekdays).isEquals + } + + override fun hashCode(): Int { + return HashCodeBuilder(17, 37).append(weekdays).toHashCode() + } + + override fun toString(): String { + return ToStringBuilder(this, defaultToStringStyle()) + .append("weekdays", weekdays) + .toString() + } + + companion object { + val EVERY_DAY = WeekdayList(127) + } +} From dedeb13f46c3b7d29ad8a2c8fc4db257485a144c Mon Sep 17 00:00:00 2001 From: Quentin Hibon Date: Mon, 18 Jan 2021 16:11:52 +0100 Subject: [PATCH 15/15] Clean up kotlin code * static imports * less nullable types * format --- uhabits-android/build.gradle | 1 + .../uhabits/HabitsActivityTestComponent.kt | 12 +- .../acceptance/steps/ListHabitsSteps.kt | 11 +- .../uhabits/acceptance/steps/WidgetSteps.kt | 10 +- .../habits/list/views/EntryPanelViewTest.kt | 24 +- .../habits/list/views/HabitCardViewTest.kt | 2 +- .../habits/list/views/NumberPanelViewTest.kt | 21 -- .../uhabits/intents/IntentSchedulerTest.kt | 8 +- .../views/CheckmarkWidgetViewTest.java | 14 -- .../isoron/platform/gui/AndroidDataView.kt | 6 +- .../org/isoron/platform/gui/AndroidImage.kt | 2 +- .../org/isoron/uhabits/HabitsApplication.kt | 8 +- .../common/dialogs/NumberPickerFactory.kt | 16 +- .../common/views/TaskProgressBar.kt | 3 +- .../activities/habits/edit/HabitTypeDialog.kt | 2 +- .../habits/list/ListHabitsRootView.kt | 4 +- .../list/views/HabitCardListController.kt | 19 +- .../habits/list/views/HabitCardListView.kt | 8 +- .../habits/list/views/HabitCardView.kt | 6 +- .../habits/list/views/NumberPanelView.kt | 2 +- .../habits/show/views/OverviewCardView.kt | 3 +- .../uhabits/activities/sync/SyncActivity.kt | 2 +- .../isoron/uhabits/database/AndroidCursor.kt | 16 +- .../uhabits/database/AndroidDatabase.kt | 2 +- .../uhabits/inject/HabitsActivityComponent.kt | 9 +- .../isoron/uhabits/intents/IntentParser.kt | 3 +- .../isoron/uhabits/intents/IntentScheduler.kt | 3 +- .../uhabits/intents/PendingIntentFactory.kt | 14 +- .../uhabits/notifications/RingtoneManager.kt | 6 +- .../isoron/uhabits/sync/RemoteSyncServer.kt | 3 +- .../widgets/CheckmarkWidgetProvider.kt | 4 +- .../isoron/uhabits/widgets/FrequencyWidget.kt | 2 +- .../widgets/FrequencyWidgetProvider.kt | 6 +- .../isoron/uhabits/widgets/HistoryWidget.kt | 2 +- .../uhabits/widgets/HistoryWidgetProvider.kt | 4 +- .../org/isoron/uhabits/widgets/ScoreWidget.kt | 2 +- .../uhabits/widgets/ScoreWidgetProvider.kt | 4 +- .../uhabits/widgets/StackWidgetService.kt | 11 +- .../isoron/uhabits/widgets/StreakWidget.kt | 2 +- .../uhabits/widgets/StreakWidgetProvider.kt | 4 +- .../isoron/uhabits/widgets/TargetWidget.kt | 2 +- .../uhabits/widgets/TargetWidgetProvider.kt | 4 +- .../widgets/views/CheckmarkWidgetView.kt | 14 +- .../uhabits/widgets/views/HabitWidgetView.kt | 3 +- .../org/isoron/uhabits/BaseAndroidJVMTest.kt | 4 +- .../receivers/ReminderControllerTest.kt | 24 +- .../uhabits/components/NumberButtonTest.kt | 8 +- uhabits-core/build.gradle | 1 + .../kotlin/org/isoron/platform/gui/Canvas.kt | 2 +- .../org/isoron/platform/gui/FontAwesome.kt | 4 +- .../kotlin/org/isoron/platform/time/Dates.kt | 6 +- .../org/isoron/platform/gui/JavaCanvas.kt | 43 ++-- .../java/org/isoron/platform/io/JavaFiles.kt | 4 +- .../isoron/uhabits/core/database/SQLParser.kt | 6 +- .../uhabits/core/io/HabitsCSVExporter.kt | 3 +- .../isoron/uhabits/core/io/LoopDBImporter.kt | 4 +- .../isoron/uhabits/core/models/EntryList.kt | 16 +- .../uhabits/core/models/ModelFactory.kt | 3 +- .../org/isoron/uhabits/core/models/Score.kt | 3 +- .../isoron/uhabits/core/models/ScoreList.kt | 2 +- .../isoron/uhabits/core/models/WeekdayList.kt | 2 +- .../habits/show/ShowHabitMenuPresenter.kt | 4 +- .../screens/habits/show/views/OverviewCard.kt | 6 +- .../ui/screens/habits/show/views/ScoreCard.kt | 14 +- .../isoron/uhabits/core/ui/views/BarChart.kt | 2 +- .../uhabits/core/ui/views/HistoryChart.kt | 8 +- .../isoron/uhabits/core/utils/DateUtils.kt | 2 +- .../uhabits/core/utils/MidnightTimer.kt | 2 +- .../isoron/uhabits/core/utils/StringUtils.kt | 3 +- .../org/isoron/uhabits/core/BaseUnitTest.kt | 7 +- .../core/commands/ArchiveHabitsCommandTest.kt | 14 +- .../commands/ChangeHabitColorCommandTest.kt | 9 +- .../core/commands/CreateHabitCommandTest.kt | 11 +- .../commands/CreateRepetitionCommandTest.kt | 18 +- .../core/commands/DeleteHabitsCommandTest.kt | 9 +- .../core/database/migrations/Version22Test.kt | 130 +++-------- .../uhabits/core/io/HabitsCSVExporterTest.kt | 10 +- .../org/isoron/uhabits/core/io/ImportTest.kt | 38 ++-- .../uhabits/core/models/HabitListTest.kt | 128 ++++------- .../isoron/uhabits/core/models/HabitTest.kt | 32 ++- .../isoron/uhabits/core/models/ScoreTest.kt | 50 +---- .../uhabits/core/models/StreakListTest.kt | 36 +-- .../uhabits/core/models/TimestampTest.kt | 8 +- .../uhabits/core/models/WeekdayListTest.kt | 20 +- .../core/models/sqlite/SQLiteEntryListTest.kt | 16 +- .../core/models/sqlite/SQLiteHabitListTest.kt | 77 +++---- .../models/sqlite/records/EntryRecordTest.kt | 4 +- .../models/sqlite/records/HabitRecordTest.kt | 52 ++--- .../core/preferences/PreferencesTest.kt | 72 +++--- .../core/preferences/PropertiesStorageTest.kt | 77 ++++--- .../core/reminders/ReminderSchedulerTest.kt | 69 +++--- .../core/tasks/SingleThreadTaskRunnerTest.kt | 15 +- .../habits/list/HabitCardListCacheTest.kt | 114 +++++----- .../ui/screens/habits/list/HintListTest.kt | 36 +-- .../habits/list/ListHabitsBehaviorTest.kt | 133 +++++------ .../habits/list/ListHabitsMenuBehaviorTest.kt | 207 +++++++----------- .../ListHabitsSelectionMenuBehaviorTest.kt | 129 ++++++----- .../habits/show/ShowHabitMenuPresenterTest.kt | 17 +- .../core/ui/widgets/WidgetBehaviorTest.kt | 83 +++---- .../uhabits/core/utils/DateUtilsTest.kt | 83 ++++--- uhabits-server/build.gradle | 4 +- .../src/org/isoron/uhabits/sync/links/Link.kt | 3 +- .../uhabits/sync/repository/Repository.kt | 4 +- .../uhabits/sync/app/LinksModuleTest.kt | 36 +-- .../sync/app/RegistrationModuleTest.kt | 25 ++- .../uhabits/sync/app/StorageModuleTest.kt | 13 +- 106 files changed, 982 insertions(+), 1287 deletions(-) diff --git a/uhabits-android/build.gradle b/uhabits-android/build.gradle index 4c84bc9de..7e71dc4d3 100644 --- a/uhabits-android/build.gradle +++ b/uhabits-android/build.gradle @@ -125,6 +125,7 @@ dependencies { testImplementation "junit:junit:4.12" testImplementation "org.mockito:mockito-core:2.28.2" testImplementation "org.mockito:mockito-inline:2.8.9" + testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" } kapt { diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt index 0ca7e26ac..9dade3a8c 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt @@ -38,19 +38,13 @@ import org.mockito.Mockito.mock @Module class TestModule { - @Provides fun ListHabitsBehavior() = mock(ListHabitsBehavior::class.java) + @Provides fun listHabitsBehavior(): ListHabitsBehavior = mock(ListHabitsBehavior::class.java) } @ActivityScope @Component( - modules = arrayOf( - ActivityContextModule::class, - HabitsActivityModule::class, - ListHabitsModule::class, - HabitModule::class, - TestModule::class - ), - dependencies = arrayOf(HabitsApplicationComponent::class) + modules = [ActivityContextModule::class, HabitsActivityModule::class, ListHabitsModule::class, HabitModule::class, TestModule::class], + dependencies = [HabitsApplicationComponent::class] ) interface HabitsActivityTestComponent { fun getCheckmarkPanelViewFactory(): CheckmarkPanelViewFactory diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt index 1f2816b2c..ceaefb7c2 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/ListHabitsSteps.kt @@ -25,7 +25,8 @@ import androidx.test.espresso.UiController import androidx.test.espresso.ViewAction import androidx.test.espresso.action.ViewActions import androidx.test.espresso.matcher.ViewMatchers -import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.allOf +import org.hamcrest.CoreMatchers.endsWith import org.hamcrest.Matcher import org.isoron.uhabits.BaseUserInterfaceTest import org.isoron.uhabits.R @@ -56,12 +57,12 @@ object ListHabitsSteps { private fun clickTextInsideOverflowMenu(id: Int) { Espresso.onView( - CoreMatchers.allOf( + allOf( ViewMatchers.withContentDescription("More options"), ViewMatchers.withParent( ViewMatchers.withParent( ViewMatchers.withClassName( - CoreMatchers.endsWith("Toolbar") + endsWith("Toolbar") ) ) ) @@ -107,9 +108,9 @@ object ListHabitsSteps { fun longPressCheckmarks(habit: String?, count: Int) { CommonSteps.scrollToText(habit) Espresso.onView( - CoreMatchers.allOf( + allOf( ViewMatchers.hasDescendant(ViewMatchers.withText(habit)), - ViewMatchers.withClassName(CoreMatchers.endsWith("HabitCardView")) + ViewMatchers.withClassName(endsWith("HabitCardView")) ) ).perform( longClickDescendantWithClass(CheckmarkButtonView::class.java, count) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt index 624720684..2d3018221 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/acceptance/steps/WidgetSteps.kt @@ -28,8 +28,8 @@ import org.isoron.uhabits.BaseUserInterfaceTest object WidgetSteps { @Throws(Exception::class) fun clickCheckmarkWidget() { - val view_id = "org.isoron.uhabits:id/imageView" - BaseUserInterfaceTest.device.findObject(UiSelector().resourceId(view_id)).click() + val viewId = "org.isoron.uhabits:id/imageView" + BaseUserInterfaceTest.device.findObject(UiSelector().resourceId(viewId)).click() } @Throws(Exception::class) @@ -66,7 +66,7 @@ object WidgetSteps { BaseUserInterfaceTest.device.findObject(UiSelector().description("Apps")).click() BaseUserInterfaceTest.device.findObject(UiSelector().description("Widgets")).click() } else { - val list_id = "com.android.launcher3:id/widgets_list_view" + val listId = "com.android.launcher3:id/widgets_list_view" BaseUserInterfaceTest.device.pressHome() BaseUserInterfaceTest.device.waitForIdle() BaseUserInterfaceTest.device.drag(w / 2, h / 2, w / 2, h / 2, 8) @@ -76,10 +76,10 @@ object WidgetSteps { } button.click() if (VERSION.SDK_INT >= 28) { - UiScrollable(UiSelector().resourceId(list_id)) + UiScrollable(UiSelector().resourceId(listId)) .scrollForward() } - UiScrollable(UiSelector().resourceId(list_id)) + UiScrollable(UiSelector().resourceId(listId)) .scrollIntoView(UiSelector().text("Checkmark")) } } diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt index b964c3654..669adb299 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt @@ -34,11 +34,12 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +private const val PATH = "habits/list/CheckmarkPanelView" + @RunWith(AndroidJUnit4::class) @MediumTest class EntryPanelViewTest : BaseViewTest() { - private val PATH = "habits/list/CheckmarkPanelView" private lateinit var view: CheckmarkPanelView @Before @@ -75,27 +76,6 @@ class EntryPanelViewTest : BaseViewTest() { assertRenders(view, "$PATH/render.png") } -// // Flaky test -// @Test -// fun testRender_withDifferentColor() { -// view.color = PaletteUtils.getAndroidTestColor(1) -// assertRenders(view, "$PATH/render_different_color.png") -// } - -// // Flaky test -// @Test -// fun testRender_Reversed() { -// prefs.isCheckmarkSequenceReversed = true -// assertRenders(view, "$PATH/render_reversed.png") -// } - -// // Flaky test -// @Test -// fun testRender_withOffset() { -// view.dataOffset = 3 -// assertRenders(view, "$PATH/render_offset.png") -// } - @Test fun testToggle() { val timestamps = mutableListOf() diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HabitCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HabitCardViewTest.kt index 2cf9a8034..20474090a 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HabitCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HabitCardViewTest.kt @@ -56,7 +56,7 @@ class HabitCardViewTest : BaseViewTest() { view = component.getHabitCardViewFactory().create().apply { habit = habit1 values = entries - score = habit1.scores.get(today).value + score = habit1.scores[today].value isSelected = false buttonCount = 5 } diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt index 7b1b68e14..0fb7ad98f 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelViewTest.kt @@ -73,27 +73,6 @@ class NumberPanelViewTest : BaseViewTest() { assertRenders(view, "$PATH/render.png") } -// // Flaky test -// @Test -// fun testRender_withDifferentColor() { -// view.color = PaletteUtils.getAndroidTestColor(1) -// assertRenders(view, "$PATH/render_different_color.png") -// } - -// // Flaky test -// @Test -// fun testRender_Reversed() { -// prefs.isCheckmarkSequenceReversed = true -// assertRenders(view, "$PATH/render_reversed.png") -// } - -// // Flaky test -// @Test -// fun testRender_withOffset() { -// view.dataOffset = 3 -// assertRenders(view, "$PATH/render_offset.png") -// } - @Test fun testEdit() { val timestamps = mutableListOf() diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt index c0991ba17..36a1926bd 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt @@ -103,9 +103,8 @@ class IntentSchedulerTest : BaseAndroidTest() { assertNull(ReminderReceiver.lastReceivedIntent) setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46) - val intent = ReminderReceiver.lastReceivedIntent - assertNotNull(intent) - assertThat(parseId(intent?.data!!), equalTo(habit.id)) + val intent = ReminderReceiver.lastReceivedIntent!! + assertThat(parseId(intent.data!!), equalTo(habit.id)) } @Test @@ -123,7 +122,6 @@ class IntentSchedulerTest : BaseAndroidTest() { assertNull(WidgetReceiver.lastReceivedIntent) setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46) - val intent = WidgetReceiver.lastReceivedIntent - assertNotNull(intent) + WidgetReceiver.lastReceivedIntent!! } } diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java index 3ce819817..05a5e3265 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java @@ -68,13 +68,6 @@ public class CheckmarkWidgetViewTest extends BaseViewTest assertRenders(view, PATH + "checked.png"); } -// @Test -// public void testRender_implicitlyChecked() throws IOException -// { -// view.setCheckmarkValue(Checkmark.YES_AUTO); -// view.refresh(); -// assertRenders(view, PATH + "implicitly_checked.png"); -// } @Test public void testRender_largeSize() throws IOException @@ -83,11 +76,4 @@ public class CheckmarkWidgetViewTest extends BaseViewTest assertRenders(view, PATH + "large_size.png"); } -// @Test -// public void testRender_unchecked() throws IOException -// { -// view.setCheckmarkValue(Checkmark.NO); -// view.refresh(); -// assertRenders(view, PATH + "unchecked.png"); -// } } diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt index a36d02146..df5d5e184 100644 --- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt +++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt @@ -25,6 +25,8 @@ import android.util.AttributeSet import android.view.GestureDetector import android.view.MotionEvent import android.widget.Scroller +import kotlin.math.abs +import kotlin.math.max /** * An AndroidView that implements scrolling. @@ -71,7 +73,7 @@ class AndroidDataView( dx: Float, dy: Float, ): Boolean { - if (Math.abs(dx) > Math.abs(dy)) { + if (abs(dx) > abs(dy)) { val parent = parent parent?.requestDisallowInterceptTouchEvent(true) } @@ -128,7 +130,7 @@ class AndroidDataView( view?.let { v -> var newDataOffset: Int = scroller.currX / (v.dataColumnWidth * canvas.innerDensity).toInt() - newDataOffset = Math.max(0, newDataOffset) + newDataOffset = max(0, newDataOffset) if (newDataOffset != v.dataOffset) { v.dataOffset = newDataOffset postInvalidate() diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt index 54cd251fd..0b313f9a4 100644 --- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt +++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt @@ -42,7 +42,7 @@ class AndroidImage(private val bmp: Bitmap) : Image { } } -public fun Color.toInt(): Int { +fun Color.toInt(): Int { return android.graphics.Color.argb( (255 * this.alpha).roundToInt(), (255 * this.red).roundToInt(), diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.kt b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.kt index 8707309f0..37fa11420 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplication.kt @@ -83,7 +83,7 @@ class HabitsApplication : Application() { notificationTray.startListening() val prefs = component.preferences - prefs.setLastAppVersion(BuildConfig.VERSION_CODE) + prefs.lastAppVersion = BuildConfig.VERSION_CODE val taskRunner = component.taskRunner taskRunner.execute { @@ -106,11 +106,11 @@ class HabitsApplication : Application() { lateinit var component: HabitsApplicationComponent fun isTestMode(): Boolean { - try { + return try { Class.forName("org.isoron.uhabits.BaseAndroidTest") - return true + true } catch (e: ClassNotFoundException) { - return false + false } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt index 470761f6a..c531e758b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt @@ -34,6 +34,7 @@ import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.InterfaceUtils import javax.inject.Inject +import kotlin.math.roundToLong class NumberPickerFactory @Inject constructor( @@ -52,7 +53,7 @@ class NumberPickerFactory val picker2 = view.findViewById(R.id.picker2) val tvUnit = view.findViewById(R.id.tvUnit) - val intValue = Math.round(value * 100).toInt() + val intValue = (value * 100).roundToLong().toInt() picker.minValue = 0 picker.maxValue = Integer.MAX_VALUE / 100 @@ -86,13 +87,12 @@ class NumberPickerFactory } InterfaceUtils.setupEditorAction( - picker, - TextView.OnEditorActionListener { _, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_DONE) - dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick() - false - } - ) + picker + ) { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) + dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick() + false + } return dialog } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/TaskProgressBar.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/TaskProgressBar.kt index 1728033f1..aa1b74a97 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/TaskProgressBar.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/TaskProgressBar.kt @@ -56,8 +56,7 @@ class TaskProgressBar( fun update() { val callback = { - val activeTaskCount = runner.activeTaskCount - val newVisibility = when (activeTaskCount) { + val newVisibility = when (runner.activeTaskCount) { 0 -> GONE else -> VISIBLE } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/HabitTypeDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/HabitTypeDialog.kt index 627247d3b..382dab282 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/HabitTypeDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/HabitTypeDialog.kt @@ -36,7 +36,7 @@ class HabitTypeDialog : AppCompatDialogFragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { val binding = SelectHabitTypeBinding.inflate(inflater, container, false) binding.buttonYesNo.setOnClickListener { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt index 3e7572934..81e01c82f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt @@ -48,9 +48,9 @@ import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.dp import org.isoron.uhabits.utils.setupToolbar import org.isoron.uhabits.utils.sres -import java.lang.Math.max -import java.lang.Math.min import javax.inject.Inject +import kotlin.math.max +import kotlin.math.min const val MAX_CHECKMARK_COUNT = 60 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt index dceadbc10..ad2ebb270 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt @@ -39,12 +39,10 @@ class HabitCardListController @Inject constructor( private val selectionMenu: Lazy ) : HabitCardListView.Controller, ModelObservable.Listener { - private val NORMAL_MODE = NormalMode() - private val SELECTION_MODE = SelectionMode() private var activeMode: Mode init { - this.activeMode = NORMAL_MODE + this.activeMode = NormalMode() adapter.observable.addListener(this) } @@ -83,9 +81,9 @@ class HabitCardListController @Inject constructor( activeMode.startDrag(position) } - protected fun toggleSelection(position: Int) { + private fun toggleSelection(position: Int) { adapter.toggleSelection(position) - activeMode = if (adapter.isSelectionEmpty) NORMAL_MODE else SELECTION_MODE + activeMode = if (adapter.isSelectionEmpty) NormalMode() else SelectionMode() } private fun cancelSelection() { @@ -116,8 +114,7 @@ class HabitCardListController @Inject constructor( */ internal inner class NormalMode : Mode { override fun onItemClick(position: Int) { - val habit = adapter.getItem(position) - if (habit == null) return + val habit = adapter.getItem(position) ?: return behavior.onClickHabit(habit) } @@ -130,9 +127,9 @@ class HabitCardListController @Inject constructor( startSelection(position) } - protected fun startSelection(position: Int) { + private fun startSelection(position: Int) { toggleSelection(position) - activeMode = SELECTION_MODE + activeMode = SelectionMode() selectionMenu.get().onSelectionStart() } } @@ -158,8 +155,8 @@ class HabitCardListController @Inject constructor( notifyListener() } - protected fun notifyListener() { - if (activeMode === SELECTION_MODE) + private fun notifyListener() { + if (activeMode === SelectionMode()) selectionMenu.get().onSelectionChange() else selectionMenu.get().onSelectionFinish() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt index 288e14305..3d8ad81c5 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt @@ -170,22 +170,22 @@ class HabitCardListView( inner class TouchHelperCallback : ItemTouchHelper.Callback() { override fun getMovementFlags( recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder + viewHolder: ViewHolder ): Int { return makeMovementFlags(UP or DOWN, START or END) } override fun onMove( recyclerView: RecyclerView, - from: RecyclerView.ViewHolder, - to: RecyclerView.ViewHolder + from: ViewHolder, + to: ViewHolder ): Boolean { controller.get().drop(from.adapterPosition, to.adapterPosition) return true } override fun onSwiped( - viewHolder: RecyclerView.ViewHolder, + viewHolder: ViewHolder, direction: Int ) { } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index e8040db14..cb76becd4 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -59,8 +59,8 @@ class HabitCardViewFactory class HabitCardView( @ActivityContext context: Context, - private val checkmarkPanelFactory: CheckmarkPanelViewFactory, - private val numberPanelFactory: NumberPanelViewFactory, + checkmarkPanelFactory: CheckmarkPanelViewFactory, + numberPanelFactory: NumberPanelViewFactory, private val behavior: ListHabitsBehavior ) : FrameLayout(context), ModelObservable.Listener { @@ -174,7 +174,7 @@ class HabitCardView( } clipToPadding = false - layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT) + layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT) val margin = dp(3f).toInt() setPadding(margin, 0, margin, margin) addView(innerFrame) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt index 379575652..491656a77 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt @@ -71,7 +71,7 @@ class NumberPanelView( setupButtons() } - override fun createButton() = buttonFactory.create()!! + override fun createButton() = buttonFactory.create() @Synchronized override fun setupButtons() { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardView.kt index 997604e89..ddf657e27 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardView.kt @@ -27,6 +27,7 @@ import org.isoron.uhabits.core.ui.screens.habits.show.views.OverviewCardState import org.isoron.uhabits.databinding.ShowHabitOverviewBinding import org.isoron.uhabits.utils.StyledResources import org.isoron.uhabits.utils.toThemedAndroidColor +import kotlin.math.abs class OverviewCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { @@ -36,7 +37,7 @@ class OverviewCardView(context: Context, attrs: AttributeSet) : LinearLayout(con return String.format( "%s%.0f%%", if (percentageDiff >= 0) "+" else "\u2212", - Math.abs(percentageDiff) * 100 + abs(percentageDiff) * 100 ) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/sync/SyncActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/sync/SyncActivity.kt index 89bf8ef52..5b84ef8c2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/sync/SyncActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/sync/SyncActivity.kt @@ -68,7 +68,7 @@ class SyncActivity : AppCompatActivity(), SyncBehavior.Screen { title = resources.getString(R.string.device_sync), ) binding.syncLink.setOnClickListener { copyToClipboard() } - binding.instructions.setText(Html.fromHtml(resources.getString(R.string.sync_instructions))) + binding.instructions.text = Html.fromHtml(resources.getString(R.string.sync_instructions)) setContentView(binding.root) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt index 683b6368b..cb0b9f894 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt @@ -27,22 +27,22 @@ class AndroidCursor(private val cursor: android.database.Cursor) : Cursor { override fun moveToNext() = cursor.moveToNext() override fun getInt(index: Int): Int? { - if (cursor.isNull(index)) return null - else return cursor.getInt(index) + return if (cursor.isNull(index)) null + else cursor.getInt(index) } override fun getLong(index: Int): Long? { - if (cursor.isNull(index)) return null - else return cursor.getLong(index) + return if (cursor.isNull(index)) null + else cursor.getLong(index) } override fun getDouble(index: Int): Double? { - if (cursor.isNull(index)) return null - else return cursor.getDouble(index) + return if (cursor.isNull(index)) null + else cursor.getDouble(index) } override fun getString(index: Int): String? { - if (cursor.isNull(index)) return null - else return cursor.getString(index) + return if (cursor.isNull(index)) null + else cursor.getString(index) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt index c225b7dac..d764e7a63 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt @@ -51,7 +51,7 @@ class AndroidDatabase( return db.update(tableName, contValues, where, params) } - override fun insert(tableName: String, values: Map): Long? { + override fun insert(tableName: String, values: Map): Long { val contValues = mapToContentValues(values) return db.insert(tableName, null, contValues) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsActivityComponent.kt b/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsActivityComponent.kt index eba75600c..3c16ef030 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsActivityComponent.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/inject/HabitsActivityComponent.kt @@ -32,13 +32,8 @@ import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior @ActivityScope @Component( - modules = arrayOf( - ActivityContextModule::class, - HabitsActivityModule::class, - ListHabitsModule::class, - HabitModule::class - ), - dependencies = arrayOf(HabitsApplicationComponent::class) + modules = [ActivityContextModule::class, HabitsActivityModule::class, ListHabitsModule::class, HabitModule::class], + dependencies = [HabitsApplicationComponent::class] ) interface HabitsActivityComponent { val colorPickerDialogFactory: ColorPickerDialogFactory diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt index 297ed027c..6be35b4c9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt @@ -44,9 +44,8 @@ class IntentParser } private fun parseHabit(uri: Uri): Habit { - val habit = habits.getById(parseId(uri)) + return habits.getById(parseId(uri)) ?: throw IllegalArgumentException("habit not found") - return habit } private fun parseTimestamp(intent: Intent): Timestamp { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentScheduler.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentScheduler.kt index 6964f3363..5a4c79f1d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentScheduler.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentScheduler.kt @@ -36,6 +36,7 @@ import org.isoron.uhabits.core.utils.DateFormats import org.isoron.uhabits.inject.AppContext import java.util.Date import javax.inject.Inject +import kotlin.math.min @AppScope class IntentScheduler @@ -84,7 +85,7 @@ class IntentScheduler } private fun logReminderScheduled(habit: Habit, reminderTime: Long) { - val min = Math.min(5, habit.name.length) + val min = min(5, habit.name.length) val name = habit.name.substring(0, min) val df = DateFormats.getBackupDateFormat() val time = df.format(Date(reminderTime)) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt index 1917ad807..0a195d9c0 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt @@ -41,7 +41,7 @@ class PendingIntentFactory ) { fun addCheckmark(habit: Habit, timestamp: Timestamp?): PendingIntent = - PendingIntent.getBroadcast( + getBroadcast( context, 1, Intent(context, WidgetReceiver::class.java).apply { @@ -53,7 +53,7 @@ class PendingIntentFactory ) fun dismissNotification(habit: Habit): PendingIntent = - PendingIntent.getBroadcast( + getBroadcast( context, 0, Intent(context, ReminderReceiver::class.java).apply { @@ -64,7 +64,7 @@ class PendingIntentFactory ) fun removeRepetition(habit: Habit): PendingIntent = - PendingIntent.getBroadcast( + getBroadcast( context, 3, Intent(context, WidgetReceiver::class.java).apply { @@ -90,7 +90,7 @@ class PendingIntentFactory reminderTime: Long?, timestamp: Long ): PendingIntent = - PendingIntent.getBroadcast( + getBroadcast( context, (habit.id!! % Integer.MAX_VALUE).toInt() + 1, Intent(context, ReminderReceiver::class.java).apply { @@ -103,7 +103,7 @@ class PendingIntentFactory ) fun snoozeNotification(habit: Habit): PendingIntent = - PendingIntent.getBroadcast( + getBroadcast( context, 0, Intent(context, ReminderReceiver::class.java).apply { @@ -114,7 +114,7 @@ class PendingIntentFactory ) fun toggleCheckmark(habit: Habit, timestamp: Long?): PendingIntent = - PendingIntent.getBroadcast( + getBroadcast( context, 2, Intent(context, WidgetReceiver::class.java).apply { @@ -145,7 +145,7 @@ class PendingIntentFactory ) fun updateWidgets(): PendingIntent = - PendingIntent.getBroadcast( + getBroadcast( context, 0, Intent(context, WidgetReceiver::class.java).apply { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt index f1db7d29e..1e79ae857 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt @@ -40,17 +40,17 @@ class RingtoneManager PreferenceManager.getDefaultSharedPreferences(context) fun getName(): String? { - try { + return try { var ringtoneName = context.resources.getString(R.string.none) val ringtoneUri = getURI() if (ringtoneUri != null) { val ringtone = getRingtone(context, ringtoneUri) if (ringtone != null) ringtoneName = ringtone.getTitle(context) } - return ringtoneName + ringtoneName } catch (e: RuntimeException) { e.printStackTrace() - return null + null } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/sync/RemoteSyncServer.kt b/uhabits-android/src/main/java/org/isoron/uhabits/sync/RemoteSyncServer.kt index ae64042b7..4e8f4a705 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/sync/RemoteSyncServer.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/sync/RemoteSyncServer.kt @@ -80,8 +80,7 @@ class RemoteSyncServer( try { val url = "${preferences.syncBaseURL}/db/$key" Log.i("RemoteSyncServer", "GET $url") - val data: SyncData = httpClient.get(url) - return@IO data + return@IO httpClient.get(url) } catch (e: ServerResponseException) { throw ServiceUnavailable() } catch (e: ClientRequestException) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt index b5535291d..af8010014 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt @@ -23,7 +23,7 @@ import android.content.Context class CheckmarkWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - if (habits.size == 1) return CheckmarkWidget(context, id, habits[0]) - else return StackWidget(context, id, StackWidgetType.CHECKMARK, habits) + return if (habits.size == 1) CheckmarkWidget(context, id, habits[0]) + else StackWidget(context, id, StackWidgetType.CHECKMARK, habits) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt index 568f98bc1..136bafceb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt @@ -36,7 +36,7 @@ class FrequencyWidget( override val defaultHeight: Int = 200 override val defaultWidth: Int = 200 - override fun getOnClickPendingIntent(context: Context): PendingIntent? = + override fun getOnClickPendingIntent(context: Context): PendingIntent = pendingIntentFactory.showHabit(habit) override fun refreshData(v: View) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt index 6ff8cc250..3d380ec25 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt @@ -24,12 +24,12 @@ import android.content.Context class FrequencyWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - if (habits.size == 1) return FrequencyWidget( + return if (habits.size == 1) FrequencyWidget( context, id, habits[0], - preferences!!.firstWeekdayInt + preferences.firstWeekdayInt ) - else return StackWidget(context, id, StackWidgetType.FREQUENCY, habits) + else StackWidget(context, id, StackWidgetType.FREQUENCY, habits) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt index e7c2800b9..7cf32e46f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt @@ -41,7 +41,7 @@ class HistoryWidget( override val defaultHeight: Int = 250 override val defaultWidth: Int = 250 - override fun getOnClickPendingIntent(context: Context): PendingIntent? { + override fun getOnClickPendingIntent(context: Context): PendingIntent { return pendingIntentFactory.showHabit(habit) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt index f673911e0..c9dd8da66 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt @@ -23,11 +23,11 @@ import android.content.Context class HistoryWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - if (habits.size == 1) return HistoryWidget( + return if (habits.size == 1) HistoryWidget( context, id, habits[0] ) - else return StackWidget(context, id, StackWidgetType.HISTORY, habits) + else StackWidget(context, id, StackWidgetType.HISTORY, habits) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt index 46c5a432c..4beeed281 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt @@ -36,7 +36,7 @@ class ScoreWidget( override val defaultHeight: Int = 300 override val defaultWidth: Int = 300 - override fun getOnClickPendingIntent(context: Context): PendingIntent? = + override fun getOnClickPendingIntent(context: Context): PendingIntent = pendingIntentFactory.showHabit(habit) override fun refreshData(view: View) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt index 221f04bc3..f271fb799 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt @@ -23,7 +23,7 @@ import android.content.Context class ScoreWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - if (habits.size == 1) return ScoreWidget(context, id, habits[0]) - else return StackWidget(context, id, StackWidgetType.SCORE, habits) + return if (habits.size == 1) ScoreWidget(context, id, habits[0]) + else StackWidget(context, id, StackWidgetType.SCORE, habits) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt index a16bda608..5351a3ceb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt @@ -48,7 +48,10 @@ class StackWidgetService : RemoteViewsService() { internal class StackRemoteViewsFactory(private val context: Context, intent: Intent) : RemoteViewsFactory { - private val widgetId: Int + private val widgetId: Int = intent.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID + ) private val habitIds: LongArray private val widgetType: StackWidgetType? private var remoteViews = ArrayList() @@ -148,15 +151,11 @@ internal class StackRemoteViewsFactory(private val context: Context, intent: Int } init { - widgetId = intent.getIntExtra( - AppWidgetManager.EXTRA_APPWIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID - ) val widgetTypeValue = intent.getIntExtra(StackWidgetService.WIDGET_TYPE, -1) val habitIdsStr = intent.getStringExtra(StackWidgetService.HABIT_IDS) if (widgetTypeValue < 0) throw RuntimeException("invalid widget type") if (habitIdsStr == null) throw RuntimeException("habitIdsStr is null") - widgetType = StackWidgetType.Companion.getWidgetTypeFromValue(widgetTypeValue) + widgetType = StackWidgetType.getWidgetTypeFromValue(widgetTypeValue) habitIds = splitLongs(habitIdsStr) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt index fb2ee2866..604e760e7 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt @@ -37,7 +37,7 @@ class StreakWidget( override val defaultHeight: Int = 200 override val defaultWidth: Int = 200 - override fun getOnClickPendingIntent(context: Context): PendingIntent? = + override fun getOnClickPendingIntent(context: Context): PendingIntent = pendingIntentFactory.showHabit(habit) override fun refreshData(view: View) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt index 280c9200c..98b9e8dd9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt @@ -23,7 +23,7 @@ import android.content.Context class StreakWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - if (habits.size == 1) return StreakWidget(context, id, habits[0]) - else return StackWidget(context, id, StackWidgetType.STREAKS, habits) + return if (habits.size == 1) StreakWidget(context, id, habits[0]) + else StackWidget(context, id, StackWidgetType.STREAKS, habits) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt index dcfbd8cc2..3c8bf8082 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt @@ -40,7 +40,7 @@ class TargetWidget( override val defaultHeight: Int = 200 override val defaultWidth: Int = 200 - override fun getOnClickPendingIntent(context: Context): PendingIntent? = + override fun getOnClickPendingIntent(context: Context): PendingIntent = pendingIntentFactory.showHabit(habit) override fun refreshData(view: View) = runBlocking { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt index 08c2aa731..cb14d61ca 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt @@ -23,7 +23,7 @@ import android.content.Context class TargetWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - if (habits.size == 1) return TargetWidget(context, id, habits[0]) - else return StackWidget(context, id, StackWidgetType.TARGET, habits) + return if (habits.size == 1) TargetWidget(context, id, habits[0]) + else StackWidget(context, id, StackWidgetType.TARGET, habits) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt index 5caa04625..a74c7982f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt @@ -37,14 +37,15 @@ import org.isoron.uhabits.inject.HabitsApplicationComponent import org.isoron.uhabits.utils.InterfaceUtils.getDimension import org.isoron.uhabits.utils.PaletteUtils.getAndroidTestColor import org.isoron.uhabits.utils.StyledResources +import kotlin.math.min class CheckmarkWidgetView : HabitWidgetView { var activeColor: Int = 0 var percentage = 0f var name: String? = null - protected lateinit var ring: RingView - protected lateinit var label: TextView + private lateinit var ring: RingView + private lateinit var label: TextView var entryValue = 0 var entryState = 0 var isNumerical = false @@ -92,7 +93,7 @@ class CheckmarkWidgetView : HabitWidgetView { postInvalidate() } - protected val text: String + private val text: String get() = if (isNumerical) { (entryValue / 1000.0).toShortString() } else when (entryState) { @@ -122,7 +123,7 @@ class CheckmarkWidgetView : HabitWidgetView { val height = MeasureSpec.getSize(heightMeasureSpec) var w = width.toFloat() var h = width * 1.25f - val scale = Math.min(width / w, height / h) + val scale = min(width / w, height / h) w *= scale h *= scale if (h < getDimension(context, R.dimen.checkmarkWidget_heightBreakpoint)) ring.visibility = @@ -131,7 +132,7 @@ class CheckmarkWidgetView : HabitWidgetView { heightMeasureSpec = MeasureSpec.makeMeasureSpec(h.toInt(), MeasureSpec.EXACTLY) var textSize = 0.15f * h val maxTextSize = getDimension(context, R.dimen.smallerTextSize) - textSize = Math.min(textSize, maxTextSize) + textSize = min(textSize, maxTextSize) label.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) ring.setTextSize(textSize) ring.setThickness(0.15f * textSize) @@ -139,8 +140,7 @@ class CheckmarkWidgetView : HabitWidgetView { } private fun init() { - val appComponent: HabitsApplicationComponent - appComponent = (context.applicationContext as HabitsApplication).component + val appComponent: HabitsApplicationComponent = (context.applicationContext as HabitsApplication).component preferences = appComponent.preferences ring = findViewById(R.id.scoreRing) as RingView label = findViewById(R.id.label) as TextView diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt index d1465b56e..85a219479 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt @@ -32,6 +32,7 @@ import org.isoron.uhabits.R import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels import org.isoron.uhabits.utils.StyledResources import java.util.Arrays +import kotlin.math.max abstract class HabitWidgetView : FrameLayout { protected var background: InsetDrawable? = null @@ -73,7 +74,7 @@ abstract class HabitWidgetView : FrameLayout { Arrays.fill(radii, cornerRadius) val shape = RoundRectShape(radii, null, null) val innerDrawable = ShapeDrawable(shape) - val insetLeftTop = Math.max(shadowRadius - shadowOffset, 0) + val insetLeftTop = max(shadowRadius - shadowOffset, 0) val insetRightBottom = shadowRadius + shadowOffset background = InsetDrawable( innerDrawable, diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt b/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt index 41e7cf570..a6a1e5021 100644 --- a/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt +++ b/uhabits-android/src/test/java/org/isoron/uhabits/BaseAndroidJVMTest.kt @@ -18,6 +18,7 @@ */ package org.isoron.uhabits +import com.nhaarman.mockitokotlin2.spy import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.models.HabitList import org.isoron.uhabits.core.models.memory.MemoryModelFactory @@ -29,7 +30,6 @@ 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 @RunWith(MockitoJUnitRunner::class) @@ -46,7 +46,7 @@ open class BaseAndroidJVMTest { setFixedLocalTime(fixedLocalTime) setStartDayOffset(0, 0) modelFactory = MemoryModelFactory() - habitList = Mockito.spy(modelFactory.buildHabitList()) + habitList = spy(modelFactory.buildHabitList()) fixtures = HabitFixtures(modelFactory, habitList) taskRunner = SingleThreadTaskRunner() commandRunner = CommandRunner(taskRunner) diff --git a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt index df37441b9..a855a9018 100644 --- a/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt +++ b/uhabits-android/src/test/java/org/isoron/uhabits/receivers/ReminderControllerTest.kt @@ -18,6 +18,9 @@ */ package org.isoron.uhabits.receivers +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import org.isoron.uhabits.BaseAndroidJVMTest import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Timestamp @@ -25,7 +28,6 @@ import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.reminders.ReminderScheduler import org.isoron.uhabits.core.ui.NotificationTray import org.junit.Test -import org.mockito.Mockito class ReminderControllerTest : BaseAndroidJVMTest() { private lateinit var controller: ReminderController @@ -34,9 +36,9 @@ class ReminderControllerTest : BaseAndroidJVMTest() { private lateinit var preferences: Preferences override fun setUp() { super.setUp() - reminderScheduler = Mockito.mock(ReminderScheduler::class.java) - notificationTray = Mockito.mock(NotificationTray::class.java) - preferences = Mockito.mock(Preferences::class.java) + reminderScheduler = mock() + notificationTray = mock() + preferences = mock() controller = ReminderController( reminderScheduler, notificationTray, @@ -47,24 +49,24 @@ class ReminderControllerTest : BaseAndroidJVMTest() { @Test @Throws(Exception::class) fun testOnDismiss() { - Mockito.verifyNoMoreInteractions(reminderScheduler) - Mockito.verifyNoMoreInteractions(notificationTray) - Mockito.verifyNoMoreInteractions(preferences) + verifyNoMoreInteractions(reminderScheduler) + verifyNoMoreInteractions(notificationTray) + verifyNoMoreInteractions(preferences) } @Test @Throws(Exception::class) fun testOnShowReminder() { - val habit = Mockito.mock(Habit::class.java) + val habit: Habit = mock() controller.onShowReminder(habit, Timestamp.ZERO.plus(100), 456) - Mockito.verify(notificationTray).show(habit, Timestamp.ZERO.plus(100), 456) - Mockito.verify(reminderScheduler).scheduleAll() + verify(notificationTray).show(habit, Timestamp.ZERO.plus(100), 456) + verify(reminderScheduler).scheduleAll() } @Test @Throws(Exception::class) fun testOnBootCompleted() { controller.onBootCompleted() - Mockito.verify(reminderScheduler).scheduleAll() + verify(reminderScheduler).scheduleAll() } } diff --git a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/NumberButtonTest.kt b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/NumberButtonTest.kt index c528f2d9d..7f65a95ac 100644 --- a/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/NumberButtonTest.kt +++ b/uhabits-core-legacy/src/test/common/org/isoron/uhabits/components/NumberButtonTest.kt @@ -55,10 +55,4 @@ class NumberButtonTest : BaseViewTest() { val btn = NumberButton(theme.color(8), 99.0, 100.0, "steps", theme) assertRenders(48, 48, "$base/render_below.png", btn) } - - //@Test - fun testRenderZero() = asyncTest { - val btn = NumberButton(theme.color(8), 0.0, 100.0, "steps", theme) - assertRenders(48, 48, "$base/render_zero.png", btn) - } -} \ No newline at end of file +} diff --git a/uhabits-core/build.gradle b/uhabits-core/build.gradle index b26d4489c..2a577424a 100644 --- a/uhabits-core/build.gradle +++ b/uhabits-core/build.gradle @@ -74,6 +74,7 @@ kotlin { implementation 'nl.jqno.equalsverifier:equalsverifier:2.4.8' implementation 'org.apache.commons:commons-io:1.3.2' implementation 'org.mockito:mockito-core:2.28.2' + implementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" } } } diff --git a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/Canvas.kt b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/Canvas.kt index 4cfec5834..faab51b87 100644 --- a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/Canvas.kt +++ b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/Canvas.kt @@ -51,7 +51,7 @@ interface Canvas { fun fillCircle(centerX: Double, centerY: Double, radius: Double) fun setTextAlign(align: TextAlign) fun toImage(): Image - fun measureText(test: String): Double + fun measureText(text: String): Double /** * Fills entire canvas with the current color. diff --git a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/FontAwesome.kt b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/FontAwesome.kt index 15e3173ab..d9fb92130 100644 --- a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/FontAwesome.kt +++ b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/FontAwesome.kt @@ -21,7 +21,7 @@ package org.isoron.platform.gui class FontAwesome { companion object { - val CHECK = "\uf00c" - val TIMES = "\uf00d" + const val CHECK = "\uf00c" + const val TIMES = "\uf00d" } } diff --git a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt index d8ff099ec..5d440be90 100644 --- a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt +++ b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/time/Dates.kt @@ -153,10 +153,10 @@ private fun daysSince2000(year: Int, month: Int, day: Int): Int { result += ceil((year - 2000) / 4.0).toInt() result -= ceil((year - 2000) / 100.0).toInt() result += ceil((year - 2000) / 400.0).toInt() - if (isLeapYear(year)) { - result += leapOffset[month - 1] + result += if (isLeapYear(year)) { + leapOffset[month - 1] } else { - result += nonLeapOffset[month - 1] + nonLeapOffset[month - 1] } result += (day - 1) return result diff --git a/uhabits-core/src/jvmMain/java/org/isoron/platform/gui/JavaCanvas.kt b/uhabits-core/src/jvmMain/java/org/isoron/platform/gui/JavaCanvas.kt index 21bd5c69d..36a8a1393 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/platform/gui/JavaCanvas.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/platform/gui/JavaCanvas.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.runBlocking import org.isoron.platform.io.JavaFileOpener import org.isoron.platform.io.JavaResourceFile import java.awt.BasicStroke +import java.awt.Graphics2D import java.awt.RenderingHints.KEY_ANTIALIASING import java.awt.RenderingHints.KEY_FRACTIONALMETRICS import java.awt.RenderingHints.KEY_TEXT_ANTIALIASING @@ -54,7 +55,7 @@ class JavaCanvas( private var textAlign = TextAlign.CENTER val widthPx = image.width val heightPx = image.height - val g2d = image.createGraphics() + val g2d: Graphics2D = image.createGraphics() private val NOTO_REGULAR_FONT = createFont("fonts/NotoSans-Regular.ttf") private val NOTO_BOLD_FONT = createFont("fonts/NotoSans-Bold.ttf") @@ -96,24 +97,28 @@ class JavaCanvas( val bx = bounds.x.roundToInt() val by = bounds.y.roundToInt() - if (textAlign == TextAlign.CENTER) { - g2d.drawString( - text, - toPixel(x) - bx - bWidth / 2, - toPixel(y) - by - bHeight / 2 - ) - } else if (textAlign == TextAlign.LEFT) { - g2d.drawString( - text, - toPixel(x) - bx, - toPixel(y) - by - bHeight / 2 - ) - } else { - g2d.drawString( - text, - toPixel(x) - bx - bWidth, - toPixel(y) - by - bHeight / 2 - ) + when (textAlign) { + TextAlign.CENTER -> { + g2d.drawString( + text, + toPixel(x) - bx - bWidth / 2, + toPixel(y) - by - bHeight / 2 + ) + } + TextAlign.LEFT -> { + g2d.drawString( + text, + toPixel(x) - bx, + toPixel(y) - by - bHeight / 2 + ) + } + else -> { + g2d.drawString( + text, + toPixel(x) - bx - bWidth, + toPixel(y) - by - bHeight / 2 + ) + } } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/platform/io/JavaFiles.kt b/uhabits-core/src/jvmMain/java/org/isoron/platform/io/JavaFiles.kt index d00e7ffef..e2a7a3e46 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/platform/io/JavaFiles.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/platform/io/JavaFiles.kt @@ -33,8 +33,8 @@ class JavaResourceFile(val path: String) : ResourceFile { get() { val mainPath = Paths.get("assets/main/$path") val testPath = Paths.get("assets/test/$path") - if (Files.exists(mainPath)) return mainPath - else return testPath + return if (Files.exists(mainPath)) mainPath + else testPath } override suspend fun exists(): Boolean { diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/SQLParser.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/SQLParser.kt index e5fa89156..40320feb0 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/SQLParser.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/database/SQLParser.kt @@ -71,7 +71,7 @@ object SQLParser { val buffer = BufferedInputStream(stream) val commands: MutableList = ArrayList() val sb = StringBuffer() - try { + buffer.use { buffer -> val tokenizer = Tokenizer(buffer) var state = STATE_NONE while (tokenizer.hasNext()) { @@ -104,7 +104,7 @@ object SQLParser { } if (state == STATE_NONE || state == STATE_STRING) { if (state == STATE_NONE && isWhitespace(c)) { - if (sb.length > 0 && sb[sb.length - 1] != ' ') { + if (sb.isNotEmpty() && sb[sb.length - 1] != ' ') { sb.append(' ') } } else { @@ -112,8 +112,6 @@ object SQLParser { } } } - } finally { - buffer.close() } if (sb.isNotEmpty()) { commands.add(sb.toString().trim { it <= ' ' }) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitsCSVExporter.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitsCSVExporter.kt index 2389da845..3126b18a3 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitsCSVExporter.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitsCSVExporter.kt @@ -37,6 +37,7 @@ import java.util.LinkedList import java.util.Locale import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream +import kotlin.math.min /** * Class that exports the application data to CSV files. @@ -77,7 +78,7 @@ class HabitsCSVExporter( private fun sanitizeFilename(name: String): String { val s = name.replace("[^ a-zA-Z0-9\\._-]+".toRegex(), "") - return s.substring(0, Math.min(s.length, 100)) + return s.substring(0, min(s.length, 100)) } private fun writeHabits() { diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt index fecd02c1a..c8f76e4a5 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt @@ -53,7 +53,7 @@ class LoopDBImporter override fun canHandle(file: File): Boolean { if (!file.isSQLite3File()) return false - val db = opener.open(file)!! + val db = opener.open(file) var canHandle = true val c = db.query("select count(*) from SQLITE_MASTER where name='Habits' or name='Repetitions'") if (!c.moveToNext() || c.getInt(0) != 2) { @@ -70,7 +70,7 @@ class LoopDBImporter } override fun importHabitsFromFile(file: File) { - val db = opener.open(file)!! + val db = opener.open(file) val helper = MigrationHelper(db) helper.migrateTo(DATABASE_VERSION) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt index 3e77aa2bf..76a2fabf8 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt @@ -156,15 +156,15 @@ open class EntryList { get() = begin.daysUntil(end) + 1 } - /** - * Converts a list of intervals into a list of entries. Entries that fall outside of any - * interval receive value UNKNOWN. Entries that fall within an interval but do not appear - * in [original] receive value YES_AUTO. Entries provided in [original] are copied over. - * - * The intervals should be sorted by timestamp. The first element in the list should - * correspond to the newest interval. - */ companion object { + /** + * Converts a list of intervals into a list of entries. Entries that fall outside of any + * interval receive value UNKNOWN. Entries that fall within an interval but do not appear + * in [original] receive value YES_AUTO. Entries provided in [original] are copied over. + * + * The intervals should be sorted by timestamp. The first element in the list should + * correspond to the newest interval. + */ fun buildEntriesFromInterval( original: List, intervals: List, diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ModelFactory.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ModelFactory.kt index a55dc1242..2edeeed51 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ModelFactory.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ModelFactory.kt @@ -31,13 +31,12 @@ interface ModelFactory { fun buildHabit(): Habit { val scores = buildScoreList() val streaks = buildStreakList() - val habit = Habit( + return Habit( scores = scores, streaks = streaks, originalEntries = buildOriginalEntries(), computedEntries = buildComputedEntries(), ) - return habit } fun buildComputedEntries(): EntryList fun buildOriginalEntries(): EntryList diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Score.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Score.kt index dc2fd3fa8..4b7bc5730 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Score.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Score.kt @@ -18,6 +18,7 @@ */ package org.isoron.uhabits.core.models +import kotlin.math.pow import kotlin.math.sqrt data class Score( @@ -40,7 +41,7 @@ data class Score( previousScore: Double, checkmarkValue: Double, ): Double { - val multiplier = Math.pow(0.5, sqrt(frequency) / 13.0) + val multiplier = 0.5.pow(sqrt(frequency) / 13.0) var score = previousScore * multiplier score += checkmarkValue * (1 - multiplier) return score diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt index 6e399a2cf..11a2b146c 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/ScoreList.kt @@ -109,7 +109,7 @@ class ScoreList { } } if (values[offset] != Entry.SKIP) { - val percentageCompleted = Math.min(1.0, rollingSum / numerator) + val percentageCompleted = min(1.0, rollingSum / numerator) previousValue = compute(freq, previousValue, percentageCompleted) } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt index d598d5d78..f104cb32b 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/WeekdayList.kt @@ -47,7 +47,7 @@ class WeekdayList { } fun toArray(): BooleanArray { - return Arrays.copyOf(weekdays, 7) + return weekdays.copyOf(7) } fun toInteger(): Int { diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenter.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenter.kt index 38dd68d28..49dc07af7 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenter.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenter.kt @@ -29,6 +29,8 @@ import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback import org.isoron.uhabits.core.utils.DateUtils import java.io.File import java.util.Random +import kotlin.math.max +import kotlin.math.min class ShowHabitMenuPresenter( private val commandRunner: CommandRunner, @@ -67,7 +69,7 @@ class ShowHabitMenuPresenter( habit.originalEntries.clear() var strength = 50.0 for (i in 0 until 365 * 5) { - if (i % 7 == 0) strength = Math.max(0.0, Math.min(100.0, strength + 10 * random.nextGaussian())) + if (i % 7 == 0) strength = max(0.0, min(100.0, strength + 10 * random.nextGaussian())) if (random.nextInt(100) > strength) continue var value = Entry.YES_MANUAL if (habit.isNumerical) value = (1000 + 250 * random.nextGaussian() * strength / 100).toInt() * 1000 diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt index a999a2689..3cd66fad4 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/OverviewCard.kt @@ -39,9 +39,9 @@ class OverviewCardPresenter { val lastMonth = today.minus(30) val lastYear = today.minus(365) val scores = habit.scores - val scoreToday = scores.get(today).value.toFloat() - val scoreLastMonth = scores.get(lastMonth).value.toFloat() - val scoreLastYear = scores.get(lastYear).value.toFloat() + val scoreToday = scores[today].value.toFloat() + val scoreLastMonth = scores[lastMonth].value.toFloat() + val scoreLastYear = scores[lastYear].value.toFloat() val totalCount = habit.originalEntries.getKnown() .filter { it.value == Entry.YES_MANUAL } .count() diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt index 823b5a042..4d487a103 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/ScoreCard.kt @@ -39,13 +39,13 @@ class ScoreCardPresenter( companion object { val BUCKET_SIZES = intArrayOf(1, 7, 31, 92, 365) fun getTruncateField(bucketSize: Int): DateUtils.TruncateField { - when (bucketSize) { - 1 -> return DateUtils.TruncateField.DAY - 7 -> return DateUtils.TruncateField.WEEK_NUMBER - 31 -> return DateUtils.TruncateField.MONTH - 92 -> return DateUtils.TruncateField.QUARTER - 365 -> return DateUtils.TruncateField.YEAR - else -> return DateUtils.TruncateField.MONTH + return when (bucketSize) { + 1 -> DateUtils.TruncateField.DAY + 7 -> DateUtils.TruncateField.WEEK_NUMBER + 31 -> DateUtils.TruncateField.MONTH + 92 -> DateUtils.TruncateField.QUARTER + 365 -> DateUtils.TruncateField.YEAR + else -> DateUtils.TruncateField.MONTH } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/BarChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/BarChart.kt index b933de6ee..ca8e700ad 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/BarChart.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/BarChart.kt @@ -63,7 +63,7 @@ class BarChart( val nColumns = floor((safeWidth) / barGroupWidth).toInt() val marginLeft = (safeWidth - nColumns * barGroupWidth) / 2 val maxBarHeight = height - footerHeight - paddingTop - var maxValue = series.map { it.max()!! }.max()!! + var maxValue = series.map { it.maxOrNull()!! }.maxOrNull()!! maxValue = max(maxValue, 1.0) canvas.setColor(theme.cardBackgroundColor) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt index c1dcc2584..699cc2ee6 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt @@ -192,15 +192,15 @@ class HistoryChart( val value = if (offset >= series.size) Square.OFF else series[offset] val squareColor: Color val color = theme.color(paletteColor.paletteIndex) - when (value) { + squareColor = when (value) { Square.ON -> { - squareColor = color + color } Square.OFF -> { - squareColor = theme.lowContrastTextColor + theme.lowContrastTextColor } Square.DIMMED, Square.HATCHED -> { - squareColor = color.blendWith(theme.cardBackgroundColor, 0.5) + color.blendWith(theme.cardBackgroundColor, 0.5) } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt index 7b388ecbc..fd7929b87 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateUtils.kt @@ -76,7 +76,7 @@ abstract class DateUtils { if (fixedLocalTime != null) return fixedLocalTime as Long val tz = getTimeZone() - val now = Date().getTime() + val now = Date().time return now + tz.getOffset(now) } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/MidnightTimer.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/MidnightTimer.kt index 4d2277563..e0661ba77 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/MidnightTimer.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/MidnightTimer.kt @@ -37,7 +37,7 @@ open class MidnightTimer @Inject constructor() { this.listeners.add(listener) } - @Synchronized fun onPause() = executor.shutdownNow() + @Synchronized fun onPause(): MutableList? = executor.shutdownNow() @Synchronized fun onResume() { executor = Executors.newSingleThreadScheduledExecutor() diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/StringUtils.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/StringUtils.kt index 6933fb1d0..a65cf4241 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/StringUtils.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/StringUtils.kt @@ -59,11 +59,10 @@ class StringUtils { @JvmStatic fun splitLongs(str: String): LongArray { val parts: Array = org.apache.commons.lang3.StringUtils.split(str, ',') - val numbers = LongArray(parts.size) { + return LongArray(parts.size) { i -> parts[i].toLong() } - return numbers } } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt index b14f2bc8f..f97991b6d 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/BaseUnitTest.kt @@ -18,6 +18,8 @@ */ package org.isoron.uhabits.core +import com.nhaarman.mockitokotlin2.spy +import com.nhaarman.mockitokotlin2.validateMockitoUsage import org.apache.commons.io.IOUtils import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.database.Database @@ -37,7 +39,6 @@ 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 @@ -78,7 +79,7 @@ open class BaseUnitTest { setFixedLocalTime(FIXED_LOCAL_TIME) setStartDayOffset(0, 0) val memoryModelFactory = MemoryModelFactory() - habitList = Mockito.spy(memoryModelFactory.buildHabitList()) + habitList = spy(memoryModelFactory.buildHabitList()) fixtures = HabitFixtures(memoryModelFactory, habitList) modelFactory = memoryModelFactory taskRunner = SingleThreadTaskRunner() @@ -88,7 +89,7 @@ open class BaseUnitTest { @After @Throws(Exception::class) open fun tearDown() { - Mockito.validateMockitoUsage() + validateMockitoUsage() setFixedLocalTime(null) setStartDayOffset(0, 0) } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.kt index 76fcc0d97..4a774340b 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ArchiveHabitsCommandTest.kt @@ -26,21 +26,21 @@ import org.junit.Before import org.junit.Test class ArchiveHabitsCommandTest : BaseUnitTest() { - private var command: ArchiveHabitsCommand? = null - private var habit: Habit? = null + private lateinit var command: ArchiveHabitsCommand + private lateinit var habit: Habit @Before @Throws(Exception::class) override fun setUp() { super.setUp() habit = fixtures.createShortHabit() - habitList.add(habit!!) - command = ArchiveHabitsCommand(habitList, listOf(habit!!)) + habitList.add(habit) + command = ArchiveHabitsCommand(habitList, listOf(habit)) } @Test fun testExecute() { - assertFalse(habit!!.isArchived) - command!!.run() - assertTrue(habit!!.isArchived) + assertFalse(habit.isArchived) + command.run() + assertTrue(habit.isArchived) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt index 27823edb6..086d0c3df 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/ChangeHabitColorCommandTest.kt @@ -18,7 +18,7 @@ */ package org.isoron.uhabits.core.commands -import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Habit @@ -54,16 +54,13 @@ class ChangeHabitColorCommandTest : BaseUnitTest() { private fun checkNewColors() { for (habit in selected) { - assertThat(habit.color, CoreMatchers.equalTo(PaletteColor(0))) + assertThat(habit.color, equalTo(PaletteColor(0))) } } private fun checkOriginalColors() { var k = 0 for (habit in selected) - assertThat( - habit.color, - CoreMatchers.equalTo(PaletteColor(++k)) - ) + assertThat(habit.color, equalTo(PaletteColor(++k))) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt index b92f549b2..f5d7f3fc0 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateHabitCommandTest.kt @@ -19,7 +19,7 @@ package org.isoron.uhabits.core.commands import junit.framework.Assert.assertTrue -import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Habit @@ -46,13 +46,8 @@ class CreateHabitCommandTest : BaseUnitTest() { fun testExecute() { assertTrue(habitList.isEmpty) command.run() - assertThat(habitList.size(), CoreMatchers.equalTo(1)) + assertThat(habitList.size(), equalTo(1)) val habit = habitList.getByPosition(0) - assertThat( - habit.name, - CoreMatchers.equalTo( - model.name - ) - ) + assertThat(habit.name, equalTo(model.name)) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt index 2859ae52c..fade73e69 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt @@ -28,26 +28,26 @@ 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 + private lateinit var command: CreateRepetitionCommand + private lateinit var habit: Habit + private lateinit var today: Timestamp @Before @Throws(Exception::class) override fun setUp() { super.setUp() habit = fixtures.createShortHabit() - habitList.add(habit!!) + habitList.add(habit) today = getToday() - command = CreateRepetitionCommand(habitList, habit!!, today!!, 100) + command = CreateRepetitionCommand(habitList, habit, today, 100) } @Test fun testExecute() { - val entries = habit!!.originalEntries - var entry = entries.get(today!!) + val entries = habit.originalEntries + var entry = entries.get(today) assertEquals(Entry.YES_MANUAL, entry.value) - command!!.run() - entry = entries.get(today!!) + command.run() + entry = entries.get(today) assertEquals(100, entry.value.toLong()) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt index d6c430139..b44328035 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/DeleteHabitsCommandTest.kt @@ -18,7 +18,7 @@ */ package org.isoron.uhabits.core.commands -import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Habit @@ -34,6 +34,7 @@ class DeleteHabitsCommandTest : BaseUnitTest() { @get:Rule var thrown = ExpectedException.none()!! + @Before @Throws(Exception::class) override fun setUp() { @@ -56,9 +57,9 @@ class DeleteHabitsCommandTest : BaseUnitTest() { @Test fun testExecute() { - assertThat(habitList.size(), CoreMatchers.equalTo(4)) + assertThat(habitList.size(), equalTo(4)) command.run() - assertThat(habitList.size(), CoreMatchers.equalTo(1)) - assertThat(habitList.getByPosition(0).name, CoreMatchers.equalTo("extra")) + assertThat(habitList.size(), equalTo(1)) + assertThat(habitList.getByPosition(0).name, equalTo("extra")) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt index e3cbc19ce..9a9927cc1 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/database/migrations/Version22Test.kt @@ -36,6 +36,7 @@ class Version22Test : BaseUnitTest() { var exception = ExpectedException.none()!! private lateinit var db: Database private lateinit var helper: MigrationHelper + @Throws(Exception::class) override fun setUp() { super.setUp() @@ -49,48 +50,25 @@ class Version22Test : BaseUnitTest() { @Test @Throws(Exception::class) fun testKeepValidReps() { - db.query( - "select count(*) from repetitions" - ) { c: Cursor -> - assertThat( - c.getInt(0), - equalTo(3) - ) + 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) - ) + 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) - ) + 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) - ) + db.query("select count(*) from repetitions where habit = 99999") { c: Cursor -> + assertThat(c.getInt(0), equalTo(0)) } } @@ -99,32 +77,19 @@ class Version22Test : BaseUnitTest() { fun testDisallowNewRepsWithInvalidRef() { helper.migrateTo(22) exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT")) - db.execute( - "insert into Repetitions(habit, timestamp, value) " + - "values (99999, 100, 2)" - ) + 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) - ) + 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) - ) + db.query("select count(*) from repetitions where timestamp is null") { c: Cursor -> + assertThat(c.getInt(0), equalTo(0)) } } @@ -140,22 +105,12 @@ class Version22Test : BaseUnitTest() { @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) - ) + 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) - ) + db.query("select count(*) from repetitions where habit is null") { c: Cursor -> + assertThat(c.getInt(0), equalTo(0)) } } @@ -164,42 +119,21 @@ class Version22Test : BaseUnitTest() { fun testDisallowNullHabit() { helper.migrateTo(22) exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT")) - db.execute( - "insert into Repetitions(timestamp, value) " + "values (5, 2)" - ) + 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) - ) + 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) - ) + db.query("select count(*) from repetitions where timestamp=100 and habit=0") { c: Cursor -> + assertThat(c.getInt(0), equalTo(1)) } } @@ -207,14 +141,8 @@ class Version22Test : BaseUnitTest() { @Throws(Exception::class) fun testDisallowNewDuplicateTimestamps() { helper.migrateTo(22) - db.execute( - "insert into repetitions(habit, timestamp, value)" + - "values (0, 100, 2)" - ) + 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)" - ) + db.execute("insert into repetitions(habit, timestamp, value)values (0, 100, 5)") } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt index 17046505c..c6655bba6 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/HabitsCSVExporterTest.kt @@ -18,7 +18,6 @@ */ 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 @@ -34,7 +33,7 @@ import java.util.LinkedList import java.util.zip.ZipFile class HabitsCSVExporterTest : BaseUnitTest() { - private var baseDir: File? = null + private lateinit var baseDir: File @Before @Throws(Exception::class) override fun setUp() { @@ -42,7 +41,6 @@ class HabitsCSVExporterTest : BaseUnitTest() { habitList.add(fixtures.createShortHabit()) habitList.add(fixtures.createEmptyHabit()) baseDir = Files.createTempDirectory("csv").toFile() - assertNotNull(baseDir) } @Throws(Exception::class) @@ -59,7 +57,7 @@ class HabitsCSVExporterTest : BaseUnitTest() { val exporter = HabitsCSVExporter( habitList, selected, - baseDir!! + baseDir ) val filename = exporter.writeArchive() assertAbsolutePathExists(filename) @@ -84,7 +82,7 @@ class HabitsCSVExporterTest : BaseUnitTest() { val stream = zip.getInputStream(entry) val outputFilename = String.format( "%s/%s", - baseDir!!.absolutePath, + baseDir.absolutePath, entry.name ) val out = File(outputFilename) @@ -96,7 +94,7 @@ class HabitsCSVExporterTest : BaseUnitTest() { } private fun assertPathExists(s: String) { - assertAbsolutePathExists(String.format("%s/%s", baseDir!!.absolutePath, s)) + assertAbsolutePathExists(String.format("%s/%s", baseDir.absolutePath, s)) } private fun assertAbsolutePathExists(s: String) { diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt index a44ed925f..0be326074 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt @@ -21,7 +21,7 @@ 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.hamcrest.core.IsEqual.equalTo import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Frequency @@ -46,11 +46,11 @@ class ImportTest : BaseUnitTest() { @Throws(IOException::class) fun testHabitBullCSV() { importFromFile("habitbull.csv") - assertThat(habitList.size(), IsEqual.equalTo(4)) + assertThat(habitList.size(), 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)) + assertThat(habit.name, equalTo("Breed dragons")) + assertThat(habit.description, equalTo("with love and fire")) + assertThat(habit.frequency, equalTo(Frequency.DAILY)) assertTrue(isChecked(habit, 2016, 3, 18)) assertTrue(isChecked(habit, 2016, 3, 19)) assertFalse(isChecked(habit, 2016, 3, 20)) @@ -60,10 +60,10 @@ class ImportTest : BaseUnitTest() { @Throws(IOException::class) fun testLoopDB() { importFromFile("loop.db") - assertThat(habitList.size(), IsEqual.equalTo(9)) + assertThat(habitList.size(), 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)) + assertThat(habit.name, equalTo("Wake up early")) + assertThat(habit.frequency, equalTo(Frequency.THREE_TIMES_PER_WEEK)) assertTrue(isChecked(habit, 2016, 3, 14)) assertTrue(isChecked(habit, 2016, 3, 16)) assertFalse(isChecked(habit, 2016, 3, 17)) @@ -73,33 +73,33 @@ class ImportTest : BaseUnitTest() { @Throws(IOException::class) fun testRewireDB() { importFromFile("rewire.db") - assertThat(habitList.size(), IsEqual.equalTo(3)) + assertThat(habitList.size(), 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)) + assertThat(habit.name, equalTo("Wake up early")) + assertThat(habit.frequency, 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)) + assertThat(habit.name, equalTo("brush teeth")) + assertThat(habit.frequency, equalTo(Frequency.THREE_TIMES_PER_WEEK)) + assertThat(habit.hasReminder(), equalTo(true)) val reminder = habit.reminder - assertThat(reminder!!.hour, IsEqual.equalTo(8)) - assertThat(reminder.minute, IsEqual.equalTo(0)) + assertThat(reminder!!.hour, equalTo(8)) + assertThat(reminder.minute, equalTo(0)) val reminderDays = booleanArrayOf(false, true, true, true, true, true, false) - assertThat(reminder.days.toArray(), IsEqual.equalTo(reminderDays)) + assertThat(reminder.days.toArray(), equalTo(reminderDays)) } @Test @Throws(IOException::class) fun testTickmateDB() { importFromFile("tickmate.db") - assertThat(habitList.size(), IsEqual.equalTo(3)) + assertThat(habitList.size(), equalTo(3)) val h = habitList.getByPosition(2) - assertThat(h.name, IsEqual.equalTo("Vegan")) + assertThat(h.name, equalTo("Vegan")) assertTrue(isChecked(h, 2016, 1, 24)) assertTrue(isChecked(h, 2016, 2, 5)) assertTrue(isChecked(h, 2016, 3, 18)) diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt index bce5119ac..7f67d3adf 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitListTest.kt @@ -19,10 +19,10 @@ package org.isoron.uhabits.core.models import junit.framework.Assert.assertEquals -import junit.framework.Assert.assertNotNull +import junit.framework.Assert.assertFalse import junit.framework.Assert.assertNull -import junit.framework.TestCase -import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.CoreMatchers.not import org.hamcrest.MatcherAssert.assertThat import org.isoron.uhabits.core.BaseUnitTest import org.junit.Rule @@ -64,48 +64,25 @@ class HabitListTest : BaseUnitTest() { @Test fun testSize() { - assertThat(habitList.size(), CoreMatchers.equalTo(10)) - assertThat(activeHabits.size(), CoreMatchers.equalTo(6)) - assertThat(reminderHabits.size(), CoreMatchers.equalTo(4)) + assertThat(habitList.size(), equalTo(10)) + assertThat(activeHabits.size(), equalTo(6)) + assertThat(reminderHabits.size(), 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]) - ) + assertThat(habitList.getByPosition(0), equalTo(habitsArray[0])) + assertThat(habitList.getByPosition(3), equalTo(habitsArray[3])) + assertThat(habitList.getByPosition(9), equalTo(habitsArray[9])) + assertThat(activeHabits.getByPosition(0), equalTo(habitsArray[2])) + assertThat(reminderHabits.getByPosition(1), equalTo(habitsArray[3])) } @Test fun testGetById() { val habit1 = habitsArray[0] val habit2 = habitList.getById(habit1.id!!) - assertThat(habit1, CoreMatchers.equalTo(habit2)) + assertThat(habit1, equalTo(habit2)) } @Test @@ -128,41 +105,41 @@ class HabitListTest : BaseUnitTest() { } 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)) + 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.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)) + 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.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)) + 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.primaryOrder = HabitList.Order.BY_NAME_ASC list.remove(h1) list.add(h1) - assertThat(list.getByPosition(0), CoreMatchers.equalTo(h1)) + assertThat(list.getByPosition(0), 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)) + 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.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)) + 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.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)) + 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 @@ -182,18 +159,13 @@ class HabitListTest : BaseUnitTest() { val actualSequence = IntArray(10) for (j in 0..9) { val habit = habitList.getByPosition(j) - assertThat(habit.position, CoreMatchers.equalTo(j)) + assertThat(habit.position, equalTo(j)) actualSequence[j] = Math.toIntExact(habit.id!!) } - assertThat( - actualSequence, - CoreMatchers.equalTo( - expectedSequence[i] - ) - ) + assertThat(actualSequence, equalTo(expectedSequence[i])) } - assertThat(activeHabits.indexOf(habitsArray[5]), CoreMatchers.equalTo(0)) - assertThat(activeHabits.indexOf(habitsArray[2]), CoreMatchers.equalTo(1)) + assertThat(activeHabits.indexOf(habitsArray[5]), equalTo(0)) + assertThat(activeHabits.indexOf(habitsArray[2]), equalTo(1)) } @Test @@ -244,26 +216,20 @@ class HabitListTest : BaseUnitTest() { """.trimIndent() val writer = StringWriter() list.writeCSV(writer) - assertThat(writer.toString(), CoreMatchers.equalTo(expectedCSV)) + assertThat(writer.toString(), equalTo(expectedCSV)) } @Test @Throws(Exception::class) fun testAdd() { val h1 = fixtures.createEmptyHabit() - TestCase.assertFalse(h1.isArchived) + assertFalse(h1.isArchived) assertNull(h1.id) - assertThat(habitList.indexOf(h1), CoreMatchers.equalTo(-1)) + assertThat(habitList.indexOf(h1), 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)) - ) + h1.id!! + assertThat(habitList.indexOf(h1), not(equalTo(-1))) + assertThat(activeHabits.indexOf(h1), not(equalTo(-1))) } @Test diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt index 933cd8c1d..d13c8468e 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/HabitTest.kt @@ -19,9 +19,9 @@ 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.hamcrest.CoreMatchers.`is` +import org.hamcrest.core.IsEqual.equalTo import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday import org.junit.Assert.assertNotEquals @@ -41,11 +41,9 @@ class HabitTest : BaseUnitTest() { @Test fun testUuidGeneration() { - val (_, _, _, _, _, _, _, _, _, _, _, _, _, uuid) = modelFactory.buildHabit() - val (_, _, _, _, _, _, _, _, _, _, _, _, _, uuid1) = modelFactory.buildHabit() - assertNotNull(uuid) - assertNotNull(uuid1) - assertNotEquals(uuid, uuid1) + val uuid1 = modelFactory.buildHabit().uuid!! + val uuid2 = modelFactory.buildHabit().uuid!! + assertNotEquals(uuid1, uuid2) } @Test @@ -57,18 +55,19 @@ class HabitTest : BaseUnitTest() { 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)) + assertTrue(habit.isArchived == model.isArchived) + assertThat(habit.isArchived, `is`(model.isArchived)) + assertThat(habit.color, `is`(model.color)) + assertThat(habit.frequency, equalTo(model.frequency)) + assertThat(habit.reminder, equalTo(model.reminder)) } @Test fun test_hasReminder() { val h = modelFactory.buildHabit() - assertThat(h.hasReminder(), CoreMatchers.`is`(false)) + assertThat(h.hasReminder(), `is`(false)) h.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY) - assertThat(h.hasReminder(), CoreMatchers.`is`(true)) + assertThat(h.hasReminder(), `is`(true)) } @Test @@ -116,10 +115,7 @@ class HabitTest : BaseUnitTest() { 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") - ) + assertThat(h.id, equalTo(0L)) + assertThat(h.uriString, equalTo("content://org.isoron.uhabits/habit/0")) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt index 9e0baaddc..329d34656 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/ScoreTest.kt @@ -36,56 +36,26 @@ class ScoreTest : BaseUnitTest() { 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) - ) + 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) - ) + 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) - ) + 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) - ) + 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 { diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt index 520ff81e7..06575a406 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/StreakListTest.kt @@ -18,16 +18,16 @@ */ package org.isoron.uhabits.core.models +import org.hamcrest.CoreMatchers.equalTo 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 + private lateinit var streaks: StreakList + private lateinit var today: Timestamp @Throws(Exception::class) override fun setUp() { @@ -42,26 +42,26 @@ class StreakListTest : BaseUnitTest() { @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)) + var best = streaks.getBest(4) + assertThat(best.size, equalTo(4)) + assertThat(best[0].length, equalTo(4)) + assertThat(best[1].length, equalTo(3)) + assertThat(best[2].length, equalTo(5)) + assertThat(best[3].length, equalTo(6)) + best = streaks.getBest(2) + assertThat(best.size, equalTo(2)) + assertThat(best[0].length, equalTo(5)) + assertThat(best[1].length, 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.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)) + val best = streaks.getBest(5) + assertThat(best.size, equalTo(1)) + assertThat(best[0].length, equalTo(1)) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt index 826bf47a2..8296528b7 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/TimestampTest.kt @@ -18,8 +18,8 @@ */ package org.isoron.uhabits.core.models +import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue -import junit.framework.TestCase import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.greaterThan @@ -39,10 +39,10 @@ class TimestampTest : BaseUnitTest() { 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)) + assertFalse(t1.isNewerThan(t1)) + assertFalse(t2.isNewerThan(t1)) assertTrue(t2.isOlderThan(t1)) - TestCase.assertFalse(t1.isOlderThan(t2)) + assertFalse(t1.isOlderThan(t2)) } @Test diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt index 72e17cbd1..8bcde06fb 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/WeekdayListTest.kt @@ -20,8 +20,8 @@ package org.isoron.uhabits.core.models import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue +import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.core.IsEqual import org.isoron.uhabits.core.BaseUnitTest import org.junit.Test @@ -29,21 +29,13 @@ class WeekdayListTest : BaseUnitTest() { @Test fun test() { val daysInt = 124 - val daysArray = booleanArrayOf( - false, - false, - true, - true, - true, - true, - true - ) + 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)) + assertThat(list.toArray(), equalTo(daysArray)) + assertThat(list.toInteger(), equalTo(daysInt)) list = WeekdayList(daysInt) - assertThat(list.toArray(), IsEqual.equalTo(daysArray)) - assertThat(list.toInteger(), IsEqual.equalTo(daysInt)) + assertThat(list.toArray(), equalTo(daysArray)) + assertThat(list.toInteger(), equalTo(daysInt)) } @Test diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt index 74b8f2ada..3057b8993 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteEntryListTest.kt @@ -20,7 +20,6 @@ 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.Companion.buildMemoryDatabase import org.isoron.uhabits.core.database.Repository @@ -87,22 +86,17 @@ class SQLiteEntryListTest { val original = Entry(today, 150) entries.add(original) - val retrieved = getByTimestamp(1, today) - assertNotNull(retrieved) - assertEquals(original, retrieved!!.toEntry()) + val retrieved = getByTimestamp(1, today)!! + assertEquals(original, retrieved.toEntry()) val replacement = Entry(today, 90) entries.add(replacement) - val retrieved2 = getByTimestamp(1, today) - assertNotNull(retrieved2) - assertEquals(replacement, retrieved2!!.toEntry()) + val retrieved2 = getByTimestamp(1, today)!! + assertEquals(replacement, retrieved2.toEntry()) } - private fun getByTimestamp( - habitId: Int, - timestamp: Timestamp, - ): EntryRecord? { + private fun getByTimestamp(habitId: Int, timestamp: Timestamp): EntryRecord? { return repository.findFirst( "where habit = ? and timestamp = ?", habitId.toString(), diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt index 230da89a3..07ac72e02 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/SQLiteHabitListTest.kt @@ -18,9 +18,10 @@ */ package org.isoron.uhabits.core.models.sqlite -import junit.framework.Assert.assertNotNull +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify import junit.framework.Assert.assertNull -import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.database.Database @@ -36,17 +37,17 @@ 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 - private lateinit var listener: ModelObservable.Listener + private var listener: ModelObservable.Listener = mock() private lateinit var habitsArray: ArrayList private lateinit var activeHabits: HabitList private lateinit var reminderHabits: HabitList + @Throws(Exception::class) override fun setUp() { super.setUp() @@ -54,10 +55,7 @@ class SQLiteHabitListTest : BaseUnitTest() { modelFactory = SQLModelFactory(db) habitList = SQLiteHabitList(modelFactory) fixtures = HabitFixtures(modelFactory, habitList) - repository = Repository( - HabitRecord::class.java, - db - ) + repository = Repository(HabitRecord::class.java, db) habitsArray = ArrayList() for (i in 0..9) { val habit = fixtures.createEmptyHabit() @@ -78,7 +76,6 @@ class SQLiteHabitListTest : BaseUnitTest() { .setReminderRequired(true) .build() ) - listener = Mockito.mock(ModelObservable.Listener::class.java) habitList.observable.addListener(listener) } @@ -92,7 +89,7 @@ class SQLiteHabitListTest : BaseUnitTest() { fun testAdd_withDuplicate() { val habit = modelFactory.buildHabit() habitList.add(habit) - Mockito.verify(listener)!!.onModelChange() + verify(listener).onModelChange() exception.expect(IllegalArgumentException::class.java) habitList.add(habit) } @@ -103,10 +100,9 @@ class SQLiteHabitListTest : BaseUnitTest() { habit.name = "Hello world with id" habit.id = 12300L habitList.add(habit) - assertThat(habit.id, CoreMatchers.equalTo(12300L)) + assertThat(habit.id, equalTo(12300L)) val record = repository.find(12300L) - assertNotNull(record) - assertThat(record!!.name, CoreMatchers.equalTo(habit.name)) + assertThat(record!!.name, equalTo(habit.name)) } @Test @@ -115,27 +111,21 @@ class SQLiteHabitListTest : BaseUnitTest() { 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)) + val record = repository.find(habit.id!!) + assertThat(record!!.name, equalTo(habit.name)) } @Test fun testSize() { - assertThat(habitList.size(), CoreMatchers.equalTo(10)) + assertThat(habitList.size(), 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)) + val h1 = habitList.getById(1)!! + assertThat(h1.name, equalTo("habit 1")) + val h2 = habitList.getById(2)!! + assertThat(h2, equalTo(h2)) } @Test @@ -148,19 +138,17 @@ class SQLiteHabitListTest : BaseUnitTest() { @Test fun testGetByPosition() { val h = habitList.getByPosition(4) - assertNotNull(h) - assertThat(h.name, CoreMatchers.equalTo("habit 5")) + assertThat(h.name, equalTo("habit 5")) } @Test fun testIndexOf() { val h1 = habitList.getByPosition(5) - assertNotNull(h1) - assertThat(habitList.indexOf(h1), CoreMatchers.equalTo(5)) + assertThat(habitList.indexOf(h1), equalTo(5)) val h2 = modelFactory.buildHabit() - assertThat(habitList.indexOf(h2), CoreMatchers.equalTo(-1)) + assertThat(habitList.indexOf(h2), equalTo(-1)) h2.id = 1000L - assertThat(habitList.indexOf(h2), CoreMatchers.equalTo(-1)) + assertThat(habitList.indexOf(h2), equalTo(-1)) } @Test @@ -168,26 +156,21 @@ class SQLiteHabitListTest : BaseUnitTest() { fun testRemove() { val h = habitList.getById(2) habitList.remove(h!!) - assertThat(habitList.indexOf(h), CoreMatchers.equalTo(-1)) + assertThat(habitList.indexOf(h), equalTo(-1)) var rec = repository.find(2L) assertNull(rec) - rec = repository.find(3L) - assertNotNull(rec) - assertThat(rec!!.position, CoreMatchers.equalTo(1)) + rec = repository.find(3L)!! + assertThat(rec.position, 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)) + val habit3 = habitList.getById(3)!! + val habit4 = habitList.getById(4)!! + habitList.reorder(habit4, habit3) + val record3 = repository.find(3L)!! + assertThat(record3.position, equalTo(3)) + val record4 = repository.find(4L)!! + assertThat(record4.position, equalTo(2)) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.kt index 993a6f2ab..2f561618b 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecordTest.kt @@ -18,8 +18,8 @@ */ package org.isoron.uhabits.core.models.sqlite.records +import org.hamcrest.CoreMatchers.equalTo 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 @@ -32,6 +32,6 @@ class EntryRecordTest : BaseUnitTest() { val check = Entry(Timestamp.ZERO.plus(100), 50) val record = EntryRecord() record.copyFrom(check) - assertThat(check, IsEqual.equalTo(record.toEntry())) + assertThat(check, equalTo(record.toEntry())) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt index 16bdb0e62..55953f0c8 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.kt @@ -18,8 +18,8 @@ */ package org.isoron.uhabits.core.models.sqlite.records +import org.hamcrest.CoreMatchers.equalTo 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 @@ -31,41 +31,43 @@ 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 original = modelFactory.buildHabit().apply() { + name = "Hello world" + question = "Did you greet the world today?" + color = PaletteColor(1) + isArchived = true + frequency = Frequency.THREE_TIMES_PER_WEEK + reminder = Reminder(8, 30, WeekdayList.EVERY_DAY) + id = 1000L + position = 20 + } val record = HabitRecord() record.copyFrom(original) val duplicate = modelFactory.buildHabit() record.copyTo(duplicate) - assertThat(original, IsEqual.equalTo(duplicate)) + assertThat(original, 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 original = modelFactory.buildHabit().apply() { + name = "Hello world" + question = "Did you greet the world today?" + color = PaletteColor(5) + isArchived = false + frequency = Frequency.DAILY + reminder = null + id = 1L + position = 15 + type = Habit.NUMBER_HABIT + targetValue = 100.0 + targetType = Habit.AT_LEAST + unit = "miles" + } val record = HabitRecord() record.copyFrom(original) val duplicate = modelFactory.buildHabit() record.copyTo(duplicate) - assertThat(original, IsEqual.equalTo(duplicate)) + assertThat(original, equalTo(duplicate)) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt index a2f857200..340f97440 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt @@ -18,26 +18,25 @@ */ package org.isoron.uhabits.core.preferences +import com.nhaarman.mockitokotlin2.mock import junit.framework.Assert.assertFalse import junit.framework.Assert.assertNull import junit.framework.Assert.assertTrue +import org.hamcrest.CoreMatchers.equalTo 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.models.Timestamp.ZERO 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 + private var listener: Preferences.Listener = mock() + private lateinit var storage: PropertiesStorage @Before @Throws(Exception::class) @@ -46,7 +45,7 @@ class PreferencesTest : BaseUnitTest() { val file = File.createTempFile("prefs", ".properties") file.deleteOnExit() storage = PropertiesStorage(file) - prefs = Preferences(storage!!) + prefs = Preferences(storage) prefs.addListener(listener) } @@ -55,66 +54,57 @@ class PreferencesTest : BaseUnitTest() { fun testClear() { prefs.setDefaultHabitColor(99) prefs.clear() - assertThat(prefs.getDefaultHabitColor(0), IsEqual.equalTo(0)) + assertThat(prefs.getDefaultHabitColor(0), equalTo(0)) } @Test @Throws(Exception::class) fun testHabitColor() { - assertThat(prefs.getDefaultHabitColor(999), IsEqual.equalTo(999)) + assertThat(prefs.getDefaultHabitColor(999), equalTo(999)) prefs.setDefaultHabitColor(10) - assertThat(prefs.getDefaultHabitColor(999), IsEqual.equalTo(10)) + assertThat(prefs.getDefaultHabitColor(999), equalTo(10)) } @Test @Throws(Exception::class) fun testDefaultOrder() { - assertThat( - prefs.defaultPrimaryOrder, - IsEqual.equalTo(HabitList.Order.BY_POSITION) - ) + assertThat(prefs.defaultPrimaryOrder, equalTo(HabitList.Order.BY_POSITION)) prefs.defaultPrimaryOrder = HabitList.Order.BY_SCORE_DESC + assertThat(prefs.defaultPrimaryOrder, equalTo(HabitList.Order.BY_SCORE_DESC)) + storage.putString("pref_default_order", "BOGUS") + assertThat(prefs.defaultPrimaryOrder, equalTo(HabitList.Order.BY_POSITION)) 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") + storage.getString("pref_default_order", ""), + equalTo("BY_POSITION") ) } @Test @Throws(Exception::class) fun testScoreCardSpinnerPosition() { - assertThat(prefs.scoreCardSpinnerPosition, IsEqual.equalTo(1)) + assertThat(prefs.scoreCardSpinnerPosition, equalTo(1)) prefs.scoreCardSpinnerPosition = 4 - assertThat(prefs.scoreCardSpinnerPosition, IsEqual.equalTo(4)) - storage!!.putInt("pref_score_view_interval", 9000) - assertThat(prefs.scoreCardSpinnerPosition, IsEqual.equalTo(4)) + assertThat(prefs.scoreCardSpinnerPosition, equalTo(4)) + storage.putInt("pref_score_view_interval", 9000) + assertThat(prefs.scoreCardSpinnerPosition, equalTo(4)) } @Test @Throws(Exception::class) fun testLastHint() { - assertThat(prefs.lastHintNumber, IsEqual.equalTo(-1)) + assertThat(prefs.lastHintNumber, 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))) + prefs.updateLastHint(34, ZERO.plus(100)) + assertThat(prefs.lastHintNumber, equalTo(34)) + assertThat(prefs.lastHintTimestamp, equalTo(ZERO.plus(100))) } @Test @Throws(Exception::class) fun testTheme() { - assertThat(prefs.theme, IsEqual.equalTo(ThemeSwitcher.THEME_AUTOMATIC)) + assertThat(prefs.theme, equalTo(ThemeSwitcher.THEME_AUTOMATIC)) prefs.theme = ThemeSwitcher.THEME_DARK - assertThat(prefs.theme, IsEqual.equalTo(ThemeSwitcher.THEME_DARK)) + assertThat(prefs.theme, equalTo(ThemeSwitcher.THEME_DARK)) assertFalse(prefs.isPureBlackEnabled) prefs.isPureBlackEnabled = true assertTrue(prefs.isPureBlackEnabled) @@ -129,23 +119,23 @@ class PreferencesTest : BaseUnitTest() { assertFalse(prefs.shouldMakeNotificationsLed()) prefs.setNotificationsLed(true) assertTrue(prefs.shouldMakeNotificationsLed()) - assertThat(prefs.snoozeInterval, IsEqual.equalTo(15L)) + assertThat(prefs.snoozeInterval, equalTo(15L)) prefs.setSnoozeInterval(30) - assertThat(prefs.snoozeInterval, IsEqual.equalTo(30L)) + assertThat(prefs.snoozeInterval, equalTo(30L)) } @Test @Throws(Exception::class) fun testAppVersionAndLaunch() { - assertThat(prefs.lastAppVersion, IsEqual.equalTo(0)) + assertThat(prefs.lastAppVersion, equalTo(0)) prefs.lastAppVersion = 23 - assertThat(prefs.lastAppVersion, IsEqual.equalTo(23)) + assertThat(prefs.lastAppVersion, equalTo(23)) assertTrue(prefs.isFirstRun) prefs.isFirstRun = false assertFalse(prefs.isFirstRun) - assertThat(prefs.launchCount, IsEqual.equalTo(0)) + assertThat(prefs.launchCount, equalTo(0)) prefs.incrementLaunchCount() - assertThat(prefs.launchCount, IsEqual.equalTo(1)) + assertThat(prefs.launchCount, equalTo(1)) } @Test diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt index bc3045285..65066b916 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PropertiesStorageTest.kt @@ -18,10 +18,11 @@ */ package org.isoron.uhabits.core.preferences +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue -import junit.framework.TestCase +import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.core.IsEqual import org.isoron.uhabits.core.BaseUnitTest import org.junit.Before import org.junit.Test @@ -29,7 +30,7 @@ import java.io.File import java.util.Arrays class PropertiesStorageTest : BaseUnitTest() { - private var storage: PropertiesStorage? = null + private lateinit var storage: PropertiesStorage private lateinit var file: File @Before @@ -44,39 +45,37 @@ class PropertiesStorageTest : BaseUnitTest() { @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)) + 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 @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 - ) + 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")) + assertThat(storage2.getInt("intKey", 200), equalTo(64)) + assertThat(storage2.getLong("intKey", 200L), equalTo(64L)) + assertThat(storage2.getString("stringKey", ""), equalTo("Hello")) } @Test @@ -86,18 +85,18 @@ class PropertiesStorageTest : BaseUnitTest() { 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()) + 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)) + assertEquals("1,2,3,5", storage.getString("key1", "")) + assertEquals(1, storage.getLong("key2", -1)) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt index d9da1457e..d354e81f0 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/reminders/ReminderSchedulerTest.kt @@ -18,6 +18,10 @@ */ package org.isoron.uhabits.core.reminders +import com.nhaarman.mockitokotlin2.eq +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Reminder @@ -31,9 +35,7 @@ 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.ArgumentMatchers.anyLong import org.mockito.junit.MockitoJUnitRunner import java.util.Calendar import java.util.TimeZone @@ -41,22 +43,20 @@ import java.util.TimeZone @RunWith(MockitoJUnitRunner::class) class ReminderSchedulerTest : BaseUnitTest() { private val habitId = 10L - private var habit: Habit? = null - private var reminderScheduler: ReminderScheduler? = null + private lateinit var habit: Habit + private lateinit var reminderScheduler: ReminderScheduler - @Mock - private val sys: ReminderScheduler.SystemScheduler? = null + private val sys: ReminderScheduler.SystemScheduler = mock() + private val widgetPreferences: WidgetPreferences = mock() - @Mock - private val widgetPreferences: WidgetPreferences? = null @Before @Throws(Exception::class) override fun setUp() { super.setUp() habit = fixtures.createEmptyHabit() - habit!!.id = habitId + habit.id = habitId reminderScheduler = - ReminderScheduler(commandRunner, habitList, sys!!, widgetPreferences!!) + ReminderScheduler(commandRunner, habitList, sys, widgetPreferences) setFixedTimeZone(TimeZone.getTimeZone("GMT-4")) } @@ -73,16 +73,16 @@ class ReminderSchedulerTest : BaseUnitTest() { 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() + reminderScheduler.scheduleAll() + verify(sys).scheduleShowReminder( + eq(unixTime(2015, 1, 27, 12, 30)), + eq(h1), + anyLong() ) - Mockito.verify(sys)!!.scheduleShowReminder( - ArgumentMatchers.eq(unixTime(2015, 1, 26, 22, 30)), - ArgumentMatchers.eq(h2), - ArgumentMatchers.anyLong() + verify(sys).scheduleShowReminder( + eq(unixTime(2015, 1, 26, 22, 30)), + eq(h2), + anyLong() ) } @@ -90,7 +90,7 @@ class ReminderSchedulerTest : BaseUnitTest() { 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) + habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY) scheduleAndVerify(atTime, expectedCheckmarkTime, atTime) } @@ -103,13 +103,14 @@ class ReminderSchedulerTest : BaseUnitTest() { 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) + habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY) + whenever(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInFuture) + reminderScheduler.schedule(habit) + verify(sys).scheduleShowReminder(snoozeTimeInFuture, habit, todayCheckmarkTime) + whenever(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInPast) + reminderScheduler.schedule(habit) + verify(sys) + .scheduleShowReminder(regularReminderTime, habit, tomorrowCheckmarkTime) } @Test @@ -118,7 +119,7 @@ class ReminderSchedulerTest : BaseUnitTest() { 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) + habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY) scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime) } @@ -128,13 +129,13 @@ class ReminderSchedulerTest : BaseUnitTest() { 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) + habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY) scheduleAndVerify(null, expectedCheckmarkTime, expectedReminderTime) } @Test fun testSchedule_withoutReminder() { - reminderScheduler!!.schedule(habit!!) + reminderScheduler.schedule(habit) } override fun unixTime(year: Int, month: Int, day: Int, hour: Int, minute: Int): Long { @@ -148,11 +149,11 @@ class ReminderSchedulerTest : BaseUnitTest() { expectedCheckmarkTime: Long, expectedReminderTime: Long ) { - if (atTime == null) reminderScheduler!!.schedule(habit!!) else reminderScheduler!!.scheduleAtTime( - habit!!, + if (atTime == null) reminderScheduler.schedule(habit) else reminderScheduler.scheduleAtTime( + habit, atTime ) - Mockito.verify(sys)!!.scheduleShowReminder( + verify(sys).scheduleShowReminder( expectedReminderTime, habit, expectedCheckmarkTime diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt index 010c6f938..0dbc97bfd 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunnerTest.kt @@ -18,28 +18,29 @@ */ package org.isoron.uhabits.core.tasks +import com.nhaarman.mockitokotlin2.inOrder +import com.nhaarman.mockitokotlin2.mock 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 + private lateinit var runner: SingleThreadTaskRunner + private var task: Task = mock() + @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!!) + runner.execute(task) + val inOrder = inOrder(task) + inOrder.verify(task).onAttached(runner) inOrder.verify(task).onPreExecute() inOrder.verify(task).doInBackground() inOrder.verify(task).onPostExecute() diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt index c44c825ad..cf4c284d8 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt @@ -18,20 +18,22 @@ */ package org.isoron.uhabits.core.ui.screens.habits.list -import junit.framework.Assert.assertNotNull +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.reset +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions +import org.hamcrest.CoreMatchers.equalTo 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 + private lateinit var cache: HabitCardListCache + private lateinit var listener: HabitCardListCache.Listener var today = getToday() @Throws(Exception::class) @@ -42,86 +44,83 @@ class HabitCardListCacheTest : BaseUnitTest() { 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!!) + cache.setCheckmarkCount(10) + cache.refreshAllHabits() + cache.onAttached() + listener = mock() + cache.setListener(listener) } override fun tearDown() { - cache!!.onDetached() + cache.onDetached() } @Test fun testCommandListener_all() { - assertThat(cache!!.habitCount, IsEqual.equalTo(10)) + assertThat(cache.habitCount, 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)) + verify(listener).onItemRemoved(0) + verify(listener).onRefreshFinished() + assertThat(cache.habitCount, 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) + verify(listener).onItemChanged(2) + verify(listener).onRefreshFinished() + verifyNoMoreInteractions(listener) } @Test fun testGet() { - assertThat(cache!!.habitCount, IsEqual.equalTo(10)) + assertThat(cache.habitCount, 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!!) + assertThat(cache.getHabitByPosition(3), equalTo(h)) + assertThat(cache.getScore(h.id!!), 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)) + assertThat(actualCheckmarks, 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)) + cache.refreshAllHabits() + verify(listener).onItemRemoved(0) + verify(listener).onItemRemoved(3) + verify(listener).onRefreshFinished() + assertThat(cache.habitCount, equalTo(8)) } @Test fun testRefreshWithNoChanges() { - cache!!.refreshAllHabits() - Mockito.verify(listener)!!.onRefreshFinished() - Mockito.verifyNoMoreInteractions(listener) + cache.refreshAllHabits() + verify(listener).onRefreshFinished() + 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) + val h2 = cache.getHabitByPosition(2) + val h3 = cache.getHabitByPosition(3) + val 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 @@ -129,26 +128,25 @@ class HabitCardListCacheTest : BaseUnitTest() { 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) + assertThat(cache.getHabitByPosition(2), equalTo(h2)) + assertThat(cache.getHabitByPosition(7), equalTo(h7)) + 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) + 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) } private fun removeHabitAt(position: Int) { val h = habitList.getByPosition(position) - assertNotNull(h) habitList.remove(h) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt index b039c0e94..333236614 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HintListTest.kt @@ -18,9 +18,12 @@ */ package org.isoron.uhabits.core.ui.screens.habits.list +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import junit.framework.Assert.assertFalse 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 @@ -29,42 +32,41 @@ 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 hintList: HintList private lateinit var hints: Array @Mock - private val prefs: Preferences? = null - private var today: Timestamp? = null - private var yesterday: Timestamp? = null + private val prefs: Preferences = mock() + private lateinit var today: Timestamp + private lateinit var yesterday: Timestamp @Throws(Exception::class) override fun setUp() { super.setUp() today = getToday() - yesterday = today!!.minus(1) + yesterday = today.minus(1) hints = arrayOf("hint1", "hint2", "hint3") - hintList = HintList(prefs!!, hints) + 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()) + whenever(prefs.lastHintNumber).thenReturn(-1) + assertThat(hintList.pop(), equalTo("hint1")) + verify(prefs).updateLastHint(0, today) + whenever(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()) + whenever(prefs.lastHintTimestamp).thenReturn(today) + assertFalse(hintList.shouldShow()) + whenever(prefs.lastHintTimestamp).thenReturn(yesterday) + assertTrue(hintList.shouldShow()) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt index a8aa04889..2f1f3c4f6 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt @@ -18,11 +18,18 @@ */ package org.isoron.uhabits.core.ui.screens.habits.list +import com.nhaarman.mockitokotlin2.KArgumentCaptor +import com.nhaarman.mockitokotlin2.argumentCaptor +import com.nhaarman.mockitokotlin2.clearInvocations +import com.nhaarman.mockitokotlin2.eq +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever 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.hamcrest.core.IsEqual.equalTo import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Habit @@ -31,32 +38,23 @@ 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 + private val dirFinder: ListHabitsBehavior.DirFinder = mock() - @Mock - private val prefs: Preferences? = null - private var behavior: ListHabitsBehavior? = null + private val prefs: Preferences = mock() + private lateinit var behavior: ListHabitsBehavior - @Mock - private val screen: ListHabitsBehavior.Screen? = null - private var habit1: Habit? = null - private var habit2: Habit? = null + private val screen: ListHabitsBehavior.Screen = mock() + private lateinit var habit1: Habit + private lateinit var habit2: Habit - @Captor - var picker: ArgumentCaptor? = null + var picker: KArgumentCaptor = argumentCaptor() - @Mock - private val bugReporter: ListHabitsBehavior.BugReporter? = null + private val bugReporter: ListHabitsBehavior.BugReporter = mock() @Before @Throws(Exception::class) @@ -64,47 +62,37 @@ class ListHabitsBehaviorTest : BaseUnitTest() { super.setUp() habit1 = fixtures.createShortHabit() habit2 = fixtures.createNumericalHabit() - habitList.add(habit1!!) - habitList.add(habit2!!) - Mockito.clearInvocations(habitList) + habitList.add(habit1) + habitList.add(habit2) + clearInvocations(habitList) behavior = ListHabitsBehavior( habitList, - dirFinder!!, + dirFinder, taskRunner, - screen!!, + screen, commandRunner, - prefs!!, - bugReporter!! + 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) + behavior.onEdit(habit2, getToday()) + verify(screen).showNumberPicker(eq(0.1), eq("miles"), picker.capture()) + picker.lastValue.onNumberPicked(100.0) val today = getTodayWithOffset() - assertThat( - habit2!!.computedEntries.get(today).value, - CoreMatchers.equalTo(100000) - ) + assertThat(habit2.computedEntries.get(today).value, 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) - ) + whenever(dirFinder.csvOutputDir).thenReturn(outputDir) + behavior.onExportCSV() + verify(screen).showSendFileScreen(ArgumentMatchers.any()) + assertThat(FileUtils.listFiles(outputDir, null, false).size, equalTo(1)) FileUtils.deleteDirectory(outputDir) } @@ -113,69 +101,66 @@ class ListHabitsBehaviorTest : BaseUnitTest() { 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) + whenever(dirFinder.csvOutputDir).thenReturn(outputDir) + behavior.onExportCSV() + verify(screen).showMessage(ListHabitsBehavior.Message.COULD_NOT_EXPORT) assertTrue(outputDir.delete()) } @Test fun testOnHabitClick() { - behavior!!.onClickHabit(habit1!!) - Mockito.verify(screen)!!.showHabitScreen( - habit1!! - ) + behavior.onClickHabit(habit1) + verify(screen).showHabitScreen(habit1) } @Test fun testOnHabitReorder() { val from = habit1 val to = habit2 - behavior!!.onReorderHabit(from!!, to!!) - Mockito.verify(habitList)!!.reorder(from, to) + behavior.onReorderHabit(from, to) + verify(habitList).reorder(from, to) } @Test fun testOnRepairDB() { - behavior!!.onRepairDB() - Mockito.verify(habitList)!!.repair() - Mockito.verify(screen)!!.showMessage(ListHabitsBehavior.Message.DATABASE_REPAIRED) + behavior.onRepairDB() + verify(habitList).repair() + 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) + whenever(bugReporter.bugReport).thenReturn("hello") + behavior.onSendBugReport() + verify(bugReporter).dumpBugReportToFile() + verify(screen).showSendBugReportToDeveloperScreen("hello") + whenever(bugReporter.bugReport).thenThrow(IOException()) + behavior.onSendBugReport() + 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() + whenever(prefs.isFirstRun).thenReturn(true) + behavior.onStartup() + verify(prefs).isFirstRun = false + verify(prefs).updateLastHint(-1, today) + verify(screen).showIntroScreen() } @Test fun testOnStartup_notFirstLaunch() { - Mockito.`when`(prefs!!.isFirstRun).thenReturn(false) - behavior!!.onStartup() - Mockito.verify(prefs).incrementLaunchCount() + whenever(prefs.isFirstRun).thenReturn(false) + behavior.onStartup() + verify(prefs).incrementLaunchCount() } @Test fun testOnToggle() { - assertTrue(habit1!!.isCompletedToday()) - behavior!!.onToggle(habit1!!, getToday(), Entry.NO) - assertFalse(habit1!!.isCompletedToday()) + assertTrue(habit1.isCompletedToday()) + behavior.onToggle(habit1, getToday(), Entry.NO) + assertFalse(habit1.isCompletedToday()) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt index 579d90349..463320d1f 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsMenuBehaviorTest.kt @@ -18,7 +18,16 @@ */ package org.isoron.uhabits.core.ui.screens.habits.list -import junit.framework.TestCase +import com.nhaarman.mockitokotlin2.KArgumentCaptor +import com.nhaarman.mockitokotlin2.argumentCaptor +import com.nhaarman.mockitokotlin2.clearInvocations +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.never +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions +import com.nhaarman.mockitokotlin2.whenever +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.isoron.uhabits.core.BaseUnitTest @@ -27,196 +36,144 @@ 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 + private lateinit var behavior: ListHabitsMenuBehavior - @Mock - private val screen: ListHabitsMenuBehavior.Screen? = null + private val screen: ListHabitsMenuBehavior.Screen = mock() - @Mock - private val adapter: ListHabitsMenuBehavior.Adapter? = null + private val adapter: ListHabitsMenuBehavior.Adapter = mock() - @Mock - private val prefs: Preferences? = null + private val prefs: Preferences = mock() - @Mock - private val themeSwitcher: ThemeSwitcher? = null + private val themeSwitcher: ThemeSwitcher = mock() - @Captor - private val matcherCaptor: ArgumentCaptor? = null + private val matcherCaptor: KArgumentCaptor = argumentCaptor() - @Captor - private val orderCaptor: ArgumentCaptor? = null + private val orderCaptor: KArgumentCaptor = argumentCaptor() - @Captor - private val secondaryOrderCaptor: ArgumentCaptor? = null + private val secondaryOrderCaptor: KArgumentCaptor = argumentCaptor() @Throws(Exception::class) override fun setUp() { super.setUp() - behavior = ListHabitsMenuBehavior(screen!!, adapter!!, prefs!!, themeSwitcher!!) - Mockito.clearInvocations(adapter) + behavior = ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher) + 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) + whenever(prefs.showArchived).thenReturn(true) + whenever(prefs.showCompleted).thenReturn(true) + behavior = ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher) + verify(adapter).setFilter(matcherCaptor.capture()) + verify(adapter).refresh() + verifyNoMoreInteractions(adapter) + clearInvocations(adapter) + assertTrue(matcherCaptor.lastValue.isArchivedAllowed) + assertTrue(matcherCaptor.lastValue.isCompletedAllowed) + whenever(prefs.showArchived).thenReturn(false) + whenever(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) + verify(adapter).setFilter(matcherCaptor.capture()) + verify(adapter).refresh() + verifyNoMoreInteractions(adapter) + assertFalse(matcherCaptor.lastValue.isArchivedAllowed) + assertFalse(matcherCaptor.lastValue.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) - ) + behavior.onSortByColor() + verify(adapter).primaryOrder = orderCaptor.capture() + assertThat(orderCaptor.lastValue, 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) - ) + behavior.onSortByManually() + verify(adapter).primaryOrder = orderCaptor.capture() + assertThat(orderCaptor.lastValue, 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) - ) + behavior.onSortByScore() + verify(adapter).primaryOrder = orderCaptor.capture() + assertThat(orderCaptor.lastValue, 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) - ) + behavior.onSortByName() + verify(adapter).primaryOrder = orderCaptor.capture() + assertThat(orderCaptor.lastValue, 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) - ) + whenever(adapter.primaryOrder).thenReturn(HabitList.Order.BY_NAME_ASC) + behavior.onSortByStatus() + verify(adapter).primaryOrder = orderCaptor.capture() + verify(adapter).setSecondaryOrder(secondaryOrderCaptor.capture()) + assertThat(orderCaptor.lastValue, equalTo(HabitList.Order.BY_STATUS_ASC)) + assertThat(secondaryOrderCaptor.lastValue, 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) - ) + whenever(adapter.primaryOrder).thenReturn(HabitList.Order.BY_STATUS_ASC) + behavior.onSortByStatus() + verify(adapter).primaryOrder = orderCaptor.capture() + verify(adapter, never()).setSecondaryOrder(ArgumentMatchers.any()) + assertThat(orderCaptor.lastValue, 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) + behavior.onToggleShowArchived() + verify(adapter).setFilter(matcherCaptor.capture()) + assertTrue(matcherCaptor.lastValue.isArchivedAllowed) + clearInvocations(adapter) + behavior.onToggleShowArchived() + verify(adapter).setFilter(matcherCaptor.capture()) + assertFalse(matcherCaptor.lastValue.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) + behavior.onToggleShowCompleted() + verify(adapter).setFilter(matcherCaptor.capture()) + assertTrue(matcherCaptor.lastValue.isCompletedAllowed) + clearInvocations(adapter) + behavior.onToggleShowCompleted() + verify(adapter).setFilter(matcherCaptor.capture()) + assertFalse(matcherCaptor.lastValue.isCompletedAllowed) } @Test fun testOnViewAbout() { - behavior!!.onViewAbout() - Mockito.verify(screen)!!.showAboutScreen() + behavior.onViewAbout() + verify(screen).showAboutScreen() } @Test fun testOnViewFAQ() { - behavior!!.onViewFAQ() - Mockito.verify(screen)!!.showFAQScreen() + behavior.onViewFAQ() + verify(screen).showFAQScreen() } @Test fun testOnViewSettings() { - behavior!!.onViewSettings() - Mockito.verify(screen)!!.showSettingsScreen() + behavior.onViewSettings() + verify(screen).showSettingsScreen() } @Test fun testOnToggleNightMode() { - behavior!!.onToggleNightMode() - Mockito.verify(themeSwitcher)!!.toggleNightMode() - Mockito.verify(screen)!!.applyTheme() + behavior.onToggleNightMode() + verify(themeSwitcher).toggleNightMode() + verify(screen).applyTheme() } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt index b5b2d626b..5974d3ad1 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehaviorTest.kt @@ -18,7 +18,15 @@ */ package org.isoron.uhabits.core.ui.screens.habits.list -import junit.framework.TestCase +import com.nhaarman.mockitokotlin2.KArgumentCaptor +import com.nhaarman.mockitokotlin2.argumentCaptor +import com.nhaarman.mockitokotlin2.eq +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertNull +import junit.framework.Assert.assertTrue import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.isoron.uhabits.core.BaseUnitTest @@ -27,126 +35,113 @@ 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 + private val screen: ListHabitsSelectionMenuBehavior.Screen = mock() - @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 + private val adapter: ListHabitsSelectionMenuBehavior.Adapter = mock() + private lateinit var behavior: ListHabitsSelectionMenuBehavior + private lateinit var habit1: Habit + private lateinit var habit2: Habit + private lateinit var habit3: Habit - @Captor - private val colorPickerCallback: ArgumentCaptor? = null + private val colorPickerCallback: KArgumentCaptor = argumentCaptor() - @Captor - private val deleteCallback: ArgumentCaptor? = null + private val deleteCallback: KArgumentCaptor = argumentCaptor() @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()) + whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) + assertFalse(behavior.canArchive()) + whenever(adapter.selected).thenReturn(listOf(habit2, habit3)) + 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()) + whenever(adapter.selected).thenReturn(listOf(habit1)) + assertTrue(behavior.canEdit()) + whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) + 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()) + whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) + assertFalse(behavior.canUnarchive()) + whenever(adapter.selected).thenReturn(listOf(habit1)) + 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) + assertFalse(habit2.isArchived) + whenever(adapter.selected).thenReturn(listOf(habit2)) + behavior.onArchiveHabits() + 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))) + assertThat(habit1.color, equalTo(PaletteColor(8))) + assertThat(habit2.color, equalTo(PaletteColor(8))) + whenever(adapter.selected).thenReturn(listOf(habit1, habit2)) + behavior.onChangeColor() + verify(screen) + .showColorPicker(eq(PaletteColor(8)), colorPickerCallback.capture()) + colorPickerCallback.lastValue.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)) + val id = habit1.id!! + habitList.getById(id)!! + whenever(adapter.selected).thenReturn(listOf(habit1)) + behavior.onDeleteHabits() + verify(screen).showDeleteConfirmationScreen(deleteCallback.capture(), eq(1)) + deleteCallback.lastValue.onConfirmed() + assertNull(habitList.getById(id)) } @Test @Throws(Exception::class) fun onEditHabits() { - val selected: List = listOf(habit1!!, habit2!!) - Mockito.`when`(adapter!!.selected).thenReturn(selected) - behavior!!.onEditHabits() - Mockito.verify(screen)!!.showEditHabitsScreen(selected) + val selected: List = listOf(habit1, habit2) + whenever(adapter.selected).thenReturn(selected) + behavior.onEditHabits() + 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) + assertTrue(habit1.isArchived) + whenever(adapter.selected).thenReturn(listOf(habit1)) + behavior.onUnarchiveHabits() + assertFalse(habit1.isArchived) } @Throws(Exception::class) override fun setUp() { super.setUp() habit1 = fixtures.createShortHabit() - habit1!!.isArchived = true + habit1.isArchived = true habit2 = fixtures.createShortHabit() habit3 = fixtures.createShortHabit() - habitList.add(habit1!!) - habitList.add(habit2!!) - habitList.add(habit3!!) + habitList.add(habit1) + habitList.add(habit2) + habitList.add(habit3) behavior = ListHabitsSelectionMenuBehavior( habitList, - screen!!, - adapter!!, + screen, + adapter, commandRunner ) } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt index 220f1db17..aac1cf320 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuPresenterTest.kt @@ -18,13 +18,15 @@ */ package org.isoron.uhabits.core.ui.screens.habits.show +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever import org.apache.commons.io.FileUtils -import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.equalTo 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() { @@ -32,11 +34,12 @@ class ShowHabitMenuPresenterTest : BaseUnitTest() { 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) + system = mock() + screen = mock() habit = fixtures.createShortHabit() menu = ShowHabitMenuPresenter( commandRunner, @@ -51,16 +54,16 @@ class ShowHabitMenuPresenterTest : BaseUnitTest() { @Test fun testOnEditHabit() { menu.onEditHabit() - Mockito.verify(screen)!!.showEditHabitScreen(habit) + verify(screen).showEditHabitScreen(habit) } @Test @Throws(Exception::class) fun testOnExport() { val outputDir = Files.createTempDirectory("CSV").toFile() - Mockito.`when`(system.getCSVOutputDir()).thenReturn(outputDir) + whenever(system.getCSVOutputDir()).thenReturn(outputDir) menu.onExportCSV() - assertThat(FileUtils.listFiles(outputDir, null, false).size, CoreMatchers.equalTo(1)) + assertThat(FileUtils.listFiles(outputDir, null, false).size, equalTo(1)) FileUtils.deleteDirectory(outputDir) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt index eb7ca2553..e02e5e043 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt @@ -18,8 +18,12 @@ */ package org.isoron.uhabits.core.ui.widgets +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.reset +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.verifyZeroInteractions +import com.nhaarman.mockitokotlin2.whenever 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 @@ -31,44 +35,43 @@ 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 + private lateinit var habit: Habit + private lateinit var today: Timestamp @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) + commandRunner = mock() + notificationTray = mock() + preferences = mock() 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) + behavior.onAddRepetition(habit, today) + verify(commandRunner).run( + CreateRepetitionCommand(habitList, habit, today, Entry.YES_MANUAL) ) - Mockito.verify(notificationTray)!!.cancel(habit!!) - Mockito.verifyZeroInteractions(preferences) + verify(notificationTray).cancel(habit) + verifyZeroInteractions(preferences) } @Test fun testOnRemoveRepetition() { - behavior.onRemoveRepetition(habit!!, today) - Mockito.verify(commandRunner)!!.run( - CreateRepetitionCommand(habitList, habit!!, today!!, Entry.NO) + behavior.onRemoveRepetition(habit, today) + verify(commandRunner).run( + CreateRepetitionCommand(habitList, habit, today, Entry.NO) ) - Mockito.verify(notificationTray)!!.cancel(habit!!) - Mockito.verifyZeroInteractions(preferences) + verify(notificationTray).cancel(habit) + verifyZeroInteractions(preferences) } @Test @@ -81,46 +84,46 @@ class WidgetBehaviorTest : BaseUnitTest() { Entry.SKIP ) ) { - Mockito.`when`(preferences.isSkipEnabled).thenReturn(skipEnabled) + whenever(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) + habit.originalEntries.add(Entry(today, currentValue)) + behavior.onToggleRepetition(habit, today) + verify(preferences).isSkipEnabled + verify(commandRunner).run( + CreateRepetitionCommand(habitList, habit, today, nextValue) ) - Mockito.verify(notificationTray)!!.cancel( - habit!! + verify(notificationTray).cancel( + habit ) - Mockito.reset(preferences, commandRunner, notificationTray) + 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) + habit.originalEntries.add(Entry(today, 500)) + habit.recompute() + behavior.onIncrement(habit, today, 100) + verify(commandRunner).run( + CreateRepetitionCommand(habitList, habit, today, 600) ) - Mockito.verify(notificationTray)!!.cancel(habit!!) - Mockito.verifyZeroInteractions(preferences) + verify(notificationTray).cancel(habit) + 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) + habit.originalEntries.add(Entry(today, 500)) + habit.recompute() + behavior.onDecrement(habit, today, 100) + verify(commandRunner).run( + CreateRepetitionCommand(habitList, habit, today, 400) ) - Mockito.verify(notificationTray)!!.cancel(habit!!) - Mockito.verifyZeroInteractions(preferences) + verify(notificationTray).cancel(habit) + verifyZeroInteractions(preferences) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt index f651d1614..1b440279e 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/utils/DateUtilsTest.kt @@ -19,8 +19,8 @@ package org.isoron.uhabits.core.utils import junit.framework.Assert.assertEquals -import org.hamcrest.CoreMatchers import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.core.IsEqual.equalTo import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.utils.DateUtils.Companion.applyTimezone @@ -42,6 +42,7 @@ import java.util.TimeZone class DateUtilsTest : BaseUnitTest() { var firstWeekday = Calendar.SUNDAY + @Before @Throws(Exception::class) override fun setUp() { @@ -54,7 +55,7 @@ class DateUtilsTest : BaseUnitTest() { val timestamp = unixTime(2015, Calendar.DECEMBER, 31) val date = Timestamp(timestamp).toCalendar() val formatted = formatHeaderDate(date) - assertThat(formatted, CoreMatchers.equalTo("Thu\n31")) + assertThat(formatted, equalTo("Thu\n31")) } @Test @@ -64,24 +65,24 @@ class DateUtilsTest : BaseUnitTest() { 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(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(truncate(field, t0, firstWeekday), CoreMatchers.equalTo(expected)) - assertThat(truncate(field, t1, firstWeekday), CoreMatchers.equalTo(expected)) - assertThat(truncate(field, t2, firstWeekday), CoreMatchers.equalTo(expected)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), equalTo(expected)) } @Test @@ -91,16 +92,16 @@ class DateUtilsTest : BaseUnitTest() { 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), equalTo(expected)) } @Test @@ -110,16 +111,16 @@ class DateUtilsTest : BaseUnitTest() { 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), equalTo(expected)) } @Test @@ -129,16 +130,16 @@ class DateUtilsTest : BaseUnitTest() { 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), 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)) + assertThat(truncate(field, t0, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t1, firstWeekday), equalTo(expected)) + assertThat(truncate(field, t2, firstWeekday), equalTo(expected)) } @Test @@ -146,41 +147,33 @@ class DateUtilsTest : BaseUnitTest() { fun testMillisecondsUntilTomorrow() { setFixedTimeZone(TimeZone.getTimeZone("GMT")) setFixedLocalTime(unixTime(2017, Calendar.JANUARY, 1, 23, 59)) - assertThat( - millisecondsUntilTomorrowWithOffset(), - CoreMatchers.equalTo( - DateUtils.MINUTE_LENGTH - ) - ) + assertThat(millisecondsUntilTomorrowWithOffset(), equalTo(DateUtils.MINUTE_LENGTH)) setFixedLocalTime(unixTime(2017, Calendar.JANUARY, 1, 20, 0)) assertThat( millisecondsUntilTomorrowWithOffset(), - CoreMatchers.equalTo(4 * DateUtils.HOUR_LENGTH) + 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) + 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) + equalTo(2 * DateUtils.HOUR_LENGTH + 30 * DateUtils.MINUTE_LENGTH) ) } @Test @Throws(Exception::class) fun testGetTodayWithOffset() { - assertThat( - getTodayWithOffset(), - CoreMatchers.equalTo(Timestamp(FIXED_LOCAL_TIME)) - ) + assertThat(getTodayWithOffset(), equalTo(Timestamp(FIXED_LOCAL_TIME))) setStartDayOffset(9, 0) assertThat( getTodayWithOffset(), - CoreMatchers.equalTo(Timestamp(FIXED_LOCAL_TIME - DateUtils.DAY_LENGTH)) + equalTo(Timestamp(FIXED_LOCAL_TIME - DateUtils.DAY_LENGTH)) ) } @@ -190,12 +183,12 @@ class DateUtilsTest : BaseUnitTest() { val timestamp = unixTime(2020, Calendar.SEPTEMBER, 3) assertThat( getStartOfDayWithOffset(timestamp + DateUtils.HOUR_LENGTH), - CoreMatchers.equalTo(timestamp) + equalTo(timestamp) ) setStartDayOffset(3, 30) assertThat( getStartOfDayWithOffset(timestamp + 3 * DateUtils.HOUR_LENGTH + 29 * DateUtils.MINUTE_LENGTH), - CoreMatchers.equalTo(timestamp - DateUtils.DAY_LENGTH) + equalTo(timestamp - DateUtils.DAY_LENGTH) ) } diff --git a/uhabits-server/build.gradle b/uhabits-server/build.gradle index 9d9b99672..f108d6a21 100644 --- a/uhabits-server/build.gradle +++ b/uhabits-server/build.gradle @@ -65,7 +65,7 @@ dependencies { implementation "io.prometheus:simpleclient_httpserver:0.9.0" implementation "io.prometheus:simpleclient_hotspot:0.9.0" testImplementation "io.ktor:ktor-server-tests:$ktor_version" - testImplementation "org.mockito:mockito-core:2.+" + testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" } shadowJar { @@ -85,4 +85,4 @@ dockerRun { ports '8080:8080' daemonize false clean true -} \ No newline at end of file +} diff --git a/uhabits-server/src/org/isoron/uhabits/sync/links/Link.kt b/uhabits-server/src/org/isoron/uhabits/sync/links/Link.kt index b28f07207..9adf50614 100644 --- a/uhabits-server/src/org/isoron/uhabits/sync/links/Link.kt +++ b/uhabits-server/src/org/isoron/uhabits/sync/links/Link.kt @@ -19,8 +19,7 @@ package org.isoron.uhabits.sync.links -import org.isoron.uhabits.sync.* -import java.time.* +import org.isoron.uhabits.sync.defaultMapper /** * A Link maps a public URL (such as https://sync.loophabits.org/links/B752A6) diff --git a/uhabits-server/src/org/isoron/uhabits/sync/repository/Repository.kt b/uhabits-server/src/org/isoron/uhabits/sync/repository/Repository.kt index abee43e73..651ca679f 100644 --- a/uhabits-server/src/org/isoron/uhabits/sync/repository/Repository.kt +++ b/uhabits-server/src/org/isoron/uhabits/sync/repository/Repository.kt @@ -19,8 +19,8 @@ package org.isoron.uhabits.sync.repository -import com.sun.org.apache.xpath.internal.operations.* -import org.isoron.uhabits.sync.* +import org.isoron.uhabits.sync.KeyNotFoundException +import org.isoron.uhabits.sync.SyncData /** * A class that knows how to store and retrieve a large number of [SyncData] items. diff --git a/uhabits-server/test/org/isoron/uhabits/sync/app/LinksModuleTest.kt b/uhabits-server/test/org/isoron/uhabits/sync/app/LinksModuleTest.kt index d86ab9f42..ef2bc8963 100644 --- a/uhabits-server/test/org/isoron/uhabits/sync/app/LinksModuleTest.kt +++ b/uhabits-server/test/org/isoron/uhabits/sync/app/LinksModuleTest.kt @@ -19,14 +19,22 @@ package org.isoron.uhabits.sync.app -import io.ktor.http.* -import io.ktor.server.testing.* -import kotlinx.coroutines.* -import org.isoron.uhabits.sync.* -import org.isoron.uhabits.sync.links.* +import com.nhaarman.mockitokotlin2.whenever +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpMethod +import io.ktor.http.HttpStatusCode +import io.ktor.server.testing.TestApplicationCall +import io.ktor.server.testing.TestApplicationEngine +import io.ktor.server.testing.handleRequest +import io.ktor.server.testing.setBody +import io.ktor.server.testing.withTestApplication +import kotlinx.coroutines.runBlocking +import org.isoron.uhabits.sync.KeyNotFoundException +import org.isoron.uhabits.sync.links.Link +import org.isoron.uhabits.sync.links.toJson import org.junit.Test -import org.mockito.Mockito.* -import kotlin.test.* +import kotlin.test.assertEquals class LinksModuleTest : BaseApplicationTest() { private val link = Link( @@ -37,7 +45,7 @@ class LinksModuleTest : BaseApplicationTest() { @Test fun `when POST is successful should return link`(): Unit = runBlocking { - `when`(server.registerLink("SECRET")).thenReturn(link) + whenever(server.registerLink("SECRET")).thenReturn(link) withTestApplication(app()) { handlePost("/links", LinkRegisterRequestData(syncKey = "SECRET")).apply { assertEquals(HttpStatusCode.OK, response.status()) @@ -48,7 +56,7 @@ class LinksModuleTest : BaseApplicationTest() { @Test fun `when GET is successful should return link`(): Unit = runBlocking { - `when`(server.getLink("ABC123")).thenReturn(link) + whenever(server.getLink("ABC123")).thenReturn(link) withTestApplication(app()) { handleGet("/links/ABC123").apply { assertEquals(HttpStatusCode.OK, response.status()) @@ -59,7 +67,7 @@ class LinksModuleTest : BaseApplicationTest() { @Test fun `GET with invalid link id should return 404`(): Unit = runBlocking { - `when`(server.getLink("ABC123")).thenThrow(KeyNotFoundException()) + whenever(server.getLink("ABC123")).thenThrow(KeyNotFoundException()) withTestApplication(app()) { handleGet("/links/ABC123").apply { assertEquals(HttpStatusCode.NotFound, response.status()) @@ -67,7 +75,10 @@ class LinksModuleTest : BaseApplicationTest() { } } - private fun TestApplicationEngine.handlePost(url: String, data: LinkRegisterRequestData): TestApplicationCall { + private fun TestApplicationEngine.handlePost( + url: String, + data: LinkRegisterRequestData + ): TestApplicationCall { return handleRequest(HttpMethod.Post, url) { addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString()) setBody(data.toJson()) @@ -77,5 +88,4 @@ class LinksModuleTest : BaseApplicationTest() { private fun TestApplicationEngine.handleGet(url: String): TestApplicationCall { return handleRequest(HttpMethod.Get, url) } - -} \ No newline at end of file +} diff --git a/uhabits-server/test/org/isoron/uhabits/sync/app/RegistrationModuleTest.kt b/uhabits-server/test/org/isoron/uhabits/sync/app/RegistrationModuleTest.kt index dfb2bfa4c..8fa80883a 100644 --- a/uhabits-server/test/org/isoron/uhabits/sync/app/RegistrationModuleTest.kt +++ b/uhabits-server/test/org/isoron/uhabits/sync/app/RegistrationModuleTest.kt @@ -19,19 +19,20 @@ package org.isoron.uhabits.sync.app -import io.ktor.http.* -import io.ktor.server.testing.* -import kotlinx.coroutines.* -import org.isoron.uhabits.sync.* +import com.nhaarman.mockitokotlin2.whenever +import io.ktor.http.HttpMethod +import io.ktor.http.HttpStatusCode +import io.ktor.server.testing.handleRequest +import io.ktor.server.testing.withTestApplication +import kotlinx.coroutines.runBlocking +import org.isoron.uhabits.sync.ServiceUnavailable import org.junit.Test -import org.mockito.* -import org.mockito.Mockito.* -import kotlin.test.* +import kotlin.test.assertEquals class RegistrationModuleTest : BaseApplicationTest() { @Test - fun `when register succeeds should return generated key`():Unit = runBlocking { - `when`(server.register()).thenReturn("ABCDEF") + fun `when register succeeds should return generated key`(): Unit = runBlocking { + whenever(server.register()).thenReturn("ABCDEF") withTestApplication(app()) { val call = handleRequest(HttpMethod.Post, "/register") assertEquals(HttpStatusCode.OK, call.response.status()) @@ -40,11 +41,11 @@ class RegistrationModuleTest : BaseApplicationTest() { } @Test - fun `when registration is unavailable should return 503`():Unit = runBlocking { - `when`(server.register()).thenThrow(ServiceUnavailable()) + fun `when registration is unavailable should return 503`(): Unit = runBlocking { + whenever(server.register()).thenThrow(ServiceUnavailable()) withTestApplication(app()) { val call = handleRequest(HttpMethod.Post, "/register") assertEquals(HttpStatusCode.ServiceUnavailable, call.response.status()) } } -} \ No newline at end of file +} diff --git a/uhabits-server/test/org/isoron/uhabits/sync/app/StorageModuleTest.kt b/uhabits-server/test/org/isoron/uhabits/sync/app/StorageModuleTest.kt index 9ba4f653f..4165bab5e 100644 --- a/uhabits-server/test/org/isoron/uhabits/sync/app/StorageModuleTest.kt +++ b/uhabits-server/test/org/isoron/uhabits/sync/app/StorageModuleTest.kt @@ -19,6 +19,7 @@ package org.isoron.uhabits.sync.app +import com.nhaarman.mockitokotlin2.whenever import io.ktor.http.* import io.ktor.server.testing.* import kotlinx.coroutines.* @@ -33,7 +34,7 @@ class StorageModuleTest : BaseApplicationTest() { @Test fun `when get succeeds should return data`(): Unit = runBlocking { - `when`(server.getData("k1")).thenReturn(data1) + whenever(server.getData("k1")).thenReturn(data1) withTestApplication(app()) { handleGet("/db/k1").apply { assertEquals(HttpStatusCode.OK, response.status()) @@ -44,7 +45,7 @@ class StorageModuleTest : BaseApplicationTest() { @Test fun `when get version succeeds should return version`(): Unit = runBlocking { - `when`(server.getDataVersion("k1")).thenReturn(30) + whenever(server.getDataVersion("k1")).thenReturn(30) withTestApplication(app()) { handleGet("/db/k1/version").apply { assertEquals(HttpStatusCode.OK, response.status()) @@ -55,7 +56,7 @@ class StorageModuleTest : BaseApplicationTest() { @Test fun `when get with invalid key should return 404`(): Unit = runBlocking { - `when`(server.getData("k1")).thenThrow(KeyNotFoundException()) + whenever(server.getData("k1")).thenThrow(KeyNotFoundException()) withTestApplication(app()) { handleGet("/db/k1").apply { assertEquals(HttpStatusCode.NotFound, response.status()) @@ -78,7 +79,7 @@ class StorageModuleTest : BaseApplicationTest() { @Test fun `when put with invalid key should return 404`(): Unit = runBlocking { - `when`(server.put("k1", data1)).thenThrow(KeyNotFoundException()) + whenever(server.put("k1", data1)).thenThrow(KeyNotFoundException()) withTestApplication(app()) { handlePut("/db/k1", data1).apply { assertEquals(HttpStatusCode.NotFound, response.status()) @@ -88,8 +89,8 @@ class StorageModuleTest : BaseApplicationTest() { @Test fun `when put with invalid version should return 409 and current data`(): Unit = runBlocking { - `when`(server.put("k1", data1)).thenThrow(EditConflictException()) - `when`(server.getData("k1")).thenReturn(data2) + whenever(server.put("k1", data1)).thenThrow(EditConflictException()) + whenever(server.getData("k1")).thenReturn(data2) withTestApplication(app()) { handlePut("/db/k1", data1).apply { assertEquals(HttpStatusCode.Conflict, response.status())