From bd0abfe3db24f995ecc53213def32c26ef27c78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne=20Martin?= Date: Wed, 31 Jan 2024 21:57:21 -0800 Subject: [PATCH] Use placeholder root for empty external secondary instance --- .../model/instance/ExternalDataInstance.java | 14 +++-- .../ExternalSecondaryInstanceParseTest.java | 59 +++++++++++++------ .../org/javarosa/xform/parse/header_only.csv | 1 + 3 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 src/test/resources/org/javarosa/xform/parse/header_only.csv diff --git a/src/main/java/org/javarosa/core/model/instance/ExternalDataInstance.java b/src/main/java/org/javarosa/core/model/instance/ExternalDataInstance.java index 4e43a800b..422926273 100644 --- a/src/main/java/org/javarosa/core/model/instance/ExternalDataInstance.java +++ b/src/main/java/org/javarosa/core/model/instance/ExternalDataInstance.java @@ -1,9 +1,5 @@ package org.javarosa.core.model.instance; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; import org.javarosa.core.model.instance.geojson.GeoJsonExternalInstance; import org.javarosa.core.reference.InvalidReferenceException; import org.javarosa.core.reference.ReferenceManager; @@ -18,6 +14,11 @@ import org.slf4j.LoggerFactory; import org.xmlpull.v1.XmlPullParserException; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + // This is still a work in progress. public class ExternalDataInstance extends DataInstance { @@ -62,6 +63,11 @@ public static ExternalDataInstance build(String instanceSrc, String instanceId) TreeElement root; try { root = parseExternalInstance(instanceSrc, instanceId); + + // Avoid parse error for missing name and label refs if a select is built on an empty placeholder file + if (!root.hasChildren()) { + root = PLACEHOLDER_ROOT; + } } catch (FileNotFoundException | InvalidReferenceException e) { logger.info("External instance not found, falling back to placeholder"); root = PLACEHOLDER_ROOT; diff --git a/src/test/java/org/javarosa/xform/parse/ExternalSecondaryInstanceParseTest.java b/src/test/java/org/javarosa/xform/parse/ExternalSecondaryInstanceParseTest.java index ff1f356d1..949172299 100644 --- a/src/test/java/org/javarosa/xform/parse/ExternalSecondaryInstanceParseTest.java +++ b/src/test/java/org/javarosa/xform/parse/ExternalSecondaryInstanceParseTest.java @@ -1,5 +1,23 @@ package org.javarosa.xform.parse; +import org.javarosa.core.model.FormDef; +import org.javarosa.core.model.SelectChoice; +import org.javarosa.core.model.condition.EvaluationContext; +import org.javarosa.core.model.data.helper.Selection; +import org.javarosa.core.model.instance.AbstractTreeElement; +import org.javarosa.core.model.instance.TreeReference; +import org.javarosa.core.test.FormParseInit; +import org.javarosa.core.test.Scenario; +import org.javarosa.core.util.externalizable.DeserializationException; +import org.javarosa.xpath.expr.XPathPathExpr; +import org.javarosa.xpath.parser.XPathSyntaxException; +import org.junit.Test; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; @@ -22,23 +40,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Path; -import java.util.List; -import org.javarosa.core.model.FormDef; -import org.javarosa.core.model.SelectChoice; -import org.javarosa.core.model.condition.EvaluationContext; -import org.javarosa.core.model.data.helper.Selection; -import org.javarosa.core.model.instance.AbstractTreeElement; -import org.javarosa.core.model.instance.TreeReference; -import org.javarosa.core.test.FormParseInit; -import org.javarosa.core.test.Scenario; -import org.javarosa.core.util.externalizable.DeserializationException; -import org.javarosa.xpath.expr.XPathPathExpr; -import org.javarosa.xpath.parser.XPathSyntaxException; -import org.junit.Test; - public class ExternalSecondaryInstanceParseTest { //region Parsing of different file types into external secondary instances @@ -132,6 +133,30 @@ public void xformParseException_whenItemsetConfiguresValueOrLabelNotInExternalIn } } + @Test + public void csvSecondaryInstanceWithHeaderOnly_parsesWithoutError() throws IOException, XFormParser.ParseException { + configureReferenceManagerCorrectly(); + + Scenario scenario = Scenario.init("Some form", html( + head( + title("Some form"), + model( + mainInstance(t("data id=\"some-form\"", + t("first") + )), + + t("instance id=\"external-csv\" src=\"jr://file-csv/header_only.csv\""), + + bind("/data/first").type("string") + ) + ), + body( + select1Dynamic("/data/first", "instance('external-csv')/root/item") + ))); + + assertThat(scenario.choicesOf("/data/first").size(), is(0)); + } + @Test public void formWithExternalSecondaryXMLInstance_ShouldSerializeAndDeserialize() throws IOException, DeserializationException, XFormParser.ParseException { configureReferenceManagerCorrectly(); diff --git a/src/test/resources/org/javarosa/xform/parse/header_only.csv b/src/test/resources/org/javarosa/xform/parse/header_only.csv new file mode 100644 index 000000000..7b342d489 --- /dev/null +++ b/src/test/resources/org/javarosa/xform/parse/header_only.csv @@ -0,0 +1 @@ +name,label,first_name,last_name \ No newline at end of file