Add support for v2/instance (#4062)

…with fallback to v1
This commit is contained in:
Levi Bard 2023-10-25 12:53:10 +02:00 committed by GitHub
commit 131ebabe85
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 344 additions and 142 deletions

View file

@ -35,8 +35,11 @@ import com.keylesspalace.tusky.db.InstanceInfoEntity
import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.entity.Instance
import com.keylesspalace.tusky.entity.InstanceConfiguration
import com.keylesspalace.tusky.entity.InstanceV1
import com.keylesspalace.tusky.entity.StatusConfiguration
import com.keylesspalace.tusky.network.MastodonApi
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.toResponseBody
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@ -51,6 +54,8 @@ import org.robolectric.Robolectric
import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config
import org.robolectric.fakes.RoboMenuItem
import retrofit2.HttpException
import retrofit2.Response
import java.util.Locale
/**
@ -87,6 +92,7 @@ class ComposeActivityTest {
notificationVibration = true,
notificationLight = true
)
private var instanceV1ResponseCallback: (() -> InstanceV1)? = null
private var instanceResponseCallback: (() -> Instance)? = null
private var composeOptions: ComposeActivity.ComposeOptions? = null
@ -102,6 +108,13 @@ class ComposeActivityTest {
apiMock = mock {
onBlocking { getCustomEmojis() } doReturn NetworkResult.success(emptyList())
onBlocking { getInstance() } doReturn instanceResponseCallback?.invoke().let { instance ->
if (instance == null) {
NetworkResult.failure(HttpException(Response.error<ResponseBody>(404, "Not found".toResponseBody())))
} else {
NetworkResult.success(instance)
}
}
onBlocking { getInstanceV1() } doReturn instanceV1ResponseCallback?.invoke().let { instance ->
if (instance == null) {
NetworkResult.failure(Throwable())
} else {
@ -192,22 +205,13 @@ class ComposeActivityTest {
@Test
fun whenMaximumTootCharsIsNull_defaultLimitIsUsed() {
instanceResponseCallback = { getInstanceWithCustomConfiguration(null) }
instanceV1ResponseCallback = { getInstanceV1WithCustomConfiguration(null) }
setupActivity()
assertEquals(InstanceInfoRepository.DEFAULT_CHARACTER_LIMIT, activity.maximumTootCharacters)
}
@Test
fun whenMaximumTootCharsIsPopulated_customLimitIsUsed() {
val customMaximum = 1000
instanceResponseCallback = { getInstanceWithCustomConfiguration(customMaximum, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum)) }
setupActivity()
shadowOf(getMainLooper()).idle()
assertEquals(customMaximum, activity.maximumTootCharacters)
}
@Test
fun whenOnlyLegacyMaximumTootCharsIsPopulated_customLimitIsUsed() {
val customMaximum = 1000
instanceResponseCallback = { getInstanceWithCustomConfiguration(customMaximum) }
setupActivity()
@ -215,10 +219,19 @@ class ComposeActivityTest {
assertEquals(customMaximum, activity.maximumTootCharacters)
}
@Test
fun whenOnlyLegacyMaximumTootCharsIsPopulated_customLimitIsUsed() {
val customMaximum = 1000
instanceV1ResponseCallback = { getInstanceV1WithCustomConfiguration(customMaximum) }
setupActivity()
shadowOf(getMainLooper()).idle()
assertEquals(customMaximum, activity.maximumTootCharacters)
}
@Test
fun whenOnlyConfigurationMaximumTootCharsIsPopulated_customLimitIsUsed() {
val customMaximum = 1000
instanceResponseCallback = { getInstanceWithCustomConfiguration(null, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum)) }
instanceV1ResponseCallback = { getInstanceV1WithCustomConfiguration(null, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum)) }
setupActivity()
shadowOf(getMainLooper()).idle()
assertEquals(customMaximum, activity.maximumTootCharacters)
@ -227,7 +240,7 @@ class ComposeActivityTest {
@Test
fun whenDifferentCharLimitsArePopulated_statusConfigurationLimitIsUsed() {
val customMaximum = 1000
instanceResponseCallback = { getInstanceWithCustomConfiguration(customMaximum, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum * 2)) }
instanceV1ResponseCallback = { getInstanceV1WithCustomConfiguration(customMaximum, getCustomInstanceConfiguration(maximumStatusCharacters = customMaximum * 2)) }
setupActivity()
shadowOf(getMainLooper()).idle()
assertEquals(customMaximum * 2, activity.maximumTootCharacters)
@ -270,7 +283,19 @@ class ComposeActivityTest {
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)) }
instanceResponseCallback = { getInstanceWithCustomConfiguration(null, customUrlLength) }
setupActivity()
shadowOf(getMainLooper()).idle()
insertSomeTextInContent(additionalContent + url)
assertEquals(activity.calculateTextLength(), additionalContent.length + customUrlLength)
}
@Test
fun whenTextContainsUrl_onlyEllipsizedURLIsCounted_withCustomConfigurationV1() {
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
instanceV1ResponseCallback = { getInstanceV1WithCustomConfiguration(configuration = getCustomInstanceConfiguration(charactersReservedPerUrl = customUrlLength)) }
setupActivity()
shadowOf(getMainLooper()).idle()
insertSomeTextInContent(additionalContent + url)
@ -283,7 +308,20 @@ class ComposeActivityTest {
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)) }
instanceResponseCallback = { getInstanceWithCustomConfiguration(null, customUrlLength) }
setupActivity()
shadowOf(getMainLooper()).idle()
insertSomeTextInContent(shortUrl + additionalContent + url)
assertEquals(activity.calculateTextLength(), additionalContent.length + (customUrlLength * 2))
}
@Test
fun whenTextContainsShortUrls_allUrlsGetEllipsized_withCustomConfigurationV1() {
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
instanceV1ResponseCallback = { getInstanceV1WithCustomConfiguration(configuration = getCustomInstanceConfiguration(charactersReservedPerUrl = customUrlLength)) }
setupActivity()
shadowOf(getMainLooper()).idle()
insertSomeTextInContent(shortUrl + additionalContent + url)
@ -295,7 +333,19 @@ class ComposeActivityTest {
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)) }
instanceResponseCallback = { getInstanceWithCustomConfiguration(null, customUrlLength) }
setupActivity()
shadowOf(getMainLooper()).idle()
insertSomeTextInContent(url + additionalContent + url)
assertEquals(activity.calculateTextLength(), additionalContent.length + (customUrlLength * 2))
}
@Test
fun whenTextContainsMultipleURLs_allURLsGetEllipsized_withCustomConfigurationV1() {
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
instanceV1ResponseCallback = { getInstanceV1WithCustomConfiguration(configuration = getCustomInstanceConfiguration(charactersReservedPerUrl = customUrlLength)) }
setupActivity()
shadowOf(getMainLooper()).idle()
insertSomeTextInContent(url + additionalContent + url)
@ -491,8 +541,33 @@ class ComposeActivityTest {
activity.findViewById<EditText>(R.id.composeEditField).setText(text ?: "Some text")
}
private fun getInstanceWithCustomConfiguration(maximumLegacyTootCharacters: Int? = null, configuration: InstanceConfiguration? = null): Instance {
private fun getInstanceWithCustomConfiguration(maximumStatusCharacters: Int? = null, charactersReservedPerUrl: Int? = null): Instance {
return Instance(
domain = "https://example.token",
version = "2.6.3",
configuration = getConfiguration(maximumStatusCharacters, charactersReservedPerUrl),
pleroma = null,
rules = emptyList()
)
}
private fun getConfiguration(maximumStatusCharacters: Int?, charactersReservedPerUrl: Int?): Instance.Configuration {
return Instance.Configuration(
Instance.Configuration.Urls(streamingApi = ""),
Instance.Configuration.Accounts(1),
Instance.Configuration.Statuses(
maximumStatusCharacters ?: InstanceInfoRepository.DEFAULT_CHARACTER_LIMIT,
InstanceInfoRepository.DEFAULT_MAX_MEDIA_ATTACHMENTS,
charactersReservedPerUrl ?: InstanceInfoRepository.DEFAULT_CHARACTERS_RESERVED_PER_URL
),
Instance.Configuration.MediaAttachments(emptyList(), 0, 0, 0, 0, 0),
Instance.Configuration.Polls(0, 0, 0, 0),
Instance.Configuration.Translation(false),
)
}
private fun getInstanceV1WithCustomConfiguration(maximumLegacyTootCharacters: Int? = null, configuration: InstanceConfiguration? = null): InstanceV1 {
return InstanceV1(
uri = "https://example.token",
version = "2.6.3",
maxTootChars = maximumLegacyTootCharacters,