2018-03-27 19:47:00 +02:00
|
|
|
/* Copyright 2018 charlag
|
|
|
|
*
|
|
|
|
* This file is a part of Tusky.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
|
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
|
|
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
|
|
* Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
|
|
|
* see <http://www.gnu.org/licenses>. */
|
|
|
|
|
2018-03-09 22:02:32 +01:00
|
|
|
package com.keylesspalace.tusky
|
|
|
|
|
2020-10-28 18:43:11 +01:00
|
|
|
import android.content.Intent
|
2020-11-22 19:02:54 +01:00
|
|
|
import android.os.Looper.getMainLooper
|
2018-03-09 22:02:32 +01:00
|
|
|
import android.widget.EditText
|
2019-12-19 19:09:40 +01:00
|
|
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
|
|
import com.keylesspalace.tusky.components.compose.ComposeActivity
|
|
|
|
import com.keylesspalace.tusky.components.compose.ComposeViewModel
|
|
|
|
import com.keylesspalace.tusky.components.compose.DEFAULT_CHARACTER_LIMIT
|
2022-03-01 19:43:36 +01:00
|
|
|
import com.keylesspalace.tusky.components.compose.DEFAULT_MAXIMUM_URL_LENGTH
|
2021-06-28 21:13:24 +02:00
|
|
|
import com.keylesspalace.tusky.db.AccountEntity
|
|
|
|
import com.keylesspalace.tusky.db.AccountManager
|
|
|
|
import com.keylesspalace.tusky.db.AppDatabase
|
|
|
|
import com.keylesspalace.tusky.db.InstanceDao
|
|
|
|
import com.keylesspalace.tusky.db.InstanceEntity
|
2019-12-19 19:09:40 +01:00
|
|
|
import com.keylesspalace.tusky.di.ViewModelFactory
|
2018-04-29 10:08:25 +02:00
|
|
|
import com.keylesspalace.tusky.entity.Account
|
2018-04-22 10:35:46 +02:00
|
|
|
import com.keylesspalace.tusky.entity.Instance
|
2022-03-01 19:43:36 +01:00
|
|
|
import com.keylesspalace.tusky.entity.InstanceConfiguration
|
|
|
|
import com.keylesspalace.tusky.entity.StatusConfiguration
|
2018-04-13 22:37:21 +02:00
|
|
|
import com.keylesspalace.tusky.network.MastodonApi
|
2021-05-16 19:53:27 +02:00
|
|
|
import io.reactivex.rxjava3.core.Single
|
2021-06-28 21:13:24 +02:00
|
|
|
import org.junit.Assert.assertEquals
|
|
|
|
import org.junit.Assert.assertFalse
|
|
|
|
import org.junit.Assert.assertTrue
|
2018-03-09 22:02:32 +01:00
|
|
|
import org.junit.Before
|
|
|
|
import org.junit.Test
|
|
|
|
import org.junit.runner.RunWith
|
2022-04-14 19:49:49 +02:00
|
|
|
import org.mockito.kotlin.any
|
|
|
|
import org.mockito.kotlin.doReturn
|
|
|
|
import org.mockito.kotlin.mock
|
2018-03-09 22:02:32 +01:00
|
|
|
import org.robolectric.Robolectric
|
2020-11-22 19:02:54 +01:00
|
|
|
import org.robolectric.Shadows.shadowOf
|
2018-03-09 22:02:32 +01:00
|
|
|
import org.robolectric.annotation.Config
|
|
|
|
import org.robolectric.fakes.RoboMenuItem
|
2019-03-07 21:33:29 +01:00
|
|
|
|
2018-03-09 22:02:32 +01:00
|
|
|
/**
|
|
|
|
* Created by charlag on 3/7/18.
|
|
|
|
*/
|
|
|
|
|
2020-02-25 19:49:15 +01:00
|
|
|
@Config(sdk = [28])
|
2019-03-30 15:18:16 +01:00
|
|
|
@RunWith(AndroidJUnit4::class)
|
2018-03-09 22:02:32 +01:00
|
|
|
class ComposeActivityTest {
|
2019-03-30 15:18:16 +01:00
|
|
|
private lateinit var activity: ComposeActivity
|
|
|
|
private lateinit var accountManagerMock: AccountManager
|
|
|
|
private lateinit var apiMock: MastodonApi
|
2018-03-09 22:02:32 +01:00
|
|
|
|
2019-12-19 19:09:40 +01:00
|
|
|
private val instanceDomain = "example.domain"
|
|
|
|
|
2019-03-30 15:18:16 +01:00
|
|
|
private val account = AccountEntity(
|
2021-06-28 21:13:24 +02:00
|
|
|
id = 1,
|
|
|
|
domain = instanceDomain,
|
|
|
|
accessToken = "token",
|
|
|
|
isActive = true,
|
|
|
|
accountId = "1",
|
|
|
|
username = "username",
|
|
|
|
displayName = "Display Name",
|
|
|
|
profilePictureUrl = "",
|
|
|
|
notificationsEnabled = true,
|
|
|
|
notificationsMentioned = true,
|
|
|
|
notificationsFollowed = true,
|
|
|
|
notificationsFollowRequested = false,
|
|
|
|
notificationsReblogged = true,
|
|
|
|
notificationsFavorited = true,
|
|
|
|
notificationSound = true,
|
|
|
|
notificationVibration = true,
|
|
|
|
notificationLight = true
|
2018-03-09 22:02:32 +01:00
|
|
|
)
|
2021-06-28 21:13:24 +02:00
|
|
|
private var instanceResponseCallback: (() -> Instance)? = null
|
2020-11-22 19:02:54 +01:00
|
|
|
private var composeOptions: ComposeActivity.ComposeOptions? = null
|
2018-03-09 22:02:32 +01:00
|
|
|
|
|
|
|
@Before
|
2018-04-29 10:08:25 +02:00
|
|
|
fun setupActivity() {
|
2018-03-09 22:02:32 +01:00
|
|
|
val controller = Robolectric.buildActivity(ComposeActivity::class.java)
|
|
|
|
activity = controller.get()
|
2018-04-13 22:37:21 +02:00
|
|
|
|
2022-04-14 19:49:49 +02:00
|
|
|
accountManagerMock = mock {
|
|
|
|
on { activeAccount } doReturn account
|
|
|
|
}
|
2018-04-13 22:37:21 +02:00
|
|
|
|
2022-04-14 19:49:49 +02:00
|
|
|
apiMock = mock {
|
|
|
|
on { getCustomEmojis() } doReturn Single.just(emptyList())
|
|
|
|
onBlocking { getInstance() } doReturn instanceResponseCallback?.invoke().let { instance ->
|
2019-08-04 20:25:07 +02:00
|
|
|
if (instance == null) {
|
2022-04-14 19:49:49 +02:00
|
|
|
Result.failure(Throwable())
|
2019-08-04 20:25:07 +02:00
|
|
|
} else {
|
2022-04-14 19:49:49 +02:00
|
|
|
Result.success(instance)
|
2019-08-04 20:25:07 +02:00
|
|
|
}
|
2018-04-29 10:08:25 +02:00
|
|
|
}
|
2022-04-14 19:49:49 +02:00
|
|
|
}
|
2018-04-13 22:37:21 +02:00
|
|
|
|
2022-04-14 19:49:49 +02:00
|
|
|
val instanceDaoMock: InstanceDao = mock {
|
|
|
|
on { loadMetadataForInstance(any()) } doReturn
|
|
|
|
Single.just(InstanceEntity(instanceDomain, emptyList(), null, null, null, null, null, null, null))
|
|
|
|
on { loadMetadataForInstance(any()) } doReturn
|
|
|
|
Single.just(InstanceEntity(instanceDomain, emptyList(), null, null, null, null, null, null, null))
|
|
|
|
}
|
2019-12-19 19:09:40 +01:00
|
|
|
|
2022-04-14 19:49:49 +02:00
|
|
|
val dbMock: AppDatabase = mock {
|
|
|
|
on { instanceDao() } doReturn instanceDaoMock
|
|
|
|
}
|
2018-05-27 10:22:12 +02:00
|
|
|
|
2019-12-19 19:09:40 +01:00
|
|
|
val viewModel = ComposeViewModel(
|
2021-06-28 21:13:24 +02:00
|
|
|
apiMock,
|
|
|
|
accountManagerMock,
|
2022-04-14 19:49:49 +02:00
|
|
|
mock(),
|
|
|
|
mock(),
|
|
|
|
mock(),
|
2021-06-28 21:13:24 +02:00
|
|
|
dbMock
|
2019-12-19 19:09:40 +01:00
|
|
|
)
|
2020-10-28 18:43:11 +01:00
|
|
|
activity.intent = Intent(activity, ComposeActivity::class.java).apply {
|
|
|
|
putExtra(ComposeActivity.COMPOSE_OPTIONS_EXTRA, composeOptions)
|
|
|
|
}
|
2018-04-13 22:37:21 +02:00
|
|
|
|
2022-04-14 19:49:49 +02:00
|
|
|
val viewModelFactoryMock: ViewModelFactory = mock {
|
|
|
|
on { create(ComposeViewModel::class.java) } doReturn viewModel
|
|
|
|
}
|
2018-04-13 22:37:21 +02:00
|
|
|
|
2019-12-19 19:09:40 +01:00
|
|
|
activity.accountManager = accountManagerMock
|
|
|
|
activity.viewModelFactory = viewModelFactoryMock
|
2018-04-13 22:37:21 +02:00
|
|
|
|
2018-03-09 22:02:32 +01:00
|
|
|
controller.create().start()
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenCloseButtonPressedAndEmpty_finish() {
|
|
|
|
clickUp()
|
|
|
|
assertTrue(activity.isFinishing)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenCloseButtonPressedNotEmpty_notFinish() {
|
|
|
|
insertSomeTextInContent()
|
|
|
|
clickUp()
|
|
|
|
assertFalse(activity.isFinishing)
|
|
|
|
// We would like to check for dialog but Robolectric doesn't work with AppCompat v7 yet
|
|
|
|
}
|
|
|
|
|
2020-10-28 18:43:11 +01:00
|
|
|
@Test
|
|
|
|
fun whenModifiedInitialState_andCloseButtonPressed_notFinish() {
|
|
|
|
composeOptions = ComposeActivity.ComposeOptions(modifiedInitialState = true)
|
|
|
|
setupActivity()
|
|
|
|
clickUp()
|
|
|
|
assertFalse(activity.isFinishing)
|
|
|
|
}
|
|
|
|
|
2018-03-09 22:02:32 +01:00
|
|
|
@Test
|
|
|
|
fun whenBackButtonPressedAndEmpty_finish() {
|
|
|
|
clickBack()
|
|
|
|
assertTrue(activity.isFinishing)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenBackButtonPressedNotEmpty_notFinish() {
|
|
|
|
insertSomeTextInContent()
|
|
|
|
clickBack()
|
|
|
|
assertFalse(activity.isFinishing)
|
|
|
|
// We would like to check for dialog but Robolectric doesn't work with AppCompat v7 yet
|
|
|
|
}
|
|
|
|
|
2020-10-28 18:43:11 +01:00
|
|
|
@Test
|
|
|
|
fun whenModifiedInitialState_andBackButtonPressed_notFinish() {
|
|
|
|
composeOptions = ComposeActivity.ComposeOptions(modifiedInitialState = true)
|
|
|
|
setupActivity()
|
|
|
|
clickBack()
|
|
|
|
assertFalse(activity.isFinishing)
|
|
|
|
}
|
|
|
|
|
2018-04-29 10:08:25 +02:00
|
|
|
@Test
|
|
|
|
fun whenMaximumTootCharsIsNull_defaultLimitIsUsed() {
|
2022-03-01 19:43:36 +01:00
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(null) }
|
2018-04-29 10:08:25 +02:00
|
|
|
setupActivity()
|
2019-12-19 19:09:40 +01:00
|
|
|
assertEquals(DEFAULT_CHARACTER_LIMIT, activity.maximumTootCharacters)
|
2018-04-29 10:08:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenMaximumTootCharsIsPopulated_customLimitIsUsed() {
|
|
|
|
val customMaximum = 1000
|
2022-03-01 19:43:36 +01:00
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(customMaximum, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum)) }
|
2018-04-29 10:08:25 +02:00
|
|
|
setupActivity()
|
2020-11-22 19:02:54 +01:00
|
|
|
shadowOf(getMainLooper()).idle()
|
2018-04-29 10:08:25 +02:00
|
|
|
assertEquals(customMaximum, activity.maximumTootCharacters)
|
|
|
|
}
|
|
|
|
|
2022-03-01 19:43:36 +01:00
|
|
|
@Test
|
|
|
|
fun whenOnlyLegacyMaximumTootCharsIsPopulated_customLimitIsUsed() {
|
|
|
|
val customMaximum = 1000
|
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(customMaximum) }
|
|
|
|
setupActivity()
|
|
|
|
shadowOf(getMainLooper()).idle()
|
|
|
|
assertEquals(customMaximum, activity.maximumTootCharacters)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenOnlyConfigurationMaximumTootCharsIsPopulated_customLimitIsUsed() {
|
|
|
|
val customMaximum = 1000
|
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(null, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum)) }
|
|
|
|
setupActivity()
|
|
|
|
shadowOf(getMainLooper()).idle()
|
|
|
|
assertEquals(customMaximum, activity.maximumTootCharacters)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenDifferentCharLimitsArePopulated_statusConfigurationLimitIsUsed() {
|
|
|
|
val customMaximum = 1000
|
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(customMaximum, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum * 2)) }
|
|
|
|
setupActivity()
|
|
|
|
shadowOf(getMainLooper()).idle()
|
|
|
|
assertEquals(customMaximum * 2, activity.maximumTootCharacters)
|
|
|
|
}
|
|
|
|
|
2018-05-16 19:14:26 +02:00
|
|
|
@Test
|
2018-07-10 19:39:52 +02:00
|
|
|
fun whenTextContainsNoUrl_everyCharacterIsCounted() {
|
|
|
|
val content = "This is test content please ignore thx "
|
|
|
|
insertSomeTextInContent(content)
|
2019-10-03 19:58:21 +02:00
|
|
|
assertEquals(activity.calculateTextLength(), content.length)
|
2018-07-10 19:39:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenTextContainsUrl_onlyEllipsizedURLIsCounted() {
|
2018-05-16 19:14:26 +02:00
|
|
|
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
|
|
|
|
val additionalContent = "Check out this @image #search result: "
|
|
|
|
insertSomeTextInContent(additionalContent + url)
|
2022-03-01 19:43:36 +01:00
|
|
|
assertEquals(activity.calculateTextLength(), additionalContent.length + DEFAULT_MAXIMUM_URL_LENGTH)
|
2018-07-10 19:39:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2022-03-24 19:52:18 +01:00
|
|
|
fun whenTextContainsShortUrls_allUrlsGetEllipsized() {
|
2018-07-10 19:39:52 +02:00
|
|
|
val shortUrl = "https://tusky.app"
|
|
|
|
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
|
|
|
|
val additionalContent = " Check out this @image #search result: "
|
|
|
|
insertSomeTextInContent(shortUrl + additionalContent + url)
|
2022-03-24 19:52:18 +01:00
|
|
|
assertEquals(activity.calculateTextLength(), additionalContent.length + (DEFAULT_MAXIMUM_URL_LENGTH * 2))
|
2018-05-16 19:14:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenTextContainsMultipleURLs_allURLsGetEllipsized() {
|
|
|
|
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
|
|
|
|
val additionalContent = " Check out this @image #search result: "
|
|
|
|
insertSomeTextInContent(url + additionalContent + url)
|
2022-03-01 19:43:36 +01:00
|
|
|
assertEquals(activity.calculateTextLength(), additionalContent.length + (DEFAULT_MAXIMUM_URL_LENGTH * 2))
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenTextContainsUrl_onlyEllipsizedURLIsCounted_withCustomConfiguration() {
|
|
|
|
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
|
|
|
|
val additionalContent = "Check out this @image #search result: "
|
|
|
|
val customUrlLength = 16
|
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(configuration = getCustomInstanceConfiguration(charactersReservedPerUrl = customUrlLength)) }
|
|
|
|
setupActivity()
|
|
|
|
shadowOf(getMainLooper()).idle()
|
|
|
|
insertSomeTextInContent(additionalContent + url)
|
|
|
|
assertEquals(activity.calculateTextLength(), additionalContent.length + customUrlLength)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
2022-03-24 19:52:18 +01:00
|
|
|
fun whenTextContainsShortUrls_allUrlsGetEllipsized_withCustomConfiguration() {
|
2022-03-01 19:43:36 +01:00
|
|
|
val shortUrl = "https://tusky.app"
|
|
|
|
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
|
|
|
|
val additionalContent = " Check out this @image #search result: "
|
|
|
|
val customUrlLength = 18 // The intention is that this is longer than shortUrl.length
|
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(configuration = getCustomInstanceConfiguration(charactersReservedPerUrl = customUrlLength)) }
|
|
|
|
setupActivity()
|
|
|
|
shadowOf(getMainLooper()).idle()
|
|
|
|
insertSomeTextInContent(shortUrl + additionalContent + url)
|
2022-03-24 19:52:18 +01:00
|
|
|
assertEquals(activity.calculateTextLength(), additionalContent.length + (customUrlLength * 2))
|
2022-03-01 19:43:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenTextContainsMultipleURLs_allURLsGetEllipsized_withCustomConfiguration() {
|
|
|
|
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
|
|
|
|
val additionalContent = " Check out this @image #search result: "
|
|
|
|
val customUrlLength = 16
|
|
|
|
instanceResponseCallback = { getInstanceWithCustomConfiguration(configuration = getCustomInstanceConfiguration(charactersReservedPerUrl = customUrlLength)) }
|
|
|
|
setupActivity()
|
|
|
|
shadowOf(getMainLooper()).idle()
|
|
|
|
insertSomeTextInContent(url + additionalContent + url)
|
|
|
|
assertEquals(activity.calculateTextLength(), additionalContent.length + (customUrlLength * 2))
|
2018-05-16 19:14:26 +02:00
|
|
|
}
|
|
|
|
|
2020-01-13 15:21:17 +01:00
|
|
|
@Test
|
|
|
|
fun whenSelectionIsEmpty_specialTextIsInsertedAtCaret() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
editor.setText("Some text")
|
|
|
|
|
|
|
|
for (caretIndex in listOf(9, 1, 0)) {
|
|
|
|
editor.setSelection(caretIndex)
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
// Text should be inserted at caret
|
2020-11-22 19:02:54 +01:00
|
|
|
assertEquals("Unexpected value at $caretIndex", insertText, editor.text.substring(caretIndex, caretIndex + insertText.length))
|
2020-01-13 15:21:17 +01:00
|
|
|
|
|
|
|
// Caret should be placed after inserted text
|
|
|
|
assertEquals(caretIndex + insertText.length, editor.selectionStart)
|
|
|
|
assertEquals(caretIndex + insertText.length, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenSelectionDoesNotIncludeWordBreak_noSpecialTextIsInserted() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
val originalText = "Some text"
|
|
|
|
val selectionStart = 1
|
|
|
|
val selectionEnd = 4
|
|
|
|
editor.setText(originalText)
|
|
|
|
editor.setSelection(selectionStart, selectionEnd) // "ome"
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
|
|
|
|
// Text and selection should be unmodified
|
|
|
|
assertEquals(originalText, editor.text.toString())
|
|
|
|
assertEquals(selectionStart, editor.selectionStart)
|
|
|
|
assertEquals(selectionEnd, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenSelectionIncludesWordBreaks_startsOfAllWordsArePrepended() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
val originalText = "one two three four"
|
|
|
|
val selectionStart = 2
|
|
|
|
val originalSelectionEnd = 15
|
|
|
|
val modifiedSelectionEnd = 18
|
|
|
|
editor.setText(originalText)
|
|
|
|
editor.setSelection(selectionStart, originalSelectionEnd) // "e two three f"
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
|
|
|
|
// text should be inserted at word starts inside selection
|
|
|
|
assertEquals("one #two #three #four", editor.text.toString())
|
|
|
|
|
|
|
|
// selection should be expanded accordingly
|
|
|
|
assertEquals(selectionStart, editor.selectionStart)
|
|
|
|
assertEquals(modifiedSelectionEnd, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenSelectionIncludesEnd_textIsNotAppended() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
val originalText = "Some text"
|
|
|
|
val selectionStart = 7
|
|
|
|
val selectionEnd = 9
|
|
|
|
editor.setText(originalText)
|
|
|
|
editor.setSelection(selectionStart, selectionEnd) // "xt"
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
|
|
|
|
// Text and selection should be unmodified
|
|
|
|
assertEquals(originalText, editor.text.toString())
|
|
|
|
assertEquals(selectionStart, editor.selectionStart)
|
|
|
|
assertEquals(selectionEnd, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenSelectionIncludesStartAndStartIsAWord_textIsPrepended() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
val originalText = "Some text"
|
|
|
|
val selectionStart = 0
|
|
|
|
val selectionEnd = 3
|
|
|
|
editor.setText(originalText)
|
|
|
|
editor.setSelection(selectionStart, selectionEnd) // "Som"
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
|
|
|
|
// Text should be inserted at beginning
|
|
|
|
assert(editor.text.startsWith(insertText))
|
|
|
|
|
|
|
|
// selection should be expanded accordingly
|
|
|
|
assertEquals(selectionStart, editor.selectionStart)
|
|
|
|
assertEquals(selectionEnd + insertText.length, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenSelectionIncludesStartAndStartIsNotAWord_textIsNotPrepended() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
val originalText = " Some text"
|
|
|
|
val selectionStart = 0
|
|
|
|
val selectionEnd = 1
|
|
|
|
editor.setText(originalText)
|
|
|
|
editor.setSelection(selectionStart, selectionEnd) // " "
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
|
|
|
|
// Text and selection should be unmodified
|
|
|
|
assertEquals(originalText, editor.text.toString())
|
|
|
|
assertEquals(selectionStart, editor.selectionStart)
|
|
|
|
assertEquals(selectionEnd, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenSelectionBeginsAtWordStart_textIsPrepended() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
val originalText = "Some text"
|
|
|
|
val selectionStart = 5
|
|
|
|
val selectionEnd = 9
|
|
|
|
editor.setText(originalText)
|
|
|
|
editor.setSelection(selectionStart, selectionEnd) // "text"
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
|
|
|
|
// Text is prepended
|
|
|
|
assertEquals("Some #text", editor.text.toString())
|
|
|
|
|
|
|
|
// Selection is expanded accordingly
|
|
|
|
assertEquals(selectionStart, editor.selectionStart)
|
|
|
|
assertEquals(selectionEnd + insertText.length, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
fun whenSelectionEndsAtWordStart_textIsAppended() {
|
|
|
|
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
|
|
|
val insertText = "#"
|
|
|
|
val originalText = "Some text"
|
|
|
|
val selectionStart = 1
|
|
|
|
val selectionEnd = 5
|
|
|
|
editor.setText(originalText)
|
|
|
|
editor.setSelection(selectionStart, selectionEnd) // "ome "
|
|
|
|
activity.prependSelectedWordsWith(insertText)
|
|
|
|
|
|
|
|
// Text is prepended
|
|
|
|
assertEquals("Some #text", editor.text.toString())
|
|
|
|
|
|
|
|
// Selection is expanded accordingly
|
|
|
|
assertEquals(selectionStart, editor.selectionStart)
|
|
|
|
assertEquals(selectionEnd + insertText.length, editor.selectionEnd)
|
|
|
|
}
|
|
|
|
|
2018-03-09 22:02:32 +01:00
|
|
|
private fun clickUp() {
|
|
|
|
val menuItem = RoboMenuItem(android.R.id.home)
|
|
|
|
activity.onOptionsItemSelected(menuItem)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun clickBack() {
|
|
|
|
activity.onBackPressed()
|
|
|
|
}
|
|
|
|
|
2018-05-16 19:14:26 +02:00
|
|
|
private fun insertSomeTextInContent(text: String? = null) {
|
|
|
|
activity.findViewById<EditText>(R.id.composeEditField).setText(text ?: "Some text")
|
2018-03-09 22:02:32 +01:00
|
|
|
}
|
2018-04-29 10:08:25 +02:00
|
|
|
|
2022-03-01 19:43:36 +01:00
|
|
|
private fun getInstanceWithCustomConfiguration(maximumLegacyTootCharacters: Int? = null, configuration: InstanceConfiguration? = null): Instance {
|
2018-04-29 10:08:25 +02:00
|
|
|
return Instance(
|
2021-06-28 21:13:24 +02:00
|
|
|
"https://example.token",
|
|
|
|
"Example dot Token",
|
|
|
|
"Example instance for testing",
|
|
|
|
"admin@example.token",
|
|
|
|
"2.6.3",
|
|
|
|
HashMap(),
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
listOf("en"),
|
|
|
|
Account(
|
|
|
|
"1",
|
|
|
|
"admin",
|
|
|
|
"admin",
|
|
|
|
"admin",
|
2022-04-15 13:20:27 +02:00
|
|
|
"",
|
2018-04-29 10:08:25 +02:00
|
|
|
"https://example.token",
|
2021-06-28 21:13:24 +02:00
|
|
|
"",
|
|
|
|
"",
|
|
|
|
false,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
2018-04-29 10:08:25 +02:00
|
|
|
null,
|
2021-06-28 21:13:24 +02:00
|
|
|
false,
|
|
|
|
emptyList(),
|
|
|
|
emptyList()
|
|
|
|
),
|
2022-03-01 19:43:36 +01:00
|
|
|
maximumLegacyTootCharacters,
|
|
|
|
null,
|
2021-06-28 21:13:24 +02:00
|
|
|
null,
|
2022-03-01 19:43:36 +01:00
|
|
|
configuration,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-04-14 19:49:49 +02:00
|
|
|
private fun getCustomInstanceConfiguration(maximumStatusCharacters: Int? = null, charactersReservedPerUrl: Int? = null): InstanceConfiguration {
|
2022-03-01 19:43:36 +01:00
|
|
|
return InstanceConfiguration(
|
|
|
|
statuses = StatusConfiguration(
|
|
|
|
maxCharacters = maximumStatusCharacters,
|
|
|
|
maxMediaAttachments = null,
|
|
|
|
charactersReservedPerUrl = charactersReservedPerUrl
|
|
|
|
),
|
|
|
|
mediaAttachments = null,
|
|
|
|
polls = null
|
2018-04-29 10:08:25 +02:00
|
|
|
)
|
|
|
|
}
|
2019-12-19 19:09:40 +01:00
|
|
|
}
|