Remove JvmBaseUnitTest and move chart and DateUtils tests to commonTest

This commit is contained in:
Alinson S. Xavier 2026-04-08 06:13:43 -05:00
parent a93e871daf
commit 9cf4ec417c
13 changed files with 93 additions and 127 deletions

View File

@ -0,0 +1,43 @@
package org.isoron.platform.gui
import org.isoron.platform.io.createTestCanvas
import org.isoron.platform.io.createTestFileOpener
import kotlin.test.fail
suspend fun assertRenders(
path: String,
canvas: Canvas
) {
val actualImage = canvas.toImage()
val failedActualPath = "/tmp/failed/$path"
val failedExpectedPath = failedActualPath.replace(".png", ".expected.png")
val failedDiffPath = failedActualPath.replace(".png", ".diff.png")
val fileOpener = createTestFileOpener()
val expectedFile = fileOpener.openResourceFile(path)
if (expectedFile.exists()) {
val expectedImage = expectedFile.toImage()
val diffImage = expectedFile.toImage()
diffImage.diff(actualImage)
val distance = diffImage.averageLuminosity * 100
if (distance >= 1.0) {
expectedImage.export(failedExpectedPath)
actualImage.export(failedActualPath)
diffImage.export(failedDiffPath)
fail("Images differ (distance=$distance)")
}
} else {
actualImage.export(failedActualPath)
fail("Expected image file is missing. Actual image: $failedActualPath")
}
}
suspend fun assertRenders(
width: Int,
height: Int,
expectedPath: String,
view: View
) {
val canvas = createTestCanvas(width, height)
view.draw(canvas)
assertRenders(expectedPath, canvas)
}

View File

@ -1,4 +1,9 @@
package org.isoron.platform.io package org.isoron.platform.io
import org.isoron.platform.gui.Canvas
import org.isoron.platform.time.LocalDateFormatter
expect fun createTestFileOpener(): FileOpener expect fun createTestFileOpener(): FileOpener
expect fun createTestDatabaseOpener(): DatabaseOpener expect fun createTestDatabaseOpener(): DatabaseOpener
expect fun createTestCanvas(width: Int, height: Int): Canvas
expect fun createTestDateFormatter(): LocalDateFormatter

View File

@ -23,9 +23,9 @@ import org.isoron.platform.io.ZipReader
import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
import kotlin.test.assertTrue import kotlin.test.assertTrue
import kotlin.test.assertEquals
class HabitsCSVExporterTest : BaseUnitTest() { class HabitsCSVExporterTest : BaseUnitTest() {

View File

@ -24,7 +24,6 @@ import dev.mokkery.answering.throws
import dev.mokkery.every import dev.mokkery.every
import dev.mokkery.matcher.any import dev.mokkery.matcher.any
import dev.mokkery.mock import dev.mokkery.mock
import dev.mokkery.resetCalls
import dev.mokkery.spy import dev.mokkery.spy
import dev.mokkery.verify import dev.mokkery.verify
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking

View File

@ -21,15 +21,14 @@ package org.isoron.uhabits.core.ui.views
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.isoron.platform.gui.assertRenders import org.isoron.platform.gui.assertRenders
import org.isoron.platform.time.JavaLocalDateFormatter import org.isoron.platform.io.createTestDateFormatter
import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDate
import org.junit.Test import kotlin.test.Test
import java.util.Locale
class BarChartTest { class BarChartTest {
val base = "views/BarChart" val base = "views/BarChart"
val today = LocalDate(2015, 1, 25) val today = LocalDate(2015, 1, 25)
private val fmt = JavaLocalDateFormatter(Locale.US) private val fmt = createTestDateFormatter()
val theme = LightTheme() val theme = LightTheme()
val component = BarChart(theme, fmt) val component = BarChart(theme, fmt)
private val axis = (0..100).map { today.minus(it) } private val axis = (0..100).map { today.minus(it) }

View File

@ -25,17 +25,16 @@ import dev.mokkery.verify
import dev.mokkery.verifyNoMoreCalls import dev.mokkery.verifyNoMoreCalls
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.isoron.platform.gui.assertRenders import org.isoron.platform.gui.assertRenders
import org.isoron.platform.io.createTestDateFormatter
import org.isoron.platform.time.DayOfWeek import org.isoron.platform.time.DayOfWeek
import org.isoron.platform.time.DayOfWeek.SUNDAY import org.isoron.platform.time.DayOfWeek.SUNDAY
import org.isoron.platform.time.JavaLocalDateFormatter
import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.DIMMED 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.HATCHED
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.OFF 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.HistoryChart.Square.ON
import org.junit.Test import kotlin.test.Test
import java.util.Locale
class HistoryChartTest { class HistoryChartTest {
val base = "views/HistoryChart" val base = "views/HistoryChart"
@ -46,7 +45,7 @@ class HistoryChartTest {
today = LocalDate(2015, 1, 25), today = LocalDate(2015, 1, 25),
paletteColor = PaletteColor(7), paletteColor = PaletteColor(7),
theme = LightTheme(), theme = LightTheme(),
dateFormatter = JavaLocalDateFormatter(Locale.US), dateFormatter = createTestDateFormatter(),
firstWeekday = SUNDAY, firstWeekday = SUNDAY,
onDateClickedListener = dateClickedListener, onDateClickedListener = dateClickedListener,
defaultSquare = OFF, defaultSquare = OFF,

View File

@ -33,9 +33,9 @@ class JavaCanvasTest {
} }
} }
fun createCanvas(w: Int, h: Int) = JavaCanvas(BufferedImage(2 * w, 2 * h, TYPE_INT_ARGB), 2.0) private fun createCanvas(w: Int, h: Int) = JavaCanvas(BufferedImage(2 * w, 2 * h, TYPE_INT_ARGB), 2.0)
suspend fun assertRenders( private suspend fun assertRenders(
path: String, path: String,
canvas: Canvas canvas: Canvas
) { ) {
@ -65,7 +65,7 @@ suspend fun assertRenders(
} }
} }
suspend fun assertRenders( private suspend fun assertRenders(
width: Int, width: Int,
height: Int, height: Int,
expectedPath: String, expectedPath: String,

View File

@ -1,4 +1,20 @@
package org.isoron.platform.io package org.isoron.platform.io
import org.isoron.platform.gui.Canvas
import org.isoron.platform.gui.JavaCanvas
import org.isoron.platform.time.JavaLocalDateFormatter
import org.isoron.platform.time.LocalDateFormatter
import java.awt.image.BufferedImage
import java.awt.image.BufferedImage.TYPE_INT_ARGB
import java.util.Locale
actual fun createTestFileOpener(): FileOpener = JavaFileOpener() actual fun createTestFileOpener(): FileOpener = JavaFileOpener()
actual fun createTestDatabaseOpener(): DatabaseOpener = JavaDatabaseOpener() actual fun createTestDatabaseOpener(): DatabaseOpener = JavaDatabaseOpener()
actual fun createTestCanvas(width: Int, height: Int): Canvas {
return JavaCanvas(BufferedImage(2 * width, 2 * height, TYPE_INT_ARGB), 2.0)
}
actual fun createTestDateFormatter(): LocalDateFormatter {
return JavaLocalDateFormatter(Locale.US)
}

View File

@ -1,29 +1,9 @@
/* package org.isoron.platform.time
* Copyright (C) 2016-2025 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core.utils
import org.isoron.platform.time.DateUtils
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.util.Calendar import java.util.Calendar
import java.util.GregorianCalendar
import java.util.TimeZone import java.util.TimeZone
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -45,13 +25,6 @@ class DateUtilsTest {
DateUtils.setFixedTimeZone(null) DateUtils.setFixedTimeZone(null)
} }
private fun unixTime(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0): Long {
val cal = GregorianCalendar(TimeZone.getTimeZone("GMT"))
cal.set(year, month, day, hour, minute, 0)
cal.set(GregorianCalendar.MILLISECOND, 0)
return cal.timeInMillis
}
// --------------------------------------------------------------- // ---------------------------------------------------------------
// getLocalTime // getLocalTime
// --------------------------------------------------------------- // ---------------------------------------------------------------

View File

@ -0,0 +1,11 @@
package org.isoron.platform.time
import java.util.GregorianCalendar
import java.util.TimeZone
fun unixTime(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, milliseconds: Long = 0): Long {
val cal = GregorianCalendar(TimeZone.getTimeZone("GMT"))
cal.set(year, month, day, hour, minute, 0)
cal.set(GregorianCalendar.MILLISECOND, 0)
return cal.timeInMillis + milliseconds
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2016-2025 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.core
import dev.mokkery.spy
import org.apache.commons.io.IOUtils
import org.isoron.uhabits.core.models.memory.MemoryModelFactory
import org.isoron.uhabits.core.test.HabitFixtures
import org.junit.Before
import org.junit.Test
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.util.GregorianCalendar
import java.util.TimeZone
open class JvmBaseUnitTest : BaseUnitTest() {
@Before
override fun setUp() {
super.setUp()
habitList = spy(habitList)
fixtures = HabitFixtures(modelFactory as MemoryModelFactory, habitList)
}
fun unixTime(year: Int, month: Int, day: Int): Long {
return unixTime(year, month, day, 0, 0)
}
open fun unixTime(year: Int, month: Int, day: Int, hour: Int, minute: Int, milliseconds: Long = 0): Long {
val cal = GregorianCalendar(TimeZone.getTimeZone("GMT"))
cal.set(year, month, day, hour, minute, 0)
cal.set(GregorianCalendar.MILLISECOND, 0)
return cal.timeInMillis + milliseconds
}
@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")
}
}

View File

@ -27,7 +27,8 @@ import org.isoron.platform.time.DateUtils
import org.isoron.platform.time.DateUtils.removeTimezone import org.isoron.platform.time.DateUtils.removeTimezone
import org.isoron.platform.time.DateUtils.setFixedLocalTime import org.isoron.platform.time.DateUtils.setFixedLocalTime
import org.isoron.platform.time.DateUtils.setFixedTimeZone import org.isoron.platform.time.DateUtils.setFixedTimeZone
import org.isoron.uhabits.core.JvmBaseUnitTest import org.isoron.platform.time.unixTime
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.Reminder import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList import org.isoron.uhabits.core.models.WeekdayList
@ -37,7 +38,7 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import java.util.TimeZone import java.util.TimeZone
class ReminderSchedulerTest : JvmBaseUnitTest() { class ReminderSchedulerTest : BaseUnitTest() {
private val habitId = 10L private val habitId = 10L
private lateinit var habit: Habit private lateinit var habit: Habit
private lateinit var reminderScheduler: ReminderScheduler private lateinit var reminderScheduler: ReminderScheduler
@ -145,13 +146,6 @@ class ReminderSchedulerTest : JvmBaseUnitTest() {
reminderScheduler.schedule(habit) reminderScheduler.schedule(habit)
} }
override fun unixTime(year: Int, month: Int, day: Int, hour: Int, minute: Int, milliseconds: Long): Long {
val cal = java.util.GregorianCalendar(TimeZone.getTimeZone("GMT"))
cal.set(year, month, day, hour, minute, 0)
cal.set(java.util.GregorianCalendar.MILLISECOND, 0)
return cal.timeInMillis
}
private fun scheduleAndVerify( private fun scheduleAndVerify(
atTime: Long?, atTime: Long?,
expectedCheckmarkTime: Long, expectedCheckmarkTime: Long,

View File

@ -5,7 +5,8 @@ import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.isoron.platform.time.DateUtils import org.isoron.platform.time.DateUtils
import org.isoron.uhabits.core.JvmBaseUnitTest import org.isoron.platform.time.unixTime
import org.isoron.uhabits.core.BaseUnitTest
import org.isoron.uhabits.core.io.StandardLogging import org.isoron.uhabits.core.io.StandardLogging
import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.preferences.Preferences
import org.junit.After import org.junit.After
@ -17,7 +18,7 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
import kotlin.test.assertEquals import kotlin.test.assertEquals
class MidnightTimerTest : JvmBaseUnitTest() { class MidnightTimerTest : BaseUnitTest() {
@After @After
fun tearDown() { fun tearDown() {
@ -56,4 +57,5 @@ class MidnightTimerTest : JvmBaseUnitTest() {
assertEquals(true, suspendedListener) assertEquals(true, suspendedListener)
} }
} }
} }