Skip to content

Commit b717023

Browse files
authored
Merge pull request #6645 from seadowg/main-instance
Fix metadata parsing for main instances with attributes
2 parents bc56a55 + 57517c4 commit b717023

File tree

8 files changed

+93
-29
lines changed

8 files changed

+93
-29
lines changed

collect_app/src/main/java/org/odk/collect/android/formmanagement/download/FormDownloadException.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import org.odk.collect.forms.FormSourceException
55
sealed class FormDownloadException : Exception() {
66
class DownloadingInterrupted : FormDownloadException()
77
class FormWithNoHash : FormDownloadException()
8-
class FormParsingError : FormDownloadException()
8+
class FormParsingError(val original: Exception) : FormDownloadException()
99
class DiskError : FormDownloadException()
1010
class InvalidSubmission : FormDownloadException()
1111
class FormSourceError(val exception: FormSourceException) : FormDownloadException()

collect_app/src/main/java/org/odk/collect/android/formmanagement/download/FormDownloadExceptionMapper.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@ class FormDownloadExceptionMapper(private val context: Context) {
1515
)
1616
}
1717
is FormDownloadException.FormParsingError -> {
18-
context.getLocalizedString(
19-
org.odk.collect.strings.R.string.form_parsing_error
20-
) + " " + context.getLocalizedString(
21-
org.odk.collect.strings.R.string.report_to_project_lead
22-
)
18+
context.getLocalizedString(org.odk.collect.strings.R.string.form_parsing_error) +
19+
"\n\n${exception.original.getStackTraceString(1)}\n\n" +
20+
context.getLocalizedString(org.odk.collect.strings.R.string.report_to_project_lead)
2321
}
2422
is FormDownloadException.DiskError -> {
2523
context.getLocalizedString(
@@ -43,4 +41,9 @@ class FormDownloadExceptionMapper(private val context: Context) {
4341
}
4442
}
4543
}
44+
45+
private fun Exception.getStackTraceString(lines: Int): String {
46+
val stackTrace = this.stackTrace
47+
return "${this.message}\n${stackTrace.take(lines).joinToString("\n") { it.toString() }}"
48+
}
4649
}

collect_app/src/main/java/org/odk/collect/android/formmanagement/download/ServerFormDownloader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ private void processOneForm(ServerFormDetails fd, OngoingWorkListener stateListe
128128

129129
Timber.i("Parse finished in %.3f seconds.", (System.currentTimeMillis() - start) / 1000F);
130130
} catch (RuntimeException e) {
131-
throw new FormDownloadException.FormParsingError();
131+
throw new FormDownloadException.FormParsingError(e);
132132
}
133133
}
134134

collect_app/src/main/java/org/odk/collect/android/formmanagement/metadata/FormMetadataParser.kt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,10 @@ object FormMetadataParser {
1919
val body = doc.getRootElement().getElement(null, "body")
2020
val title = head.getElement(null, "title").getChild(0).toString()
2121

22-
lateinit var mainInstanceRoot: Element
23-
var submission: Element? = null
24-
for (i in 0 until model.childCount) {
25-
val child = model.getElement(i) ?: continue
26-
27-
if (child.name == "instance" && child.attributeCount == 0) {
28-
for (j in 0 until child.childCount) {
29-
val mainInstanceChild = child.getElement(j) ?: continue
30-
mainInstanceRoot = mainInstanceChild
31-
break
32-
}
33-
} else if (child.name == "submission") {
34-
submission = child
35-
}
36-
}
22+
val modelElements = getChildren(model)
23+
val mainInstance = modelElements.first { it.name == "instance" }
24+
val mainInstanceRoot = getChildren(mainInstance).first()
25+
val submission = modelElements.firstOrNull { it.name == "submission" }
3726

3827
val id = mainInstanceRoot.getAttributeValue(null, "id")
3928
val version = mainInstanceRoot.getAttributeValue(null, "version")
@@ -57,6 +46,17 @@ object FormMetadataParser {
5746
)
5847
}
5948

49+
private fun getChildren(element: Element): List<Element> {
50+
return 0.until(element.childCount).fold(emptyList()) { list, i ->
51+
val child = element.getElement(i)
52+
if (child != null) {
53+
list + listOf(child)
54+
} else {
55+
list
56+
}
57+
}
58+
}
59+
6060
/**
6161
* Finds the first geopoint reference in the primary instance by:
6262
* 1. Retrieving all geopoint binds from the model.

collect_app/src/test/java/org/odk/collect/android/formmanagement/download/FormDownloadExceptionMapperTest.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import androidx.test.core.app.ApplicationProvider
55
import androidx.test.ext.junit.runners.AndroidJUnit4
66
import org.hamcrest.MatcherAssert.assertThat
7+
import org.hamcrest.Matchers.equalTo
78
import org.hamcrest.Matchers.`is`
89
import org.junit.Before
910
import org.junit.Test
@@ -33,12 +34,20 @@ class FormDownloadExceptionMapperTest {
3334

3435
@Test
3536
fun formParsingError_returnsFormParsingErrorMessage() {
36-
val expectedString = context.getString(
37-
org.odk.collect.strings.R.string.form_parsing_error
38-
) + " " + context.getString(org.odk.collect.strings.R.string.report_to_project_lead)
37+
val original = Exception("original message")
38+
original.stackTrace = arrayOf(
39+
StackTraceElement("Class", "method", "File", 1),
40+
StackTraceElement("Class", "method", "File", 2)
41+
)
42+
3943
assertThat(
40-
mapper.getMessage(FormDownloadException.FormParsingError()),
41-
`is`(expectedString)
44+
mapper.getMessage(FormDownloadException.FormParsingError(original)),
45+
equalTo(
46+
context.getString(org.odk.collect.strings.R.string.form_parsing_error) + "\n\n" +
47+
original.message + "\n" +
48+
"Class.method(File:1)" + "\n\n" +
49+
context.getString(org.odk.collect.strings.R.string.report_to_project_lead)
50+
)
4251
)
4352
}
4453

collect_app/src/test/java/org/odk/collect/android/formmanagement/metadata/FormMetadataParserTest.kt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,58 @@ import org.junit.Test
66
import org.odk.collect.android.formmanagement.metadata.FormMetadataParser.readMetadata
77

88
class FormMetadataParserTest {
9+
10+
@Test
11+
fun readMetadata_canParseWithAttributesOnMainInstance() {
12+
val metadata = readMetadata(
13+
"""
14+
<?xml version="1.0"?>
15+
<h:html xmlns:h="http://www.w3.org/1999/xhtml"
16+
xmlns="http://www.w3.org/2002/xforms"
17+
xmlns:custom="http://example.com/custom">
18+
<h:head>
19+
<h:title>Form</h:title>
20+
<model>
21+
<instance custom:attribute="blah">
22+
<data id="form">
23+
</data>
24+
</instance>
25+
</model>
26+
</h:head>
27+
<h:body>
28+
</h:body>
29+
</h:html>
30+
""".trimIndent().byteInputStream()
31+
)
32+
33+
assertThat(metadata.id, equalTo("form"))
34+
}
35+
36+
@Test
37+
fun readMetadata_canParseWithXformsNamespace() {
38+
val metadata = readMetadata(
39+
"""
40+
<?xml version="1.0"?>
41+
<h:html xmlns:h="http://www.w3.org/1999/xhtml"
42+
xmlns:custom="http://www.w3.org/2002/xforms">
43+
<h:head>
44+
<h:title>Form</h:title>
45+
<custom:model>
46+
<custom:instance>
47+
<custom:data custom:id="form">
48+
</custom:data>
49+
</custom:instance>
50+
</custom:model>
51+
</h:head>
52+
<h:body>
53+
</h:body>
54+
</h:html>
55+
""".trimIndent().byteInputStream()
56+
)
57+
58+
assertThat(metadata.id, equalTo("form"))
59+
}
60+
961
@Test
1062
fun readMetadata_canParseFormsWithComments() {
1163
readMetadata(

collect_app/src/test/java/org/odk/collect/android/utilities/FormsDownloadResultInterpreterTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class FormsDownloadResultInterpreterTest {
2525

2626
private var resultWithOneError = mapOf<ServerFormDetails, FormDownloadException?>(
2727
formDetails1 to null,
28-
formDetails2 to FormDownloadException.FormParsingError()
28+
formDetails2 to FormDownloadException.FormParsingError(RuntimeException())
2929
)
3030

3131
@Test

strings/src/main/res/values/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@
748748
<string name="form_with_no_hash_error">The server did not provide a hash for this form.</string>
749749

750750
<!-- Displayed in error dialog for form downloads. Followed by instructions to talk to person who asked to collect data -->
751-
<string name="form_parsing_error">This form cannot be processed.</string>
751+
<string name="form_parsing_error">This form cannot be processed:</string>
752752

753753
<!-- Displayed in error dialog for form downloads. Followed by instructions to talk to person who asked to collect data -->
754754
<string name="form_save_disk_error">A disk error occurred on device while downloading this form.</string>

0 commit comments

Comments
 (0)