forked from github/wulkanowy-mirror
Fallback to subject name from timetable when attendance item doesn't have it (#2052)
* Fallback to subject name from timetable when attendance item doesn't have it * Fix tests * Add some unit tests
This commit is contained in:
parent
7a408899df
commit
6c115fb915
@ -49,8 +49,8 @@ fun <T, U> Resource<T>.mapData(block: (T) -> U) = when (this) {
|
||||
|
||||
fun <T> Flow<Resource<T>>.logResourceStatus(name: String, showData: Boolean = false) = onEach {
|
||||
val description = when (it) {
|
||||
is Resource.Loading -> "started"
|
||||
is Resource.Intermediate -> "intermediate data received" + if (showData) " (data: `${it.data}`)" else ""
|
||||
is Resource.Loading -> "started"
|
||||
is Resource.Success -> "success" + if (showData) " (data: `${it.data}`)" else ""
|
||||
is Resource.Error -> "exception occurred: ${it.error}"
|
||||
}
|
||||
|
@ -13,4 +13,7 @@ interface TimetableDao : BaseDao<Timetable> {
|
||||
|
||||
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Timetable>>
|
||||
|
||||
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||
fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): List<Timetable>
|
||||
}
|
||||
|
@ -3,17 +3,22 @@ package io.github.wulkanowy.data.mappers
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.sdk.pojo.Attendance as SdkAttendance
|
||||
import io.github.wulkanowy.sdk.pojo.AttendanceSummary as SdkAttendanceSummary
|
||||
|
||||
fun List<SdkAttendance>.mapToEntities(semester: Semester) = map {
|
||||
fun List<SdkAttendance>.mapToEntities(semester: Semester, lessons: List<Timetable>) = map {
|
||||
Attendance(
|
||||
studentId = semester.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
date = it.date,
|
||||
timeId = it.timeId,
|
||||
number = it.number,
|
||||
subject = it.subject,
|
||||
subject = it.subject.ifBlank {
|
||||
lessons.find { lesson ->
|
||||
lesson.date == it.date && lesson.number == it.number
|
||||
}?.subject.orEmpty()
|
||||
},
|
||||
name = it.name,
|
||||
presence = it.presence,
|
||||
absence = it.absence,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
@ -9,8 +10,10 @@ import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.pojo.Absent
|
||||
import io.github.wulkanowy.utils.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
@ -20,6 +23,7 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
class AttendanceRepository @Inject constructor(
|
||||
private val attendanceDb: AttendanceDao,
|
||||
private val timetableDb: TimetableDao,
|
||||
private val sdk: Sdk,
|
||||
private val refreshHelper: AutoRefreshHelper,
|
||||
) {
|
||||
@ -48,10 +52,15 @@ class AttendanceRepository @Inject constructor(
|
||||
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
||||
},
|
||||
fetch = {
|
||||
val lessons = withContext(Dispatchers.IO) {
|
||||
timetableDb.load(
|
||||
semester.diaryId, semester.studentId, start.monday, end.sunday
|
||||
)
|
||||
}
|
||||
sdk.init(student)
|
||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||
.getAttendance(start.monday, end.sunday, semester.semesterId)
|
||||
.mapToEntities(semester)
|
||||
.mapToEntities(semester, lessons)
|
||||
},
|
||||
saveFetchResult = { old, new ->
|
||||
attendanceDb.deleteAll(old uniqueSubtract new)
|
||||
|
@ -0,0 +1,143 @@
|
||||
package io.github.wulkanowy.data.mappers
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.sdk.pojo.Attendance
|
||||
import io.github.wulkanowy.sdk.scrapper.attendance.SentExcuse
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class AttendanceMapperTest {
|
||||
|
||||
@Test
|
||||
fun `map attendance when fallback is not necessary`() {
|
||||
val attendance = listOf(
|
||||
getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"),
|
||||
getSdkAttendance(2, LocalDate.of(2022, 11, 17), "Oryginalna 2"),
|
||||
)
|
||||
val lessons = listOf(
|
||||
getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
|
||||
getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"),
|
||||
)
|
||||
|
||||
val result = attendance.mapToEntities(getEntitySemester(), lessons)
|
||||
assertEquals("Oryginalna 1", result[0].subject)
|
||||
assertEquals("Oryginalna 2", result[1].subject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `map attendance when fallback is not always necessary`() {
|
||||
val attendance = listOf(
|
||||
getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"),
|
||||
getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""),
|
||||
)
|
||||
val lessons = listOf(
|
||||
getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
|
||||
getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"),
|
||||
)
|
||||
|
||||
val result = attendance.mapToEntities(getEntitySemester(), lessons)
|
||||
assertEquals("Oryginalna 1", result[0].subject)
|
||||
assertEquals("Druga", result[1].subject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `map attendance when fallback is sometimes empty`() {
|
||||
val attendance = listOf(
|
||||
getSdkAttendance(1, LocalDate.of(2022, 11, 17), "Oryginalna 1"),
|
||||
getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""),
|
||||
)
|
||||
val lessons = listOf(
|
||||
getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
|
||||
)
|
||||
|
||||
val result = attendance.mapToEntities(getEntitySemester(), lessons)
|
||||
assertEquals("Oryginalna 1", result[0].subject)
|
||||
assertEquals("", result[1].subject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `map attendance when fallback is empty`() {
|
||||
val attendance = listOf(
|
||||
getSdkAttendance(1, LocalDate.of(2022, 11, 17), ""),
|
||||
getSdkAttendance(2, LocalDate.of(2022, 11, 17), ""),
|
||||
)
|
||||
val lessons = listOf(
|
||||
getEntityTimetable(1, LocalDate.of(2022, 11, 18), "Pierwsza"),
|
||||
getEntityTimetable(2, LocalDate.of(2022, 10, 17), "Druga"),
|
||||
)
|
||||
|
||||
val result = attendance.mapToEntities(getEntitySemester(), lessons)
|
||||
assertEquals("", result[0].subject)
|
||||
assertEquals("", result[1].subject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `map attendance with all subject fallback`() {
|
||||
val attendance = listOf(
|
||||
getSdkAttendance(1, LocalDate.of(2022, 11, 17)),
|
||||
getSdkAttendance(2, LocalDate.of(2022, 11, 17)),
|
||||
)
|
||||
val lessons = listOf(
|
||||
getEntityTimetable(1, LocalDate.of(2022, 11, 17), "Pierwsza"),
|
||||
getEntityTimetable(2, LocalDate.of(2022, 11, 17), "Druga"),
|
||||
)
|
||||
|
||||
val result = attendance.mapToEntities(getEntitySemester(), lessons)
|
||||
assertEquals("Pierwsza", result[0].subject)
|
||||
assertEquals("Druga", result[1].subject)
|
||||
}
|
||||
|
||||
private fun getSdkAttendance(number: Int, date: LocalDate, subject: String = "") = Attendance(
|
||||
number = number,
|
||||
name = "ABSENCE",
|
||||
subject = subject,
|
||||
date = date,
|
||||
timeId = 1,
|
||||
categoryId = 1,
|
||||
deleted = false,
|
||||
excuseStatus = SentExcuse.Status.WAITING,
|
||||
excusable = false,
|
||||
absence = false,
|
||||
excused = false,
|
||||
exemption = false,
|
||||
lateness = false,
|
||||
presence = false,
|
||||
)
|
||||
|
||||
private fun getEntityTimetable(number: Int, date: LocalDate, subject: String = "") = Timetable(
|
||||
number = number,
|
||||
start = Instant.now(),
|
||||
end = Instant.now(),
|
||||
date = date,
|
||||
subject = subject,
|
||||
subjectOld = "",
|
||||
group = "",
|
||||
room = "",
|
||||
roomOld = "",
|
||||
teacher = "",
|
||||
teacherOld = "",
|
||||
info = "",
|
||||
changes = false,
|
||||
canceled = false,
|
||||
studentId = 0,
|
||||
diaryId = 0,
|
||||
isStudentPlan = false,
|
||||
)
|
||||
|
||||
private fun getEntitySemester() = Semester(
|
||||
studentId = 0,
|
||||
diaryId = 0,
|
||||
kindergartenDiaryId = 0,
|
||||
diaryName = "",
|
||||
schoolYear = 0,
|
||||
semesterId = 0,
|
||||
semesterName = 0,
|
||||
start = LocalDate.now(),
|
||||
end = LocalDate.now(),
|
||||
classId = 0,
|
||||
unitId = 0
|
||||
)
|
||||
}
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.dataOrNull
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||
import io.github.wulkanowy.data.errorOrNull
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.toFirstResult
|
||||
@ -29,6 +30,9 @@ class AttendanceRepositoryTest {
|
||||
@MockK
|
||||
private lateinit var attendanceDb: AttendanceDao
|
||||
|
||||
@MockK
|
||||
private lateinit var timetableDb: TimetableDao
|
||||
|
||||
@MockK(relaxUnitFun = true)
|
||||
private lateinit var refreshHelper: AutoRefreshHelper
|
||||
|
||||
@ -51,8 +55,9 @@ class AttendanceRepositoryTest {
|
||||
fun setUp() {
|
||||
MockKAnnotations.init(this)
|
||||
every { refreshHelper.shouldBeRefreshed(any()) } returns false
|
||||
coEvery { timetableDb.load(any(), any(), any(), any()) } returns emptyList()
|
||||
|
||||
attendanceRepository = AttendanceRepository(attendanceDb, sdk, refreshHelper)
|
||||
attendanceRepository = AttendanceRepository(attendanceDb, timetableDb, sdk, refreshHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -60,8 +65,8 @@ class AttendanceRepositoryTest {
|
||||
// prepare
|
||||
coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList
|
||||
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||
flowOf(remoteList.mapToEntities(semester)),
|
||||
flowOf(remoteList.mapToEntities(semester))
|
||||
flowOf(remoteList.mapToEntities(semester, emptyList())),
|
||||
flowOf(remoteList.mapToEntities(semester, emptyList()))
|
||||
)
|
||||
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
|
||||
coEvery { attendanceDb.deleteAll(any()) } just Runs
|
||||
@ -83,9 +88,9 @@ class AttendanceRepositoryTest {
|
||||
// prepare
|
||||
coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList
|
||||
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||
flowOf(remoteList.dropLast(1).mapToEntities(semester)),
|
||||
flowOf(remoteList.dropLast(1).mapToEntities(semester)), // after fetch end before save result
|
||||
flowOf(remoteList.mapToEntities(semester))
|
||||
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())),
|
||||
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())), // after fetch end before save result
|
||||
flowOf(remoteList.mapToEntities(semester, emptyList()))
|
||||
)
|
||||
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
|
||||
coEvery { attendanceDb.deleteAll(any()) } just Runs
|
||||
@ -100,7 +105,7 @@ class AttendanceRepositoryTest {
|
||||
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
|
||||
coVerify {
|
||||
attendanceDb.insertAll(match {
|
||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
|
||||
})
|
||||
}
|
||||
coVerify { attendanceDb.deleteAll(match { it.isEmpty() }) }
|
||||
@ -111,9 +116,9 @@ class AttendanceRepositoryTest {
|
||||
// prepare
|
||||
coEvery { sdk.getAttendance(startDate, endDate, 1) } returns remoteList.dropLast(1)
|
||||
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||
flowOf(remoteList.mapToEntities(semester)),
|
||||
flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result
|
||||
flowOf(remoteList.dropLast(1).mapToEntities(semester))
|
||||
flowOf(remoteList.mapToEntities(semester, emptyList())),
|
||||
flowOf(remoteList.mapToEntities(semester, emptyList())), // after fetch end before save result
|
||||
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList()))
|
||||
)
|
||||
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
|
||||
coEvery { attendanceDb.deleteAll(any()) } just Runs
|
||||
@ -129,7 +134,7 @@ class AttendanceRepositoryTest {
|
||||
coVerify { attendanceDb.insertAll(match { it.isEmpty() }) }
|
||||
coVerify {
|
||||
attendanceDb.deleteAll(match {
|
||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user