Implement database access (with migrations)

This commit is contained in:
2019-01-26 22:58:53 -06:00
parent e19339d808
commit 7cab0a39e5
67 changed files with 1826 additions and 136 deletions

Binary file not shown.

View File

View File

View File

View File

View File

View File

View File

View File

View File

@@ -0,0 +1,5 @@
create table Habits ( id integer primary key autoincrement, archived integer, color integer, description text, freq_den integer, freq_num integer, highlight integer, name text, position integer, reminder_hour integer, reminder_min integer )
create table Checkmarks ( id integer primary key autoincrement, habit integer references habits(id), timestamp integer, value integer )
create table Repetitions ( id integer primary key autoincrement, habit integer references habits(id), timestamp integer )
create table Streak ( id integer primary key autoincrement, end integer, habit integer references habits(id), length integer, start integer )
create table Score ( id integer primary key autoincrement, habit integer references habits(id), score integer, timestamp integer )

View File

@@ -0,0 +1,3 @@
delete from Score
delete from Streak
delete from Checkmarks

View File

@@ -0,0 +1 @@
alter table Habits add column reminder_days integer not null default 127

View File

@@ -0,0 +1,3 @@
delete from Score
delete from Streak
delete from Checkmarks

View File

@@ -0,0 +1,4 @@
create index idx_score_habit_timestamp on Score(habit, timestamp)
create index idx_checkmark_habit_timestamp on Checkmarks(habit, timestamp)
create index idx_repetitions_habit_timestamp on Repetitions(habit, timestamp)
create index idx_streak_habit_end on Streak(habit, end)

View File

@@ -0,0 +1,14 @@
update habits set color=0 where color=-2937041
update habits set color=1 where color=-1684967
update habits set color=2 where color=-415707
update habits set color=3 where color=-5262293
update habits set color=4 where color=-13070788
update habits set color=5 where color=-16742021
update habits set color=6 where color=-16732991
update habits set color=7 where color=-16540699
update habits set color=8 where color=-10603087
update habits set color=9 where color=-7461718
update habits set color=10 where color=-2614432
update habits set color=11 where color=-13619152
update habits set color=12 where color=-5592406
update habits set color=0 where color<0 or color>12

View File

@@ -0,0 +1,3 @@
delete from Score
delete from Streak
delete from Checkmarks

View File

@@ -0,0 +1,2 @@
alter table Habits add column type integer not null default 0
alter table Repetitions add column value integer not null default 2

View File

@@ -0,0 +1,5 @@
drop table Score
create table Score ( id integer primary key autoincrement, habit integer references habits(id), score real, timestamp integer)
create index idx_score_habit_timestamp on Score(habit, timestamp)
delete from streak
delete from checkmarks

View File

@@ -0,0 +1,3 @@
alter table Habits add column target_type integer not null default 0
alter table Habits add column target_value real not null default 0
alter table Habits add column unit text not null default ""

View File

@@ -0,0 +1 @@
create table Events ( id integer primary key autoincrement, timestamp integer, message text, server_id integer )

View File

@@ -0,0 +1,3 @@
drop table checkmarks
drop table streak
drop table score

View File

@@ -0,0 +1,12 @@
update habits set color=19 where color=12
update habits set color=17 where color=11
update habits set color=15 where color=10
update habits set color=14 where color=9
update habits set color=13 where color=8
update habits set color=10 where color=7
update habits set color=9 where color=6
update habits set color=8 where color=5
update habits set color=7 where color=4
update habits set color=5 where color=3
update habits set color=4 where color=2
update habits set color=0 where color<0 or color>19

View File

@@ -0,0 +1,11 @@
delete from repetitions where habit not in (select id from habits)
delete from repetitions where timestamp is null
delete from repetitions where habit is null
delete from repetitions where rowid not in ( select min(rowid) from repetitions group by habit, timestamp )
alter table Repetitions rename to RepetitionsBak
create table Repetitions ( id integer primary key autoincrement, habit integer not null references habits(id), timestamp integer not null, value integer not null)
drop index if exists idx_repetitions_habit_timestamp
create unique index idx_repetitions_habit_timestamp on Repetitions( habit, timestamp)
insert into Repetitions select * from RepetitionsBak
drop table RepetitionsBak
pragma foreign_keys=ON

View File

@@ -0,0 +1,2 @@
Hello World!
This is a resource.

View File

@@ -48,8 +48,8 @@ kotlin {
compilations.main.outputKinds('FRAMEWORK')
}
// Replace the target above with the following to produce a framework
// which can be installed on a real iPhone.
// Replace the target above by the following one to produce a framework
// which can be installed on a real iPhone:
// fromPreset(presets.iosArm64, 'iOS') {
// compilations.main.outputKinds('FRAMEWORK')
// }
@@ -76,6 +76,20 @@ kotlin {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
implementation 'org.xerial:sqlite-jdbc:3.25.2'
}
}
}
task iosTest {
dependsOn 'linkTestDebugExecutableIOS'
group = JavaBasePlugin.VERIFICATION_GROUP
description = "Runs tests for target 'ios' on an iOS simulator"
doLast {
def binary = kotlin.targets.iOS.compilations.test.getBinary('EXECUTABLE', 'DEBUG')
exec {
commandLine 'xcrun', 'simctl', 'spawn', "iPhone 8", binary.absolutePath
}
}
}

View File

@@ -19,37 +19,38 @@
package org.isoron.uhabits
import org.isoron.uhabits.models.Color
import org.isoron.uhabits.models.Frequency
import org.isoron.uhabits.models.Habit
import org.isoron.uhabits.models.HabitType
import kotlin.random.Random
import org.isoron.uhabits.models.HabitList
import org.isoron.uhabits.utils.*
class Backend {
var nextId = 1
var habits = mutableListOf<Habit>()
class Backend(var databaseOpener: DatabaseOpener,
var fileOpener: FileOpener,
var log: Log) {
fun getHabitList(): Map<Int, Map<String, *>> {
return habits.map { h ->
h.id to mapOf("name" to h.name,
"color" to h.color.paletteIndex)
}.toMap()
var db: Database
var habits: HabitList
init {
val dbFile = fileOpener.openUserFile("uhabits.sqlite3")
db = databaseOpener.open(dbFile)
db.migrateTo(LOOP_DATABASE_VERSION, fileOpener, log)
habits = HabitList(db)
}
fun getHabitList(): List<Map<String, *>> {
return habits.getActive().map { h ->
mapOf("key" to h.id.toString(),
"name" to h.name,
"color" to h.color.paletteIndex)
}
}
fun createHabit(name: String) {
val c = (nextId / 4) % 5
habits.add(Habit(nextId, name, "", Frequency(1, 1), Color(c),
false, habits.size, "", 0, HabitType.YES_NO_HABIT))
nextId += 1
}
fun deleteHabit(id: Int) {
val h = habits.find { h -> h.id == id }
if (h != null) habits.remove(h)
}
fun updateHabit(id: Int, name: String) {
val h = habits.find { h -> h.id == id }
h?.name = name
}
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits
const val LOOP_DATABASE_VERSION = 22

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.models
import org.isoron.uhabits.utils.Database
import org.isoron.uhabits.utils.StepResult
class HabitList(var db: Database) {
var habits = mutableListOf<Habit>()
init {
loadHabitsFromDatabase()
}
fun getActive(): List<Habit> {
return habits.filter { h -> !h.isArchived }
}
private fun loadHabitsFromDatabase() {
val stmt = db.prepareStatement(
"select id, name, description, freq_num, freq_den, color, " +
"archived, position, unit, target_value, type " +
"from habits")
while (stmt.step() == StepResult.ROW) {
habits.add(Habit(id = stmt.getInt(0),
name = stmt.getText(1),
description = stmt.getText(2),
frequency = Frequency(stmt.getInt(3),
stmt.getInt(4)),
color = Color(stmt.getInt(5)),
isArchived = (stmt.getInt(6) != 0),
position = stmt.getInt(7),
unit = stmt.getText(8),
target = 0,
type = HabitType.YES_NO_HABIT))
}
stmt.finalize()
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
enum class StepResult {
ROW,
DONE
}
interface PreparedStatement {
fun step(): StepResult
fun finalize()
fun getInt(index: Int): Int
fun getText(index: Int): String
fun bindInt(index: Int, value: Int)
fun bindText(index: Int, value: String)
fun reset()
}
interface Database {
fun prepareStatement(sql: String): PreparedStatement
fun close()
}
interface DatabaseOpener {
fun open(file: UserFile): Database
}
fun Database.execute(sql: String) {
val stmt = prepareStatement(sql)
stmt.step()
stmt.finalize()
}
fun Database.queryInt(sql: String): Int {
val stmt = prepareStatement(sql)
stmt.step()
val result = stmt.getInt(0)
stmt.finalize()
return result
}
fun Database.begin() = execute("begin")
fun Database.commit() = execute("commit")
fun Database.rollback() = execute("rollback")
fun Database.getVersion() = queryInt("pragma user_version")
fun Database.setVersion(v: Int) = execute("pragma user_version = $v")
fun Database.migrateTo(newVersion: Int, fileOpener: FileOpener, log: Log) {
val currentVersion = getVersion()
log.debug("Current database version: $currentVersion")
if (currentVersion == newVersion) return
log.debug("Upgrading to version: $newVersion")
if (currentVersion > newVersion)
throw RuntimeException("database produced by future version of the application")
begin()
for (v in (currentVersion + 1)..newVersion) {
log.debug("Running migration $v")
val filename = sprintf("migrations/%03d.sql", v)
val migrationFile = fileOpener.openResourceFile(filename)
for (line in migrationFile.readLines()) {
if (line.isEmpty()) continue
execute(line)
}
setVersion(v)
}
commit()
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
/**
* Represents a file that was shipped with the application, such as migration
* files or translations. These files cannot be deleted.
*/
interface ResourceFile {
fun readLines(): List<String>
}
/**
* Represents a file that was created after the application was installed, as a
* result of some user action, such as databases and logs. These files can be
* deleted.
*/
interface UserFile {
fun delete()
fun exists(): Boolean
}
interface FileOpener {
/**
* Opens a file which was shipped bundled with the application, such as a
* migration file.
*
* The path is relative to the assets folder. For example, to open
* assets/main/migrations/09.sql you should provide migrations/09.sql
* as the filename.
*/
fun openResourceFile(filename: String): ResourceFile
/**
* Opens a file which was not shipped with the application, such as
* databases and logs.
*
* The path is relative to the user folder. For example, if the application
* stores the user data at /home/user/.loop/ and you wish to open the file
* /home/user/.loop/crash.log, you should provide crash.log as the filename.
*/
fun openUserFile(filename: String): UserFile
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
interface Log {
fun info(msg: String)
fun debug(msg: String)
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
expect fun sprintf(format: String, vararg args: Any?): String

View File

@@ -17,33 +17,14 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits
package org.isoron.uhabits.utils
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class BackendTest {
class StringsTest {
@Test
fun testBackend() {
val backend = Backend()
assertEquals(backend.getHabitList().size, 0)
backend.createHabit("Brush teeth")
backend.createHabit("Wake up early")
var result = backend.getHabitList()
assertEquals(result.size, 2)
assertEquals(result[1]!!["name"], "Brush teeth")
assertEquals(result[2]!!["name"], "Wake up early")
backend.deleteHabit(1)
result = backend.getHabitList()
assertEquals(result.size, 1)
assertTrue(2 in result.keys)
backend.updateHabit(2, "Wake up late")
result = backend.getHabitList()
assertEquals(result[2]!!["name"], "Wake up late")
fun testSprintf() {
assertEquals("Number 004", sprintf("Number %03d", 4))
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
import kotlinx.cinterop.*
actual fun sprintf(format: String, vararg args: Any?): String {
val buffer = ByteArray(1000)
buffer.usePinned { p ->
platform.posix.sprintf(p.addressOf(0), format, *args)
}
return buffer.stringFromUtf8()
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.database
import org.isoron.uhabits.utils.*
import java.sql.Connection
import java.sql.DriverManager
import java.sql.PreparedStatement
import java.sql.ResultSet
class JavaPreparedStatement(private var stmt : PreparedStatement) : org.isoron.uhabits.utils.PreparedStatement {
private var rs: ResultSet? = null
private var hasExecuted = false
override fun step(): StepResult {
if (!hasExecuted) {
hasExecuted = true
val hasResult = stmt.execute()
if (hasResult) rs = stmt.resultSet
}
if (rs == null || !rs!!.next()) return StepResult.DONE
return StepResult.ROW
}
override fun finalize() {
stmt.close()
}
override fun getInt(index: Int): Int {
return rs!!.getInt(index + 1)
}
override fun getText(index: Int): String {
return rs!!.getString(index + 1)
}
override fun bindInt(index: Int, value: Int) {
stmt.setInt(index, value)
}
override fun bindText(index: Int, value: String) {
stmt.setString(index, value)
}
override fun reset() {
stmt.clearParameters()
}
}
class JavaDatabase(private var conn: Connection,
private val log: Log) : Database {
override fun prepareStatement(sql: String): org.isoron.uhabits.utils.PreparedStatement {
log.debug("Running SQL: ${sql}")
return JavaPreparedStatement(conn.prepareStatement(sql))
}
override fun close() {
conn.close()
}
}
class JavaDatabaseOpener(private val log: Log) : DatabaseOpener {
override fun open(file: UserFile): Database {
val platformFile = file as JavaUserFile
val conn = DriverManager.getConnection("jdbc:sqlite:${platformFile.path}")
return JavaDatabase(conn, log)
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
class JavaResourceFile(private val path: Path) : ResourceFile {
override fun readLines(): List<String> {
return Files.readAllLines(path)
}
}
class JavaUserFile(val path: Path) : UserFile {
override fun exists(): Boolean {
return Files.exists(path)
}
override fun delete() {
Files.delete(path)
}
}
class JavaFileOpener : FileOpener {
override fun openUserFile(filename: String): UserFile {
val path = Paths.get("/tmp/$filename")
return JavaUserFile(path)
}
override fun openResourceFile(filename: String): ResourceFile {
val rootFolders = listOf("assets/main",
"assets/test")
for (root in rootFolders) {
val path = Paths.get("$root/$filename")
if (Files.exists(path) && Files.isReadable(path)) {
return JavaResourceFile(path)
}
}
throw RuntimeException("file not found")
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
class JavaLog : Log {
override fun info(msg: String) {
println("[I] $msg")
}
override fun debug(msg: String) {
println("[D] $msg")
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
actual fun sprintf(format: String, vararg args: Any?): String {
return String.format(format, *args)
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.junit.Test
class BackendTest : BaseTest() {
@Test
fun testBackend() {
// val backend = Backend(databaseOpener, fileOpener)
// assertEquals(backend.getHabitList().size, 0)
//
// backend.createHabit("Brush teeth")
// backend.createHabit("Wake up early")
// var result = backend.getHabitList()
// assertEquals(2, result.size)
// assertEquals(result[0]["name"], "Brush teeth")
// assertEquals(result[0]["name"], "Wake up early")
//
// backend.deleteHabit(1)
// result = backend.getHabitList()
// assertEquals(result.size, 1)
//
// backend.updateHabit(2, "Wake up late")
// result = backend.getHabitList()
// assertEquals(result[2]["name"], "Wake up late")
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits
import org.isoron.uhabits.utils.JavaFileOpener
import org.isoron.uhabits.database.JavaDatabaseOpener
import org.isoron.uhabits.utils.JavaLog
open class BaseTest {
val fileOpener = JavaFileOpener()
val databaseOpener = JavaDatabaseOpener(JavaLog())
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.database
import org.isoron.uhabits.BaseTest
import org.isoron.uhabits.utils.*
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
class JavaDatabaseTest : BaseTest() {
private lateinit var db: Database
@Before
fun setup() {
val dbFile = fileOpener.openUserFile("test.sqlite3")
if (dbFile.exists()) dbFile.delete()
db = databaseOpener.open(dbFile)
}
@Test
fun testUsage() {
db.setVersion(0)
assertEquals(db.getVersion(), 0)
db.setVersion(23)
assertEquals(db.getVersion(), 23)
var stmt = db.prepareStatement("drop table if exists demo")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("create table if not exists demo(key int, value text)")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("insert into demo(key, value) values (?1, ?2)")
stmt.bindInt(1, 42)
stmt.bindText(2, "Hello World")
stmt.step()
stmt.finalize()
stmt = db.prepareStatement("select * from demo where key > ?1")
stmt.bindInt(1, 10)
var result = stmt.step()
assertEquals(result, StepResult.ROW)
assertEquals(stmt.getInt(0), 42)
assertEquals(stmt.getText(1), "Hello World")
result = stmt.step()
assertEquals(result, StepResult.DONE)
stmt.finalize()
db.close()
}
@Test
fun testMigrateTo() {
assertEquals(0, db.getVersion())
db.migrateTo(22, fileOpener)
assertEquals(22, db.getVersion())
db.execute("select * from habits")
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils
import org.isoron.uhabits.BaseTest
import org.junit.Test
import kotlin.test.assertEquals
class JavaFilesTest : BaseTest() {
@Test
fun testReadLines() {
val hello = fileOpener.openResourceFile("hello.txt")
var lines = hello.readLines()
assertEquals("Hello World!", lines[0])
assertEquals("This is a resource.", lines[1])
val migration = fileOpener.openResourceFile("migrations/012.sql")
lines = migration.readLines()
assertEquals("delete from Score", lines[0])
}
}