fix: ipv6/ipv4 баги

This commit is contained in:
xtclovver 2026-04-18 02:36:13 +03:00
parent f1db21809e
commit b1ddb1183e
8 changed files with 308 additions and 5 deletions

View file

@ -0,0 +1,136 @@
package com.notcvnt.rknhardering
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.test.core.app.ApplicationProvider
import com.google.android.material.card.MaterialCardView
import com.notcvnt.rknhardering.model.CategoryResult
import com.notcvnt.rknhardering.model.CdnPullingResponse
import com.notcvnt.rknhardering.model.Finding
import com.notcvnt.rknhardering.model.IpCheckerGroupResult
import com.notcvnt.rknhardering.model.IpCheckerResponse
import com.notcvnt.rknhardering.model.IpCheckerScope
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class MainActivityUiRenderingTest {
@Test
fun `ip comparison response view hides raw error details`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).setup().get()
val response = IpCheckerResponse(
label = "ip.sb IPv6",
url = "https://api-ipv6.ip.sb/ip",
scope = IpCheckerScope.NON_RU,
error = "OkHttp failed after 3 attempts: Could not connect to server",
)
val view = invokePrivate<View>(activity, "createIpCheckerResponseView", response, false)
val text = collectText(view)
assertTrueContains(text, "ip.sb IPv6")
assertTrueContains(text, "https://api-ipv6.ip.sb/ip")
assertTrueContains(text, activity.getString(R.string.main_card_status_error))
assertFalse(text.contains("OkHttp failed after 3 attempts"))
assertFalse(text.contains("Could not connect to server"))
}
@Test
fun `ip comparison response view hides ignored ipv6 diagnostics`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).setup().get()
val response = IpCheckerResponse(
label = "ip.sb IPv6",
url = "https://api-ipv6.ip.sb/ip",
scope = IpCheckerScope.NON_RU,
error = "native curl failed",
ignoredIpv6Error = true,
)
val view = invokePrivate<View>(activity, "createIpCheckerResponseView", response, false)
val text = collectText(view)
assertFalse(text.contains(activity.getString(R.string.main_ipv6_error_ignored).trim()))
assertFalse(text.contains("native curl failed"))
}
@Test
fun `cdn pulling response view hides raw error details`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).setup().get()
val response = CdnPullingResponse(
targetLabel = "meduza.io",
url = "https://meduza.io",
error = "SSLHandshakeException: certificate path validation failed",
)
val view = invokePrivate<View>(activity, "createCdnPullingResponseView", response, false)
val text = collectText(view)
assertTrueContains(text, "meduza.io")
assertTrueContains(text, "https://meduza.io")
assertTrueContains(text, activity.getString(R.string.main_card_status_error))
assertFalse(text.contains("SSLHandshakeException"))
assertFalse(text.contains("certificate path validation failed"))
}
@Test
fun `display category keeps error status and hides error finding text`() {
val activity = Robolectric.buildActivity(MainActivity::class.java).setup().get()
val category = CategoryResult(
name = "direct",
detected = false,
findings = listOf(Finding("Socket timeout to 203.0.113.64", isError = true)),
)
val card = activity.findViewById<MaterialCardView>(R.id.cardIndirect)
val icon = activity.findViewById<ImageView>(R.id.iconIndirect)
val status = activity.findViewById<TextView>(R.id.statusIndirect)
val findings = activity.findViewById<LinearLayout>(R.id.findingsIndirect)
invokePrivate<Unit>(
activity,
"displayCategory",
category,
card,
icon,
status,
findings,
false,
)
assertEquals(activity.getString(R.string.main_card_status_error), status.text.toString())
assertFalse(collectText(findings).contains("Socket timeout to 203.0.113.64"))
}
private fun collectText(view: View): String {
if (view is TextView) return view.text.toString()
if (view !is ViewGroup) return ""
return buildString {
for (index in 0 until view.childCount) {
val childText = collectText(view.getChildAt(index))
if (childText.isBlank()) continue
if (isNotBlank()) append('\n')
append(childText)
}
}
}
private fun assertTrueContains(text: String, expected: String) {
assertFalse("Expected text to contain <$expected>, got <$text>", !text.contains(expected))
}
@Suppress("UNCHECKED_CAST")
private fun <T> invokePrivate(target: Any, name: String, vararg args: Any?): T {
val method = target::class.java.declaredMethods.first { candidate ->
candidate.name == name && candidate.parameterTypes.size == args.size
}
method.isAccessible = true
return method.invoke(target, *args) as T
}
}