Skip to content

Commit

Permalink
Added unit tests for easy-to-test utils (#629)
Browse files Browse the repository at this point in the history
* Added unit tests for easy-to-test utils

Also includes some small changes, fixes, and comments here and there.

* Enable unit tests in CI

Also ignore the example unit tests.
  • Loading branch information
beatgammit authored Jun 15, 2023
1 parent 0d08add commit 241c384
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .woodpecker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ pipeline:
commands:
- prettier -c "*.md" "*.yml"

run_tests:
image: cimg/android:2023.05
commands:
- sudo chown -R circleci:circleci .
- ./gradlew testDebug

build_project:
image: cimg/android:2023.05
commands:
Expand Down
22 changes: 14 additions & 8 deletions app/src/main/java/com/jerboa/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import android.os.Build.VERSION.SDK_INT
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import android.util.Patterns
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.foundation.ExperimentalFoundationApi
Expand Down Expand Up @@ -46,6 +45,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.lerp
import androidx.core.util.PatternsCompat
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.jerboa.api.API
Expand Down Expand Up @@ -126,8 +126,7 @@ enum class VoteType {
fun calculateNewInstantScores(instantScores: InstantScores, voteType: VoteType): InstantScores {
val newVote = newVote(
currentVote = instantScores.myVote,
voteType =
voteType,
voteType = voteType,
)
val score = newScore(
instantScores.score,
Expand All @@ -136,8 +135,7 @@ fun calculateNewInstantScores(instantScores: InstantScores, voteType: VoteType):
)
val votes = newVoteCount(
Pair(instantScores.upvotes, instantScores.downvotes),
instantScores
.myVote,
instantScores.myVote,
voteType,
)

Expand All @@ -149,6 +147,9 @@ fun calculateNewInstantScores(instantScores: InstantScores, voteType: VoteType):
)
}

/*
* User changed their vote, so calculate score difference given this user's new vote.
*/
fun newVote(currentVote: Int?, voteType: VoteType): Int {
return if (voteType == VoteType.Upvote) {
if (currentVote == 1) {
Expand All @@ -165,6 +166,9 @@ fun newVote(currentVote: Int?, voteType: VoteType): Int {
}
}

/*
* Calculate the new score after the user votes.
*/
fun newScore(currentScore: Int, currentVote: Int?, voteType: VoteType): Int {
return if (voteType == VoteType.Upvote) {
when (currentVote) {
Expand Down Expand Up @@ -421,9 +425,11 @@ fun pictrsImageThumbnail(src: String, thumbnailSize: Int): String {
}

val host = split[0]
val path = split[1]
// eliminate the query param portion of the path so we can replace it later
// without this, we'd end up with something like host/path?thumbnail=...?thumbnail=...
val path = split[1].replaceAfter('?', "")

return "$host/pictrs/image/$path?thumbnail=$thumbnailSize&format=webp"
return "$host/pictrs/image/${path}thumbnail=$thumbnailSize&format=webp"
}

fun isImage(url: String): Boolean {
Expand Down Expand Up @@ -647,7 +653,7 @@ fun validatePostName(
fun validateUrl(
url: String,
): InputField {
return if (url.isNotEmpty() && !Patterns.WEB_URL.matcher(url).matches()) {
return if (url.isNotEmpty() && !PatternsCompat.WEB_URL.matcher(url).matches()) {
InputField(
label = "Invalid Url",
hasError = true,
Expand Down
3 changes: 2 additions & 1 deletion app/src/test/java/com/jerboa/ExampleUnitTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import com.jerboa.datatypes.api.GetSite
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Ignore
import org.junit.Test

/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@Ignore
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
Expand Down Expand Up @@ -58,7 +60,6 @@ class ExampleUnitTest {
auth = null,
)
val out = api.getPost(form.serializeToMap()).body()!!
println(out.comments)
assertNotNull(out)
}

Expand Down
139 changes: 139 additions & 0 deletions app/src/test/java/com/jerboa/UtilsKtTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.jerboa

import androidx.compose.ui.unit.dp
import com.jerboa.datatypes.api.GetUnreadCountResponse
import com.jerboa.ui.theme.SMALL_PADDING
import org.junit.Assert.*
import org.junit.Test

class UtilsKtTest {
@Test
fun testCalculateCommentOffset() {
assertEquals(0.dp, calculateCommentOffset(0, 0))
assertEquals(3.dp + SMALL_PADDING, calculateCommentOffset(2, 3))
assertEquals(6.dp + SMALL_PADDING, calculateCommentOffset(-1, 3))
}

@Test
fun testNewVote() {
assertEquals(1, newVote(null, VoteType.Upvote))
assertEquals(1, newVote(0, VoteType.Upvote))
assertEquals(0, newVote(1, VoteType.Upvote))

assertEquals(-1, newVote(null, VoteType.Downvote))
assertEquals(-1, newVote(0, VoteType.Downvote))
assertEquals(0, newVote(-1, VoteType.Downvote))
}

@Test
fun testNewScore() {
assertEquals(4, newScore(3, null, VoteType.Upvote))
assertEquals(2, newScore(3, 1, VoteType.Upvote))
assertEquals(5, newScore(3, -1, VoteType.Upvote))

assertEquals(2, newScore(3, null, VoteType.Downvote))
assertEquals(1, newScore(3, 1, VoteType.Downvote))
assertEquals(4, newScore(3, -1, VoteType.Downvote))
}

@Test
fun testNewVoteCount() {
assertEquals(Pair(3, 3), newVoteCount(Pair(2, 3), null, VoteType.Upvote))
assertEquals(Pair(3, 2), newVoteCount(Pair(2, 3), -1, VoteType.Upvote))
assertEquals(Pair(3, 3), newVoteCount(Pair(2, 3), 0, VoteType.Upvote))
assertEquals(Pair(1, 3), newVoteCount(Pair(2, 3), 1, VoteType.Upvote))

assertEquals(Pair(2, 4), newVoteCount(Pair(2, 3), null, VoteType.Downvote))
assertEquals(Pair(2, 2), newVoteCount(Pair(2, 3), -1, VoteType.Downvote))
assertEquals(Pair(2, 4), newVoteCount(Pair(2, 3), 0, VoteType.Downvote))
assertEquals(Pair(1, 4), newVoteCount(Pair(2, 3), 1, VoteType.Downvote))
}

@Test
fun testCalculateNewInstantScores() {
assertEquals(
InstantScores(1, 1, 1, 0),
calculateNewInstantScores(InstantScores(null, 0, 0, 0), VoteType.Upvote),
)
assertEquals(
InstantScores(0, 0, 0, 0),
calculateNewInstantScores(InstantScores(1, 1, 1, 0), VoteType.Upvote),
)
}

@Test
fun testHostName() {
assertEquals("test.ml", hostName("https://test.ml/unnecessary/path"))
assertEquals(null, hostName("invalid"))
}

@Test
fun testUnreadOrAll() {
assertEquals(UnreadOrAll.Unread, unreadOrAllFromBool(true))
assertEquals(UnreadOrAll.All, unreadOrAllFromBool(false))
}

@Test
fun testValidatePostName() {
assertTrue(validatePostName("").hasError)
assertTrue(validatePostName("a").hasError)
assertTrue(validatePostName("a".repeat(MAX_POST_TITLE_LENGTH)).hasError)

assertFalse(validatePostName("totally fine").hasError)
assertFalse(validatePostName("a".repeat(MAX_POST_TITLE_LENGTH - 1)).hasError)
}

@Test
fun testValidateUrl() {
assertTrue(validateUrl("nonsense").hasError)

assertFalse(validateUrl("").hasError)
assertFalse(validateUrl("https://example.com").hasError)
}

@Test
fun testSerializeToMap() {
val dataClass = InputField(label = "some label", hasError = true)
val exp = mapOf("hasError" to dataClass.hasError.toString(), "label" to dataClass.label)
val converted = dataClass.serializeToMap()

exp.keys.forEach {
assertTrue(converted.containsKey(it))
assertEquals(exp[it], converted[it])
}
}

@Test
fun testIsImage() {
assertTrue(isImage("http://example.com/test.jpg"))
assertFalse(isImage("test.jpg"))
assertFalse(isImage("http://example.com/test.csv"))
}

@Test
fun testPictrsImageThumbnail() {
assertEquals("invalid", pictrsImageThumbnail("invalid", 3))
assertEquals(
"http://localhost:8535/pictrs/image/file.png?thumbnail=3&format=webp",
pictrsImageThumbnail(
"http://localhost:8535/pictrs/image/file.png?thumbnail=256&format=jpg",
3,
),
)
}

@Test
fun testUnreadCountTotal() {
assertEquals(6, unreadCountTotal(GetUnreadCountResponse(1, 2, 3)))
}

@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))
}
}

0 comments on commit 241c384

Please sign in to comment.