Compare commits

...

6 Commits

Author SHA1 Message Date
Faierbel
2bae532f6d Merge branch 'develop' into bugfix/classid-zero 2024-05-05 10:46:47 +02:00
Faierbel
157e04b239 Add clearing all tables dependent on classId 2024-04-21 04:01:21 +02:00
Faierbel
2a0ac7f91e Add test for StudentDao 2024-04-14 17:48:44 +02:00
Faierbel
d7b1a08098 Merge branch 'develop' into bugfix/classid-zero 2024-04-14 16:32:24 +02:00
Faierbel
985be92a4d Fix tests 2024-04-14 02:57:05 +02:00
Faierbel
6616a313e2 Fix checking classId condition when is eduOne 2024-04-14 02:48:26 +02:00
24 changed files with 324 additions and 102 deletions

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@ -11,5 +12,16 @@ import javax.inject.Singleton
interface SchoolDao : BaseDao<School> {
@Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId")
fun load(studentId: Int, classId: Int): Flow<School?>
fun loadWithClassId(studentId: Int, classId: Int): Flow<School?>
@Query("SELECT * FROM School WHERE student_id = :studentId")
fun loadNoClassId(studentId: Int): Flow<School?>
fun load(student: Student): Flow<School?> {
return if (student.isEduOne == true) {
loadNoClassId(student.studentId)
} else {
loadWithClassId(student.studentId, student.classId)
}
}
}

View File

@ -5,6 +5,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import javax.inject.Singleton
@Singleton
@ -14,6 +15,17 @@ interface SemesterDao : BaseDao<Semester> {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertSemesters(items: List<Semester>): List<Long>
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId) OR (student_id = :studentId AND class_id = 0)")
suspend fun loadAll(studentId: Int, classId: Int): List<Semester>
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId)")
suspend fun loadAllWithClassId(studentId: Int, classId: Int): List<Semester>
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
suspend fun loadAllNoClassId(studentId: Int): List<Semester>
suspend fun loadAll(student: Student): List<Semester> {
return if (student.isEduOne == true) {
loadAllNoClassId(student.studentId)
} else {
loadAllWithClassId(student.studentId, student.classId)
}
}
}

View File

@ -47,13 +47,9 @@ abstract class StudentDao {
abstract suspend fun loadAll(): List<Student>
@Transaction
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0)")
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id)")
abstract suspend fun loadStudentsWithSemesters(): Map<Student, List<Semester>>
@Transaction
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0) WHERE Students.id = :id")
abstract suspend fun loadStudentWithSemestersById(id: Long): Map<Student, List<Semester>>
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
abstract suspend fun updateCurrent(id: Long)

View File

@ -2,6 +2,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Teacher
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@ -11,5 +12,16 @@ import javax.inject.Singleton
interface TeacherDao : BaseDao<Teacher> {
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
fun loadAll(studentId: Int, classId: Int): Flow<List<Teacher>>
fun loadAllWithClassId(studentId: Int, classId: Int): Flow<List<Teacher>>
@Query("SELECT * FROM Teachers WHERE student_id = :studentId")
fun loadAllNoClassId(studentId: Int): Flow<List<Teacher>>
fun loadAll(student: Student): Flow<List<Teacher>> {
return if (student.isEduOne == true) {
loadAllNoClassId(student.studentId)
} else {
loadAllWithClassId(student.studentId, student.classId)
}
}
}

View File

@ -6,6 +6,15 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration63 : AutoMigrationSpec {
override fun onPostMigrate(db: SupportSQLiteDatabase) {
db.execSQL("UPDATE Students SET is_edu_one = NULL WHERE is_edu_one = 0")
db.execSQL("DROP TABLE IF EXISTS `Semesters`")
db.execSQL("DROP TABLE IF EXISTS `School`")
db.execSQL("DROP TABLE IF EXISTS `Teachers`")
db.execSQL("CREATE TABLE IF NOT EXISTS `Semesters` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)")
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `Semesters` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)")
db.execSQL("CREATE TABLE IF NOT EXISTS `School` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)")
db.execSQL("CREATE TABLE IF NOT EXISTS `Teachers` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)")
db.execSQL("UPDATE Students SET is_edu_one = NULL")
}
}

View File

@ -0,0 +1,4 @@
package io.github.wulkanowy.data.exceptions
class NoSuchStudentException(id: Long) :
Exception("There is no student with id $id in database")

View File

@ -36,7 +36,7 @@ class SchoolRepository @Inject constructor(
)
it == null || forceRefresh || isExpired
},
query = { schoolDb.load(semester.studentId, semester.classId) },
query = { schoolDb.load(student) },
fetch = {
wulkanowySdkFactory.create(student, semester)
.getSchool()

View File

@ -27,11 +27,11 @@ class SemesterRepository @Inject constructor(
forceRefresh: Boolean = false,
refreshOnNoCurrent: Boolean = false
) = withContext(dispatchers.io) {
val semesters = semesterDb.loadAll(student.studentId, student.classId)
val semesters = semesterDb.loadAll(student)
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
refreshSemesters(student)
semesterDb.loadAll(student.studentId, student.classId)
semesterDb.loadAll(student)
} else semesters
}
@ -69,7 +69,7 @@ class SemesterRepository @Inject constructor(
return
}
val old = semesterDb.loadAll(student.studentId, student.classId)
val old = semesterDb.loadAll(student)
semesterDb.removeOldAndSaveNew(
oldItems = old uniqueSubtract new,
newItems = new uniqueSubtract old,

View File

@ -12,6 +12,7 @@ import io.github.wulkanowy.data.db.entities.StudentName
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
import io.github.wulkanowy.data.exceptions.NoSuchStudentException
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.mappers.mapToPojo
import io.github.wulkanowy.data.pojos.RegisterUser
@ -65,7 +66,8 @@ class StudentRepository @Inject constructor(
.mapToPojo(password)
.also { it.logErrors() }
suspend fun getSavedStudents(decryptPass: Boolean = true): List<StudentWithSemesters> {
@Deprecated("Semesters are not synced within this method and students with empty semesters are not returned")
suspend fun getSavedStudentsWithSemesters(decryptPass: Boolean = true): List<StudentWithSemesters> {
return studentDb.loadStudentsWithSemesters().map { (student, semesters) ->
StudentWithSemesters(
student = student.apply {
@ -80,22 +82,25 @@ class StudentRepository @Inject constructor(
}
}
suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true): StudentWithSemesters? =
studentDb.loadStudentWithSemestersById(id).let { res ->
StudentWithSemesters(
student = res.keys.firstOrNull() ?: return null,
semesters = res.values.first(),
)
}.apply {
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
student.password = withContext(dispatchers.io) {
suspend fun getSavedStudents(decryptPass: Boolean = true): List<Student> {
val students = studentDb.loadAll()
if (!decryptPass) return students
return students.map { student ->
if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) {
return@map student
}
student.apply {
password = withContext(dispatchers.io) {
scrambler.decrypt(student.password)
}
}
}
}
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
val student = studentDb.loadById(id) ?: throw NoSuchStudentException(id)
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
student.password = withContext(dispatchers.io) {
@ -123,7 +128,7 @@ class StudentRepository @Inject constructor(
return
}
val currentStudentSemesters = semesterDb.loadAll(student.studentId, student.classId)
val currentStudentSemesters = semesterDb.loadAll(student)
if (currentStudentSemesters.isEmpty()) {
Timber.d("Check isAuthorized: apply empty semesters workaround")
semesterDb.insertSemesters(
@ -181,8 +186,8 @@ class StudentRepository @Inject constructor(
}
}
suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) {
studentDb.switchCurrent(studentWithSemesters.student.id)
suspend fun switchStudent(student: Student) {
studentDb.switchCurrent(student.id)
}
suspend fun logoutStudent(student: Student) = studentDb.delete(student)
@ -190,8 +195,8 @@ class StudentRepository @Inject constructor(
suspend fun updateStudentNickAndAvatar(studentNickAndAvatar: StudentNickAndAvatar) =
studentDb.update(studentNickAndAvatar)
suspend fun isOneUniqueStudent() = getSavedStudents(false)
.distinctBy { it.student.studentName }.size == 1
suspend fun isOneUniqueStudent() = studentDb.loadAll()
.distinctBy { it.studentName }.size == 1
suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) =
wulkanowySdkFactory.create(student, semester)
@ -209,7 +214,7 @@ class StudentRepository @Inject constructor(
studentDb.update(studentName)
semesterDb.removeOldAndSaveNew(
oldItems = semesterDb.loadAll(student.studentId, semester.classId),
oldItems = semesterDb.loadAll(student),
newItems = newCurrentApiStudent.semesters.mapToEntities(newCurrentApiStudent.studentId)
)
}

View File

@ -35,7 +35,7 @@ class TeacherRepository @Inject constructor(
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
it.isEmpty() || forceRefresh || isExpired
},
query = { teacherDb.loadAll(semester.studentId, semester.classId) },
query = { teacherDb.loadAll(student) },
fetch = {
wulkanowySdkFactory.create(student, semester)
.getTeachers()

View File

@ -33,7 +33,7 @@ class AccountPresenter @Inject constructor(
}
private fun loadData() {
resourceFlow { studentRepository.getSavedStudents(false) }
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
.logResourceStatus("load account data")
.onResourceSuccess { view?.updateData(createAccountItems(it)) }
.onResourceError(errorHandler::dispatch)

View File

@ -1,9 +1,15 @@
package io.github.wulkanowy.ui.modules.account.accountdetails
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.logResourceStatus
import io.github.wulkanowy.data.onResourceError
import io.github.wulkanowy.data.onResourceLoading
import io.github.wulkanowy.data.onResourceNotLoading
import io.github.wulkanowy.data.onResourceSuccess
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.resourceFlow
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
@ -14,6 +20,7 @@ import javax.inject.Inject
class AccountDetailsPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val semeRepository: SemesterRepository,
private val syncManager: SyncManager
) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) {
@ -46,7 +53,12 @@ class AccountDetailsPresenter @Inject constructor(
}
private fun loadData() {
resourceFlow { studentRepository.getSavedStudentById(studentId ?: -1) }
resourceFlow {
val student = studentRepository.getStudentById(studentId ?: -1)
val semesters = semeRepository.getSemesters(student)
StudentWithSemesters(student, semesters)
}
.logResourceStatus("loading account details view")
.onResourceLoading {
view?.run {
@ -85,7 +97,7 @@ class AccountDetailsPresenter @Inject constructor(
Timber.i("Select student ${studentWithSemesters!!.student.id}")
resourceFlow { studentRepository.switchStudent(studentWithSemesters!!) }
resourceFlow { studentRepository.switchStudent(studentWithSemesters!!.student) }
.logResourceStatus("change student")
.onResourceSuccess { view?.recreateMainView() }
.onResourceNotLoading { view?.popViewToMain() }
@ -122,10 +134,12 @@ class AccountDetailsPresenter @Inject constructor(
syncManager.stopSyncWorker()
openClearLoginView()
}
studentWithSemesters?.student?.isCurrent == true -> {
Timber.i("Logout result: Logout student and switch to another")
recreateMainView()
}
else -> {
Timber.i("Logout result: Logout student")
recreateMainView()

View File

@ -1,8 +1,12 @@
package io.github.wulkanowy.ui.modules.account.accountquick
import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.logResourceStatus
import io.github.wulkanowy.data.onResourceError
import io.github.wulkanowy.data.onResourceNotLoading
import io.github.wulkanowy.data.onResourceSuccess
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.resourceFlow
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.ui.modules.account.AccountItem
@ -40,7 +44,7 @@ class AccountQuickPresenter @Inject constructor(
return
}
resourceFlow { studentRepository.switchStudent(studentWithSemesters) }
resourceFlow { studentRepository.switchStudent(studentWithSemesters.student) }
.logResourceStatus("change student")
.onResourceSuccess { view?.recreateMainView() }
.onResourceNotLoading { view?.popView() }

View File

@ -80,7 +80,7 @@ class LoginStudentSelectPresenter @Inject constructor(
private fun loadData() {
resetSelectedState()
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach {
students = it.dataOrNull.orEmpty()
when (it) {
is Resource.Loading -> Timber.d("Login student select students load started")

View File

@ -35,7 +35,7 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
}
private fun loadData() {
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach {
when (it) {
is Resource.Loading -> Timber.d("Lucky number widget configure students data load")
is Resource.Success -> {

View File

@ -132,7 +132,7 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
private fun getLuckyNumber(studentId: Long, appWidgetId: Int) = runBlocking {
try {
val students = studentRepository.getSavedStudents()
val student = students.singleOrNull { it.student.id == studentId }?.student
val student = students.singleOrNull { it.id == studentId }
val currentStudent = when {
student != null -> student
studentId != 0L && studentRepository.isCurrentStudentSet() -> {

View File

@ -85,7 +85,7 @@ class MainPresenter @Inject constructor(
return
}
resourceFlow { studentRepository.getSavedStudents(false) }
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
.logResourceStatus("load student avatar")
.onResourceSuccess {
studentsWitSemesters = it

View File

@ -42,7 +42,8 @@ class TimetableWidgetConfigurePresenter @Inject constructor(
}
private fun loadData() {
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
.onEach {
when (it) {
is Resource.Loading -> Timber.d("Timetable widget configure students data load")
is Resource.Success -> {
@ -55,6 +56,7 @@ class TimetableWidgetConfigurePresenter @Inject constructor(
else -> view?.updateData(it.data, selectedStudentId)
}
}
is Resource.Error -> errorHandler.dispatch(it.error)
}
}.launch()

View File

@ -95,7 +95,7 @@ class TimetableWidgetFactory(
private suspend fun getStudent(studentId: Long): Student? {
val students = studentRepository.getSavedStudents()
return students.singleOrNull { it.student.id == studentId }?.student
return students.singleOrNull { it.id == studentId }
}
private suspend fun getLessons(

View File

@ -2,7 +2,11 @@ package io.github.wulkanowy.ui.modules.timetablewidget
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetManager.*
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_DELETED
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@ -22,7 +26,14 @@ import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.services.widgets.TimetableWidgetService
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.*
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.capitalise
import io.github.wulkanowy.utils.nextOrSameSchoolDay
import io.github.wulkanowy.utils.nextSchoolDay
import io.github.wulkanowy.utils.nickOrName
import io.github.wulkanowy.utils.previousSchoolDay
import io.github.wulkanowy.utils.toFormattedString
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@ -244,7 +255,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try {
val students = studentRepository.getSavedStudents(false)
val student = students.singleOrNull { it.student.id == studentId }?.student
val student = students.singleOrNull { it.id == studentId }
when {
student != null -> student
studentId != 0L && studentRepository.isCurrentStudentSet() -> {
@ -263,7 +274,10 @@ class TimetableWidgetProvider : BroadcastReceiver() {
}
private fun setupAccountView(
context: Context, student: Student, remoteViews: RemoteViews, widgetId: Int
context: Context,
student: Student,
remoteViews: RemoteViews,
widgetId: Int
) {
val accountInitials = getAccountInitials(student.nickOrName)
val accountPickerPendingIntent = createAccountPickerPendingIntent(context, widgetId)

View File

@ -0,0 +1,161 @@
package io.github.wulkanowy.data.db.dao
import android.content.Context
import android.os.Build
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import dagger.hilt.android.testing.HiltTestApplication
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.getSemesterEntity
import io.github.wulkanowy.getStudentEntity
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.Test
import kotlin.test.assertEquals
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
class StudentDaoTest {
private lateinit var studentDao: StudentDao
private lateinit var semesterDao: SemesterDao
private lateinit var db: AppDatabase
@Before
fun createDb() {
val context: Context = ApplicationProvider.getApplicationContext()
db = Room.inMemoryDatabaseBuilder(
context = context,
klass = AppDatabase::class.java
).build()
studentDao = db.studentDao
semesterDao = db.semesterDao
}
@Test
fun `get students associated with correct semester with same studentId`() = runTest {
val notEduOneStudent = getStudentEntity()
.copy(
isEduOne = false,
classId = 42,
studentId = 100
)
.apply { id = 1 }
val eduOneStudent = getStudentEntity()
.copy(
isEduOne = true,
classId = 0,
studentId = 100
)
.apply { id = 2 }
val semesterAssociatedWithNotEduOneStudent = getSemesterEntity()
.copy(
studentId = notEduOneStudent.studentId,
classId = notEduOneStudent.classId,
diaryId = 1 // make semester unique
)
.apply { id = 0 }
val semesterAssociatedWithEduOneStudent = getSemesterEntity()
.copy(
studentId = eduOneStudent.studentId,
classId = eduOneStudent.classId,
diaryId = 2 // make semester unique
)
.apply { id = 0 }
studentDao.insertAll(listOf(notEduOneStudent, eduOneStudent))
semesterDao.insertAll(
listOf(
semesterAssociatedWithNotEduOneStudent,
semesterAssociatedWithEduOneStudent
)
)
val studentsWithSemesters = studentDao.loadStudentsWithSemesters()
val notEduOneSemestersResult = studentsWithSemesters.entries
.find { (student, _) -> student.id == notEduOneStudent.id }
?.value
val eduOneSemestersResult = studentsWithSemesters.entries
.find { (student, _) -> student.id == eduOneStudent.id }
?.value
assertEquals(2, studentsWithSemesters.size)
assertEquals(1, notEduOneSemestersResult?.size)
assertEquals(1, eduOneSemestersResult?.size)
assertEquals(semesterAssociatedWithEduOneStudent, eduOneSemestersResult?.firstOrNull())
assertEquals(
semesterAssociatedWithNotEduOneStudent,
notEduOneSemestersResult?.firstOrNull()
)
}
@Test
fun `get students associated with correct semester with different studentId`() = runTest {
val notEduOneStudent = getStudentEntity()
.copy(
isEduOne = false,
classId = 42,
studentId = 100
)
.apply { id = 1 }
val eduOneStudent = getStudentEntity()
.copy(
isEduOne = true,
classId = 0,
studentId = 101
)
.apply { id = 2 }
val semesterAssociatedWithNotEduOneStudent = getSemesterEntity()
.copy(
studentId = notEduOneStudent.studentId,
classId = notEduOneStudent.classId,
)
.apply { id = 0 }
val semesterAssociatedWithEduOneStudent = getSemesterEntity()
.copy(
studentId = eduOneStudent.studentId,
classId = eduOneStudent.classId,
)
.apply { id = 0 }
studentDao.insertAll(listOf(notEduOneStudent, eduOneStudent))
semesterDao.insertAll(
listOf(
semesterAssociatedWithNotEduOneStudent,
semesterAssociatedWithEduOneStudent
)
)
val studentsWithSemesters = studentDao.loadStudentsWithSemesters()
val notEduOneSemestersResult = studentsWithSemesters.entries
.find { (student, _) -> student.id == notEduOneStudent.id }
?.value
val eduOneSemestersResult = studentsWithSemesters.entries
.find { (student, _) -> student.id == eduOneStudent.id }
?.value
assertEquals(2, studentsWithSemesters.size)
assertEquals(1, notEduOneSemestersResult?.size)
assertEquals(1, eduOneSemestersResult?.size)
assertEquals(semesterAssociatedWithEduOneStudent, eduOneSemestersResult?.firstOrNull())
assertEquals(
semesterAssociatedWithNotEduOneStudent,
notEduOneSemestersResult?.firstOrNull()
)
}
@After
fun closeDb() {
db.close()
}
}

View File

@ -12,9 +12,7 @@ import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
@HiltAndroidTest
@RunWith(RobolectricTestRunner::class)
@ -22,9 +20,10 @@ import kotlin.test.assertTrue
class Migration63Test : AbstractMigrationTest() {
@Test
fun `update is_edu_one to null if 0`() = runTest {
fun `update is_edu_one to null`() = runTest {
with(helper.createDatabase(dbName, 62)) {
createStudent(1, 0)
createStudent(2, 1)
close()
}
@ -32,31 +31,15 @@ class Migration63Test : AbstractMigrationTest() {
val database = getMigratedRoomDatabase()
val studentDb = database.studentDao
val student = studentDb.loadById(1)
val student1 = studentDb.loadById(1)
val student2 = studentDb.loadById(2)
assertNull(student!!.isEduOne)
assertNull(student1!!.isEduOne)
assertNull(student2!!.isEduOne)
database.close()
}
@Test
fun `check is_edu_one is stay same`() = runTest {
with(helper.createDatabase(dbName, 62)) {
createStudent(1, 1)
close()
}
helper.runMigrationsAndValidate(dbName, 63, true)
val database = getMigratedRoomDatabase()
val studentDb = database.studentDao
val student = studentDb.loadById(1)
val isEduOne = assertNotNull(student!!.isEduOne)
assertTrue(isEduOne)
database.close()
}
private fun SupportSQLiteDatabase.createStudent(id: Long, isEduOneValue: Int) {
insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("scrapper_base_url", "https://fakelog.cf")

View File

@ -50,7 +50,7 @@ class SemesterRepositoryTest {
getSemesterPojo(1, 2, now().minusMonths(3), now())
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns emptyList()
coEvery { semesterDb.loadAll(student) } returns emptyList()
coEvery { sdk.getSemesters() } returns semesters
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
@ -77,10 +77,7 @@ class SemesterRepositoryTest {
)
coEvery {
semesterDb.loadAll(
student.studentId,
student.classId
)
semesterDb.loadAll(student)
} returns badSemesters.mapToEntities(student.studentId)
coEvery { sdk.getSemesters() } returns goodSemesters
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
@ -103,7 +100,7 @@ class SemesterRepositoryTest {
getSemesterPojo(2, 3, now(), now().plusMonths(6)),
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returnsMany listOf(
coEvery { semesterDb.loadAll(any()) } returnsMany listOf(
badSemesters.mapToEntities(student.studentId),
badSemesters.mapToEntities(student.studentId),
goodSemesters.mapToEntities(student.studentId)
@ -125,7 +122,7 @@ class SemesterRepositoryTest {
getSemesterEntity(1, 2, now().minusMonths(6), now().minusMonths(1))
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
coEvery { semesterDb.loadAll(student) } returns semesters
val items = runBlocking { semesterRepository.getSemesters(student) }
assertEquals(2, items.size)
@ -138,7 +135,7 @@ class SemesterRepositoryTest {
getSemesterEntity(1, 2, now().minusMonths(3), now())
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
coEvery { semesterDb.loadAll(student) } returns semesters
val items = runBlocking { semesterRepository.getSemesters(student) }
assertEquals(2, items.size)
@ -151,7 +148,7 @@ class SemesterRepositoryTest {
getSemesterEntity(1, 2, now(), now())
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
coEvery { semesterDb.loadAll(student) } returns semesters
val items = runBlocking { semesterRepository.getSemesters(student) }
assertEquals(2, items.size)
@ -164,7 +161,7 @@ class SemesterRepositoryTest {
getSemesterPojo(1, 2, now().minusMonths(3), now())
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns emptyList()
coEvery { semesterDb.loadAll(student) } returns emptyList()
coEvery { sdk.getSemesters() } returns semesters
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
@ -194,10 +191,7 @@ class SemesterRepositoryTest {
)
coEvery {
semesterDb.loadAll(
student.studentId,
student.classId
)
semesterDb.loadAll(student)
} returns semestersWithNoCurrent
coEvery { sdk.getSemesters() } returns newSemesters
coEvery { semesterDb.removeOldAndSaveNew(any(), any()) } just Runs
@ -214,7 +208,7 @@ class SemesterRepositoryTest {
getSemesterEntity(1, 2, now().minusMonths(1), now().plusMonths(1))
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
coEvery { semesterDb.loadAll(student) } returns semesters
val items = semesterRepository.getSemesters(student, refreshOnNoCurrent = true)
assertEquals(2, items.size)
@ -227,14 +221,14 @@ class SemesterRepositoryTest {
getSemesterEntity(1, 1, now(), now())
)
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
coEvery { semesterDb.loadAll(student) } returns semesters
runBlocking { semesterRepository.getCurrentSemester(student) }
}
@Test(expected = RuntimeException::class)
fun getCurrentSemester_emptyList() {
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns emptyList()
coEvery { semesterDb.loadAll(student) } returns emptyList()
coEvery { sdk.getSemesters() } returns emptyList()
runBlocking { semesterRepository.getCurrentSemester(student) }