Replace Mockito with Mokkery

This commit is contained in:
Alinson S. Xavier 2026-04-08 03:44:54 -05:00
parent 232be1440e
commit a527389b96
36 changed files with 425 additions and 436 deletions

View File

@ -8,7 +8,6 @@ commonsIo = "1.3.2"
commonsLang3 = "3.14.0"
kotlin-inject = "0.9.0"
desugar = "2.1.4"
dexmaker = "2.28.3"
espresso = "3.6.1"
guava = "33.2.1-android"
hamcrest = "2.2"
@ -25,7 +24,7 @@ ktor = "1.6.8"
ktxCoroutine = "1.10.1"
legacy-support = "1.0.0"
material = "1.12.0"
mockito-kotlin = "5.4.0"
mokkery = "2.7.1"
opencsv = "5.9"
rules = "1.6.1"
shadow = "8.1.1"
@ -43,7 +42,6 @@ commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "co
kotlin-inject-runtime = { group = "me.tatarka.inject", name = "kotlin-inject-runtime", version.ref = "kotlin-inject" }
kotlin-inject-compiler = { group = "me.tatarka.inject", name = "kotlin-inject-compiler-ksp", version.ref = "kotlin-inject" }
desugar_jdk_libs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugar" }
dexmaker-mockito = { group = "com.linkedin.dexmaker", name = "dexmaker-mockito", version.ref = "dexmaker" }
espresso-contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "espresso" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
@ -67,36 +65,16 @@ ktor-jackson = { group = "io.ktor", name = "ktor-jackson", version.ref = "ktor"
legacy-preference-v14 = { group = "androidx.legacy", name = "legacy-preference-v14", version.ref = "legacy-support" }
legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacy-support" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" }
opencsv = { group = "com.opencsv", name = "opencsv", version.ref = "opencsv" }
rules = { group = "androidx.test", name = "rules", version.ref = "rules" }
sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqliteJdbc" }
uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" }
documentfile = { group = "androidx.documentfile", name = "documentfile", version.ref = "documentfile" }
[bundles]
androidTest = [
"annotation",
"kotlin-inject-runtime",
"dexmaker-mockito",
"espresso-contrib",
"espresso-core",
"junit",
"ktor-client-mock",
"ktor-jackson",
"mockito-kotlin",
"rules",
"uiautomator"
]
test = [
"kotlin-inject-runtime",
"junit-junit",
"mockito-kotlin",
]
[plugins]
agp = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
ktlint-plugin = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" }
mokkery = { id = "dev.mokkery", version.ref = "mokkery" }
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }

View File

@ -22,6 +22,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.ktlint.plugin)
alias(libs.plugins.mokkery)
}
tasks.compileLint {
@ -88,6 +89,10 @@ android {
lint.abortOnError = false
}
mokkery {
defaultMockMode.set(dev.mokkery.MockMode.autofill)
}
dependencies {
coreLibraryDesugaring(libs.desugar.jdk.libs)
implementation(libs.appIntro)
@ -111,6 +116,16 @@ dependencies {
implementation(project(":uhabits-core"))
ksp(libs.kotlin.inject.compiler)
androidTestImplementation(libs.bundles.androidTest)
testImplementation(libs.bundles.test)
androidTestImplementation(libs.annotation)
androidTestImplementation(libs.kotlin.inject.runtime)
androidTestImplementation(libs.espresso.contrib)
androidTestImplementation(libs.espresso.core)
androidTestImplementation(libs.junit)
androidTestImplementation(libs.ktor.client.mock)
androidTestImplementation(libs.ktor.jackson)
androidTestImplementation(libs.rules)
androidTestImplementation(libs.uiautomator)
testImplementation(libs.kotlin.inject.runtime)
testImplementation(libs.junit.junit)
}

View File

@ -23,7 +23,6 @@
-keep class org.isoron.** { *; }
-keep class sun.misc.Unsafe { *; }
-keep class android.support.test.** { *; }
-keep class org.mockito.** { *; }
-keep class org.junit.** { *; }
-keep class kotlin.** { *; }

View File

@ -52,10 +52,8 @@ import java.util.concurrent.CountDownLatch
@MediumTest
abstract class BaseAndroidTest : TestCase() {
@JvmField
protected var testContext: Context = InstrumentationRegistry.getInstrumentation().context
@JvmField
protected var targetContext: Context =
InstrumentationRegistry.getInstrumentation().targetContext
protected lateinit var prefs: Preferences

View File

@ -20,6 +20,7 @@
package org.isoron.uhabits
import android.content.Context
import dev.mokkery.mock
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.isoron.uhabits.activities.HabitsDirFinder
@ -37,7 +38,6 @@ import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsSelectionMenuBeh
import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.inject.ActivityScope
import org.isoron.uhabits.inject.HabitsApplicationComponent
import org.mockito.kotlin.mock
@ActivityScope
@Component

View File

@ -20,15 +20,15 @@ package org.isoron.uhabits.activities.habits.list.views
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.mock
import dev.mokkery.verify
import dev.mokkery.verifyNoMoreCalls
import org.isoron.uhabits.BaseViewTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@MediumTest
@ -47,19 +47,19 @@ class HeaderViewTest : BaseViewTest() {
@Test
@Throws(Exception::class)
fun testRender() {
whenever(prefs.isCheckmarkSequenceReversed).thenReturn(false)
every { prefs.isCheckmarkSequenceReversed } returns false
assertRenders(view, PATH + "render.png")
verify(prefs).isCheckmarkSequenceReversed
verifyNoMoreInteractions(prefs)
verify { prefs.isCheckmarkSequenceReversed }
verifyNoMoreCalls(prefs)
}
@Test
@Throws(Exception::class)
fun testRender_reverse() {
doReturn(true).whenever(prefs).isCheckmarkSequenceReversed
every { prefs.isCheckmarkSequenceReversed } returns true
assertRenders(view, PATH + "render_reverse.png")
verify(prefs).isCheckmarkSequenceReversed
verifyNoMoreInteractions(prefs)
verify { prefs.isCheckmarkSequenceReversed }
verifyNoMoreCalls(prefs)
}
companion object {

View File

@ -20,6 +20,9 @@ package org.isoron.uhabits.activities.habits.list.views
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.mock
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.BaseViewTest
@ -27,9 +30,6 @@ import org.isoron.uhabits.core.ui.screens.habits.list.HintList
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@MediumTest
@ -44,8 +44,8 @@ class HintViewTest : BaseViewTest() {
view = HintView(targetContext, list)
measureView(view, 400f, 200f)
val text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
doReturn(true).whenever(list).shouldShow()
doReturn(text).whenever(list).pop()
every { list.shouldShow() } returns true
every { list.pop() } returns text
view.showNext()
skipAnimation(view)
}

View File

@ -25,7 +25,7 @@ import android.os.Parcelable.ClassLoaderCreator
import androidx.customview.view.AbsSavedState
class BundleSavedState : AbsSavedState {
@JvmField val bundle: Bundle?
val bundle: Bundle?
constructor(superState: Parcelable?, bundle: Bundle?) : super(superState!!) {
this.bundle = bundle

View File

@ -28,11 +28,7 @@ import org.isoron.uhabits.core.test.HabitFixtures
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.spy
@RunWith(MockitoJUnitRunner::class)
open class BaseAndroidJVMTest {
private lateinit var habitList: HabitList
protected lateinit var fixtures: HabitFixtures
@ -44,7 +40,7 @@ open class BaseAndroidJVMTest {
open fun setUp() {
setToday(LocalDate(2015, 1, 25))
modelFactory = MemoryModelFactory()
habitList = spy(modelFactory.buildHabitList())
habitList = modelFactory.buildHabitList()
fixtures = HabitFixtures(modelFactory, habitList)
taskRunner = SingleThreadTaskRunner()
commandRunner = CommandRunner(taskRunner)

View File

@ -18,16 +18,15 @@
*/
package org.isoron.uhabits.receivers
import dev.mokkery.mock
import dev.mokkery.verify
import dev.mokkery.verifyNoMoreCalls
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.BaseAndroidJVMTest
import org.isoron.uhabits.core.models.Habit
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.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
class ReminderControllerTest : BaseAndroidJVMTest() {
private lateinit var controller: ReminderController
@ -49,25 +48,25 @@ class ReminderControllerTest : BaseAndroidJVMTest() {
@Test
@Throws(Exception::class)
fun testOnDismiss() {
verifyNoMoreInteractions(reminderScheduler)
verifyNoMoreInteractions(notificationTray)
verifyNoMoreInteractions(preferences)
verifyNoMoreCalls(reminderScheduler)
verifyNoMoreCalls(notificationTray)
verifyNoMoreCalls(preferences)
}
@Test
@Throws(Exception::class)
fun testOnShowReminder() {
val habit: Habit = mock()
val habit = fixtures.createEmptyHabit()
val date = LocalDate(2015, 1, 25)
controller.onShowReminder(habit, date, 456)
verify(notificationTray).show(habit, date, 456)
verify(reminderScheduler).scheduleAll()
verify { notificationTray.show(habit, date, 456) }
verify { reminderScheduler.scheduleAll() }
}
@Test
@Throws(Exception::class)
fun testOnBootCompleted() {
controller.onBootCompleted()
verify(reminderScheduler).scheduleAll()
verify { reminderScheduler.scheduleAll() }
}
}

View File

@ -20,6 +20,7 @@
plugins {
kotlin("multiplatform")
alias(libs.plugins.ktlint.plugin)
alias(libs.plugins.mokkery)
}
kotlin {
@ -61,13 +62,22 @@ kotlin {
implementation(libs.sqlite.jdbc)
implementation(libs.hamcrest)
implementation(libs.commons.io)
implementation(libs.mockito.kotlin)
implementation(libs.junit.jupiter)
}
}
}
}
mokkery {
defaultMockMode.set(dev.mokkery.MockMode.autofill)
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
freeCompilerArgs.add("-Xjvm-default=all")
}
}
tasks.withType<ProcessResources> {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

View File

@ -43,15 +43,15 @@ open class CommandRunner(
)
}
fun addListener(l: Listener) {
open fun addListener(l: Listener) {
listeners.add(l)
}
fun notifyListeners(command: Command) {
open fun notifyListeners(command: Command) {
for (l in listeners) l.onCommandFinished(command)
}
fun removeListener(l: Listener) {
open fun removeListener(l: Listener) {
listeners.remove(l)
}

View File

@ -34,16 +34,12 @@ data class Frequency(
}
companion object {
@JvmField
val DAILY = Frequency(1, 1)
@JvmField
val THREE_TIMES_PER_WEEK = Frequency(3, 7)
@JvmField
val TWO_TIMES_PER_WEEK = Frequency(2, 7)
@JvmField
val WEEKLY = Frequency(1, 7)
}
}

View File

@ -25,10 +25,10 @@ import org.isoron.platform.io.format
* An ordered collection of [Habit]s.
*/
abstract class HabitList : Iterable<Habit> {
val observable: ModelObservable
open val observable: ModelObservable = ModelObservable()
@JvmField
protected val filter: HabitMatcher
open var filter: HabitMatcher = HabitMatcher(isArchivedAllowed = true)
internal set
/**
* Creates a new HabitList.
@ -37,13 +37,9 @@ abstract class HabitList : Iterable<Habit> {
* populated by some pre-existing habits, for example, from a certain
* database.
*/
constructor() {
observable = ModelObservable()
filter = HabitMatcher(isArchivedAllowed = true)
}
constructor()
protected constructor(filter: HabitMatcher) {
observable = ModelObservable()
this.filter = filter
}
@ -104,7 +100,7 @@ abstract class HabitList : Iterable<Habit> {
* @return the index of the habit, or -1 if not in the list
*/
abstract fun indexOf(h: Habit): Int
val isEmpty: Boolean
open val isEmpty: Boolean
get() = size() == 0
/**
@ -159,7 +155,7 @@ abstract class HabitList : Iterable<Habit> {
*
* @param habit the habit that has been modified.
*/
fun update(habit: Habit) {
open fun update(habit: Habit) {
update(listOf(habit))
}
@ -168,7 +164,7 @@ abstract class HabitList : Iterable<Habit> {
* habit, containing the fields name, description, frequency numerator,
* frequency denominator and color.
*/
fun writeCSV(): String {
open fun writeCSV(): String {
val sb = StringBuilder()
val header = arrayOf(
"Position",

View File

@ -33,7 +33,6 @@ data class HabitMatcher(
}
companion object {
@JvmField
val WITH_ALARM = HabitMatcher(
isArchivedAllowed = true,
isReminderRequired = true

View File

@ -25,7 +25,7 @@ import org.isoron.uhabits.core.models.HabitMatcher
/**
* In-memory implementation of [HabitList].
*/
class MemoryHabitList : HabitList {
open class MemoryHabitList : HabitList {
private val list = mutableListOf<Habit>()
@get:Synchronized

View File

@ -31,18 +31,18 @@ import kotlin.math.min
open class Preferences(private val storage: Storage) {
private val listeners: MutableList<Listener>
private var shouldReverseCheckmarks: Boolean? = null
fun addListener(listener: Listener) {
open fun addListener(listener: Listener) {
listeners.add(listener)
}
fun getDefaultHabitColor(fallbackColor: Int): Int {
open fun getDefaultHabitColor(fallbackColor: Int): Int {
return storage.getInt(
"pref_default_habit_palette_color",
fallbackColor
)
}
var defaultPrimaryOrder: HabitList.Order
open var defaultPrimaryOrder: HabitList.Order
get() {
val name = storage.getString("pref_default_order", "BY_POSITION")
return try {
@ -55,7 +55,7 @@ open class Preferences(private val storage: Storage) {
set(order) {
storage.putString("pref_default_order", order.name)
}
var defaultSecondaryOrder: HabitList.Order
open var defaultSecondaryOrder: HabitList.Order
get() {
val name = storage.getString("pref_default_secondary_order", "BY_NAME_ASC")
return try {
@ -68,22 +68,22 @@ open class Preferences(private val storage: Storage) {
set(order) {
storage.putString("pref_default_secondary_order", order.name)
}
var scoreCardSpinnerPosition: Int
open var scoreCardSpinnerPosition: Int
get() = min(4, max(0, storage.getInt("pref_score_view_interval", 1)))
set(position) {
storage.putInt("pref_score_view_interval", position)
}
var barCardBoolSpinnerPosition: Int
open var barCardBoolSpinnerPosition: Int
get() = min(3, max(0, storage.getInt("pref_bar_card_bool_spinner", 0)))
set(position) {
storage.putInt("pref_bar_card_bool_spinner", position)
}
var barCardNumericalSpinnerPosition: Int
open var barCardNumericalSpinnerPosition: Int
get() = min(4, max(0, storage.getInt("pref_bar_card_numerical_spinner", 0)))
set(position) {
storage.putInt("pref_bar_card_numerical_spinner", position)
}
val lastHintNumber: Int
open val lastHintNumber: Int
get() = storage.getInt("last_hint_number", -1)
open val lastHintDate: LocalDate?
get() {
@ -91,74 +91,74 @@ open class Preferences(private val storage: Storage) {
return if (unixTime < 0) null else LocalDate.fromUnixTime(unixTime)
}
var showArchived: Boolean
open var showArchived: Boolean
get() = storage.getBoolean("pref_show_archived", false)
set(showArchived) {
storage.putBoolean("pref_show_archived", showArchived)
}
var showCompleted: Boolean
open var showCompleted: Boolean
get() = storage.getBoolean("pref_show_completed", true)
set(showCompleted) {
storage.putBoolean("pref_show_completed", showCompleted)
}
var theme: Int
open var theme: Int
get() = storage.getInt("pref_theme", ThemeSwitcher.THEME_AUTOMATIC)
set(theme) {
storage.putInt("pref_theme", theme)
}
fun incrementLaunchCount() {
open fun incrementLaunchCount() {
storage.putInt("launch_count", launchCount + 1)
}
val launchCount: Int
open val launchCount: Int
get() = storage.getInt("launch_count", 0)
var isDeveloper: Boolean
open var isDeveloper: Boolean
get() = storage.getBoolean("pref_developer", false)
set(isDeveloper) {
storage.putBoolean("pref_developer", isDeveloper)
}
var isFirstRun: Boolean
open var isFirstRun: Boolean
get() = storage.getBoolean("pref_first_run", true)
set(isFirstRun) {
storage.putBoolean("pref_first_run", isFirstRun)
}
var isPureBlackEnabled: Boolean
open var isPureBlackEnabled: Boolean
get() = storage.getBoolean("pref_pure_black", false)
set(enabled) {
storage.putBoolean("pref_pure_black", enabled)
}
var isShortToggleEnabled: Boolean
open var isShortToggleEnabled: Boolean
get() = storage.getBoolean("pref_short_toggle", false)
set(enabled) {
storage.putBoolean("pref_short_toggle", enabled)
}
var isConfettiAnimationDisabled: Boolean
open var isConfettiAnimationDisabled: Boolean
get() = storage.getBoolean("pref_disable_animation", false)
set(enabled) {
storage.putBoolean("pref_disable_animation", enabled)
}
fun removeListener(listener: Listener) {
open fun removeListener(listener: Listener) {
listeners.remove(listener)
}
fun clear() {
open fun clear() {
storage.clear()
}
fun setDefaultHabitColor(color: Int) {
open fun setDefaultHabitColor(color: Int) {
storage.putInt("pref_default_habit_palette_color", color)
}
fun setNotificationsSticky(sticky: Boolean) {
open fun setNotificationsSticky(sticky: Boolean) {
storage.putBoolean("pref_sticky_notifications", sticky)
for (l in listeners) l.onNotificationsChanged()
}
fun shouldMakeNotificationsSticky(): Boolean {
open fun shouldMakeNotificationsSticky(): Boolean {
return storage.getBoolean("pref_sticky_notifications", false)
}
@ -183,35 +183,35 @@ open class Preferences(private val storage: Storage) {
for (l in listeners) l.onCheckmarkSequenceChanged()
}
val midnightDelayHours: Int
open val midnightDelayHours: Int
get() = if (isMidnightDelayEnabled) MIDNIGHT_DELAY_HOURS else 0
companion object {
const val MIDNIGHT_DELAY_HOURS = 3
}
fun updateLastHint(number: Int, date: LocalDate) {
open fun updateLastHint(number: Int, date: LocalDate) {
storage.putInt("last_hint_number", number)
storage.putLong("last_hint_timestamp", date.unixTime)
}
var lastAppVersion: Int
open var lastAppVersion: Int
get() = storage.getInt("last_version", 0)
set(version) {
storage.putInt("last_version", version)
}
var widgetOpacity: Int
open var widgetOpacity: Int
get() = storage.getString("pref_widget_opacity", "255").toInt()
set(value) {
storage.putString("pref_widget_opacity", value.toString())
}
var isSkipEnabled: Boolean
open var isSkipEnabled: Boolean
get() = storage.getBoolean("pref_skip_enabled", false)
set(value) {
storage.putBoolean("pref_skip_enabled", value)
}
var areQuestionMarksEnabled: Boolean
open var areQuestionMarksEnabled: Boolean
get() = storage.getBoolean("pref_unknown_enabled", false)
set(value) {
storage.putBoolean("pref_unknown_enabled", value)
@ -225,12 +225,12 @@ open class Preferences(private val storage: Storage) {
* unless the user changed this in the settings.
*/
@get:Deprecated("")
val firstWeekdayInt: Int
open val firstWeekdayInt: Int
get() {
val weekday = storage.getString("pref_first_weekday", "")
return if (weekday.isEmpty()) getFirstWeekdayNumberAccordingToLocale() else weekday.toInt()
}
val firstWeekday: DayOfWeek
open val firstWeekday: DayOfWeek
get() {
var weekday = storage.getString("pref_first_weekday", "-1").toInt()
if (weekday < 0) weekday = getFirstWeekdayNumberAccordingToLocale()
@ -258,7 +258,7 @@ open class Preferences(private val storage: Storage) {
fun getInt(key: String, defValue: Int): Int
fun getLong(key: String, defValue: Long): Long
fun getString(key: String, defValue: String): String
fun onAttached(preferences: Preferences)
fun onAttached(preferences: Preferences) {}
fun putBoolean(key: String, value: Boolean)
fun putInt(key: String, value: Int)
fun putLong(key: String, value: Long)

View File

@ -24,12 +24,12 @@ import org.isoron.uhabits.core.AppScope
@AppScope
@Inject
class WidgetPreferences(private val storage: Preferences.Storage) {
fun addWidget(widgetId: Int, habitIds: LongArray) {
open class WidgetPreferences(private val storage: Preferences.Storage) {
open fun addWidget(widgetId: Int, habitIds: LongArray) {
storage.putLongArray(getHabitIdKey(widgetId), habitIds)
}
fun getHabitIdsFromWidgetId(widgetId: Int): LongArray {
open fun getHabitIdsFromWidgetId(widgetId: Int): LongArray {
val habitIdKey = getHabitIdKey(widgetId)
return try {
storage.getLongArray(habitIdKey, longArrayOf())
@ -43,12 +43,12 @@ class WidgetPreferences(private val storage: Preferences.Storage) {
}
}
fun removeWidget(id: Int) {
open fun removeWidget(id: Int) {
val habitIdKey = getHabitIdKey(id)
storage.remove(habitIdKey)
}
fun getSnoozeTime(id: Long): Long {
open fun getSnoozeTime(id: Long): Long {
return storage.getLong(getSnoozeKey(id), 0)
}
@ -60,11 +60,11 @@ class WidgetPreferences(private val storage: Preferences.Storage) {
return format("snooze-%06d", id.toInt())
}
fun removeSnoozeTime(id: Long) {
open fun removeSnoozeTime(id: Long) {
storage.putLong(getSnoozeKey(id), 0)
}
fun setSnoozeTime(id: Long, time: Long) {
open fun setSnoozeTime(id: Long, time: Long) {
storage.putLong(getSnoozeKey(id), time)
}
}

View File

@ -33,14 +33,14 @@ import org.isoron.uhabits.core.tasks.TaskRunner
@AppScope
@Inject
class NotificationTray(
open class NotificationTray(
private val taskRunner: TaskRunner,
private val commandRunner: CommandRunner,
private val preferences: Preferences,
private val systemTray: SystemTray
) : CommandRunner.Listener, Preferences.Listener {
private val active: MutableMap<Habit, NotificationData> = mutableMapOf()
fun cancel(habit: Habit) {
open fun cancel(habit: Habit) {
val notificationId = getNotificationId(habit)
systemTray.removeNotification(notificationId)
active.remove(habit)
@ -61,18 +61,18 @@ class NotificationTray(
reshowAll()
}
fun show(habit: Habit, date: LocalDate, reminderTime: Long) {
open fun show(habit: Habit, date: LocalDate, reminderTime: Long) {
val data = NotificationData(date, reminderTime)
active[habit] = data
taskRunner.execute(ShowNotificationTask(habit, data))
}
fun startListening() {
open fun startListening() {
commandRunner.addListener(this)
preferences.addListener(this)
}
fun stopListening() {
open fun stopListening() {
commandRunner.removeListener(this)
preferences.removeListener(this)
}
@ -88,7 +88,7 @@ class NotificationTray(
}
}
fun reshow(habit: Habit) {
open fun reshow(habit: Habit) {
active[habit]?.let {
taskRunner.execute(ShowNotificationTask(habit, it))
}

View File

@ -22,7 +22,7 @@ import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.views.Theme
abstract class ThemeSwitcher(private val preferences: Preferences) {
fun apply() {
open fun apply() {
if (isNightMode) {
if (preferences.isPureBlackEnabled) applyPureBlackTheme() else applyDarkTheme()
} else {
@ -35,7 +35,7 @@ abstract class ThemeSwitcher(private val preferences: Preferences) {
abstract fun applyPureBlackTheme()
abstract fun getSystemTheme(): Int
abstract val currentTheme: Theme?
val isNightMode: Boolean
open val isNightMode: Boolean
get() {
val systemTheme = getSystemTheme()
val userTheme = preferences.theme
@ -43,7 +43,7 @@ abstract class ThemeSwitcher(private val preferences: Preferences) {
systemTheme == THEME_DARK && userTheme == THEME_AUTOMATIC
}
fun toggleNightMode() {
open fun toggleNightMode() {
val systemTheme = getSystemTheme()
val userTheme = preferences.theme
if (userTheme == THEME_AUTOMATIC) {

View File

@ -48,11 +48,11 @@ open class ListHabitsBehavior(
private val prefs: Preferences,
private val bugReporter: BugReporter
) {
fun onClickHabit(h: Habit) {
open fun onClickHabit(h: Habit) {
screen.showHabitScreen(h)
}
fun onEdit(habit: Habit, date: LocalDate, x: Float, y: Float) {
open fun onEdit(habit: Habit, date: LocalDate, x: Float, y: Float) {
val entry = habit.computedEntries.get(date)
if (habit.type == HabitType.NUMERICAL) {
val oldValue = entry.value.toDouble() / 1000
@ -80,7 +80,7 @@ open class ListHabitsBehavior(
}
}
fun onExportCSV() {
open fun onExportCSV() {
val selected = habitList.toList()
val outputDir = dirFinder.getCSVOutputDir()
taskRunner.execute(
@ -96,24 +96,24 @@ open class ListHabitsBehavior(
)
}
fun onFirstRun() {
open fun onFirstRun() {
prefs.isFirstRun = false
prefs.updateLastHint(-1, getToday())
screen.showIntroScreen()
}
fun onReorderHabit(from: Habit, to: Habit) {
open fun onReorderHabit(from: Habit, to: Habit) {
taskRunner.execute { habitList.reorder(from, to) }
}
fun onRepairDB() {
open fun onRepairDB() {
taskRunner.execute {
habitList.repair()
screen.showMessage(Message.DATABASE_REPAIRED)
}
}
fun onSendBugReport() {
open fun onSendBugReport() {
bugReporter.dumpBugReportToFile()
try {
val log = bugReporter.getBugReport()
@ -124,12 +124,12 @@ open class ListHabitsBehavior(
}
}
fun onStartup() {
open fun onStartup() {
prefs.incrementLaunchCount()
if (prefs.isFirstRun) onFirstRun()
}
fun onToggle(habit: Habit, date: LocalDate, value: Int, notes: String, x: Float, y: Float) {
open fun onToggle(habit: Habit, date: LocalDate, value: Int, notes: String, x: Float, y: Float) {
commandRunner.run(
CreateRepetitionCommand(habitList, habit, date, value, notes)
)

View File

@ -32,7 +32,7 @@ import org.isoron.uhabits.core.preferences.WidgetPreferences
@AppScope
@Inject
class ReminderScheduler(
open class ReminderScheduler(
private val commandRunner: CommandRunner,
private val habitList: HabitList,
private val sys: SystemScheduler,
@ -46,7 +46,7 @@ class ReminderScheduler(
}
@Synchronized
fun schedule(habit: Habit) {
open fun schedule(habit: Habit) {
if (habit.id == null) {
sys.log("ReminderScheduler", "Habit has null id. Returning.")
return
@ -75,7 +75,7 @@ class ReminderScheduler(
}
@Synchronized
fun scheduleAtTime(habit: Habit, reminderTime: Long) {
open fun scheduleAtTime(habit: Habit, reminderTime: Long) {
sys.log("ReminderScheduler", "Scheduling alarm for habit=" + habit.id)
if (!habit.hasReminder()) {
sys.log("ReminderScheduler", "habit=" + habit.id + " has no reminder. Skipping.")
@ -91,29 +91,29 @@ class ReminderScheduler(
}
@Synchronized
fun scheduleAll() {
open fun scheduleAll() {
sys.log("ReminderScheduler", "Scheduling all alarms")
val reminderHabits = habitList.getFiltered(HabitMatcher.WITH_ALARM)
for (habit in reminderHabits) schedule(habit)
}
@Synchronized
fun hasHabitsWithReminders(): Boolean {
open fun hasHabitsWithReminders(): Boolean {
return !habitList.getFiltered(HabitMatcher.WITH_ALARM).isEmpty
}
@Synchronized
fun startListening() {
open fun startListening() {
commandRunner.addListener(this)
}
@Synchronized
fun stopListening() {
open fun stopListening() {
commandRunner.removeListener(this)
}
@Synchronized
fun snoozeReminder(habit: Habit, minutes: Long) {
open fun snoozeReminder(habit: Habit, minutes: Long) {
val now = DateUtils.applyTimezone(DateUtils.getLocalTime())
val snoozedUntil = now + minutes * 60 * 1000
widgetPreferences.setSnoozeTime(habit.id!!, snoozedUntil)

View File

@ -44,18 +44,18 @@ open class MidnightTimer(
private val logger = logging.getLogger("MidnightTimer")
@Synchronized
fun addListener(listener: MidnightListener) {
open fun addListener(listener: MidnightListener) {
this.listeners.add(listener)
}
@Synchronized
fun onPause(): MutableList<Runnable>? {
open fun onPause(): MutableList<Runnable>? {
logger.info("Pausing timer")
return executor.shutdownNow()
}
@Synchronized
fun onResume(
open fun onResume(
delayOffsetInMillis: Long = DateUtils.SECOND_LENGTH,
testExecutor: ScheduledExecutorService? = null
) {
@ -71,7 +71,7 @@ open class MidnightTimer(
}
@Synchronized
fun removeListener(listener: MidnightListener) = this.listeners.remove(listener)
open fun removeListener(listener: MidnightListener) = this.listeners.remove(listener)
@Synchronized
private fun notifyListeners() {

View File

@ -18,17 +18,13 @@
*/
package org.isoron.uhabits.core
import dev.mokkery.spy
import org.apache.commons.io.IOUtils
import org.isoron.platform.io.JavaDatabaseOpener
import org.isoron.uhabits.core.models.memory.MemoryModelFactory
import org.isoron.uhabits.core.test.HabitFixtures
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.spy
import org.mockito.kotlin.validateMockitoUsage
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
@ -38,7 +34,6 @@ import java.nio.file.Paths
import java.util.GregorianCalendar
import java.util.TimeZone
@RunWith(MockitoJUnitRunner::class)
open class JvmBaseUnitTest : BaseUnitTest() {
protected var databaseOpener: org.isoron.platform.io.DatabaseOpener = JavaDatabaseOpener()
@ -49,12 +44,6 @@ open class JvmBaseUnitTest : BaseUnitTest() {
fixtures = HabitFixtures(modelFactory as MemoryModelFactory, habitList)
}
@After
@Throws(Exception::class)
open fun tearDown() {
validateMockitoUsage()
}
fun unixTime(year: Int, month: Int, day: Int): Long {
return unixTime(year, month, day, 0, 0)
}

View File

@ -18,6 +18,8 @@
*/
package org.isoron.uhabits.core.models.sqlite
import dev.mokkery.mock
import dev.mokkery.verify
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.JvmBaseUnitTest
@ -29,10 +31,9 @@ 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.test.HabitFixtures
import org.junit.After
import org.junit.Assert.assertThrows
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import java.util.ArrayList
import kotlin.test.assertNull
@ -74,17 +75,16 @@ class SQLiteHabitListTest : JvmBaseUnitTest() {
habitList.observable.addListener(listener)
}
@Throws(Exception::class)
override fun tearDown() {
@After
fun tearDown() {
habitList.observable.removeListener(listener)
super.tearDown()
}
@Test
fun testAdd_withDuplicate() {
val habit = modelFactory.buildHabit()
habitList.add(habit)
verify(listener).onModelChange()
verify { listener.onModelChange() }
assertThrows(IllegalArgumentException::class.java) {
habitList.add(habit)
}

View File

@ -18,6 +18,11 @@
*/
package org.isoron.uhabits.core.reminders
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.matcher.any
import dev.mokkery.mock
import dev.mokkery.verify
import org.isoron.platform.time.DateUtils
import org.isoron.platform.time.DateUtils.removeTimezone
import org.isoron.platform.time.DateUtils.setFixedLocalTime
@ -30,16 +35,8 @@ import org.isoron.uhabits.core.preferences.WidgetPreferences
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import java.util.TimeZone
@RunWith(MockitoJUnitRunner::class)
class ReminderSchedulerTest : JvmBaseUnitTest() {
private val habitId = 10L
private lateinit var habit: Habit
@ -60,8 +57,7 @@ class ReminderSchedulerTest : JvmBaseUnitTest() {
}
@After
override fun tearDown() {
super.tearDown()
fun tearDown() {
setFixedLocalTime(null)
setFixedTimeZone(null)
}
@ -80,16 +76,20 @@ class ReminderSchedulerTest : JvmBaseUnitTest() {
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()
)
verify {
sys.scheduleShowReminder(
unixTime(2015, 1, 27, 12, 30),
h1,
any()
)
}
verify {
sys.scheduleShowReminder(
unixTime(2015, 1, 26, 22, 30),
h2,
any()
)
}
}
@Test
@ -110,13 +110,14 @@ class ReminderSchedulerTest : JvmBaseUnitTest() {
val todayCheckmarkTime = unixTime(2015, 1, 1, 0, 0)
val tomorrowCheckmarkTime = unixTime(2015, 1, 2, 0, 0)
habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY)
whenever(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInFuture)
every { widgetPreferences.getSnoozeTime(habitId) } returns snoozeTimeInFuture
reminderScheduler.schedule(habit)
verify(sys).scheduleShowReminder(snoozeTimeInFuture, habit, todayCheckmarkTime)
whenever(widgetPreferences.getSnoozeTime(habitId)).thenReturn(snoozeTimeInPast)
verify { sys.scheduleShowReminder(snoozeTimeInFuture, habit, todayCheckmarkTime) }
every { widgetPreferences.getSnoozeTime(habitId) } returns snoozeTimeInPast
reminderScheduler.schedule(habit)
verify(sys)
.scheduleShowReminder(regularReminderTime, habit, tomorrowCheckmarkTime)
verify {
sys.scheduleShowReminder(regularReminderTime, habit, tomorrowCheckmarkTime)
}
}
@Test
@ -164,10 +165,12 @@ class ReminderSchedulerTest : JvmBaseUnitTest() {
atTime
)
}
verify(sys).scheduleShowReminder(
expectedReminderTime,
habit,
expectedCheckmarkTime
)
verify {
sys.scheduleShowReminder(
expectedReminderTime,
habit,
expectedCheckmarkTime
)
}
}
}

View File

@ -18,12 +18,13 @@
*/
package org.isoron.uhabits.core.tasks
import dev.mokkery.mock
import dev.mokkery.verify
import dev.mokkery.verify.VerifyMode.Companion.order
import org.isoron.uhabits.core.JvmBaseUnitTest
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.kotlin.inOrder
import org.mockito.kotlin.mock
@RunWith(JUnit4::class)
class SingleThreadTaskRunnerTest : JvmBaseUnitTest() {
@ -39,10 +40,11 @@ class SingleThreadTaskRunnerTest : JvmBaseUnitTest() {
@Test
fun test() {
runner.execute(task)
val inOrder = inOrder(task)
inOrder.verify(task).onAttached(runner)
inOrder.verify(task).onPreExecute()
inOrder.verify(task).doInBackground()
inOrder.verify(task).onPostExecute()
verify(order) {
task.onAttached(runner)
task.onPreExecute()
task.doInBackground()
task.onPostExecute()
}
}
}

View File

@ -18,6 +18,10 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import dev.mokkery.mock
import dev.mokkery.resetCalls
import dev.mokkery.verify
import dev.mokkery.verifyNoMoreCalls
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.platform.time.LocalDate
@ -26,10 +30,6 @@ import org.isoron.uhabits.core.commands.CreateRepetitionCommand
import org.isoron.uhabits.core.commands.DeleteHabitsCommand
import org.isoron.uhabits.core.models.Entry
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.reset
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
class HabitCardListCacheTest : JvmBaseUnitTest() {
private lateinit var cache: HabitCardListCache
@ -51,7 +51,7 @@ class HabitCardListCacheTest : JvmBaseUnitTest() {
cache.setListener(listener)
}
override fun tearDown() {
fun tearDown() {
cache.onDetached()
}
@ -62,8 +62,8 @@ class HabitCardListCacheTest : JvmBaseUnitTest() {
commandRunner.run(
DeleteHabitsCommand(habitList, listOf(h))
)
verify(listener).onItemRemoved(0)
verify(listener).onRefreshFinished()
verify { listener.onItemRemoved(0) }
verify { listener.onRefreshFinished() }
assertThat(cache.habitCount, equalTo(9))
}
@ -71,9 +71,9 @@ class HabitCardListCacheTest : JvmBaseUnitTest() {
fun testCommandListener_single() {
val h2 = habitList.getByPosition(2)
commandRunner.run(CreateRepetitionCommand(habitList, h2, today, Entry.NO, ""))
verify(listener).onItemChanged(2)
verify(listener).onRefreshFinished()
verifyNoMoreInteractions(listener)
verify { listener.onItemChanged(2) }
verify { listener.onRefreshFinished() }
verifyNoMoreCalls(listener)
}
@Test
@ -97,17 +97,17 @@ class HabitCardListCacheTest : JvmBaseUnitTest() {
removeHabitAt(0)
removeHabitAt(3)
cache.refreshAllHabits()
verify(listener).onItemRemoved(0)
verify(listener).onItemRemoved(3)
verify(listener).onRefreshFinished()
verify { listener.onItemRemoved(0) }
verify { listener.onItemRemoved(3) }
verify { listener.onRefreshFinished() }
assertThat(cache.habitCount, equalTo(8))
}
@Test
fun testRefreshWithNoChanges() {
cache.refreshAllHabits()
verify(listener).onRefreshFinished()
verifyNoMoreInteractions(listener)
verify { listener.onRefreshFinished() }
verifyNoMoreCalls(listener)
}
@Test
@ -119,8 +119,8 @@ class HabitCardListCacheTest : JvmBaseUnitTest() {
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)
verify { listener.onItemMoved(2, 7) }
verifyNoMoreCalls(listener)
}
@Test
@ -130,19 +130,19 @@ class HabitCardListCacheTest : JvmBaseUnitTest() {
val h7 = habitList.getByPosition(7)
assertThat(cache.getHabitByPosition(2), equalTo(h2))
assertThat(cache.getHabitByPosition(7), equalTo(h7))
reset(listener)
resetCalls(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)
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() }
verifyNoMoreCalls(listener)
}
private fun removeHabitAt(position: Int) {

View File

@ -18,6 +18,10 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.mock
import dev.mokkery.verify
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.isoron.platform.time.LocalDate
@ -25,9 +29,6 @@ import org.isoron.platform.time.getToday
import org.isoron.uhabits.core.JvmBaseUnitTest
import org.isoron.uhabits.core.preferences.Preferences
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
@ -52,19 +53,19 @@ class HintListTest : JvmBaseUnitTest() {
@Test
@Throws(Exception::class)
fun pop() {
whenever(prefs.lastHintNumber).thenReturn(-1)
every { prefs.lastHintNumber } returns -1
assertThat(hintList.pop(), equalTo("hint1"))
verify(prefs).updateLastHint(0, today)
whenever(prefs.lastHintNumber).thenReturn(2)
verify { prefs.updateLastHint(0, today) }
every { prefs.lastHintNumber } returns 2
assertNull(hintList.pop())
}
@Test
@Throws(Exception::class)
fun shouldShow() {
whenever(prefs.lastHintDate).thenReturn(today)
every { prefs.lastHintDate } returns today
assertFalse(hintList.shouldShow())
whenever(prefs.lastHintDate).thenReturn(yesterday)
every { prefs.lastHintDate } returns yesterday
assertTrue(hintList.shouldShow())
}
}

View File

@ -18,6 +18,14 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import dev.mokkery.answering.calls
import dev.mokkery.answering.returns
import dev.mokkery.answering.throws
import dev.mokkery.every
import dev.mokkery.matcher.any
import dev.mokkery.mock
import dev.mokkery.resetCalls
import dev.mokkery.verify
import org.apache.commons.io.FileUtils
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual.equalTo
@ -30,14 +38,6 @@ import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.callbacks.NumberPickerCallback
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.KArgumentCaptor
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.clearInvocations
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import java.nio.file.Files
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -52,7 +52,7 @@ class ListHabitsBehaviorTest : JvmBaseUnitTest() {
private lateinit var habit1: Habit
private lateinit var habit2: Habit
var picker: KArgumentCaptor<NumberPickerCallback> = argumentCaptor()
private var capturedPicker: NumberPickerCallback? = null
private val bugReporter: ListHabitsBehavior.BugReporter = mock()
@ -64,7 +64,7 @@ class ListHabitsBehaviorTest : JvmBaseUnitTest() {
habit2 = fixtures.createNumericalHabit()
habitList.add(habit1)
habitList.add(habit2)
clearInvocations(habitList)
resetCalls(habitList)
behavior = ListHabitsBehavior(
habitList,
dirFinder,
@ -79,13 +79,17 @@ class ListHabitsBehaviorTest : JvmBaseUnitTest() {
@Test
fun testOnEdit() {
val today = getToday()
every {
screen.showNumberPopup(any(), any(), any())
} calls { args ->
capturedPicker = args.arg<NumberPickerCallback>(2)
Unit
}
behavior.onEdit(habit2, today, 0f, 0f)
verify(screen).showNumberPopup(
eq(0.1),
eq(""),
picker.capture()
)
picker.lastValue.onNumberPicked(100.0, "")
verify {
screen.showNumberPopup(0.1, "", any())
}
capturedPicker!!.onNumberPicked(100.0, "")
assertThat(habit2.computedEntries.get(today).value, equalTo(100000))
}
@ -93,9 +97,9 @@ class ListHabitsBehaviorTest : JvmBaseUnitTest() {
@Throws(Exception::class)
fun testOnExportCSV() {
val outputDir = Files.createTempDirectory("CSV").toFile()
whenever(dirFinder.getCSVOutputDir()).thenReturn(JavaUserFile(outputDir.toPath()))
every { dirFinder.getCSVOutputDir() } returns JavaUserFile(outputDir.toPath())
behavior.onExportCSV()
verify(screen).showSendFileScreen(any())
verify { screen.showSendFileScreen(any()) }
assertThat(FileUtils.listFiles(outputDir, null, false).size, equalTo(1))
FileUtils.deleteDirectory(outputDir)
}
@ -105,16 +109,16 @@ class ListHabitsBehaviorTest : JvmBaseUnitTest() {
fun testOnExportCSV_fail() {
val outputDir = Files.createTempDirectory("CSV").toFile()
outputDir.setWritable(false)
whenever(dirFinder.getCSVOutputDir()).thenReturn(JavaUserFile(outputDir.toPath()))
every { dirFinder.getCSVOutputDir() } returns JavaUserFile(outputDir.toPath())
behavior.onExportCSV()
verify(screen).showMessage(ListHabitsBehavior.Message.COULD_NOT_EXPORT)
verify { screen.showMessage(ListHabitsBehavior.Message.COULD_NOT_EXPORT) }
assertTrue(outputDir.delete())
}
@Test
fun testOnHabitClick() {
behavior.onClickHabit(habit1)
verify(screen).showHabitScreen(habit1)
verify { screen.showHabitScreen(habit1) }
}
@Test
@ -122,42 +126,42 @@ class ListHabitsBehaviorTest : JvmBaseUnitTest() {
val from = habit1
val to = habit2
behavior.onReorderHabit(from, to)
verify(habitList).reorder(from, to)
verify { habitList.reorder(from, to) }
}
@Test
fun testOnRepairDB() {
behavior.onRepairDB()
verify(habitList).repair()
verify(screen).showMessage(ListHabitsBehavior.Message.DATABASE_REPAIRED)
verify { habitList.repair() }
verify { screen.showMessage(ListHabitsBehavior.Message.DATABASE_REPAIRED) }
}
@Test
fun testOnSendBugReport() {
whenever(bugReporter.getBugReport()).thenReturn("hello")
every { bugReporter.getBugReport() } returns "hello"
behavior.onSendBugReport()
verify(bugReporter).dumpBugReportToFile()
verify(screen).showSendBugReportToDeveloperScreen("hello")
whenever(bugReporter.getBugReport()).thenThrow(RuntimeException())
verify { bugReporter.dumpBugReportToFile() }
verify { screen.showSendBugReportToDeveloperScreen("hello") }
every { bugReporter.getBugReport() } throws RuntimeException()
behavior.onSendBugReport()
verify(screen).showMessage(ListHabitsBehavior.Message.COULD_NOT_GENERATE_BUG_REPORT)
verify { screen.showMessage(ListHabitsBehavior.Message.COULD_NOT_GENERATE_BUG_REPORT) }
}
@Test
fun testOnStartup_firstLaunch() {
val today = getToday()
whenever(prefs.isFirstRun).thenReturn(true)
every { prefs.isFirstRun } returns true
behavior.onStartup()
verify(prefs).isFirstRun = false
verify(prefs).updateLastHint(-1, today)
verify(screen).showIntroScreen()
verify { prefs.isFirstRun = false }
verify { prefs.updateLastHint(-1, today) }
verify { screen.showIntroScreen() }
}
@Test
fun testOnStartup_notFirstLaunch() {
whenever(prefs.isFirstRun).thenReturn(false)
every { prefs.isFirstRun } returns false
behavior.onStartup()
verify(prefs).incrementLaunchCount()
verify { prefs.incrementLaunchCount() }
}
@Test

View File

@ -18,25 +18,20 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.matcher.any
import dev.mokkery.mock
import dev.mokkery.resetCalls
import dev.mokkery.verify
import dev.mokkery.verifyNoMoreCalls
import org.isoron.uhabits.core.JvmBaseUnitTest
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.kotlin.KArgumentCaptor
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.clearInvocations
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import dev.mokkery.verify.VerifyMode.Companion.not as notCalled
class ListHabitsMenuBehaviorTest : JvmBaseUnitTest() {
private lateinit var behavior: ListHabitsMenuBehavior
@ -49,131 +44,124 @@ class ListHabitsMenuBehaviorTest : JvmBaseUnitTest() {
private val themeSwitcher: ThemeSwitcher = mock()
private val matcherCaptor: KArgumentCaptor<HabitMatcher> = argumentCaptor()
private val orderCaptor: KArgumentCaptor<HabitList.Order> = argumentCaptor()
private val secondaryOrderCaptor: KArgumentCaptor<HabitList.Order> = argumentCaptor()
private var capturedMatcher: HabitMatcher? = null
private var capturedOrder: HabitList.Order? = null
private var capturedSecondaryOrder: HabitList.Order? = null
@Throws(Exception::class)
override fun setUp() {
super.setUp()
every { adapter.setFilter(any()) } returns Unit
every { adapter.refresh() } returns Unit
behavior = ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher)
clearInvocations(adapter)
resetCalls(adapter)
}
@Test
fun testInitialFilter() {
whenever(prefs.showArchived).thenReturn(true)
whenever(prefs.showCompleted).thenReturn(true)
every { prefs.showArchived } returns true
every { prefs.showCompleted } returns true
every { adapter.setFilter(any()) } returns Unit
every { adapter.refresh() } returns Unit
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)
verify { adapter.setFilter(any()) }
verify { adapter.refresh() }
verifyNoMoreCalls(adapter)
resetCalls(adapter)
every { prefs.showArchived } returns false
every { prefs.showCompleted } returns false
every { adapter.setFilter(any()) } returns Unit
every { adapter.refresh() } returns Unit
behavior = ListHabitsMenuBehavior(screen, adapter, prefs, themeSwitcher)
verify(adapter).setFilter(matcherCaptor.capture())
verify(adapter).refresh()
verifyNoMoreInteractions(adapter)
assertFalse(matcherCaptor.lastValue.isArchivedAllowed)
assertFalse(matcherCaptor.lastValue.isCompletedAllowed)
verify { adapter.setFilter(any()) }
verify { adapter.refresh() }
verifyNoMoreCalls(adapter)
}
@Test
fun testOnSortByColor() {
behavior.onSortByColor()
verify(adapter).primaryOrder = orderCaptor.capture()
assertThat(orderCaptor.lastValue, equalTo(HabitList.Order.BY_COLOR_ASC))
verify { adapter.primaryOrder = HabitList.Order.BY_COLOR_ASC }
}
@Test
fun testOnSortManually() {
behavior.onSortByManually()
verify(adapter).primaryOrder = orderCaptor.capture()
assertThat(orderCaptor.lastValue, equalTo(HabitList.Order.BY_POSITION))
verify { adapter.primaryOrder = HabitList.Order.BY_POSITION }
}
@Test
fun testOnSortScore() {
behavior.onSortByScore()
verify(adapter).primaryOrder = orderCaptor.capture()
assertThat(orderCaptor.lastValue, equalTo(HabitList.Order.BY_SCORE_DESC))
verify { adapter.primaryOrder = HabitList.Order.BY_SCORE_DESC }
}
@Test
fun testOnSortName() {
behavior.onSortByName()
verify(adapter).primaryOrder = orderCaptor.capture()
assertThat(orderCaptor.lastValue, equalTo(HabitList.Order.BY_NAME_ASC))
verify { adapter.primaryOrder = HabitList.Order.BY_NAME_ASC }
}
@Test
fun testOnSortStatus() {
whenever(adapter.primaryOrder).thenReturn(HabitList.Order.BY_NAME_ASC)
every { adapter.primaryOrder } returns HabitList.Order.BY_NAME_ASC
behavior.onSortByStatus()
verify(adapter).primaryOrder = orderCaptor.capture()
verify(adapter).secondaryOrder = secondaryOrderCaptor.capture()
assertThat(orderCaptor.lastValue, equalTo(HabitList.Order.BY_STATUS_ASC))
assertThat(secondaryOrderCaptor.lastValue, equalTo(HabitList.Order.BY_NAME_ASC))
verify { adapter.primaryOrder = HabitList.Order.BY_STATUS_ASC }
verify { adapter.secondaryOrder = HabitList.Order.BY_NAME_ASC }
}
@Test
fun testOnSortStatusToggle() {
whenever(adapter.primaryOrder).thenReturn(HabitList.Order.BY_STATUS_ASC)
every { adapter.primaryOrder } returns HabitList.Order.BY_STATUS_ASC
behavior.onSortByStatus()
verify(adapter).primaryOrder = orderCaptor.capture()
verify(adapter, never()).secondaryOrder = any()
assertThat(orderCaptor.lastValue, equalTo(HabitList.Order.BY_STATUS_DESC))
verify { adapter.primaryOrder = HabitList.Order.BY_STATUS_DESC }
verify(notCalled) { adapter.secondaryOrder = any() }
}
@Test
fun testOnToggleShowArchived() {
every { adapter.setFilter(any()) } returns Unit
behavior.onToggleShowArchived()
verify(adapter).setFilter(matcherCaptor.capture())
assertTrue(matcherCaptor.lastValue.isArchivedAllowed)
clearInvocations(adapter)
verify { adapter.setFilter(any()) }
resetCalls(adapter)
every { adapter.setFilter(any()) } returns Unit
behavior.onToggleShowArchived()
verify(adapter).setFilter(matcherCaptor.capture())
assertFalse(matcherCaptor.lastValue.isArchivedAllowed)
verify { adapter.setFilter(any()) }
}
@Test
fun testOnToggleShowCompleted() {
every { adapter.setFilter(any()) } returns Unit
behavior.onToggleShowCompleted()
verify(adapter).setFilter(matcherCaptor.capture())
assertTrue(matcherCaptor.lastValue.isCompletedAllowed)
clearInvocations(adapter)
verify { adapter.setFilter(any()) }
resetCalls(adapter)
every { adapter.setFilter(any()) } returns Unit
behavior.onToggleShowCompleted()
verify(adapter).setFilter(matcherCaptor.capture())
assertFalse(matcherCaptor.lastValue.isCompletedAllowed)
verify { adapter.setFilter(any()) }
}
@Test
fun testOnViewAbout() {
behavior.onViewAbout()
verify(screen).showAboutScreen()
verify { screen.showAboutScreen() }
}
@Test
fun testOnViewFAQ() {
behavior.onViewFAQ()
verify(screen).showFAQScreen()
verify { screen.showFAQScreen() }
}
@Test
fun testOnViewSettings() {
behavior.onViewSettings()
verify(screen).showSettingsScreen()
verify { screen.showSettingsScreen() }
}
@Test
fun testOnToggleNightMode() {
behavior.onToggleNightMode()
verify(themeSwitcher).toggleNightMode()
verify(screen).applyTheme()
verify { themeSwitcher.toggleNightMode() }
verify { screen.applyTheme() }
}
}

View File

@ -18,6 +18,12 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import dev.mokkery.answering.calls
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.matcher.any
import dev.mokkery.mock
import dev.mokkery.verify
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.isoron.uhabits.core.JvmBaseUnitTest
@ -26,12 +32,6 @@ 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.kotlin.KArgumentCaptor
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
@ -45,34 +45,30 @@ class ListHabitsSelectionMenuBehaviorTest : JvmBaseUnitTest() {
private lateinit var habit2: Habit
private lateinit var habit3: Habit
private val colorPickerCallback: KArgumentCaptor<OnColorPickedCallback> = argumentCaptor()
private val deleteCallback: KArgumentCaptor<OnConfirmedCallback> = argumentCaptor()
@Test
@Throws(Exception::class)
fun canArchive() {
whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
every { adapter.getSelected() } returns listOf(habit1, habit2)
assertFalse(behavior.canArchive())
whenever(adapter.getSelected()).thenReturn(listOf(habit2, habit3))
every { adapter.getSelected() } returns listOf(habit2, habit3)
assertTrue(behavior.canArchive())
}
@Test
@Throws(Exception::class)
fun canEdit() {
whenever(adapter.getSelected()).thenReturn(listOf(habit1))
every { adapter.getSelected() } returns listOf(habit1)
assertTrue(behavior.canEdit())
whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
every { adapter.getSelected() } returns listOf(habit1, habit2)
assertFalse(behavior.canEdit())
}
@Test
@Throws(Exception::class)
fun canUnarchive() {
whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
every { adapter.getSelected() } returns listOf(habit1, habit2)
assertFalse(behavior.canUnarchive())
whenever(adapter.getSelected()).thenReturn(listOf(habit1))
every { adapter.getSelected() } returns listOf(habit1)
assertTrue(behavior.canUnarchive())
}
@ -80,7 +76,7 @@ class ListHabitsSelectionMenuBehaviorTest : JvmBaseUnitTest() {
@Throws(Exception::class)
fun onArchiveHabits() {
assertFalse(habit2.isArchived)
whenever(adapter.getSelected()).thenReturn(listOf(habit2))
every { adapter.getSelected() } returns listOf(habit2)
behavior.onArchiveHabits()
assertTrue(habit2.isArchived)
}
@ -90,11 +86,14 @@ class ListHabitsSelectionMenuBehaviorTest : JvmBaseUnitTest() {
fun onChangeColor() {
assertThat(habit1.color, equalTo(PaletteColor(8)))
assertThat(habit2.color, equalTo(PaletteColor(8)))
whenever(adapter.getSelected()).thenReturn(listOf(habit1, habit2))
every { adapter.getSelected() } returns listOf(habit1, habit2)
every {
screen.showColorPicker(any(), any())
} calls { args ->
val callback = args.arg<OnColorPickedCallback>(1)
callback.onColorPicked(PaletteColor(30))
}
behavior.onChangeColor()
verify(screen)
.showColorPicker(eq(PaletteColor(8)), colorPickerCallback.capture())
colorPickerCallback.lastValue.onColorPicked(PaletteColor(30))
assertThat(habit1.color, equalTo(PaletteColor(30)))
}
@ -103,10 +102,14 @@ class ListHabitsSelectionMenuBehaviorTest : JvmBaseUnitTest() {
fun onDeleteHabits() {
val id = habit1.id!!
habitList.getById(id)!!
whenever(adapter.getSelected()).thenReturn(listOf(habit1))
every { adapter.getSelected() } returns listOf(habit1)
every {
screen.showDeleteConfirmationScreen(any(), any())
} calls { args ->
val callback = args.arg<OnConfirmedCallback>(0)
callback.onConfirmed()
}
behavior.onDeleteHabits()
verify(screen).showDeleteConfirmationScreen(deleteCallback.capture(), eq(1))
deleteCallback.lastValue.onConfirmed()
assertNull(habitList.getById(id))
}
@ -114,16 +117,16 @@ class ListHabitsSelectionMenuBehaviorTest : JvmBaseUnitTest() {
@Throws(Exception::class)
fun onEditHabits() {
val selected: List<Habit> = listOf(habit1, habit2)
whenever(adapter.getSelected()).thenReturn(selected)
every { adapter.getSelected() } returns selected
behavior.onEditHabits()
verify(screen).showEditHabitsScreen(selected)
verify { screen.showEditHabitsScreen(selected) }
}
@Test
@Throws(Exception::class)
fun onUnarchiveHabits() {
assertTrue(habit1.isArchived)
whenever(adapter.getSelected()).thenReturn(listOf(habit1))
every { adapter.getSelected() } returns listOf(habit1)
behavior.onUnarchiveHabits()
assertFalse(habit1.isArchived)
}

View File

@ -18,6 +18,10 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.show
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.mock
import dev.mokkery.verify
import org.apache.commons.io.FileUtils
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
@ -25,9 +29,6 @@ import org.isoron.platform.io.JavaUserFile
import org.isoron.uhabits.core.JvmBaseUnitTest
import org.isoron.uhabits.core.models.Habit
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import java.nio.file.Files
class ShowHabitMenuPresenterTest : JvmBaseUnitTest() {
@ -55,14 +56,14 @@ class ShowHabitMenuPresenterTest : JvmBaseUnitTest() {
@Test
fun testOnEditHabit() {
menu.onEditHabit()
verify(screen).showEditHabitScreen(habit)
verify { screen.showEditHabitScreen(habit) }
}
@Test
@Throws(Exception::class)
fun testOnExport() {
val outputDir = Files.createTempDirectory("CSV").toFile()
whenever(system.getCSVOutputDir()).thenReturn(JavaUserFile(outputDir.toPath()))
every { system.getCSVOutputDir() } returns JavaUserFile(outputDir.toPath())
menu.onExportCSV()
assertThat(FileUtils.listFiles(outputDir, null, false).size, equalTo(1))
FileUtils.deleteDirectory(outputDir)

View File

@ -19,6 +19,10 @@
package org.isoron.uhabits.core.ui.views
import dev.mokkery.mock
import dev.mokkery.resetCalls
import dev.mokkery.verify
import dev.mokkery.verifyNoMoreCalls
import kotlinx.coroutines.runBlocking
import org.isoron.platform.gui.assertRenders
import org.isoron.platform.time.DayOfWeek
@ -31,10 +35,6 @@ 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.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.reset
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import java.util.Locale
class HistoryChartTest {
@ -89,29 +89,29 @@ class HistoryChartTest {
// Click top left date
view.onClick(20.0, 46.0)
verify(dateClickedListener).onDateShortPress(LocalDate(2014, 10, 26))
reset(dateClickedListener)
verify { dateClickedListener.onDateShortPress(LocalDate(2014, 10, 26)) }
resetCalls(dateClickedListener)
view.onClick(2.0, 28.0)
verify(dateClickedListener).onDateShortPress(LocalDate(2014, 10, 26))
reset(dateClickedListener)
verify { dateClickedListener.onDateShortPress(LocalDate(2014, 10, 26)) }
resetCalls(dateClickedListener)
// Click date in the middle
view.onClick(163.0, 113.0)
verify(dateClickedListener).onDateShortPress(LocalDate(2014, 12, 10))
reset(dateClickedListener)
verify { dateClickedListener.onDateShortPress(LocalDate(2014, 12, 10)) }
resetCalls(dateClickedListener)
// Click today
view.onClick(336.0, 37.0)
verify(dateClickedListener).onDateShortPress(LocalDate(2015, 1, 25))
reset(dateClickedListener)
verify { dateClickedListener.onDateShortPress(LocalDate(2015, 1, 25)) }
resetCalls(dateClickedListener)
// Click header
view.onClick(160.0, 15.0)
verifyNoMoreInteractions(dateClickedListener)
verifyNoMoreCalls(dateClickedListener)
// Click right axis
view.onClick(360.0, 60.0)
verifyNoMoreInteractions(dateClickedListener)
verifyNoMoreCalls(dateClickedListener)
}
@Test
@ -120,29 +120,29 @@ class HistoryChartTest {
// Click top left date
view.onLongClick(20.0, 46.0)
verify(dateClickedListener).onDateLongPress(LocalDate(2014, 10, 26))
reset(dateClickedListener)
verify { dateClickedListener.onDateLongPress(LocalDate(2014, 10, 26)) }
resetCalls(dateClickedListener)
view.onLongClick(2.0, 28.0)
verify(dateClickedListener).onDateLongPress(LocalDate(2014, 10, 26))
reset(dateClickedListener)
verify { dateClickedListener.onDateLongPress(LocalDate(2014, 10, 26)) }
resetCalls(dateClickedListener)
// Click date in the middle
view.onLongClick(163.0, 113.0)
verify(dateClickedListener).onDateLongPress(LocalDate(2014, 12, 10))
reset(dateClickedListener)
verify { dateClickedListener.onDateLongPress(LocalDate(2014, 12, 10)) }
resetCalls(dateClickedListener)
// Click today
view.onLongClick(336.0, 37.0)
verify(dateClickedListener).onDateLongPress(LocalDate(2015, 1, 25))
reset(dateClickedListener)
verify { dateClickedListener.onDateLongPress(LocalDate(2015, 1, 25)) }
resetCalls(dateClickedListener)
// Click header
view.onLongClick(160.0, 15.0)
verifyNoMoreInteractions(dateClickedListener)
verifyNoMoreCalls(dateClickedListener)
// Click right axis
view.onLongClick(360.0, 60.0)
verifyNoMoreInteractions(dateClickedListener)
verifyNoMoreCalls(dateClickedListener)
}
@Test

View File

@ -18,6 +18,11 @@
*/
package org.isoron.uhabits.core.ui.widgets
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.mock
import dev.mokkery.resetCalls
import dev.mokkery.verify
import org.isoron.platform.time.LocalDate
import org.isoron.platform.time.getToday
import org.isoron.uhabits.core.JvmBaseUnitTest
@ -29,11 +34,7 @@ import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.NotificationTray
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.reset
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoInteractions
import org.mockito.kotlin.whenever
import dev.mokkery.verify.VerifyMode.Companion.not as notCalled
class WidgetBehaviorTest : JvmBaseUnitTest() {
private lateinit var notificationTray: NotificationTray
@ -57,21 +58,25 @@ class WidgetBehaviorTest : JvmBaseUnitTest() {
@Test
fun testOnAddRepetition() {
behavior.onAddRepetition(habit, today)
verify(commandRunner).run(
CreateRepetitionCommand(habitList, habit, today, Entry.YES_MANUAL, "")
)
verify(notificationTray).cancel(habit)
verifyNoInteractions(preferences)
verify {
commandRunner.run(
CreateRepetitionCommand(habitList, habit, today, Entry.YES_MANUAL, "")
)
}
verify { notificationTray.cancel(habit) }
verify(notCalled) { preferences.isSkipEnabled }
}
@Test
fun testOnRemoveRepetition() {
behavior.onRemoveRepetition(habit, today)
verify(commandRunner).run(
CreateRepetitionCommand(habitList, habit, today, Entry.NO, "")
)
verify(notificationTray).cancel(habit)
verifyNoInteractions(preferences)
verify {
commandRunner.run(
CreateRepetitionCommand(habitList, habit, today, Entry.NO, "")
)
}
verify { notificationTray.cancel(habit) }
verify(notCalled) { preferences.isSkipEnabled }
}
@Test
@ -84,7 +89,7 @@ class WidgetBehaviorTest : JvmBaseUnitTest() {
Entry.SKIP
)
) {
whenever(preferences.isSkipEnabled).thenReturn(skipEnabled)
every { preferences.isSkipEnabled } returns skipEnabled
val nextValue: Int = nextToggleValue(
currentValue,
isSkipEnabled = skipEnabled,
@ -92,14 +97,18 @@ class WidgetBehaviorTest : JvmBaseUnitTest() {
)
habit.originalEntries.add(Entry(today, currentValue))
behavior.onToggleRepetition(habit, today)
verify(preferences).isSkipEnabled
verify(commandRunner).run(
CreateRepetitionCommand(habitList, habit, today, nextValue, "")
)
verify(notificationTray).cancel(
habit
)
reset(preferences, commandRunner, notificationTray)
verify { preferences.isSkipEnabled }
verify {
commandRunner.run(
CreateRepetitionCommand(habitList, habit, today, nextValue, "")
)
}
verify {
notificationTray.cancel(
habit
)
}
resetCalls(preferences, commandRunner, notificationTray)
}
}
@ -109,11 +118,13 @@ class WidgetBehaviorTest : JvmBaseUnitTest() {
habit.originalEntries.add(Entry(today, 500))
habit.recompute()
behavior.onIncrement(habit, today, 100)
verify(commandRunner).run(
CreateRepetitionCommand(habitList, habit, today, 600, "")
)
verify(notificationTray).cancel(habit)
verifyNoInteractions(preferences)
verify {
commandRunner.run(
CreateRepetitionCommand(habitList, habit, today, 600, "")
)
}
verify { notificationTray.cancel(habit) }
verify(notCalled) { preferences.isSkipEnabled }
}
@Test
@ -122,10 +133,12 @@ class WidgetBehaviorTest : JvmBaseUnitTest() {
habit.originalEntries.add(Entry(today, 500))
habit.recompute()
behavior.onDecrement(habit, today, 100)
verify(commandRunner).run(
CreateRepetitionCommand(habitList, habit, today, 400, "")
)
verify(notificationTray).cancel(habit)
verifyNoInteractions(preferences)
verify {
commandRunner.run(
CreateRepetitionCommand(habitList, habit, today, 400, "")
)
}
verify { notificationTray.cancel(habit) }
verify(notCalled) { preferences.isSkipEnabled }
}
}

View File

@ -1,5 +1,6 @@
package org.isoron.uhabits.core.utils
import dev.mokkery.mock
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
@ -9,7 +10,6 @@ import org.isoron.uhabits.core.io.StandardLogging
import org.isoron.uhabits.core.preferences.Preferences
import org.junit.After
import org.junit.Test
import org.mockito.Mockito.mock
import java.util.Calendar
import java.util.TimeZone
import java.util.concurrent.Executors
@ -20,8 +20,7 @@ import kotlin.test.assertEquals
class MidnightTimerTest : JvmBaseUnitTest() {
@After
override fun tearDown() {
super.tearDown()
fun tearDown() {
DateUtils.setFixedLocalTime(null)
DateUtils.setFixedTimeZone(null)
}
@ -46,7 +45,7 @@ class MidnightTimerTest : JvmBaseUnitTest() {
)
val suspendedListener = suspendCoroutine<Boolean> { continuation ->
MidnightTimer(StandardLogging(), mock(Preferences::class.java)).apply {
MidnightTimer(StandardLogging(), mock<Preferences>()).apply {
addListener { continuation.resume(true) }
// When
onResume(1, executor)