fix(android): AVTransport test assertions escape DIDL; consolidate xmlEscape
android / Build + lint + test (push) Failing after 1m18s
android / Build + lint + test (push) Failing after 1m18s
DIDL assertion now checks for XML-escaped form (<dc:title>) since SoapClient.buildEnvelope escapes all arg values. Lifts xmlEscape to a top-level internal fun in SoapClient.kt, removing the duplicate private copy from AVTransportClient. Fixes @Suppress rationale (not Compose). Renames seek test to reflect colon-separated format; adds unknown-state getTransportInfo test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+2
-8
@@ -7,7 +7,8 @@ import okhttp3.HttpUrl
|
||||
* Covers SetAVTransportURI / SetNextAVTransportURI / Play / Pause /
|
||||
* Stop / Seek / GetPositionInfo / GetTransportInfo.
|
||||
*/
|
||||
@Suppress("TooManyFunctions") // Compose-adjacent helper density: all are direct SOAP verbs.
|
||||
// One method per AVTransport SOAP verb; splitting would obscure the 1:1 protocol mapping.
|
||||
@Suppress("TooManyFunctions")
|
||||
class AVTransportClient(
|
||||
private val soap: SoapClient,
|
||||
private val controlUrl: HttpUrl,
|
||||
@@ -151,13 +152,6 @@ class AVTransportClient(
|
||||
}
|
||||
}
|
||||
|
||||
private fun xmlEscape(v: String): String = v
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace("\"", """)
|
||||
.replace("'", "'")
|
||||
|
||||
private fun formatHhMmSs(positionMs: Long): String {
|
||||
val totalSec = (positionMs / MILLIS_PER_SECOND).coerceAtLeast(0)
|
||||
val h = totalSec / SECONDS_PER_HOUR
|
||||
|
||||
@@ -69,13 +69,6 @@ class SoapClient(
|
||||
append("</s:Envelope>")
|
||||
}
|
||||
|
||||
private fun xmlEscape(v: String): String = v
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace("\"", """)
|
||||
.replace("'", "'")
|
||||
|
||||
private fun parseResponseArgs(body: String, action: String): Map<String, String> {
|
||||
val parser = XmlPullParserFactory.newInstance().newPullParser().apply {
|
||||
setInput(body.reader())
|
||||
@@ -138,3 +131,11 @@ class SoapClient(
|
||||
*/
|
||||
class SoapFaultException(val code: String, val description: String) :
|
||||
Exception("SOAP fault $code: $description")
|
||||
|
||||
/** XML-escapes a string value for embedding as text content inside a SOAP envelope. */
|
||||
internal fun xmlEscape(v: String): String = v
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace("\"", """)
|
||||
.replace("'", "'")
|
||||
|
||||
+24
-3
@@ -29,7 +29,7 @@ class AVTransportClientTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `seek formats position as hh-mm-ss`() = runTest {
|
||||
fun `seek sends Target in HH MM SS format`() = runTest {
|
||||
server.enqueue(emptyResponse("Seek"))
|
||||
client.seek(positionMs = 65_000L)
|
||||
val body = server.takeRequest().body.readUtf8()
|
||||
@@ -81,6 +81,27 @@ class AVTransportClientTest {
|
||||
assertEquals(TransportState.PAUSED, info.state)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTransportInfo maps unknown state to UNKNOWN`() = runTest {
|
||||
server.enqueue(
|
||||
MockResponse().setBody(
|
||||
"""<?xml version="1.0"?>
|
||||
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<s:Body>
|
||||
<u:GetTransportInfoResponse
|
||||
xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
|
||||
<CurrentTransportState>BUFFERING_PLAYBACK</CurrentTransportState>
|
||||
<CurrentTransportStatus>OK</CurrentTransportStatus>
|
||||
<CurrentSpeed>1</CurrentSpeed>
|
||||
</u:GetTransportInfoResponse>
|
||||
</s:Body>
|
||||
</s:Envelope>""".trimIndent(),
|
||||
),
|
||||
)
|
||||
val info = client.getTransportInfo()
|
||||
assertEquals(TransportState.UNKNOWN, info.state)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setNextAVTransportURI sends DIDL-Lite with mime and title`() = runTest {
|
||||
server.enqueue(emptyResponse("SetNextAVTransportURI"))
|
||||
@@ -93,8 +114,8 @@ class AVTransportClientTest {
|
||||
assertTrue(body.contains("<NextURI>http://x/y.mp3</NextURI>")) {
|
||||
"body missing NextURI: $body"
|
||||
}
|
||||
assertTrue(body.contains("<dc:title>Song</dc:title>")) {
|
||||
"body missing dc:title: $body"
|
||||
assertTrue(body.contains("<dc:title>Song</dc:title>")) {
|
||||
"title missing: $body"
|
||||
}
|
||||
assertTrue(body.contains("audio/mpeg")) {
|
||||
"body missing mime type: $body"
|
||||
|
||||
Reference in New Issue
Block a user