From 6d1fa0cf056289457c3ca7616861a3dd362caea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 10 May 2020 10:51:01 +0200 Subject: [PATCH] Optimize grade average provider (#792) --- app/build.gradle | 2 +- .../data/repositories/grade/GradeLocalTest.kt | 4 +- .../repositories/grade/GradeRepositoryTest.kt | 27 +-- .../data/repositories/grade/GradeLocal.kt | 21 +- .../data/repositories/grade/GradeRemote.kt | 20 +- .../repositories/grade/GradeRepository.kt | 58 +++-- .../gradessummary/GradeSummaryLocal.kt | 24 --- .../gradessummary/GradeSummaryRemote.kt | 35 --- .../gradessummary/GradeSummaryRepository.kt | 35 --- .../wulkanowy/services/ServicesModule.kt | 5 - .../services/sync/works/GradeSummaryWork.kt | 14 -- .../services/sync/works/GradeWork.kt | 1 - .../ui/modules/grade/GradeAverageProvider.kt | 87 ++++---- .../modules/grade/GradeDetailsWithAverage.kt | 12 ++ .../grade/details/GradeDetailsAdapter.kt | 2 +- .../modules/grade/details/GradeDetailsItem.kt | 1 - .../grade/details/GradeDetailsPresenter.kt | 25 +-- .../grade/summary/GradeSummaryPresenter.kt | 26 +-- .../modules/grade/GradeAverageProviderTest.kt | 203 ++++++++++-------- 19 files changed, 278 insertions(+), 324 deletions(-) delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryLocal.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeDetailsWithAverage.kt diff --git a/app/build.gradle b/app/build.gradle index 412dd1bd..0f35bc82 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -122,7 +122,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:0.17.4" + implementation "io.github.wulkanowy:sdk:445905b" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeLocalTest.kt index 7233c306..eb1a5548 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeLocalTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeLocalTest.kt @@ -24,7 +24,7 @@ class GradeLocalTest { fun createDb() { testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java) .build() - gradeLocal = GradeLocal(testDb.gradeDao) + gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao) } @After @@ -43,7 +43,7 @@ class GradeLocalTest { val semester = Semester(1, 2, "", 2019, 2, 1, now(), now(), 1, 1) val grades = gradeLocal - .getGrades(semester) + .getGradesDetails(semester) .blockingGet() assertEquals(2, grades.size) diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeRepositoryTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeRepositoryTest.kt index f3c6b7a1..cdd51477 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeRepositoryTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/grade/GradeRepositoryTest.kt @@ -11,6 +11,7 @@ import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.sdk.pojo.Grade import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK @@ -52,7 +53,7 @@ class GradeRepositoryTest { fun initApi() { MockKAnnotations.init(this) testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build() - gradeLocal = GradeLocal(testDb.gradeDao) + gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao) gradeRemote = GradeRemote(mockSdk) every { studentMock.registrationDate } returns LocalDateTime.of(2019, 2, 27, 12, 0) @@ -75,10 +76,10 @@ class GradeRepositoryTest { createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"), createGradeApi(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"), createGradeApi(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza") - )) + ) to emptyList()) val grades = GradeRepository(settings, gradeLocal, gradeRemote) - .getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date } + .getGrades(studentMock, semesterMock, true).blockingGet().first.sortedByDescending { it.date } assertFalse { grades[0].isRead } assertFalse { grades[1].isRead } @@ -99,10 +100,10 @@ class GradeRepositoryTest { createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"), createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"), createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa") - )) + ) to emptyList()) val grades = GradeRepository(settings, gradeLocal, gradeRemote) - .getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date } + .getGrades(studentMock, semesterMock, true).blockingGet().first.sortedByDescending { it.date } assertFalse { grades[0].isRead } assertFalse { grades[1].isRead } @@ -121,12 +122,12 @@ class GradeRepositoryTest { every { mockSdk.getGrades(1) } returns Single.just(listOf( createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"), createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena") - )) + ) to emptyList()) val grades = GradeRepository(settings, gradeLocal, gradeRemote) .getGrades(studentMock, semesterMock, true).blockingGet() - assertEquals(2, grades.size) + assertEquals(2, grades.first.size) } @Test @@ -140,12 +141,12 @@ class GradeRepositoryTest { createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"), createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"), createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena") - )) + ) to emptyList()) val grades = GradeRepository(settings, gradeLocal, gradeRemote) .getGrades(studentMock, semesterMock, true).blockingGet() - assertEquals(3, grades.size) + assertEquals(3, grades.first.size) } @Test @@ -156,12 +157,12 @@ class GradeRepositoryTest { createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"), createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"), createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena") - )) + ) to emptyList()) val grades = GradeRepository(settings, gradeLocal, gradeRemote) .getGrades(studentMock, semesterMock, true).blockingGet() - assertEquals(3, grades.size) + assertEquals(3, grades.first.size) } @Test @@ -171,11 +172,11 @@ class GradeRepositoryTest { createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena") )) - every { mockSdk.getGrades(1) } returns Single.just(listOf()) + every { mockSdk.getGrades(1) } returns Single.just(emptyList() to emptyList()) val grades = GradeRepository(settings, gradeLocal, gradeRemote) .getGrades(studentMock, semesterMock, true).blockingGet() - assertEquals(0, grades.size) + assertEquals(0, grades.first.size) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeLocal.kt index 4983a474..944ed34a 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeLocal.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeLocal.kt @@ -1,14 +1,19 @@ package io.github.wulkanowy.data.repositories.grade import io.github.wulkanowy.data.db.dao.GradeDao +import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.entities.Grade +import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Semester import io.reactivex.Maybe import javax.inject.Inject import javax.inject.Singleton @Singleton -class GradeLocal @Inject constructor(private val gradeDb: GradeDao) { +class GradeLocal @Inject constructor( + private val gradeDb: GradeDao, + private val gradeSummaryDb: GradeSummaryDao +) { fun saveGrades(grades: List) { gradeDb.insertAll(grades) @@ -22,7 +27,19 @@ class GradeLocal @Inject constructor(private val gradeDb: GradeDao) { gradeDb.updateAll(grades) } - fun getGrades(semester: Semester): Maybe> { + fun getGradesDetails(semester: Semester): Maybe> { return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() } } + + fun saveGradesSummary(gradesSummary: List) { + gradeSummaryDb.insertAll(gradesSummary) + } + + fun deleteGradesSummary(gradesSummary: List) { + gradeSummaryDb.deleteAll(gradesSummary) + } + + fun getGradesSummary(semester: Semester): Maybe> { + return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() } + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt index 6f19095b..abb2f98c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt @@ -1,6 +1,7 @@ package io.github.wulkanowy.data.repositories.grade import io.github.wulkanowy.data.db.entities.Grade +import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk @@ -12,11 +13,11 @@ import javax.inject.Singleton @Singleton class GradeRemote @Inject constructor(private val sdk: Sdk) { - fun getGrades(student: Student, semester: Semester): Single> { + fun getGrades(student: Student, semester: Semester): Single, List>> { return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) .getGrades(semester.semesterId) - .map { grades -> - grades.map { + .map { (details, summary) -> + details.map { Grade( studentId = semester.studentId, semesterId = semester.semesterId, @@ -33,6 +34,19 @@ class GradeRemote @Inject constructor(private val sdk: Sdk) { date = it.date, teacher = it.teacher ) + } to summary.map { + GradeSummary( + semesterId = semester.semesterId, + studentId = semester.studentId, + position = 0, + subject = it.name, + predictedGrade = it.predicted, + finalGrade = it.final, + pointsSum = it.pointsSum, + proposedPoints = it.proposedPoints, + finalPoints = it.finalPoints, + average = it.average + ) } } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt index 351ebc39..e28350a5 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.grade import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.Grade +import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.uniqueSubtract @@ -19,34 +20,47 @@ class GradeRepository @Inject constructor( private val remote: GradeRemote ) { - fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single> { - return local.getGrades(semester).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getGrades(student, semester) - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getGrades(semester).toSingle(emptyList()) - .doOnSuccess { old -> - val notifyBreakDate = old.maxBy { it.date }?.date ?: student.registrationDate.toLocalDate() - local.deleteGrades(old.uniqueSubtract(new)) - local.saveGrades(new.uniqueSubtract(old) - .onEach { - if (it.date >= notifyBreakDate) it.apply { - isRead = false - if (notify) isNotified = false - } - }) - } - }.flatMap { local.getGrades(semester).toSingle(emptyList()) }) + fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single, List>> { + return local.getGradesDetails(semester).flatMap { details -> + local.getGradesSummary(semester).map { summary -> details to summary } + }.filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap { + if (it) remote.getGrades(student, semester) + else Single.error(UnknownHostException()) + }.flatMap { (newDetails, newSummary) -> + local.getGradesDetails(semester).toSingle(emptyList()) + .doOnSuccess { old -> + val notifyBreakDate = old.maxBy { it.date }?.date ?: student.registrationDate.toLocalDate() + local.deleteGrades(old.uniqueSubtract(newDetails)) + local.saveGrades(newDetails.uniqueSubtract(old) + .onEach { + if (it.date >= notifyBreakDate) it.apply { + isRead = false + if (notify) isNotified = false + } + }) + }.flatMap { + local.getGradesSummary(semester).toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteGradesSummary(old.uniqueSubtract(newSummary)) + local.saveGradesSummary(newSummary.uniqueSubtract(old)) + } + } + }.flatMap { + local.getGradesDetails(semester).toSingle(emptyList()).flatMap { details -> + local.getGradesSummary(semester).toSingle(emptyList()).map { summary -> + details to summary + } + } + }) } fun getUnreadGrades(semester: Semester): Single> { - return local.getGrades(semester).map { it.filter { grade -> !grade.isRead } }.toSingle(emptyList()) + return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isRead } }.toSingle(emptyList()) } fun getNotNotifiedGrades(semester: Semester): Single> { - return local.getGrades(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList()) + return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList()) } fun updateGrade(grade: Grade): Completable { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryLocal.kt deleted file mode 100644 index e74641d3..00000000 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryLocal.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.wulkanowy.data.repositories.gradessummary - -import io.github.wulkanowy.data.db.dao.GradeSummaryDao -import io.github.wulkanowy.data.db.entities.GradeSummary -import io.github.wulkanowy.data.db.entities.Semester -import io.reactivex.Maybe -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSummaryDao) { - - fun saveGradesSummary(gradesSummary: List) { - gradeSummaryDb.insertAll(gradesSummary) - } - - fun deleteGradesSummary(gradesSummary: List) { - gradeSummaryDb.deleteAll(gradesSummary) - } - - fun getGradesSummary(semester: Semester): Maybe> { - return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt deleted file mode 100644 index 1b09974d..00000000 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.wulkanowy.data.repositories.gradessummary - -import io.github.wulkanowy.data.db.entities.GradeSummary -import io.github.wulkanowy.data.db.entities.Semester -import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.sdk.Sdk -import io.github.wulkanowy.utils.init -import io.reactivex.Single -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GradeSummaryRemote @Inject constructor(private val sdk: Sdk) { - - fun getGradeSummary(student: Student, semester: Semester): Single> { - return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) - .getGradesSummary(semester.semesterId) - .map { gradesSummary -> - gradesSummary.map { - GradeSummary( - semesterId = semester.semesterId, - studentId = semester.studentId, - position = 0, - subject = it.name, - predictedGrade = it.predicted, - finalGrade = it.final, - pointsSum = it.pointsSum, - proposedPoints = it.proposedPoints, - finalPoints = it.finalPoints, - average = it.average - ) - } - } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt deleted file mode 100644 index f1d7a6c1..00000000 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.wulkanowy.data.repositories.gradessummary - -import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork -import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.db.entities.GradeSummary -import io.github.wulkanowy.data.db.entities.Semester -import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.utils.uniqueSubtract -import io.reactivex.Single -import java.net.UnknownHostException -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GradeSummaryRepository @Inject constructor( - private val settings: InternetObservingSettings, - private val local: GradeSummaryLocal, - private val remote: GradeSummaryRemote -) { - - fun getGradesSummary(student: Student, semester: Semester, forceRefresh: Boolean = false): Single> { - return local.getGradesSummary(semester).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getGradeSummary(student, semester) - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getGradesSummary(semester).toSingle(emptyList()) - .doOnSuccess { old -> - local.deleteGradesSummary(old.uniqueSubtract(new)) - local.saveGradesSummary(new.uniqueSubtract(old)) - } - }.flatMap { local.getGradesSummary(semester).toSingle(emptyList()) }) - } -} diff --git a/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt b/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt index 7240a50b..c7c573e2 100644 --- a/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt +++ b/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt @@ -21,7 +21,6 @@ import io.github.wulkanowy.services.sync.works.AttendanceWork import io.github.wulkanowy.services.sync.works.CompletedLessonWork import io.github.wulkanowy.services.sync.works.ExamWork import io.github.wulkanowy.services.sync.works.GradeStatisticsWork -import io.github.wulkanowy.services.sync.works.GradeSummaryWork import io.github.wulkanowy.services.sync.works.GradeWork import io.github.wulkanowy.services.sync.works.HomeworkWork import io.github.wulkanowy.services.sync.works.LuckyNumberWork @@ -64,10 +63,6 @@ abstract class ServicesModule { @IntoSet abstract fun provideAttendanceWork(work: AttendanceWork): Work - @Binds - @IntoSet - abstract fun provideGradeSummaryWork(work: GradeSummaryWork): Work - @Binds @IntoSet abstract fun provideExamWork(work: ExamWork): Work diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt deleted file mode 100644 index 4c8e955d..00000000 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt +++ /dev/null @@ -1,14 +0,0 @@ -package io.github.wulkanowy.services.sync.works - -import io.github.wulkanowy.data.db.entities.Semester -import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository -import io.reactivex.Completable -import javax.inject.Inject - -class GradeSummaryWork @Inject constructor(private val gradeSummaryRepository: GradeSummaryRepository) : Work { - - override fun create(student: Student, semester: Semester): Completable { - return gradeSummaryRepository.getGradesSummary(student, semester, true).ignoreElement() - } -} diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt index 7559d289..6e90826a 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeWork.kt @@ -58,4 +58,3 @@ class GradeWork @Inject constructor( ) } } - diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt index 3bb084d3..954b5756 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt @@ -3,71 +3,76 @@ package io.github.wulkanowy.ui.modules.grade import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.grade.GradeRepository -import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository +import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.utils.calcAverage import io.github.wulkanowy.utils.changeModifier -import io.reactivex.Maybe import io.reactivex.Single import javax.inject.Inject class GradeAverageProvider @Inject constructor( - private val preferencesRepository: PreferencesRepository, + private val semesterRepository: SemesterRepository, private val gradeRepository: GradeRepository, - private val gradeSummaryRepository: GradeSummaryRepository + private val preferencesRepository: PreferencesRepository ) { private val plusModifier = preferencesRepository.gradePlusModifier private val minusModifier = preferencesRepository.gradeMinusModifier - fun getGradeAverage(student: Student, semesters: List, selectedSemesterId: Int, forceRefresh: Boolean): Single>> { - return when (preferencesRepository.gradeAverageMode) { - "all_year" -> getAllYearAverage(student, semesters, selectedSemesterId, forceRefresh) - "only_one_semester" -> getOnlyOneSemesterAverage(student, semesters, selectedSemesterId, forceRefresh) - else -> throw IllegalArgumentException("Incorrect grade average mode: ${preferencesRepository.gradeAverageMode} ") + fun getGradesDetailsWithAverage(student: Student, semesterId: Int, forceRefresh: Boolean = false): Single> { + return semesterRepository.getSemesters(student).flatMap { semesters -> + when (preferencesRepository.gradeAverageMode) { + "only_one_semester" -> getSemesterDetailsWithAverage(student, semesters.single { it.semesterId == semesterId }, forceRefresh) + "all_year" -> calculateWholeYearAverage(student, semesters, semesterId, forceRefresh) + else -> throw IllegalArgumentException("Incorrect grade average mode: ${preferencesRepository.gradeAverageMode} ") + } } } - private fun getAllYearAverage(student: Student, semesters: List, semesterId: Int, forceRefresh: Boolean): Single>> { + private fun calculateWholeYearAverage(student: Student, semesters: List, semesterId: Int, forceRefresh: Boolean): Single> { val selectedSemester = semesters.single { it.semesterId == semesterId } val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 } - return getAverageFromGradeSummary(student, selectedSemester, forceRefresh) - .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) - .flatMap { firstGrades -> - if (selectedSemester == firstSemester) Single.just(firstGrades) - else { - gradeRepository.getGrades(student, firstSemester) - .map { secondGrades -> secondGrades + firstGrades } + return getSemesterDetailsWithAverage(student, selectedSemester, forceRefresh).flatMap { selectedDetails -> + val isAnyAverage = selectedDetails.any { it.average != .0 } + + if (selectedSemester != firstSemester) { + getSemesterDetailsWithAverage(student, firstSemester, forceRefresh).map { secondDetails -> + selectedDetails.map { selected -> + val second = secondDetails.singleOrNull { it.subject == selected.subject } + selected.copy( + average = if (!isAnyAverage || preferencesRepository.gradeAverageForceCalc) { + (selected.grades + second?.grades.orEmpty()).calcAverage() + } else (selected.average + (second?.average ?: selected.average)) / 2 + ) } - }.map { grades -> - grades.map { if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) else it } - .groupBy { it.subject } - .map { Triple(it.key, it.value.calcAverage(), "") } - }) + } + } else Single.just(selectedDetails) + } } - private fun getOnlyOneSemesterAverage(student: Student, semesters: List, semesterId: Int, forceRefresh: Boolean): Single>> { - val selectedSemester = semesters.single { it.semesterId == semesterId } + private fun getSemesterDetailsWithAverage(student: Student, semester: Semester, forceRefresh: Boolean): Single> { + return gradeRepository.getGrades(student, semester, forceRefresh).map { (details, summaries) -> + val isAnyAverage = summaries.any { it.average != .0 } + val allGrades = details.groupBy { it.subject } - return getAverageFromGradeSummary(student, selectedSemester, forceRefresh) - .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) - .map { grades -> - grades.map { if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) else it } - .groupBy { it.subject } - .map { Triple(it.key, it.value.calcAverage(), "") } - }) - } - - private fun getAverageFromGradeSummary(student: Student, selectedSemester: Semester, forceRefresh: Boolean): Maybe>> { - return gradeSummaryRepository.getGradesSummary(student, selectedSemester, forceRefresh) - .toMaybe() - .flatMap { - if (it.any { summary -> summary.average != .0 }) { - Maybe.just(it.map { summary -> Triple(summary.subject, summary.average, summary.pointsSum) }) - } else Maybe.empty() - }.filter { !preferencesRepository.gradeAverageForceCalc } + summaries.map { summary -> + val grades = allGrades[summary.subject].orEmpty() + GradeDetailsWithAverage( + subject = summary.subject, + average = if (!isAnyAverage || preferencesRepository.gradeAverageForceCalc) { + grades.map { + if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) + else it + }.calcAverage() + } else summary.average, + points = summary.pointsSum, + summary = summary, + grades = grades + ) + } + } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeDetailsWithAverage.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeDetailsWithAverage.kt new file mode 100644 index 00000000..3f5d706b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeDetailsWithAverage.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.ui.modules.grade + +import io.github.wulkanowy.data.db.entities.Grade +import io.github.wulkanowy.data.db.entities.GradeSummary + +data class GradeDetailsWithAverage( + val subject: String, + val average: Double, + val points: String, + val summary: GradeSummary, + val grades: List +) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsAdapter.kt index 22367d02..7adab547 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsAdapter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsAdapter.kt @@ -107,7 +107,7 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter 0) View.VISIBLE else View.GONE if (header.newGrades > 0) gradeHeaderNote.text = header.newGrades.toString(10) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt index f1adbdea..28197496 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsItem.kt @@ -12,7 +12,6 @@ data class GradeDetailsItem( data class GradeDetailsHeader( val subject: String, - val number: Int, val average: Double?, val pointsSum: String?, var newGrades: Int, diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt index 83501182..26c22264 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt @@ -8,6 +8,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider +import io.github.wulkanowy.ui.modules.grade.GradeDetailsWithAverage import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber @@ -126,14 +127,7 @@ class GradeDetailsPresenter @Inject constructor( private fun loadData(semesterId: Int, forceRefresh: Boolean) { Timber.i("Loading grade details data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getSemesters(it).map { semester -> it to semester } } - .flatMap { (student, semesters) -> - averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh).flatMap { averages -> - gradeRepository.getGrades(student, semesters.first { it.semesterId == semesterId }, forceRefresh) - .map { it.sortedByDescending { grade -> grade.date } } - .map { createGradeItems(it, averages) } - } - } + .flatMap { averageProvider.getGradesDetailsWithAverage(it, semesterId, forceRefresh) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { @@ -146,16 +140,14 @@ class GradeDetailsPresenter @Inject constructor( } .subscribe({ grades -> Timber.i("Loading grade details result: Success") - newGradesAmount = grades - .filter { it.viewType == ViewType.HEADER } - .sumBy { item -> (item.value as GradeDetailsHeader).newGrades } + newGradesAmount = grades.sumBy { it.grades.sumBy { grade -> if (!grade.isRead) 1 else 0 } } updateMarkAsDoneButton() view?.run { showEmpty(grades.isEmpty()) showErrorView(false) showContent(grades.isNotEmpty()) updateData( - data = grades, + data = createGradeItems(grades), isGradeExpandable = preferencesRepository.isGradeExpandable, gradeColorTheme = preferencesRepository.gradeColorTheme ) @@ -178,17 +170,16 @@ class GradeDetailsPresenter @Inject constructor( } } - private fun createGradeItems(items: List, averages: List>): List { - return items.groupBy { grade -> grade.subject }.toSortedMap().map { (subject, grades) -> + private fun createGradeItems(items: List): List { + return items.filter { it.grades.isNotEmpty() }.map { (subject, average, points, _, grades) -> val subItems = grades.map { GradeDetailsItem(it, ViewType.ITEM) } listOf(GradeDetailsItem(GradeDetailsHeader( subject = subject, - average = averages.singleOrNull { subject == it.first }?.second, - pointsSum = averages.singleOrNull { subject == it.first }?.third, - number = grades.size, + average = average, + pointsSum = points, newGrades = grades.filter { grade -> !grade.isRead }.size, grades = subItems ), ViewType.HEADER)) + if (preferencesRepository.isGradeExpandable) emptyList() else subItems diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt index 53c69db7..9b837213 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt @@ -1,12 +1,11 @@ package io.github.wulkanowy.ui.modules.grade.summary import io.github.wulkanowy.data.db.entities.GradeSummary -import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository -import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider +import io.github.wulkanowy.ui.modules.grade.GradeDetailsWithAverage import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import timber.log.Timber @@ -16,8 +15,6 @@ class GradeSummaryPresenter @Inject constructor( schedulers: SchedulersProvider, errorHandler: ErrorHandler, studentRepository: StudentRepository, - private val gradeSummaryRepository: GradeSummaryRepository, - private val semesterRepository: SemesterRepository, private val averageProvider: GradeAverageProvider, private val analytics: FirebaseAnalyticsHelper ) : BasePresenter(errorHandler, studentRepository, schedulers) { @@ -33,15 +30,8 @@ class GradeSummaryPresenter @Inject constructor( fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) { Timber.i("Loading grade summary data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getSemesters(it).map { semesters -> it to semesters } } - .flatMap { (student, semesters) -> - gradeSummaryRepository.getGradesSummary(student, semesters.first { it.semesterId == semesterId }, forceRefresh) - .map { it.sortedBy { subject -> subject.subject } } - .flatMap { gradesSummary -> - averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh) - .map { averages -> createGradeSummaryItems(gradesSummary, averages) } - } - } + .flatMap { averageProvider.getGradesDetailsWithAverage(it, semesterId, forceRefresh) } + .map { createGradeSummaryItems(it) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { @@ -112,12 +102,10 @@ class GradeSummaryPresenter @Inject constructor( disposable.clear() } - private fun createGradeSummaryItems(gradesSummary: List, averages: List>): List { - return gradesSummary - .filter { !checkEmpty(it, averages) } - .map { gradeSummary -> - gradeSummary.copy(average = averages.singleOrNull { gradeSummary.subject == it.first }?.second ?: .0) - } + private fun createGradeSummaryItems(items: List): List { + return items.map { + it.summary.copy(average = it.average) + } } private fun checkEmpty(gradeSummary: GradeSummary, averages: List>): Boolean { diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt index 009ed610..68b3f6bb 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt @@ -3,17 +3,17 @@ package io.github.wulkanowy.ui.modules.grade import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.data.repositories.grade.GradeRepository -import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository -import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.createSemesterEntity +import io.github.wulkanowy.data.repositories.grade.GradeRepository +import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository +import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.sdk.Sdk import io.reactivex.Single import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.mockito.Mock -import org.mockito.Mockito.doReturn +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.threeten.bp.LocalDate.now import org.threeten.bp.LocalDate.of @@ -25,10 +25,10 @@ class GradeAverageProviderTest { lateinit var preferencesRepository: PreferencesRepository @Mock - lateinit var gradeRepository: GradeRepository + lateinit var semesterRepository: SemesterRepository @Mock - lateinit var gradeSummaryRepository: GradeSummaryRepository + lateinit var gradeRepository: GradeRepository private lateinit var gradeAverageProvider: GradeAverageProvider @@ -41,165 +41,192 @@ class GradeAverageProviderTest { ) private val firstGrades = listOf( + // avg: 3.5 getGrade(22, "Matematyka", 4.0), getGrade(22, "Matematyka", 3.0), + + // avg: 3.5 getGrade(22, "Fizyka", 6.0), getGrade(22, "Fizyka", 1.0) ) - private val secondGrade = listOf( + private val firstSummaries = listOf( + getSummary(semesterId = 22, subject = "Matematyka", average = 3.9), + getSummary(semesterId = 22, subject = "Fizyka", average = 3.1) + ) + + private val secondGrades = listOf( + // avg: 2.5 getGrade(23, "Matematyka", 2.0), getGrade(23, "Matematyka", 3.0), + + // avg: 3.0 getGrade(23, "Fizyka", 4.0), getGrade(23, "Fizyka", 2.0) ) + private val secondSummaries = listOf( + getSummary(semesterId = 23, subject = "Matematyka", average = 2.9), + getSummary(semesterId = 23, subject = "Fizyka", average = 3.4) + ) + private val secondGradeWithModifier = listOf( + // avg: 3.375 getGrade(24, "Język polski", 3.0, -0.50), getGrade(24, "Język polski", 4.0, 0.25) ) + private val secondSummariesWithModifier = listOf( + getSummary(24, "Język polski", 3.49) + ) + @Before - fun initTest() { + fun setUp() { MockitoAnnotations.initMocks(this) - gradeAverageProvider = GradeAverageProvider(preferencesRepository, gradeRepository, gradeSummaryRepository) - doReturn(.33).`when`(preferencesRepository).gradeMinusModifier - doReturn(.33).`when`(preferencesRepository).gradePlusModifier - doReturn(false).`when`(preferencesRepository).gradeAverageForceCalc + `when`(preferencesRepository.gradeMinusModifier).thenReturn(.33) + `when`(preferencesRepository.gradePlusModifier).thenReturn(.33) + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(false) + `when`(semesterRepository.getSemesters(student)).thenReturn(Single.just(semesters)) - doReturn(Single.just(firstGrades)).`when`(gradeRepository).getGrades(student, semesters[1], true) - doReturn(Single.just(secondGrade)).`when`(gradeRepository).getGrades(student, semesters[2], true) + gradeAverageProvider = GradeAverageProvider(semesterRepository, gradeRepository, preferencesRepository) } @Test fun onlyOneSemesterTest() { - doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("only_one_semester") + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGrades to secondSummaries)) - val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) - .blockingGet() + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() - assertEquals(2, averages.size) - assertEquals(2.5, averages.single { it.first == "Matematyka" }.second, .0) - assertEquals(3.0, averages.single { it.first == "Fizyka" }.second, .0) + assertEquals(2, items.size) + assertEquals(2.5, items.single { it.subject == "Matematyka" }.average, .0) + assertEquals(3.0, items.single { it.subject == "Fizyka" }.average, .0) } @Test fun onlyOneSemester_gradesWithModifiers_default() { - doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) - doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student, semesters[2], true) + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("only_one_semester") + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGradeWithModifier to secondSummariesWithModifier)) - val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) - .blockingGet() + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() - assertEquals(3.5, averages.single { it.first == "Język polski" }.second, .0) + assertEquals(3.5, items.single { it.subject == "Język polski" }.average, .0) } @Test fun onlyOneSemester_gradesWithModifiers_api() { - doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student.copy(loginMode = Sdk.Mode.API.name), semesters[2], true) - doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.API.name), semesters[2], true) + val student = student.copy(loginMode = Sdk.Mode.API.name) - val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.API.name), semesters, semesters[2].semesterId, true) - .blockingGet() + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("only_one_semester") + `when`(semesterRepository.getSemesters(student)).thenReturn(Single.just(semesters)) + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGradeWithModifier to secondSummariesWithModifier)) - assertEquals(3.375, averages.single { it.first == "Język polski" }.second, .0) + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() + + assertEquals(3.375, items.single { it.subject == "Język polski" }.average, .0) } @Test fun onlyOneSemester_gradesWithModifiers_scrapper() { - doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) - doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.SCRAPPER.name), semesters[2], true) + val student = student.copy(loginMode = Sdk.Mode.SCRAPPER.name) - val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.SCRAPPER.name), semesters, semesters[2].semesterId, true) - .blockingGet() + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("only_one_semester") + `when`(semesterRepository.getSemesters(student)).thenReturn(Single.just(semesters)) + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGradeWithModifier to secondSummariesWithModifier)) - assertEquals(3.5, averages.single { it.first == "Język polski" }.second, .0) + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() + + assertEquals(3.5, items.single { it.subject == "Język polski" }.average, .0) } @Test fun onlyOneSemester_gradesWithModifiers_hybrid() { - doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters[2], true) - doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters[2], true) + val student = student.copy(loginMode = Sdk.Mode.HYBRID.name) - val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters, semesters[2].semesterId, true) - .blockingGet() + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("only_one_semester") + `when`(semesterRepository.getSemesters(student)).thenReturn(Single.just(semesters)) + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGradeWithModifier to secondSummariesWithModifier)) - assertEquals(3.375, averages.single { it.first == "Język polski" }.second, .0) + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() + + assertEquals(3.375, items.single { it.subject == "Język polski" }.average, .0) } @Test fun allYearFirstSemesterTest() { - doReturn("all_year").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[1], true) + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("all_year") + `when`(gradeRepository.getGrades(student, semesters[1])).thenReturn(Single.just(firstGrades to firstSummaries)) - val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[1].semesterId, true) - .blockingGet() + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[1].semesterId).blockingGet() - assertEquals(2, averages.size) - assertEquals(3.5, averages.single { it.first == "Matematyka" }.second, .0) - assertEquals(3.5, averages.single { it.first == "Fizyka" }.second, .0) + assertEquals(2, items.size) + assertEquals(3.5, items.single { it.subject == "Matematyka" }.average, .0) + assertEquals(3.5, items.single { it.subject == "Fizyka" }.average, .0) } @Test fun allYearSecondSemesterTest() { - doReturn("all_year").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(firstGrades)).`when`(gradeRepository).getGrades(student, semesters[1], false) - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("all_year") + `when`(gradeRepository.getGrades(student, semesters[1])).thenReturn(Single.just(firstGrades to firstSummaries)) + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGrades to secondSummaries)) - val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) - .blockingGet() + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() - assertEquals(2, averages.size) - assertEquals(3.0, averages.single { it.first == "Matematyka" }.second, .0) - assertEquals(3.25, averages.single { it.first == "Fizyka" }.second, .0) + assertEquals(2, items.size) + assertEquals(3.0, items.single { it.subject == "Matematyka" }.average, .0) + assertEquals(3.25, items.single { it.subject == "Fizyka" }.average, .0) } @Test(expected = IllegalArgumentException::class) fun incorrectAverageModeTest() { - doReturn("test_mode").`when`(preferencesRepository).gradeAverageMode + `when`(preferencesRepository.gradeAverageMode).thenReturn("test_mode") - gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true).blockingGet() + gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId, true).blockingGet() } @Test - fun onlyOneSemester_averageFromSummary() { - doReturn("all_year").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(firstGrades)).`when`(gradeRepository).getGrades(student, semesters[1], false) - doReturn(Single.just(listOf( - getSummary(22, "Matematyka", 3.1), - getSummary(22, "Fizyka", 3.26) - ))).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) + fun allYearSemester_averageFromSummary() { + `when`(preferencesRepository.gradeAverageMode).thenReturn("all_year") + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(false) + `when`(gradeRepository.getGrades(student, semesters[1])).thenReturn(Single.just(firstGrades to listOf( + getSummary(22, "Matematyka", 3.0), + getSummary(22, "Fizyka", 3.5) + ))) + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGrades to listOf( + getSummary(22, "Matematyka", 3.5), + getSummary(22, "Fizyka", 4.0) + ))) - val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) - .blockingGet() + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() - assertEquals(2, averages.size) - assertEquals(3.1, averages.single { it.first == "Matematyka" }.second, .0) - assertEquals(3.26, averages.single { it.first == "Fizyka" }.second, .0) + assertEquals(2, items.size) + assertEquals(3.25, items.single { it.subject == "Matematyka" }.average, .0) + assertEquals(3.75, items.single { it.subject == "Fizyka" }.average, .0) } @Test fun onlyOneSemester_averageFromSummary_forceCalc() { - doReturn(true).`when`(preferencesRepository).gradeAverageForceCalc - doReturn("all_year").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(firstGrades)).`when`(gradeRepository).getGrades(student, semesters[1], false) - doReturn(Single.just(listOf( - getSummary(22, "Matematyka", 3.1), - getSummary(22, "Fizyka", 3.26) - ))).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) + `when`(preferencesRepository.gradeAverageMode).thenReturn("all_year") + `when`(preferencesRepository.gradeAverageForceCalc).thenReturn(true) + `when`(gradeRepository.getGrades(student, semesters[1])).thenReturn(Single.just(firstGrades to firstSummaries)) + `when`(gradeRepository.getGrades(student, semesters[2])).thenReturn(Single.just(secondGrades to listOf( + getSummary(22, "Matematyka", 1.1), + getSummary(22, "Fizyka", 7.26) + ))) - val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) - .blockingGet() + val items = gradeAverageProvider.getGradesDetailsWithAverage(student, semesters[2].semesterId).blockingGet() - assertEquals(2, averages.size) - assertEquals(3.0, averages.single { it.first == "Matematyka" }.second, .0) - assertEquals(3.25, averages.single { it.first == "Fizyka" }.second, .0) + assertEquals(2, items.size) + assertEquals(3.0, items.single { it.subject == "Matematyka" }.average, .0) + assertEquals(3.25, items.single { it.subject == "Fizyka" }.average, .0) } private fun getGrade(semesterId: Int, subject: String, value: Double, modifier: Double = 0.0): Grade { @@ -221,12 +248,12 @@ class GradeAverageProviderTest { ) } - private fun getSummary(semesterId: Int, subject: String, value: Double): GradeSummary { + private fun getSummary(semesterId: Int, subject: String, average: Double): GradeSummary { return GradeSummary( studentId = 101, semesterId = semesterId, subject = subject, - average = value, + average = average, pointsSum = "", proposedPoints = "", finalPoints = "",