From 9244cb0430a4ddb8cac1e218177f0a7d9acdfb1b Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 22 Sep 2021 10:36:05 +0200 Subject: [PATCH] Add some more tests --- Habitica/build.gradle | 39 +++- .../android/habitica/data/TaskRepository.kt | 2 +- .../data/implementation/TaskRepositoryImpl.kt | 2 +- .../data/local/BaseLocalRepository.kt | 2 - .../RealmBaseLocalRepository.kt | 10 - .../RealmSocialLocalRepository.kt | 8 +- .../habitica/interactors/NotifyUserUseCase.kt | 2 +- .../android/habitica/models/Avatar.kt | 3 +- .../android/habitica/models/AvatarFlags.kt | 5 + .../habitica/models/inventory/QuestBoss.kt | 6 +- .../android/habitica/models/members/Member.kt | 8 +- .../habitica/models/members/MemberFlags.kt | 10 + .../habitica/models/social/UserStyles.kt | 10 +- .../android/habitica/models/user/Flags.kt | 5 +- .../habitica/models/user/SpecialItems.kt | 7 +- .../habitica/models/user/SubscriptionPlan.kt | 18 +- .../android/habitica/models/user/User.kt | 25 +-- .../habitica/models/user/UserAchievement.kt | 7 +- .../habitica/ui/AvatarWithBarsViewModel.kt | 2 +- .../ui/fragments/NavigationDrawerFragment.kt | 11 +- .../fragments/inventory/shops/ShopFragment.kt | 2 +- .../social/party/NoPartyFragmentFragment.kt | 2 +- .../ui/viewHolders/GroupMemberViewHolder.kt | 2 +- .../habitica/ui/views/shops/PurchaseDialog.kt | 6 +- .../views/shops/PurchaseDialogQuestContent.kt | 2 +- .../ui/views/social/OldQuestProgressView.kt | 2 +- .../ui/views/social/QuestProgressView.kt | 2 +- .../subscriptions/SubscriptionDetailsView.kt | 2 +- .../habitica/BaseAnnotationTestCase.kt | 2 +- .../implementation/TaskRepositoryImplTest.kt | 170 +++++++++++++++ .../habitica/helpers/HealthFormatterTest.kt | 1 - .../habitica/helpers/NumberAbbreviatorTest.kt | 7 +- .../habitica/helpers/UserStatComputerTest.kt | 39 +++- .../habitica/models/SubscriptionPlanTest.kt | 2 +- .../android/habitica/models/UserTest.kt | 6 +- .../habitica/models/inventory/MountTest.kt | 3 +- .../habitica/models/inventory/PetTest.kt | 3 +- .../habitica/models/members/MemberTest.kt | 38 +++- .../habitica/models/user/SpecialItemsTest.kt | 37 ++++ .../models/user/SubscriptionPlanTest.kt | 70 +++++++ .../android/habitica/models/user/UserTest.kt | 82 ++++++++ .../habitica/utils/DateDeserializerTest.kt | 8 +- .../src/test/resources/robolectric.properties | 4 - detekt_baseline.xml | 2 +- reports/profile/css/base-style.css | 179 ---------------- reports/profile/css/style.css | 4 - reports/profile/js/report.js | 194 ------------------ .../profile/profile-2016-05-09-17-48-55.html | 148 ------------- .../profile/profile-2016-05-09-17-50-45.html | 148 ------------- 49 files changed, 573 insertions(+), 776 deletions(-) create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarFlags.kt create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberFlags.kt create mode 100644 Habitica/src/test/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImplTest.kt create mode 100644 Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SpecialItemsTest.kt create mode 100644 Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanTest.kt create mode 100644 Habitica/src/test/java/com/habitrpg/android/habitica/models/user/UserTest.kt delete mode 100644 Habitica/src/test/resources/robolectric.properties delete mode 100644 reports/profile/css/base-style.css delete mode 100644 reports/profile/css/style.css delete mode 100644 reports/profile/js/report.js delete mode 100644 reports/profile/profile-2016-05-09-17-48-55.html delete mode 100644 reports/profile/profile-2016-05-09-17-50-45.html diff --git a/Habitica/build.gradle b/Habitica/build.gradle index cbec1dffb..3f7fac59c 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -6,6 +6,7 @@ apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'realm-android' apply plugin: 'androidx.navigation.safeargs' apply plugin: 'com.google.firebase.firebase-perf' +apply plugin: 'jacoco' buildscript { repositories { @@ -90,6 +91,7 @@ dependencies { testImplementation "io.mockk:mockk:1.12.0" testImplementation "io.mockk:mockk-android:1.12.0" testImplementation 'io.kotest:kotest-assertions-core:4.6.2' + testImplementation 'io.kotest:kotest-framework-datatest:4.6.2' //Leak Detection debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' @@ -111,8 +113,8 @@ dependencies { implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' implementation "androidx.paging:paging-runtime-ktx:3.0.1" implementation 'com.plattysoft.leonids:LeonidsLib:1.3.2' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2' implementation 'com.willowtreeapps:signinwithapplebutton:0.3' @@ -262,6 +264,7 @@ android { android.testOptions { unitTests.all { useJUnitPlatform() + unitTests.returnDefaultValues = true } } @@ -337,6 +340,38 @@ gradle.projectsEvaluated { apply plugin: 'com.google.gms.google-services' +jacoco { + toolVersion = "0.8.7" +} + +// packages to exclude for example generated classes, R class and models package, add all packages that you wish to exclude from test coverage +def fileFilter = [ + '**/*$ViewInjector*.*','**/*$ViewBinder*.*', '**/HabiticaIcons*.*', '**/DeviceName.*', '**/databinding/*Binding.*', + '**/R.class', '**/R.styleable', '**/R$*.class', '**/BuildConfig.*', '**/EmojiMap.*', + '**/Manifest*.*', 'android/**/*.*', '**/*RealmProxy*.*', '**/io/realm/*'] +def debugTree = fileTree(dir: "${buildDir}/intermediates/asm_instrumented_project_classes/prodDebug", excludes: fileFilter) +def mainSrc = "${project.projectDir}/src/main/java" + +// override jacocTestReport task +task jacocoTestReport(type: JacocoReport, dependsOn: 'testProdDebugUnitTest') { + group = "Reporting" + reports { + html.enabled = true + xml.enabled = true + //html.destination = "${buildDir}/reports/jacoco" + } + + sourceDirectories.from(files([mainSrc])) + classDirectories.from(files([debugTree])) + executionData.from(files("${buildDir}/jacoco/testProdDebugUnitTest.exec")) + + afterEvaluate { + classDirectories.from(files(classDirectories.files.collect { + fileTree(dir: it, exclude: fileFilter) + })) + } +} + task ktlint(type: JavaExec, group: "verification") { description = "Check Kotlin code style." classpath = configurations.ktlint diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt index 69feb2468..48c9bb663 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt @@ -19,7 +19,7 @@ interface TaskRepository : BaseRepository { fun retrieveTasks(userId: String, tasksOrder: TasksOrder): Flowable fun retrieveTasks(userId: String, tasksOrder: TasksOrder, dueDate: Date): Flowable - fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable + fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Maybe fun scoreChecklistItem(taskId: String, itemId: String): Flowable diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt index 0c686391d..9c02f26d6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt @@ -52,7 +52,7 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli } @Suppress("ReturnCount") - override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable { + override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable { val localData = if (user != null && appConfigManager.enableLocalTaskScoring()) { ScoreTaskLocallyInteractor.score(user, task, if (up) TaskDirection.UP else TaskDirection.DOWN) } else null diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/BaseLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/BaseLocalRepository.kt index 1a1440056..8fc7c97b4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/BaseLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/BaseLocalRepository.kt @@ -12,9 +12,7 @@ interface BaseLocalRepository { fun close() fun executeTransaction(transaction: (Realm) -> Unit) - fun executeTransaction(transaction: Realm.Transaction) fun executeTransactionAsync(transaction: (Realm) -> Unit) - fun executeTransactionAsync(transaction: Realm.Transaction) fun modify(obj: T, transaction: (T) -> Unit) fun modifyWithRealm(obj: T, transaction: (Realm, T) -> Unit) fun getLiveObject(obj: T): T? diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt index de38ed084..d218ea08a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmBaseLocalRepository.kt @@ -25,11 +25,6 @@ abstract class RealmBaseLocalRepository internal constructor(override var realm: } } - override fun executeTransaction(transaction: Realm.Transaction) { - if (isClosed) { return } - realm.executeTransaction(transaction) - } - override fun executeTransactionAsync(transaction: (Realm) -> Unit) { if (isClosed) { return } realm.executeTransactionAsync { @@ -37,11 +32,6 @@ abstract class RealmBaseLocalRepository internal constructor(override var realm: } } - override fun executeTransactionAsync(transaction: Realm.Transaction) { - if (isClosed) { return } - realm.executeTransactionAsync(transaction) - } - override fun getUnmanagedCopy(managedObject: T): T { return if (managedObject is RealmObject && managedObject.isManaged && managedObject.isValid) { realm.copyFromRealm(managedObject) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt index 67640095d..efbced2a6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt @@ -211,11 +211,9 @@ class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm) } } else { liveMessage?.likes?.filter { userId == it.id }?.forEach { like -> - executeTransaction( - Realm.Transaction { - like.deleteFromRealm() - } - ) + executeTransaction { + like.deleteFromRealm() + } } executeTransaction { liveMessage?.likeCount = liveMessage?.likes?.size ?: 0 diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt index e1eb5a6f7..5187fb51a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt @@ -79,7 +79,7 @@ constructor( displayType = SnackbarDisplayType.FAILURE } } - if (mp != null && mp > 0 && user?.hasClass() == true) { + if (mp != null && mp > 0 && user?.hasClass == true) { container.addView(createTextView(context, mp, HabiticaIconsHelper.imageOfMagic())) } if (questDamage != null && questDamage > 0) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.kt index 5b6531c8a..e9a393c6c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.kt @@ -12,10 +12,11 @@ interface Avatar { val sleep: Boolean val stats: Stats? val preferences: AvatarPreferences? + val flags: AvatarFlags? val gemCount: Int val hourglassCount: Int val costume: Outfit? val equipped: Outfit? - fun hasClass(): Boolean + val hasClass: Boolean fun isValid(): Boolean } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarFlags.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarFlags.kt new file mode 100644 index 000000000..4e59e94de --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarFlags.kt @@ -0,0 +1,5 @@ +package com.habitrpg.android.habitica.models + +interface AvatarFlags { + var classSelected: Boolean +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestBoss.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestBoss.kt index 8ba0d279f..6e63df4be 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestBoss.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestBoss.kt @@ -19,7 +19,7 @@ open class QuestBoss : RealmObject(), BaseObject { var rage: QuestBossRage? = null val hasRage: Boolean - get() { - return rage?.value ?: 0.0 > 0.0 - } + get() { + return rage?.value ?: 0.0 > 0.0 + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt index c983e160a..89729b0a1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt @@ -16,6 +16,7 @@ open class Member : RealmObject(), Avatar, BaseObject { override var stats: Stats? = null var inbox: Inbox? = null override var preferences: MemberPreferences? = null + override var flags: MemberFlags? = null override val gemCount: Int get() = 0 override val hourglassCount: Int @@ -50,9 +51,10 @@ open class Member : RealmObject(), Avatar, BaseObject { val formattedUsername: String? get() = if (username != null) "@$username" else null - override fun hasClass(): Boolean { - return preferences?.disableClasses == false && stats?.habitClass?.isNotEmpty() == true - } + override val hasClass: Boolean + get() { + return preferences?.disableClasses == false && stats?.habitClass?.isNotEmpty() == true + } override val sleep: Boolean get() = preferences?.sleep ?: false diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberFlags.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberFlags.kt new file mode 100644 index 000000000..4e74fdbd6 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberFlags.kt @@ -0,0 +1,10 @@ +package com.habitrpg.android.habitica.models.members + +import com.habitrpg.android.habitica.models.AvatarFlags +import io.realm.RealmObject +import io.realm.annotations.RealmClass + +@RealmClass(embedded = true) +open class MemberFlags : RealmObject(), AvatarFlags { + override var classSelected: Boolean = false +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt index c8380e6e1..3d9525312 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt @@ -1,6 +1,7 @@ package com.habitrpg.android.habitica.models.social import com.habitrpg.android.habitica.models.Avatar +import com.habitrpg.android.habitica.models.AvatarFlags import com.habitrpg.android.habitica.models.user.Items import com.habitrpg.android.habitica.models.user.Outfit import com.habitrpg.android.habitica.models.user.Preferences @@ -30,11 +31,14 @@ open class UserStyles : RealmObject(), Avatar { override val equipped: Outfit? get() = items?.gear?.equipped - override fun hasClass(): Boolean { - return false - } + override val hasClass: Boolean + get() { + return false + } override var stats: Stats? = null override var preferences: Preferences? = null + override val flags: AvatarFlags? + get() = null private var items: Items? = null } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.kt index c8cd2f657..395ebb521 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.kt @@ -1,5 +1,6 @@ package com.habitrpg.android.habitica.models.user +import com.habitrpg.android.habitica.models.AvatarFlags import com.habitrpg.android.habitica.models.BaseObject import com.habitrpg.android.habitica.models.TutorialStep import io.realm.RealmList @@ -7,14 +8,14 @@ import io.realm.RealmObject import io.realm.annotations.RealmClass @RealmClass(embedded = true) -open class Flags : RealmObject(), BaseObject { +open class Flags : RealmObject(), BaseObject, AvatarFlags { var tutorial: RealmList? = null var showTour = false var dropsEnabled = false var itemsEnabled = false var newStuff = false var lastNewStuffRead: String? = null - var classSelected = false + override var classSelected = false var rebirthEnabled = false var welcomed = false var armoireEnabled = false diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SpecialItems.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SpecialItems.kt index 5e615e2dd..681e158eb 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SpecialItems.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SpecialItems.kt @@ -13,7 +13,8 @@ open class SpecialItems : RealmObject(), BaseObject { var snowball: Int = 0 var spookySparkles: Int = 0 - fun hasSpecialItems(): Boolean { - return seafoam > 0 || shinySeed > 0 || snowball > 0 || spookySparkles > 0 - } + val hasSpecialItems: Boolean + get() { + return seafoam > 0 || shinySeed > 0 || snowball > 0 || spookySparkles > 0 + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt index da989b026..a1e7136f0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt @@ -34,15 +34,17 @@ open class SubscriptionPlan : RealmObject(), BaseObject { return customerId != null && (dateTerminated == null || dateTerminated!!.after(today)) } - fun totalNumberOfGems(): Int { - return if (customerId == null || consecutive == null) { - 0 - } else 25 + consecutive!!.gemCapExtra - } + val totalNumberOfGems: Int + get() { + return if (isActive) { + 25 + (consecutive?.gemCapExtra ?: 0) + } else 0 + } - fun numberOfGemsLeft(): Int { - return totalNumberOfGems() - gemsBought!! - } + val numberOfGemsLeft: Int + get() { + return totalNumberOfGems - (gemsBought ?: 0) + } companion object { var PLANID_BASIC = "basic" diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt index e37b07e19..930949462 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt @@ -42,7 +42,7 @@ open class User : RealmObject(), BaseMainObject, Avatar, VersionedObject { var items: Items? = null @SerializedName("auth") var authentication: Authentication? = null - var flags: Flags? = null + override var flags: Flags? = null var contributor: ContributorInfo? = null var backer: Backer? = null var invitations: Invitations? = null @@ -98,9 +98,10 @@ open class User : RealmObject(), BaseMainObject, Avatar, VersionedObject { override val equipped: Outfit? get() = items?.gear?.equipped - override fun hasClass(): Boolean { - return preferences?.disableClasses != true && flags?.classSelected == true && stats?.habitClass?.isNotEmpty() == true - } + override val hasClass: Boolean + get() { + return preferences?.disableClasses != true && flags?.classSelected == true && stats?.habitClass?.isNotEmpty() == true + } override val currentMount: String? get() = items?.currentMount ?: "" @@ -110,20 +111,14 @@ open class User : RealmObject(), BaseMainObject, Avatar, VersionedObject { override val sleep: Boolean get() = preferences?.sleep ?: false - fun hasParty(): Boolean { - return this.party?.id?.length ?: 0 > 0 - } + val hasParty: Boolean + get() { + return this.party?.id?.length ?: 0 > 0 + } val isSubscribed: Boolean get() { - val plan = purchased?.plan - var isSubscribed = false - if (plan != null) { - if (plan.isActive) { - isSubscribed = true - } - } - return isSubscribed + return purchased?.plan?.isActive == true } val onboardingAchievements: List diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/UserAchievement.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/UserAchievement.kt index a26565f58..414d221d8 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/UserAchievement.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/UserAchievement.kt @@ -5,7 +5,12 @@ import io.realm.RealmObject import io.realm.annotations.RealmClass @RealmClass(embedded = true) -open class UserAchievement : RealmObject(), BaseObject { +open class UserAchievement() : RealmObject(), BaseObject { var key: String? = null var earned: Boolean = false + + constructor(key: String, earned: Boolean) : this() { + this.key = key + this.earned = earned + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt index 325317186..03a6e92ac 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt @@ -59,7 +59,7 @@ class AvatarWithBarsViewModel(private val context: Context, private val binding: binding.mpBar.visibility = if (stats.habitClass == null || stats.lvl ?: 0 < 10 || user.preferences?.disableClasses == true) View.GONE else View.VISIBLE - if (!user.hasClass()) { + if (!user.hasClass) { setUserLevel(context, binding.lvlTv, stats.lvl) } else { setUserLevelWithClass( diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt index fe40f0029..ee260d8bd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt @@ -248,7 +248,7 @@ class NavigationDrawerFragment : DialogFragment() { .distinctUntilChanged { firstTeams, secondTeams -> firstTeams == secondTeams } .subscribe( { - getItemWithIdentifier(SIDEBAR_TEAMS)?.isVisible = it.size != 0 + getItemWithIdentifier(SIDEBAR_TEAMS)?.isVisible = it.isNotEmpty() adapter.setTeams(it) }, RxErrorHandler.handleEmptyError() @@ -281,7 +281,6 @@ class NavigationDrawerFragment : DialogFragment() { market.pillText = null market.subtitle = null } - adapter.notifyDataSetChanged() val shop = getItemWithIdentifier(SIDEBAR_SHOPS_SEASONAL) ?: return shop.pillText = context?.getString(R.string.open) @@ -313,11 +312,11 @@ class NavigationDrawerFragment : DialogFragment() { val specialItems = user.items?.special var hasSpecialItems = false if (specialItems != null) { - hasSpecialItems = specialItems.hasSpecialItems() + hasSpecialItems = specialItems.hasSpecialItems } val item = getItemWithIdentifier(SIDEBAR_SKILLS) if (item != null) { - if (!user.hasClass() && !hasSpecialItems) { + if (!user.hasClass && !hasSpecialItems) { item.isVisible = false } else { if (user.stats?.lvl ?: 0 < HabiticaSnackbar.MIN_LEVEL_FOR_SKILLS && (!hasSpecialItems)) { @@ -378,10 +377,10 @@ class NavigationDrawerFragment : DialogFragment() { } val partyMenuItem = getItemWithIdentifier(SIDEBAR_PARTY) - if (user.hasParty() && partyMenuItem?.bundle == null) { + if (user.hasParty && partyMenuItem?.bundle == null) { partyMenuItem?.transitionId = R.id.partyFragment partyMenuItem?.bundle = bundleOf(Pair("partyID", user.party?.id)) - } else if (!user.hasParty()) { + } else if (!user.hasParty) { partyMenuItem?.transitionId = R.id.noPartyFragment partyMenuItem?.bundle = null } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt index b7d5e153a..c140c3e10 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt @@ -171,7 +171,7 @@ open class ShopFragment : BaseMainFragment() specialCategory.text = getString(R.string.special) if (user?.isValid == true && user.purchased?.plan?.isActive == true) { val item = ShopItem.makeGemItem(context?.resources) - item.limitedNumberLeft = user.purchased?.plan?.numberOfGemsLeft() + item.limitedNumberLeft = user.purchased?.plan?.numberOfGemsLeft specialCategory.items.add(item) } specialCategory.items.add(ShopItem.makeFortifyItem(context?.resources)) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt index d0965f600..a92ee5ee9 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt @@ -176,7 +176,7 @@ class NoPartyFragmentFragment : BaseMainFragment() { private fun refresh() { compositeSubscription.add( userRepository.retrieveUser(false, forced = true) - .filter { it.hasParty() } + .filter { it.hasParty } .flatMap { socialRepository.retrieveGroup("party") } .flatMap { group1 -> socialRepository.retrieveGroupMembers(group1.id, true) } .doOnComplete { binding?.refreshLayout?.isRefreshing = false } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/GroupMemberViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/GroupMemberViewHolder.kt index 9dde3f289..8bdc10c86 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/GroupMemberViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/GroupMemberViewHolder.kt @@ -70,7 +70,7 @@ class GroupMemberViewHolder(itemView: View) : androidx.recyclerview.widget.Recyc binding.displayNameTextview.username = user.profile?.name binding.displayNameTextview.tier = user.contributor?.level ?: 0 - if (user.hasClass()) { + if (user.hasClass) { binding.sublineTextview.text = itemView.context.getString(R.string.user_level_with_class, user.stats?.lvl, user.stats?.getTranslatedClassName(itemView.context)) } else { binding.sublineTextview.text = itemView.context.getString(R.string.user_level, user.stats?.lvl) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt index cc2a7faca..86a44f406 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt @@ -255,8 +255,8 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop currencyView.hourglasses = user.hourglassCount.toDouble() if ("gems" == shopItem.purchaseType) { - val maxGems = user.purchased?.plan?.totalNumberOfGems() ?: 0 - val gemsLeft = user.purchased?.plan?.numberOfGemsLeft() + val maxGems = user.purchased?.plan?.totalNumberOfGems ?: 0 + val gemsLeft = user.purchased?.plan?.numberOfGemsLeft if (maxGems > 0) { limitedTextView.text = context.getString(R.string.gems_left_max, gemsLeft, maxGems) } else { @@ -269,7 +269,7 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop limitedTextView.setBackgroundColor(ContextCompat.getColor(context, R.color.green_10)) } val gemContent = additionalContentView as? PurchaseDialogGemsContent - gemContent?.binding?.stepperView?.maxValue = (user.purchased?.plan?.numberOfGemsLeft() ?: 1).toDouble() + gemContent?.binding?.stepperView?.maxValue = (user.purchased?.plan?.numberOfGemsLeft ?: 1).toDouble() } buyButton.elevation = 0f diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt index 1d17a9944..45060520a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogQuestContent.kt @@ -28,7 +28,7 @@ class PurchaseDialogQuestContent(context: Context) : PurchaseDialogContent(conte binding.questTypeTextView.setText(R.string.boss_quest) binding.questCollectView.visibility = View.GONE binding.bossHealthText.text = questContent.boss?.hp.toString() - if (questContent.boss?.hasRage() == true) { + if (questContent.boss?.hasRage == true) { binding.rageMeterView.visibility = View.VISIBLE } binding.questDifficultyView.rating = questContent.boss?.str ?: 1f diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt index 30509a306..eedd0e479 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/OldQuestProgressView.kt @@ -76,7 +76,7 @@ class OldQuestProgressView : LinearLayout { if (progress != null) { binding.bossHealthView.set(progress.hp, quest.boss?.hp?.toDouble() ?: 0.0) } - if (quest.boss?.hasRage() == true) { + if (quest.boss?.hasRage == true) { binding.bossRageView.visibility = View.VISIBLE binding.bossRageView.set(progress?.rage ?: 0.0, quest.boss?.rage?.value ?: 0.0) } else { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt index 2a9425787..f6ddb620d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt @@ -119,7 +119,7 @@ class QuestProgressView : LinearLayout { binding.bossHealthView.set(progress.progress?.hp ?: 0.0, quest.boss?.hp?.toDouble() ?: 0.0) binding.collectedItemsNumberView.visibility = View.GONE - if (quest.boss?.hasRage() == true) { + if (quest.boss?.hasRage == true) { binding.rageMeterView.visibility = View.VISIBLE binding.bossRageView.visibility = View.VISIBLE binding.rageMeterView.text = quest.boss?.rage?.title diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt index 00b688734..e67a0c12b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt @@ -96,7 +96,7 @@ class SubscriptionDetailsView : LinearLayout { } else { binding.monthsSubscribedTextView.text = resources.getString(R.string.x_months, plan.consecutive?.count ?: 0) } - binding.gemCapTextView.text = plan.totalNumberOfGems().toString() + binding.gemCapTextView.text = plan.totalNumberOfGems.toString() binding.currentHourglassesTextView.text = plan.consecutive?.trinkets.toString() binding.changeSubscriptionButton.visibility = View.VISIBLE diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/BaseAnnotationTestCase.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/BaseAnnotationTestCase.kt index 0feebd69c..97e7256f9 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/BaseAnnotationTestCase.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/BaseAnnotationTestCase.kt @@ -5,7 +5,7 @@ import io.kotest.core.spec.style.AnnotationSpec import io.mockk.MockKAnnotations import io.mockk.impl.annotations.MockK -open class BaseAnnotationTestCase: AnnotationSpec() { +open class BaseAnnotationTestCase : AnnotationSpec() { @MockK lateinit var mockContext: Context diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImplTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImplTest.kt new file mode 100644 index 000000000..86bd7a8ed --- /dev/null +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImplTest.kt @@ -0,0 +1,170 @@ +package com.habitrpg.android.habitica.data.implementation + +import com.habitrpg.android.habitica.data.ApiClient +import com.habitrpg.android.habitica.data.TaskRepository +import com.habitrpg.android.habitica.data.local.TaskLocalRepository +import com.habitrpg.android.habitica.models.BaseObject +import com.habitrpg.android.habitica.models.responses.TaskDirectionData +import com.habitrpg.android.habitica.models.responses.TaskScoringResult +import com.habitrpg.android.habitica.models.tasks.Task +import com.habitrpg.android.habitica.models.tasks.TaskList +import com.habitrpg.android.habitica.models.tasks.TasksOrder +import com.habitrpg.android.habitica.models.user.Stats +import com.habitrpg.android.habitica.models.user.User +import io.kotest.common.ExperimentalKotest +import io.kotest.core.spec.style.WordSpec +import io.kotest.framework.concurrency.eventually +import io.kotest.matchers.shouldBe +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot +import io.mockk.spyk +import io.mockk.verify +import io.reactivex.rxjava3.core.Flowable +import io.reactivex.subscribers.TestSubscriber +import io.realm.Realm +import java.util.UUID + +@OptIn(ExperimentalKotest::class) +class TaskRepositoryImplTest : WordSpec({ + lateinit var repository: TaskRepository + val localRepository = mockk() + val apiClient = mockk() + beforeEach { + val slot = slot<((Realm) -> Unit)>() + every { localRepository.executeTransaction(transaction = capture(slot)) } answers { + slot.captured(mockk(relaxed = true)) + } + repository = TaskRepositoryImpl( + localRepository, + apiClient, + "", + mockk(relaxed = true), + mockk(relaxed = true) + ) + val liveObjectSlot = slot() + every { localRepository.getLiveObject(capture(liveObjectSlot)) } answers { + liveObjectSlot.captured + } + } + "retrieveTasks" should { + "save tasks locally" { + val list = TaskList() + every { apiClient.tasks } returns Flowable.just(list) + every { localRepository.saveTasks("", any(), any()) } returns Unit + val order = TasksOrder() + val subscriber = TestSubscriber() + repository.retrieveTasks("", order).subscribe(subscriber) + subscriber.assertComplete() + verify { localRepository.saveTasks("", order, list) } + } + } + "taskChecked" should { + val task = Task() + task.id = UUID.randomUUID().toString() + lateinit var user: User + beforeEach { + user = spyk(User()) + user.stats = Stats() + } + "debounce" { + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(TaskDirectionData()) + repository.taskChecked(user, task, true, false, null).subscribe() + repository.taskChecked(user, task, true, false, null).subscribe() + verify(exactly = 1) { apiClient.postTaskDirection(any(), any()) } + } + "get user if not passed" { + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(TaskDirectionData()) + every { localRepository.getUser("") } returns Flowable.just(user) + repository.taskChecked(null, task, true, false, null) + eventually(5000) { + localRepository.getUser("") + } + } + "does not update user for team tasks" { + val data = TaskDirectionData() + data.lvl = 0 + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data) + val subscriber = TestSubscriber() + repository.taskChecked(user, task, true, false, null).subscribe(subscriber) + subscriber.assertComplete() + verify(exactly = 0) { user.stats } + subscriber.values().first().level shouldBe null + } + "builds task result correctly" { + val data = TaskDirectionData() + data.lvl = 10 + data.hp = 20.0 + data.mp = 30.0 + data.gp = 40.0 + user.stats?.lvl = 10 + user.stats?.hp = 8.0 + user.stats?.mp = 4.0 + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data) + val subscriber = TestSubscriber() + repository.taskChecked(user, task, true, false, null).subscribe(subscriber) + subscriber.assertComplete() + subscriber.values().first().level shouldBe 10 + subscriber.values().first().healthDelta shouldBe 12.0 + subscriber.values().first().manaDelta shouldBe 26.0 + subscriber.values().first().hasLeveledUp shouldBe false + } + "set hasLeveledUp correctly" { + val subscriber = TestSubscriber() + val data = TaskDirectionData() + data.lvl = 11 + user.stats?.lvl = 10 + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data) + repository.taskChecked(user, task, true, false, null).subscribe(subscriber) + + subscriber.assertComplete() + subscriber.values().first().level shouldBe 11 + subscriber.values().first().hasLeveledUp shouldBe true + } + "handle stats not being there" { + val subscriber = TestSubscriber() + val data = TaskDirectionData() + data.lvl = 1 + user.stats = null + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data) + repository.taskChecked(user, task, true, false, null).subscribe(subscriber) + subscriber.assertComplete() + } + "update daily streak" { + val subscriber = TestSubscriber() + val data = TaskDirectionData() + data.delta = 1.0f + data.lvl = 1 + task.type = Task.TYPE_DAILY + task.value = 0.0 + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data) + repository.taskChecked(user, task, true, false, null).subscribe(subscriber) + + subscriber.assertComplete() + task.streak shouldBe 1 + task.completed shouldBe true + } + "update habit counter" { + val subscriber = TestSubscriber() + val data = TaskDirectionData() + data.delta = 1.0f + data.lvl = 1 + task.type = Task.TYPE_HABIT + task.value = 0.0 + every { apiClient.postTaskDirection(any(), "up") } returns Flowable.just(data) + repository.taskChecked(user, task, true, false, null).subscribe(subscriber) + subscriber.assertComplete() + task.counterUp shouldBe 1 + + data.delta = -10.0f + every { apiClient.postTaskDirection(any(), "down") } returns Flowable.just(data) + val downSubscriber = TestSubscriber() + repository.taskChecked(user, task, false, true, null).subscribe(downSubscriber) + downSubscriber.assertComplete() + task.counterUp shouldBe 1 + task.counterDown shouldBe 1 + } + } + afterEach { clearAllMocks() } +}) diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/HealthFormatterTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/HealthFormatterTest.kt index de2ecc977..543ed5f2a 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/HealthFormatterTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/HealthFormatterTest.kt @@ -1,7 +1,6 @@ package com.habitrpg.android.habitica.helpers import io.kotest.matchers.shouldBe -import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.util.Locale diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/NumberAbbreviatorTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/NumberAbbreviatorTest.kt index 76a233d3c..193f66a49 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/NumberAbbreviatorTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/NumberAbbreviatorTest.kt @@ -9,7 +9,7 @@ import io.mockk.clearMocks import io.mockk.every import io.mockk.mockk -class NumberAbbreviatorTest: StringSpec({ +class NumberAbbreviatorTest : StringSpec({ val mockContext = mockk() beforeEach { every { mockContext.getString(R.string.thousand_abbrev) } returns "k" @@ -35,9 +35,14 @@ class NumberAbbreviatorTest: StringSpec({ abbreviate(mockContext, 1990000000.0, 2) shouldBe "1.99b" } + "it abbreviates trillions" { + abbreviate(mockContext, 1990000000000.0, 2) shouldBe "1.99t" + } + "it abbreviates thousands without additional decimals" { abbreviate(mockContext, 1000.0, 2) shouldBe "1k" abbreviate(mockContext, 1500.0, 2) shouldBe "1.5k" + abbreviate(mockContext, 1500.0, 0) shouldBe "1k" } "it rounds correctly" { diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/UserStatComputerTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/UserStatComputerTest.kt index ef28c6760..58d52c6b6 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/UserStatComputerTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/helpers/UserStatComputerTest.kt @@ -8,10 +8,9 @@ import com.habitrpg.android.habitica.models.inventory.Equipment import com.habitrpg.android.habitica.models.members.Member import com.habitrpg.android.habitica.models.user.Stats import io.kotest.matchers.shouldBe - import java.util.ArrayList -class UserStatComputerTest: BaseAnnotationTestCase() { +class UserStatComputerTest : BaseAnnotationTestCase() { private val userStatComputer: UserStatComputer = UserStatComputer() private val user: Member = Member() private val equipment: Equipment @@ -46,6 +45,42 @@ class UserStatComputerTest: BaseAnnotationTestCase() { attributeRow.summary shouldBe false } + @Test + fun shouldReturnClassBonusForHealer() { + user.stats!!.habitClass = Stats.HEALER + equipment.klass = Stats.HEALER + val statsRows = userStatComputer.computeClassBonus(equipmentList, user) + val attributeRow = statsRows[2] as AttributeRow + (str * 0.0f).toDouble() shouldBe attributeRow.strVal.toDouble() + (intStat * 0.5f).toDouble() shouldBe attributeRow.intVal.toDouble() + (con * 0.5f).toDouble() shouldBe attributeRow.conVal.toDouble() + (per * 0.0f).toDouble() shouldBe attributeRow.perVal.toDouble() + } + + @Test + fun shouldReturnClassBonusForWarrior() { + user.stats!!.habitClass = Stats.WARRIOR + equipment.klass = Stats.WARRIOR + val statsRows = userStatComputer.computeClassBonus(equipmentList, user) + val attributeRow = statsRows[2] as AttributeRow + (str * 0.5f).toDouble() shouldBe attributeRow.strVal.toDouble() + (intStat * 0.0f).toDouble() shouldBe attributeRow.intVal.toDouble() + (con * 0.5f).toDouble() shouldBe attributeRow.conVal.toDouble() + (per * 0.0f).toDouble() shouldBe attributeRow.perVal.toDouble() + } + + @Test + fun shouldReturnClassBonusForMage() { + user.stats!!.habitClass = Stats.MAGE + equipment.klass = Stats.MAGE + val statsRows = userStatComputer.computeClassBonus(equipmentList, user) + val attributeRow = statsRows[2] as AttributeRow + (str * 0.0f).toDouble() shouldBe attributeRow.strVal.toDouble() + (intStat * 0.5f).toDouble() shouldBe attributeRow.intVal.toDouble() + (con * 0.0f).toDouble() shouldBe attributeRow.conVal.toDouble() + (per * 0.5f).toDouble() shouldBe attributeRow.perVal.toDouble() + } + @Test fun ShouldReturnClassBonusRowWhenSpecialClassMatches() { user.stats!!.habitClass = Stats.ROGUE diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/SubscriptionPlanTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/SubscriptionPlanTest.kt index ce865ca71..c2f282c9a 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/models/SubscriptionPlanTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/SubscriptionPlanTest.kt @@ -7,7 +7,7 @@ import io.kotest.matchers.shouldBe import java.util.Calendar import java.util.Date -class SubscriptionPlanTest: BaseAnnotationTestCase() { +class SubscriptionPlanTest : BaseAnnotationTestCase() { private var plan: SubscriptionPlan? = null @AnnotationSpec.BeforeEach fun setUp() { diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/UserTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/UserTest.kt index 26a6dbd17..1d6cc54a9 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/models/UserTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/UserTest.kt @@ -8,7 +8,7 @@ import com.habitrpg.android.habitica.models.user.User import io.kotest.matchers.shouldBe import io.realm.RealmList -class UserTest: BaseAnnotationTestCase() { +class UserTest : BaseAnnotationTestCase() { private var user: User? = null @BeforeEach fun setup() { @@ -33,7 +33,7 @@ class UserTest: BaseAnnotationTestCase() { @get:Test val petsFoundCount_onNoPetCollectionAvailable_shouldReturnZero: Unit get() { - user?.petsFoundCount shouldBe 0 + user?.petsFoundCount shouldBe 0 } @get:Test @@ -52,6 +52,6 @@ class UserTest: BaseAnnotationTestCase() { @get:Test val mountsTamedCount_onNoMountCollectionAvailable_shouldReturnZero: Unit get() { - user?.mountsTamedCount shouldBe 0 + user?.mountsTamedCount shouldBe 0 } } diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/MountTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/MountTest.kt index eee8afee1..38e6be6c0 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/MountTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/MountTest.kt @@ -1,6 +1,5 @@ package com.habitrpg.android.habitica.models.inventory -import android.content.Context import com.habitrpg.android.habitica.BaseAnnotationTestCase import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.getTranslatedType @@ -10,7 +9,7 @@ import io.mockk.every private const val FAKE_STANDARD = "Standard" private const val FAKE_PREMIUM = "premium" -class MountTest: BaseAnnotationTestCase() { +class MountTest : BaseAnnotationTestCase() { private var mount: Mount = Mount() @Test diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/PetTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/PetTest.kt index ced6f50db..1f58c31cd 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/PetTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/inventory/PetTest.kt @@ -1,6 +1,5 @@ package com.habitrpg.android.habitica.models.inventory -import android.content.Context import com.habitrpg.android.habitica.BaseAnnotationTestCase import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.extensions.getTranslatedType @@ -10,7 +9,7 @@ import io.mockk.every private const val FAKE_STANDARD = "Standard" private const val FAKE_PREMIUM = "premium" -class PetTest: BaseAnnotationTestCase() { +class PetTest : BaseAnnotationTestCase() { private var pet: Pet = Pet() @Test diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/members/MemberTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/members/MemberTest.kt index 249fc4dec..1908d6cc1 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/models/members/MemberTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/members/MemberTest.kt @@ -1,8 +1,40 @@ package com.habitrpg.android.habitica.models.members -import io.kotest.core.spec.style.StringSpec +import com.habitrpg.android.habitica.models.user.Stats +import io.kotest.core.spec.style.WordSpec import io.kotest.matchers.shouldBe -class MemberTest : StringSpec({ - "hasClass" { } +class MemberTest : WordSpec({ + val member = Member() + beforeEach { + member.preferences = MemberPreferences() + member.stats = Stats() + } + "hasClass" should { + "false if classes are disabled" { + member.preferences?.disableClasses = true + member.hasClass shouldBe false + } + + "false if class is empty" { + member.hasClass shouldBe false + } + + "false if no class was chosen" { + member.flags?.classSelected = false + member.hasClass shouldBe false + } + + "false if class was selected but then disabled" { + member.flags?.classSelected = true + member.preferences?.disableClasses = true + member.hasClass shouldBe false + } + + "true if class was selected and not disabled" { + member.flags?.classSelected = true + member.stats?.habitClass = Stats.ROGUE + member.hasClass shouldBe true + } + } }) diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SpecialItemsTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SpecialItemsTest.kt new file mode 100644 index 000000000..b459b4afd --- /dev/null +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SpecialItemsTest.kt @@ -0,0 +1,37 @@ +package com.habitrpg.android.habitica.models.user + +import io.kotest.common.ExperimentalKotest +import io.kotest.core.spec.style.WordSpec +import io.kotest.datatest.withData +import io.kotest.matchers.shouldBe + +@ExperimentalKotest +class SpecialItemsTest : WordSpec({ + data class SpecialItemsData(val snowBalls: Int, val seafoam: Int, val shinyseed: Int, val spookySparkles: Int) + lateinit var items: SpecialItems + beforeEach { + items = SpecialItems() + } + "hasSpecialItems" should { + "false if none are owned" { + items.hasSpecialItems shouldBe false + } + "true if any are owned" { + items.snowball = 4 + items.hasSpecialItems shouldBe true + } + withData( + SpecialItemsData(1, 0, 0, 0), + SpecialItemsData(0, 1, 0, 0), + SpecialItemsData(0, 0, 1, 0), + SpecialItemsData(0, 0, 0, 1), + SpecialItemsData(1, 3, 4, 8) + ) { (snowballs, seafoam, shinyseeds, spookySparkles) -> + items.snowball = snowballs + items.seafoam = seafoam + items.shinySeed = shinyseeds + items.spookySparkles = spookySparkles + items.hasSpecialItems shouldBe true + } + } +}) diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanTest.kt new file mode 100644 index 000000000..c16dd757f --- /dev/null +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanTest.kt @@ -0,0 +1,70 @@ +package com.habitrpg.android.habitica.models.user + +import io.kotest.core.spec.style.WordSpec +import io.kotest.matchers.shouldBe +import java.util.Date + +class SubscriptionPlanTest : WordSpec({ + lateinit var plan: SubscriptionPlan + beforeEach { + plan = SubscriptionPlan() + } + "isActive" should { + "true if user has valid subscription" { + plan.customerId = "some-id" + plan.isActive shouldBe true + } + "true if user has cancelled subscription with remaining time" { + plan.customerId = "some-id" + plan.dateTerminated = Date(Date().time + 10000) + plan.isActive shouldBe true + } + "false if user has cancelled subscription without remaining time" { + plan.customerId = "some-id" + plan.dateTerminated = Date(Date().time - 10000) + plan.isActive shouldBe false + } + } + + "totalNumberOfGems" should { + beforeEach { + plan.customerId = "some-id" + } + "0 without an active subscription" { + plan.customerId = null + plan.totalNumberOfGems shouldBe 0 + } + + "25 without extra consecutive bonus" { + plan.totalNumberOfGems shouldBe 25 + } + + "35 with extra consecutive bonus" { + plan.consecutive = SubscriptionPlanConsecutive() + plan.consecutive?.gemCapExtra = 15 + plan.totalNumberOfGems shouldBe 40 + } + } + + "numberOfGemsLeft" should { + beforeEach { + plan.customerId = "some-id" + } + "0 without an active subscription" { + plan.customerId = null + plan.numberOfGemsLeft shouldBe 0 + } + + "according to already purchased amount" { + plan.gemsBought = 10 + plan.numberOfGemsLeft shouldBe 15 + } + + "according to already purchased amount with bonus" { + plan.consecutive = SubscriptionPlanConsecutive() + plan.consecutive?.gemCapExtra = 10 + plan.gemsBought = 10 + plan.numberOfGemsLeft shouldBe 25 + } + } +}) diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/UserTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/UserTest.kt new file mode 100644 index 000000000..a5812ccbc --- /dev/null +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/UserTest.kt @@ -0,0 +1,82 @@ +package com.habitrpg.android.habitica.models.user + +import com.habitrpg.android.habitica.models.social.UserParty +import io.kotest.core.spec.style.WordSpec +import io.kotest.matchers.shouldBe +import io.realm.RealmList +import java.util.UUID + +class UserTest : WordSpec({ + val user = User() + beforeEach { + user.preferences = Preferences() + user.stats = Stats() + user.flags = Flags() + user.party = UserParty() + user.purchased = Purchases() + user.purchased?.plan = SubscriptionPlan() + } + "hasClass" should { + "false if classes are disabled" { + user.preferences?.disableClasses = true + user.hasClass shouldBe false + } + + "false if class is empty" { + user.hasClass shouldBe false + } + + "false if no class was chosen" { + user.flags?.classSelected = false + user.hasClass shouldBe false + } + + "false if class was selected but then disabled" { + user.flags?.classSelected = true + user.preferences?.disableClasses = true + user.hasClass shouldBe false + } + + "true if class was selected and not disabled" { + user.flags?.classSelected = true + user.preferences?.disableClasses = false + user.stats?.habitClass = Stats.ROGUE + user.hasClass shouldBe true + } + } + + "Onboarding Achievements" should { + beforeEach { + user.achievements = RealmList() + for (key in User.ONBOARDING_ACHIEVEMENT_KEYS) { + user.achievements.add(UserAchievement(key, false)) + } + } + + "hasCompletedOnboarding should be true if all onboarding achievements are completed" { + user.onboardingAchievements.forEach { it.earned = true } + user.hasCompletedOnboarding shouldBe true + } + + "hasCompletedOnboarding should be false if not all onboarding achievements are completed" { + user.onboardingAchievements.get(2).earned = true + user.hasCompletedOnboarding shouldBe false + } + } + + "hasParty" should { + "true if user has valid party" { + user.party?.id = UUID.randomUUID().toString() + user.hasParty shouldBe true + } + + "false if user has no party data" { + user.party = null + user.hasParty shouldBe false + } + + "false if user has invalid party" { + user.hasParty shouldBe false + } + } +}) diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/utils/DateDeserializerTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/utils/DateDeserializerTest.kt index 78355f15f..33ffe3701 100644 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/utils/DateDeserializerTest.kt +++ b/Habitica/src/test/java/com/habitrpg/android/habitica/utils/DateDeserializerTest.kt @@ -2,7 +2,6 @@ package com.habitrpg.android.habitica.utils import com.google.gson.JsonDeserializationContext import com.google.gson.JsonElement -import com.google.gson.JsonParseException import com.google.gson.JsonPrimitive import com.google.gson.JsonSerializationContext import com.habitrpg.android.habitica.BaseAnnotationTestCase @@ -10,7 +9,7 @@ import io.kotest.matchers.shouldBe import java.lang.reflect.Type import java.util.Date -class DateDeserializerTest: BaseAnnotationTestCase() { +class DateDeserializerTest : BaseAnnotationTestCase() { var deserializer = DateDeserializer() lateinit var deserializationContext: JsonDeserializationContext lateinit var serializationContext: JsonSerializationContext @@ -66,7 +65,8 @@ class DateDeserializerTest: BaseAnnotationTestCase() { val dateElement: JsonElement = deserializer!!.serialize( Date( referenceTimestamp!! - ), Date::class.java, serializationContext + ), + Date::class.java, serializationContext ) dateElement.asString shouldBe "2015-09-28T13:00:00.000Z" } @@ -77,4 +77,4 @@ class DateDeserializerTest: BaseAnnotationTestCase() { deserializer!!.serialize(null, Date::class.java, serializationContext) dateElement.asString shouldBe "" } -} \ No newline at end of file +} diff --git a/Habitica/src/test/resources/robolectric.properties b/Habitica/src/test/resources/robolectric.properties deleted file mode 100644 index 696137acb..000000000 --- a/Habitica/src/test/resources/robolectric.properties +++ /dev/null @@ -1,4 +0,0 @@ -sdk=21 -packageName=com.habitrpg.android.habitica -manifest=AndroidManifest.xml -application=com.habitrpg.android.habitica.TestApplication \ No newline at end of file diff --git a/detekt_baseline.xml b/detekt_baseline.xml index 08d2c4451..09b043944 100644 --- a/detekt_baseline.xml +++ b/detekt_baseline.xml @@ -49,7 +49,7 @@ ComplexMethod:SubscriptionDetailsView.kt$SubscriptionDetailsView$fun setPlan(plan: SubscriptionPlan) ComplexMethod:TaskFormActivity.kt$TaskFormActivity$override fun onCreate(savedInstanceState: Bundle?) ComplexMethod:TaskFormActivity.kt$TaskFormActivity$private fun fillForm(task: Task) - ComplexMethod:TaskRepositoryImpl.kt$TaskRepositoryImpl$@Suppress("ReturnCount") override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult?> + ComplexMethod:TaskRepositoryImpl.kt$TaskRepositoryImpl$@Suppress("ReturnCount") override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult> ComplexMethod:TaskRepositoryImpl.kt$TaskRepositoryImpl$private fun handleTaskResponse(user: User, res: TaskDirectionData, task: Task, up: Boolean, localDelta: Float) ComplexMethod:TaskSchedulingControls.kt$TaskSchedulingControls$private fun generateSummary() ComplexMethod:TaskSerializer.kt$TaskSerializer$override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext): Task diff --git a/reports/profile/css/base-style.css b/reports/profile/css/base-style.css deleted file mode 100644 index 4afa73e3d..000000000 --- a/reports/profile/css/base-style.css +++ /dev/null @@ -1,179 +0,0 @@ - -body { - margin: 0; - padding: 0; - font-family: sans-serif; - font-size: 12pt; -} - -body, a, a:visited { - color: #303030; -} - -#content { - padding-left: 50px; - padding-right: 50px; - padding-top: 30px; - padding-bottom: 30px; -} - -#content h1 { - font-size: 160%; - margin-bottom: 10px; -} - -#footer { - margin-top: 100px; - font-size: 80%; - white-space: nowrap; -} - -#footer, #footer a { - color: #a0a0a0; -} - -#line-wrapping-toggle { - vertical-align: middle; -} - -#label-for-line-wrapping-toggle { - vertical-align: middle; -} - -ul { - margin-left: 0; -} - -h1, h2, h3 { - white-space: nowrap; -} - -h2 { - font-size: 120%; -} - -ul.tabLinks { - padding-left: 0; - padding-top: 10px; - padding-bottom: 10px; - overflow: auto; - min-width: 800px; - width: auto !important; - width: 800px; -} - -ul.tabLinks li { - float: left; - height: 100%; - list-style: none; - padding-left: 10px; - padding-right: 10px; - padding-top: 5px; - padding-bottom: 5px; - margin-bottom: 0; - -moz-border-radius: 7px; - border-radius: 7px; - margin-right: 25px; - border: solid 1px #d4d4d4; - background-color: #f0f0f0; -} - -ul.tabLinks li:hover { - background-color: #fafafa; -} - -ul.tabLinks li.selected { - background-color: #c5f0f5; - border-color: #c5f0f5; -} - -ul.tabLinks a { - font-size: 120%; - display: block; - outline: none; - text-decoration: none; - margin: 0; - padding: 0; -} - -ul.tabLinks li h2 { - margin: 0; - padding: 0; -} - -div.tab { -} - -div.selected { - display: block; -} - -div.deselected { - display: none; -} - -div.tab table { - min-width: 350px; - width: auto !important; - width: 350px; - border-collapse: collapse; -} - -div.tab th, div.tab table { - border-bottom: solid #d0d0d0 1px; -} - -div.tab th { - text-align: left; - white-space: nowrap; - padding-left: 6em; -} - -div.tab th:first-child { - padding-left: 0; -} - -div.tab td { - white-space: nowrap; - padding-left: 6em; - padding-top: 5px; - padding-bottom: 5px; -} - -div.tab td:first-child { - padding-left: 0; -} - -div.tab td.numeric, div.tab th.numeric { - text-align: right; -} - -span.code { - display: inline-block; - margin-top: 0em; - margin-bottom: 1em; -} - -span.code pre { - font-size: 11pt; - padding-top: 10px; - padding-bottom: 10px; - padding-left: 10px; - padding-right: 10px; - margin: 0; - background-color: #f7f7f7; - border: solid 1px #d0d0d0; - min-width: 700px; - width: auto !important; - width: 700px; -} - -span.wrapped pre { - word-wrap: break-word; - white-space: pre-wrap; - word-break: break-all; -} - -label.hidden { - display: none; -} \ No newline at end of file diff --git a/reports/profile/css/style.css b/reports/profile/css/style.css deleted file mode 100644 index c4a423933..000000000 --- a/reports/profile/css/style.css +++ /dev/null @@ -1,4 +0,0 @@ - -div.tab td.indentPath { - padding-left: 3em; -} diff --git a/reports/profile/js/report.js b/reports/profile/js/report.js deleted file mode 100644 index 83bab4a19..000000000 --- a/reports/profile/js/report.js +++ /dev/null @@ -1,194 +0,0 @@ -(function (window, document) { - "use strict"; - - var tabs = {}; - - function changeElementClass(element, classValue) { - if (element.getAttribute("className")) { - element.setAttribute("className", classValue); - } else { - element.setAttribute("class", classValue); - } - } - - function getClassAttribute(element) { - if (element.getAttribute("className")) { - return element.getAttribute("className"); - } else { - return element.getAttribute("class"); - } - } - - function addClass(element, classValue) { - changeElementClass(element, getClassAttribute(element) + " " + classValue); - } - - function removeClass(element, classValue) { - changeElementClass(element, getClassAttribute(element).replace(classValue, "")); - } - - function initTabs() { - var container = document.getElementById("tabs"); - - tabs.tabs = findTabs(container); - tabs.titles = findTitles(tabs.tabs); - tabs.headers = findHeaders(container); - tabs.select = select; - tabs.deselectAll = deselectAll; - tabs.select(0); - - return true; - } - - function getCheckBox() { - return document.getElementById("line-wrapping-toggle"); - } - - function getLabelForCheckBox() { - return document.getElementById("label-for-line-wrapping-toggle"); - } - - function findCodeBlocks() { - var spans = document.getElementById("tabs").getElementsByTagName("span"); - var codeBlocks = []; - for (var i = 0; i < spans.length; ++i) { - if (spans[i].className.indexOf("code") >= 0) { - codeBlocks.push(spans[i]); - } - } - return codeBlocks; - } - - function forAllCodeBlocks(operation) { - var codeBlocks = findCodeBlocks(); - - for (var i = 0; i < codeBlocks.length; ++i) { - operation(codeBlocks[i], "wrapped"); - } - } - - function toggleLineWrapping() { - var checkBox = getCheckBox(); - - if (checkBox.checked) { - forAllCodeBlocks(addClass); - } else { - forAllCodeBlocks(removeClass); - } - } - - function initControls() { - if (findCodeBlocks().length > 0) { - var checkBox = getCheckBox(); - var label = getLabelForCheckBox(); - - checkBox.onclick = toggleLineWrapping; - checkBox.checked = false; - - removeClass(label, "hidden"); - } - } - - function switchTab() { - var id = this.id.substr(1); - - for (var i = 0; i < tabs.tabs.length; i++) { - if (tabs.tabs[i].id === id) { - tabs.select(i); - break; - } - } - - return false; - } - - function select(i) { - this.deselectAll(); - - changeElementClass(this.tabs[i], "tab selected"); - changeElementClass(this.headers[i], "selected"); - - while (this.headers[i].firstChild) { - this.headers[i].removeChild(this.headers[i].firstChild); - } - - var h2 = document.createElement("H2"); - - h2.appendChild(document.createTextNode(this.titles[i])); - this.headers[i].appendChild(h2); - } - - function deselectAll() { - for (var i = 0; i < this.tabs.length; i++) { - changeElementClass(this.tabs[i], "tab deselected"); - changeElementClass(this.headers[i], "deselected"); - - while (this.headers[i].firstChild) { - this.headers[i].removeChild(this.headers[i].firstChild); - } - - var a = document.createElement("A"); - - a.setAttribute("id", "ltab" + i); - a.setAttribute("href", "#tab" + i); - a.onclick = switchTab; - a.appendChild(document.createTextNode(this.titles[i])); - - this.headers[i].appendChild(a); - } - } - - function findTabs(container) { - return findChildElements(container, "DIV", "tab"); - } - - function findHeaders(container) { - var owner = findChildElements(container, "UL", "tabLinks"); - return findChildElements(owner[0], "LI", null); - } - - function findTitles(tabs) { - var titles = []; - - for (var i = 0; i < tabs.length; i++) { - var tab = tabs[i]; - var header = findChildElements(tab, "H2", null)[0]; - - header.parentNode.removeChild(header); - - if (header.innerText) { - titles.push(header.innerText); - } else { - titles.push(header.textContent); - } - } - - return titles; - } - - function findChildElements(container, name, targetClass) { - var elements = []; - var children = container.childNodes; - - for (var i = 0; i < children.length; i++) { - var child = children.item(i); - - if (child.nodeType === 1 && child.nodeName === name) { - if (targetClass && child.className.indexOf(targetClass) < 0) { - continue; - } - - elements.push(child); - } - } - - return elements; - } - - // Entry point. - - window.onload = function() { - initTabs(); - initControls(); - }; -} (window, window.document)); \ No newline at end of file diff --git a/reports/profile/profile-2016-05-09-17-48-55.html b/reports/profile/profile-2016-05-09-17-48-55.html deleted file mode 100644 index 25b139160..000000000 --- a/reports/profile/profile-2016-05-09-17-48-55.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - -Profile report - - - - - -
-

Profile report

- -
- -
-

Summary

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DescriptionDuration
Total Build Time8.294s
Startup2.120s
Settings and BuildSrc0.225s
Loading Projects0.502s
Configuring Projects4.522s
Task Execution0s
-
-
-

Configuration

- - - - - - - - - - - - - - - - - - - -
ProjectDuration
All projects4.522s
:Habitica2.818s
:1.704s
-
-
-

Dependency Resolution

- - - - - - - - - - - - - - - - - - - -
DependenciesDuration
All dependencies0.915s
:classpath0.709s
:Habitica:classpath0.206s
-
-
-

Task Execution

- - - - - - - - - - - - - - - - - - -
TaskDurationResult
:0s(total)
:Habitica0s(total)
-
-
- -
- - diff --git a/reports/profile/profile-2016-05-09-17-50-45.html b/reports/profile/profile-2016-05-09-17-50-45.html deleted file mode 100644 index 309ccddf6..000000000 --- a/reports/profile/profile-2016-05-09-17-50-45.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - -Profile report - - - - - -
-

Profile report

- -
- -
-

Summary

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DescriptionDuration
Total Build Time1.721s
Startup0.704s
Settings and BuildSrc0.003s
Loading Projects0.007s
Configuring Projects0.778s
Task Execution0s
-
-
-

Configuration

- - - - - - - - - - - - - - - - - - - -
ProjectDuration
All projects0.778s
:Habitica0.586s
:0.192s
-
-
-

Dependency Resolution

- - - - - - - - - - - - - - - - - - - -
DependenciesDuration
All dependencies0.318s
:classpath0.160s
:Habitica:classpath0.158s
-
-
-

Task Execution

- - - - - - - - - - - - - - - - - - -
TaskDurationResult
:0s(total)
:Habitica0s(total)
-
-
- -
- -