Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 8f96097f authored by Ricki Hirner's avatar Ricki Hirner Committed by GitHub
Browse files

Fix TODO and add some tests for ResponseParser (#146)

- Move callback to parseResponse method in ResponseParser
- Update MultiStatusParser to use new ResponseParser signature
- Add comprehensive tests for ResponseParser
parent 391ca3d7
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ class MultiStatusParser(

    suspend fun parseResponse(parser: XmlPullParser): List<Property> {
        val responseProperties = mutableListOf<Property>()
        val responseParser = ResponseParser(location, callback)
        val responseParser = ResponseParser(location)

        // <!ELEMENT multistatus (response*, responsedescription?,
        //                        sync-token?) >
@@ -40,7 +40,7 @@ class MultiStatusParser(
            if (eventType == XmlPullParser.START_TAG && parser.depth == depth + 1)
                when (parser.propertyName()) {
                    WebDAV.Response ->
                        responseParser.parseResponse(parser)
                        responseParser.parseResponse(parser, callback)
                    WebDAV.SyncToken ->
                        XmlReader(parser).readText()?.let {
                            responseProperties += SyncToken(it)
+6 −6
Original line number Diff line number Diff line
@@ -32,8 +32,7 @@ import java.util.logging.Logger
 * @param location  location of the request (used to resolve possible relative `<href>`)
 */
class ResponseParser(
    private val location: Url,
    private val callback: MultiResponseCallback
    private val location: Url
) {

    private val logger
@@ -49,8 +48,11 @@ class ResponseParser(
     *
     * So if you want PROPFIND results to have a trailing slash when they are collections, make sure
     * that you query [at.bitfire.dav4jvm.property.webdav.ResourceType].
     *
     * @param parser    XML document to parse
     * @param callback  callback to be called for every multistatus `<response>`
     */
    suspend fun parseResponse(parser: XmlPullParser) {
    suspend fun parseResponse(parser: XmlPullParser, callback: MultiResponseCallback) {
        val depth = parser.depth

        var hrefOrNull: Url? = null
@@ -72,7 +74,7 @@ class ResponseParser(
                    WebDAV.Error ->
                        error = Error.parseError(parser)
                    WebDAV.Location ->
                        newLocation = Url(parser.nextText())    // TODO: Need to catch exception here?
                        newLocation = parser.nextText().toUrlOrNull()
                }
            eventType = parser.next()
        }
@@ -94,8 +96,6 @@ class ResponseParser(
                    href = UrlUtils.withTrailingSlash(href)
            }

        //log.log(Level.FINE, "Received properties for $href", if (status != null) status else propStat)

        // Which resource does this <response> represent?
        val relation = when {
            UrlUtils.omitTrailingSlash(href).equalsForWebDAV(UrlUtils.omitTrailingSlash(location)) ->
+103 −10
Original line number Diff line number Diff line
@@ -10,37 +10,130 @@

package at.bitfire.dav4jvm.ktor

import at.bitfire.dav4jvm.XmlUtils
import io.ktor.http.Url
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Test
import java.io.StringReader

class ResponseParserTest {

    val baseUrl = Url("https://example.com/collection/")
    val parser = ResponseParser(baseUrl, callback = { _, _ ->
        // no-op
    })
    private val baseUrl = Url("http://www.example.com/container/")
    private val parser = ResponseParser(baseUrl)


    @Test
    fun `parseResponse relation=SELF`() = runTest {
        val xml = XmlUtils.newPullParser()
        xml.setInput(StringReader("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
                "<multistatus xmlns=\"DAV:\">\n" +
                "<response>\n" +
                "  <href>http://www.example.com/container/</href>\n" +
                "  <propstat>\n" +
                "    <prop xmlns:R=\"http://ns.example.com/boxschema/\">\n" +
                "      <R:bigbox/>\n" +
                "      <R:author/>\n" +
                "      <creationdate/>\n" +
                "      <displayname/>\n" +
                "      <resourcetype/>\n" +
                "      <supportedlock/>\n" +
                "    </prop>\n" +
                "    <status>HTTP/1.1 200 OK</status>\n" +
                "  </propstat>\n" +
                "</response>"
        ))
        xml.nextTag()   // multistatus
        xml.nextTag()   // response
        parser.parseResponse(xml) { response, relation ->
            assertEquals(Url("http://www.example.com/container/"), response.href)
            assertEquals(Response.HrefRelation.SELF, relation)
        }
    }

    @Test
    fun `parseResponse relation=MEMBER`() = runTest {
        val xml = XmlUtils.newPullParser()
        xml.setInput(StringReader("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
                "<multistatus xmlns=\"DAV:\">\n" +
                "<response>\n" +
                "  <href>http://www.example.com/container/front.html</href>\n" +
                "  <propstat>\n" +
                "    <prop xmlns:R=\"http://ns.example.com/boxschema/\">\n" +
                "      <R:bigbox/>\n" +
                "      <creationdate/>\n" +
                "      <displayname/>\n" +
                "      <getcontentlength/>\n" +
                "      <getcontenttype/>\n" +
                "      <getetag/>\n" +
                "      <getlastmodified/>\n" +
                "      <resourcetype/>\n" +
                "      <supportedlock/>\n" +
                "    </prop>\n" +
                "    <status>HTTP/1.1 200 OK</status>\n" +
                "  </propstat>\n" +
                "</response>"
        ))
        xml.nextTag()   // multistatus
        xml.nextTag()   // response
        parser.parseResponse(xml) { response, relation ->
            assertEquals(Url("http://www.example.com/container/front.html"), response.href)
            assertEquals(Response.HrefRelation.MEMBER, relation)
        }
    }

    @Test
    fun `parseResponse relation=OTHER`() = runTest {
        val xml = XmlUtils.newPullParser()
        xml.setInput(StringReader("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
                "<multistatus xmlns=\"DAV:\">\n" +
                "<response>\n" +
                "  <href>http://other.example.com/was-not-requested</href>\n" +
                "  <propstat>\n" +
                "    <prop xmlns:R=\"http://ns.example.com/boxschema/\">\n" +
                "      <R:bigbox/>\n" +
                "      <creationdate/>\n" +
                "      <displayname/>\n" +
                "      <getcontentlength/>\n" +
                "      <getcontenttype/>\n" +
                "      <getetag/>\n" +
                "      <getlastmodified/>\n" +
                "      <resourcetype/>\n" +
                "      <supportedlock/>\n" +
                "    </prop>\n" +
                "    <status>HTTP/1.1 200 OK</status>\n" +
                "  </propstat>\n" +
                "</response>"
        ))
        xml.nextTag()   // multistatus
        xml.nextTag()   // response
        parser.parseResponse(xml) { response, relation ->
            assertEquals(Url("http://other.example.com/was-not-requested"), response.href)
            assertEquals(Response.HrefRelation.OTHER, relation)
        }
    }


    @Test
    fun `resolveHref with absolute URL`() {
        assertEquals(
            Url("https://example.com/collection/member"),
            parser.resolveHref("https://example.com/collection/member")
            Url("http://www.example.com/container/member"),
            parser.resolveHref("http://www.example.com/container/member")
        )
    }

    @Test
    fun `resolveHref with absolute path`() {
        assertEquals(
            Url("https://example.com/collection/member"),
            parser.resolveHref("/collection/member")
            Url("http://www.example.com/container/member"),
            parser.resolveHref("/container/member")
        )
    }

    @Test
    fun `resolveHref with relative path`() {
        assertEquals(
            Url("https://example.com/collection/member"),
            Url("http://www.example.com/container/member"),
            parser.resolveHref("member")
        )
    }
@@ -48,7 +141,7 @@ class ResponseParserTest {
    @Test
    fun `resolveHref with relative path with colon`() {
        assertEquals(
            Url("https://example.com/collection/mem:ber"),
            Url("http://www.example.com/container/mem:ber"),
            parser.resolveHref("mem:ber")
        )
    }