diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 0cbe6db7d..e3266ea0a 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -176,6 +176,9 @@ dependencies {
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+ testImplementation("org.mockito:mockito-core:5.4.0")
+ testImplementation("org.mockito.kotlin:mockito-kotlin:5.0.0")
+
implementation("androidx.browser:browser:1.5.0")
implementation("androidx.profileinstaller:profileinstaller:1.3.1")
diff --git a/app/src/main/java/com/jerboa/Utils.kt b/app/src/main/java/com/jerboa/Utils.kt
index 03a70e8cf..952c9fb46 100644
--- a/app/src/main/java/com/jerboa/Utils.kt
+++ b/app/src/main/java/com/jerboa/Utils.kt
@@ -691,42 +691,44 @@ data class InputField(
)
fun validatePostName(
+ ctx: Context,
name: String,
): InputField {
return if (name.isEmpty()) {
InputField(
- label = "Title required",
+ label = ctx.getString(R.string.title_required),
hasError = true,
)
} else if (name.length < 3) {
InputField(
- label = "Title must be > 3 chars",
+ label = ctx.getString(R.string.title_min_3_chars),
hasError = true,
)
} else if (name.length >= MAX_POST_TITLE_LENGTH) {
InputField(
- label = "Title cannot be > 200 chars",
+ label = ctx.getString(R.string.title_less_than_200_chars),
hasError = true,
)
} else {
InputField(
- label = "Title",
+ label = ctx.getString(R.string.title),
hasError = false,
)
}
}
fun validateUrl(
+ ctx: Context,
url: String,
): InputField {
return if (url.isNotEmpty() && !PatternsCompat.WEB_URL.matcher(url).matches()) {
InputField(
- label = "Invalid Url",
+ label = ctx.getString(R.string.url_invalid),
hasError = true,
)
} else {
InputField(
- label = "Url",
+ label = ctx.getString(R.string.url),
hasError = false,
)
}
diff --git a/app/src/main/java/com/jerboa/ui/components/post/create/CreatePostActivity.kt b/app/src/main/java/com/jerboa/ui/components/post/create/CreatePostActivity.kt
index 5b44468e5..ab5f5d839 100644
--- a/app/src/main/java/com/jerboa/ui/components/post/create/CreatePostActivity.kt
+++ b/app/src/main/java/com/jerboa/ui/components/post/create/CreatePostActivity.kt
@@ -84,8 +84,8 @@ fun CreatePostActivity(
}
var isUploadingImage by rememberSaveable { mutableStateOf(false) }
- val nameField = validatePostName(name)
- val urlField = validateUrl(url)
+ val nameField = validatePostName(ctx, name)
+ val urlField = validateUrl(ctx, url)
val formValid = !nameField.hasError && !urlField.hasError && (selectedCommunity !== null)
LaunchedEffect(initialUrl) {
diff --git a/app/src/main/java/com/jerboa/ui/components/post/edit/PostEditActivity.kt b/app/src/main/java/com/jerboa/ui/components/post/edit/PostEditActivity.kt
index 7e82f5cb3..0f9506546 100644
--- a/app/src/main/java/com/jerboa/ui/components/post/edit/PostEditActivity.kt
+++ b/app/src/main/java/com/jerboa/ui/components/post/edit/PostEditActivity.kt
@@ -68,8 +68,8 @@ fun PostEditActivity(
}
var isUploadingImage by rememberSaveable { mutableStateOf(false) }
- val nameField = validatePostName(name)
- val urlField = validateUrl(url)
+ val nameField = validatePostName(ctx, name)
+ val urlField = validateUrl(ctx, url)
val formValid = !nameField.hasError && !urlField.hasError
Scaffold(
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index abab2ff5b..b7919a857 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -303,7 +303,13 @@
TopWeek
TopYear
%1$s %2$s ago
+ Title
+ Title cannot be more than 200 characters
+ Title must be at least three characters
+ Title required
Back
+ URL
+ Invalid URL
Login first
Upvote
Downvote
diff --git a/app/src/test/java/com/jerboa/UtilsKtTest.kt b/app/src/test/java/com/jerboa/UtilsKtTest.kt
index e4d7304cc..34a4ffb33 100644
--- a/app/src/test/java/com/jerboa/UtilsKtTest.kt
+++ b/app/src/test/java/com/jerboa/UtilsKtTest.kt
@@ -1,12 +1,20 @@
package com.jerboa
+import android.content.Context
import androidx.compose.ui.unit.dp
import com.jerboa.api.API
import com.jerboa.ui.theme.SMALL_PADDING
import junitparams.JUnitParamsRunner
+import junitparams.Parameters
import org.junit.Assert.*
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
import org.ocpsoft.prettytime.PrettyTime
import java.time.Duration
import java.time.Instant
@@ -15,6 +23,11 @@ import java.util.Locale
@RunWith(JUnitParamsRunner::class)
class UtilsKtTest {
+
+ @JvmField
+ @Rule
+ val rule: MockitoRule = MockitoJUnit.rule()
+
@Test
fun testCalculateCommentOffset() {
assertEquals(0.dp, calculateCommentOffset(0, 0))
@@ -83,20 +96,31 @@ class UtilsKtTest {
@Test
fun testValidatePostName() {
- assertTrue(validatePostName("").hasError)
- assertTrue(validatePostName("a").hasError)
- assertTrue(validatePostName("a".repeat(MAX_POST_TITLE_LENGTH)).hasError)
+ val ctx = mock {
+ on { getString(anyInt()) } doReturn ""
+ }
+
+ assertTrue(validatePostName(ctx, "").hasError)
+ assertTrue(validatePostName(ctx, "a").hasError)
+ assertTrue(validatePostName(ctx, "a".repeat(MAX_POST_TITLE_LENGTH)).hasError)
- assertFalse(validatePostName("totally fine").hasError)
- assertFalse(validatePostName("a".repeat(MAX_POST_TITLE_LENGTH - 1)).hasError)
+ assertFalse(validatePostName(ctx, "totally fine").hasError)
+ assertFalse(validatePostName(ctx, "a".repeat(MAX_POST_TITLE_LENGTH - 1)).hasError)
}
@Test
fun testValidateUrl() {
- assertTrue(validateUrl("nonsense").hasError)
+ val ctx = mock {
+ on { getString(R.string.url) } doReturn "url"
+ on { getString(R.string.url_invalid) } doReturn "url_invalid"
+ }
+
+ assertTrue(validateUrl(ctx, "nonsense").hasError)
+ assertSame("url_invalid", validateUrl(ctx, "nonsense").label)
- assertFalse(validateUrl("").hasError)
- assertFalse(validateUrl("https://example.com").hasError)
+ assertFalse(validateUrl(ctx, "").hasError)
+ assertFalse(validateUrl(ctx, "https://example.com").hasError)
+ assertSame("url", validateUrl(ctx, "https://example.com").label)
}
@Test
@@ -154,15 +178,20 @@ class UtilsKtTest {
}
@Test
- fun testSiFormat() {
- assertEquals("0", siFormat(0))
- assertEquals("1K", siFormat(1000))
- assertEquals("1.1K", siFormat(1100))
- assertEquals("1M", siFormat(1000000))
- assertEquals("1.2M", siFormat(1234500))
- assertEquals("12M", siFormat(12345000))
+ @Parameters(method = "siFormatCases")
+ fun testSiFormat(expected: String, input: Int) {
+ assertEquals(expected, siFormat(input))
}
+ fun siFormatCases() = listOf(
+ listOf("0", 0),
+ listOf("1K", 1000),
+ listOf("1.1K", 1100),
+ listOf("1M", 1000000),
+ listOf("1.2M", 1234500),
+ listOf("12M", 12345000),
+ )
+
@Test
fun testParseUrl() {
val cases = mapOf(