mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 11:46:32 +00:00
Add some more tests
This commit is contained in:
parent
7cc7c6f87e
commit
9244cb0430
49 changed files with 573 additions and 776 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ interface TaskRepository : BaseRepository {
|
|||
fun retrieveTasks(userId: String, tasksOrder: TasksOrder): Flowable<TaskList>
|
||||
fun retrieveTasks(userId: String, tasksOrder: TasksOrder, dueDate: Date): Flowable<TaskList>
|
||||
|
||||
fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult?>
|
||||
fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult>
|
||||
fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Maybe<TaskScoringResult?>
|
||||
fun scoreChecklistItem(taskId: String, itemId: String): Flowable<Task>
|
||||
|
||||
|
|
|
|||
|
|
@ -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<TaskScoringResult?> {
|
||||
override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult> {
|
||||
val localData = if (user != null && appConfigManager.enableLocalTaskScoring()) {
|
||||
ScoreTaskLocallyInteractor.score(user, task, if (up) TaskDirection.UP else TaskDirection.DOWN)
|
||||
} else null
|
||||
|
|
|
|||
|
|
@ -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 <T : BaseMainObject> modify(obj: T, transaction: (T) -> Unit)
|
||||
fun <T : BaseMainObject> modifyWithRealm(obj: T, transaction: (Realm, T) -> Unit)
|
||||
fun <T : BaseObject> getLiveObject(obj: T): T?
|
||||
|
|
|
|||
|
|
@ -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 <T : BaseObject> getUnmanagedCopy(managedObject: T): T {
|
||||
return if (managedObject is RealmObject && managedObject.isManaged && managedObject.isValid) {
|
||||
realm.copyFromRealm(managedObject)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package com.habitrpg.android.habitica.models
|
||||
|
||||
interface AvatarFlags {
|
||||
var classSelected: Boolean
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TutorialStep>? = 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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<UserAchievement>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ open class ShopFragment : BaseMainFragment<FragmentRefreshRecyclerviewBinding>()
|
|||
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))
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ class NoPartyFragmentFragment : BaseMainFragment<FragmentNoPartyBinding>() {
|
|||
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 }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<TaskLocalRepository>()
|
||||
val apiClient = mockk<ApiClient>()
|
||||
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<BaseObject>()
|
||||
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<TaskList>()
|
||||
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<TaskScoringResult>()
|
||||
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<TaskScoringResult>()
|
||||
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<TaskScoringResult>()
|
||||
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<TaskScoringResult>()
|
||||
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<TaskScoringResult>()
|
||||
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<TaskScoringResult>()
|
||||
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<TaskScoringResult>()
|
||||
repository.taskChecked(user, task, false, true, null).subscribe(downSubscriber)
|
||||
downSubscriber.assertComplete()
|
||||
task.counterUp shouldBe 1
|
||||
task.counterDown shouldBe 1
|
||||
}
|
||||
}
|
||||
afterEach { clearAllMocks() }
|
||||
})
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Context>()
|
||||
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" {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -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 ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
sdk=21
|
||||
packageName=com.habitrpg.android.habitica
|
||||
manifest=AndroidManifest.xml
|
||||
application=com.habitrpg.android.habitica.TestApplication
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
<ID>ComplexMethod:SubscriptionDetailsView.kt$SubscriptionDetailsView$fun setPlan(plan: SubscriptionPlan)</ID>
|
||||
<ID>ComplexMethod:TaskFormActivity.kt$TaskFormActivity$override fun onCreate(savedInstanceState: Bundle?)</ID>
|
||||
<ID>ComplexMethod:TaskFormActivity.kt$TaskFormActivity$private fun fillForm(task: Task)</ID>
|
||||
<ID>ComplexMethod:TaskRepositoryImpl.kt$TaskRepositoryImpl$@Suppress("ReturnCount") override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult?></ID>
|
||||
<ID>ComplexMethod:TaskRepositoryImpl.kt$TaskRepositoryImpl$@Suppress("ReturnCount") override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult></ID>
|
||||
<ID>ComplexMethod:TaskRepositoryImpl.kt$TaskRepositoryImpl$private fun handleTaskResponse(user: User, res: TaskDirectionData, task: Task, up: Boolean, localDelta: Float)</ID>
|
||||
<ID>ComplexMethod:TaskSchedulingControls.kt$TaskSchedulingControls$private fun generateSummary()</ID>
|
||||
<ID>ComplexMethod:TaskSerializer.kt$TaskSerializer$override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext): Task</ID>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
div.tab td.indentPath {
|
||||
padding-left: 3em;
|
||||
}
|
||||
|
|
@ -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));
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
|
||||
<title>Profile report</title>
|
||||
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="css/style.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="js/report.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<h1>Profile report</h1>
|
||||
<div id="header">
|
||||
<p>Profiled build: build </p>
|
||||
<p>Started on: 2016/05/09 - 17:48:55</p>
|
||||
</div>
|
||||
<div id="tabs">
|
||||
<ul class="tabLinks">
|
||||
<li>
|
||||
<a href="#tab0">Summary</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tab1">Configuration</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tab2">Dependency Resolution</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tab3">Task Execution</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab" id="tab0">
|
||||
<h2>Summary</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<th class="numeric">Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>Total Build Time</td>
|
||||
<td class="numeric">8.294s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Startup</td>
|
||||
<td class="numeric">2.120s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Settings and BuildSrc</td>
|
||||
<td class="numeric">0.225s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Loading Projects</td>
|
||||
<td class="numeric">0.502s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Configuring Projects</td>
|
||||
<td class="numeric">4.522s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Task Execution</td>
|
||||
<td class="numeric">0s</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab" id="tab1">
|
||||
<h2>Configuration</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Project</th>
|
||||
<th class="numeric">Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>All projects</td>
|
||||
<td class="numeric">4.522s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:Habitica</td>
|
||||
<td class="numeric">2.818s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:</td>
|
||||
<td class="numeric">1.704s</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab" id="tab2">
|
||||
<h2>Dependency Resolution</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dependencies</th>
|
||||
<th class="numeric">Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>All dependencies</td>
|
||||
<td class="numeric">0.915s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:classpath</td>
|
||||
<td class="numeric">0.709s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:Habitica:classpath</td>
|
||||
<td class="numeric">0.206s</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab" id="tab3">
|
||||
<h2>Task Execution</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Task</th>
|
||||
<th class="numeric">Duration</th>
|
||||
<th>Result</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>:</td>
|
||||
<td class="numeric">0s</td>
|
||||
<td>(total)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:Habitica</td>
|
||||
<td class="numeric">0s</td>
|
||||
<td>(total)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>
|
||||
<div>
|
||||
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
|
||||
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
|
||||
</label>
|
||||
</div>Generated by
|
||||
<a href="http://www.gradle.org">Gradle 2.13</a> at May 9, 2016 5:49:02 PM</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
|
||||
<title>Profile report</title>
|
||||
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="css/style.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="js/report.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<h1>Profile report</h1>
|
||||
<div id="header">
|
||||
<p>Profiled build: build </p>
|
||||
<p>Started on: 2016/05/09 - 17:50:45</p>
|
||||
</div>
|
||||
<div id="tabs">
|
||||
<ul class="tabLinks">
|
||||
<li>
|
||||
<a href="#tab0">Summary</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tab1">Configuration</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tab2">Dependency Resolution</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#tab3">Task Execution</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab" id="tab0">
|
||||
<h2>Summary</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<th class="numeric">Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>Total Build Time</td>
|
||||
<td class="numeric">1.721s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Startup</td>
|
||||
<td class="numeric">0.704s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Settings and BuildSrc</td>
|
||||
<td class="numeric">0.003s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Loading Projects</td>
|
||||
<td class="numeric">0.007s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Configuring Projects</td>
|
||||
<td class="numeric">0.778s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Task Execution</td>
|
||||
<td class="numeric">0s</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab" id="tab1">
|
||||
<h2>Configuration</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Project</th>
|
||||
<th class="numeric">Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>All projects</td>
|
||||
<td class="numeric">0.778s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:Habitica</td>
|
||||
<td class="numeric">0.586s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:</td>
|
||||
<td class="numeric">0.192s</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab" id="tab2">
|
||||
<h2>Dependency Resolution</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dependencies</th>
|
||||
<th class="numeric">Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>All dependencies</td>
|
||||
<td class="numeric">0.318s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:classpath</td>
|
||||
<td class="numeric">0.160s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:Habitica:classpath</td>
|
||||
<td class="numeric">0.158s</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab" id="tab3">
|
||||
<h2>Task Execution</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Task</th>
|
||||
<th class="numeric">Duration</th>
|
||||
<th>Result</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>:</td>
|
||||
<td class="numeric">0s</td>
|
||||
<td>(total)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>:Habitica</td>
|
||||
<td class="numeric">0s</td>
|
||||
<td>(total)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>
|
||||
<div>
|
||||
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
|
||||
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
|
||||
</label>
|
||||
</div>Generated by
|
||||
<a href="http://www.gradle.org">Gradle 2.13</a> at May 9, 2016 5:50:46 PM</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue