diff --git a/pom.xml b/pom.xml
index 7691c2a5..1dbc12eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,9 @@
lunatic-model
jar
- 2.3.1
+
+ 2.3.2
+
Lunatic Model
Classes and converters for the Lunatic model
@@ -16,6 +18,7 @@
9.7.0-8
UTF-8
UTF-8
+ 11
@@ -48,12 +51,7 @@
slf4j-api
1.7.25
-
- junit
- junit
- 4.13.1
- test
-
+
org.xmlunit
xmlunit-matchers
@@ -83,22 +81,22 @@
jaxb-api
2.3.1
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.8.1
+ test
+
+
org.apache.maven.plugins
maven-compiler-plugin
-
-
- 1.8
- UTF-8
- UTF-8
- UTF-8
- -Dfile.encoding=UTF-8
-
+ 3.10.1
@@ -109,8 +107,6 @@
2.22.0
UTF-8
- UTF-8
- UTF-8
-Dfile.encoding=UTF-8
-Djavax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
diff --git a/src/main/java/fr/insee/lunatic/conversion/JSONCleaner.java b/src/main/java/fr/insee/lunatic/conversion/JSONCleaner.java
index 326750a9..bbd93f4c 100644
--- a/src/main/java/fr/insee/lunatic/conversion/JSONCleaner.java
+++ b/src/main/java/fr/insee/lunatic/conversion/JSONCleaner.java
@@ -1,15 +1,12 @@
package fr.insee.lunatic.conversion;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-
+import fr.insee.lunatic.Constants;
+import fr.insee.lunatic.utils.XslTransformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import fr.insee.lunatic.Constants;
-import fr.insee.lunatic.utils.XslTransformation;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
/**
* remove technical attribute as xsi:type
@@ -19,7 +16,7 @@
*/
public class JSONCleaner {
- private static XslTransformation saxonService = new XslTransformation();
+ private static final XslTransformation saxonService = new XslTransformation();
private static final Logger logger = LoggerFactory.getLogger(JSONCleaner.class);
@@ -28,15 +25,21 @@ public String clean(String jsonString) throws Exception {
if ((jsonString == null) || (jsonString.length() == 0))
return null;
- InputStream json = new ByteArrayInputStream(wrapJsonWithXml(jsonString).getBytes("UTF-8"));
+ InputStream json = new ByteArrayInputStream(wrapJsonWithXml(jsonString).getBytes(StandardCharsets.UTF_8));
+
+ // Unchanged step: use XSLT "cleaning" sheet
+ String generatedUsingXslt = generate(json);
- return this.generate(json);
+ // New step: apply (Java) symLinks cleaning
+ JSONSymLinksCleaner jsonSymLinksCleaner = new JSONSymLinksCleaner();
+ return jsonSymLinksCleaner.clean(generatedUsingXslt);
}
public String generate(InputStream isFinalInput) throws Exception {
OutputStream osOutputFile = generateOS(isFinalInput);
String res = osOutputFile.toString();
osOutputFile.close();
+
return res;
}
@@ -63,4 +66,5 @@ public String preProcessJson2XML(String json) {
.replaceAll("<", "<")
.replaceAll(">", ">");
}
+
}
diff --git a/src/main/java/fr/insee/lunatic/conversion/JSONDeserializer.java b/src/main/java/fr/insee/lunatic/conversion/JSONDeserializer.java
index e1412913..97ae451f 100644
--- a/src/main/java/fr/insee/lunatic/conversion/JSONDeserializer.java
+++ b/src/main/java/fr/insee/lunatic/conversion/JSONDeserializer.java
@@ -1,15 +1,15 @@
package fr.insee.lunatic.conversion;
+import fr.insee.lunatic.model.flat.Questionnaire;
+import org.eclipse.persistence.jaxb.UnmarshallerProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.eclipse.persistence.jaxb.UnmarshallerProperties;
-
-import fr.insee.lunatic.model.flat.Questionnaire;
+import java.io.InputStream;
public class JSONDeserializer {
@@ -36,4 +36,23 @@ public Questionnaire deserialize(String fileName) throws JAXBException {
return questionnaire;
}
+ public Questionnaire deserialize(InputStream jsonQuestionnaire) throws JAXBException {
+ if (jsonQuestionnaire == null) return null;
+
+ logger.debug("Deserializing questionnaire from input stream");
+
+ JAXBContext context = JAXBContext.newInstance(Questionnaire.class);
+ Unmarshaller unmarshaller = context.createUnmarshaller();
+ unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
+ unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
+
+ StreamSource json = new StreamSource(jsonQuestionnaire);
+ Questionnaire questionnaire = unmarshaller.unmarshal(json, Questionnaire.class).getValue();
+
+ logger.debug("Questionnaire " + questionnaire.getId() + " successfully deserialized");
+
+ return questionnaire;
+ }
+
+
}
diff --git a/src/main/java/fr/insee/lunatic/conversion/JSONSerializer.java b/src/main/java/fr/insee/lunatic/conversion/JSONSerializer.java
index 4a68d944..04785c97 100644
--- a/src/main/java/fr/insee/lunatic/conversion/JSONSerializer.java
+++ b/src/main/java/fr/insee/lunatic/conversion/JSONSerializer.java
@@ -1,17 +1,20 @@
package fr.insee.lunatic.conversion;
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
+import fr.insee.lunatic.exception.SerializationException;
+import fr.insee.lunatic.model.flat.Questionnaire;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.eclipse.persistence.jaxb.MarshallerProperties;
-
-import fr.insee.lunatic.model.flat.Questionnaire;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
public class JSONSerializer {
@@ -37,8 +40,36 @@ public String serialize(Questionnaire questionnaire) throws JAXBException, Unsup
ByteArrayOutputStream baos = new ByteArrayOutputStream();
marshaller.marshal(questionnaire, baos);
-
+
return baos.toString("UTF-8");
}
+
+ /** serialize
method returns a json string beginning with {"Questionnaire": {...}}.
+ * The need is to actually have questionnaire content directly at the root of the json tree.
+ * This method returns the json content of the given questionnaire without the "Questionnaire" level.
+ * @param questionnaire Lunatic questionnaire object (flat model).
+ * @return The questionnaire as a json string.
+ */
+ public String serialize2(Questionnaire questionnaire) throws SerializationException {
+ //
+ String questionnaireString;
+ try {
+ questionnaireString = serialize(questionnaire);
+ } catch (JAXBException | UnsupportedEncodingException e) {
+ throw new SerializationException("Error when calling first serialize method.", e);
+ }
+ //
+ try (JsonReader jsonReader = Json.createReader(
+ new ByteArrayInputStream(questionnaireString.getBytes(StandardCharsets.UTF_8)));
+ OutputStream outputStream = new ByteArrayOutputStream();
+ JsonWriter jsonWriter = Json.createWriter(outputStream)) {
+ JsonObject questionnaireJson = jsonReader.readObject();
+ JsonObject contentJson = questionnaireJson.getJsonObject("Questionnaire");
+ jsonWriter.writeObject(contentJson);
+ return outputStream.toString();
+ } catch (IOException e) {
+ throw new SerializationException("Error when removing \"Questionnaire\" level of given questionnaire.", e);
+ }
+ }
}
diff --git a/src/main/java/fr/insee/lunatic/conversion/JSONSymLinksCleaner.java b/src/main/java/fr/insee/lunatic/conversion/JSONSymLinksCleaner.java
new file mode 100644
index 00000000..322e19f5
--- /dev/null
+++ b/src/main/java/fr/insee/lunatic/conversion/JSONSymLinksCleaner.java
@@ -0,0 +1,102 @@
+package fr.insee.lunatic.conversion;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.json.*;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+
+public class JSONSymLinksCleaner {
+
+ private static final Logger logger = LoggerFactory.getLogger(JSONSymLinksCleaner.class);
+
+ /**
+ * Given a Lunatic JSON flat questionnaire, replace the source/target fields by key/values in "symLinks" attribute
+ * in "PairwiseLinks" components to be compliant with the Lunatic JS library.
+ * Warning: no validation is done on the string input. */
+ public String clean(String stringFlatQuestionnaire) throws IOException {
+
+ if (stringFlatQuestionnaire == null) {
+ logger.warn("null string given in JSON SymLinks cleaner.");
+ return null;
+ }
+
+ // Read the json string into a JsonObject
+ try (JsonReader jsonReader = Json.createReader(
+ new ByteArrayInputStream(stringFlatQuestionnaire.getBytes(StandardCharsets.UTF_8)))) {
+ JsonObject jsonQuestionnaire = jsonReader.readObject();
+
+ // We will copy the entire input json object, except the "symLinks" attribute in PairwiseLinks components
+ JsonObjectBuilder jsonQuestionnaireBuilder = Json.createObjectBuilder();
+ editQuestionnaire(jsonQuestionnaire, jsonQuestionnaireBuilder);
+
+ OutputStream outputStream = new ByteArrayOutputStream();
+
+ JsonWriter jsonWriter = Json.createWriter(outputStream);
+ jsonWriter.writeObject(jsonQuestionnaireBuilder.build());
+
+ String result = outputStream.toString();
+ outputStream.close();
+
+ return result;
+ }
+
+ }
+
+ private static void editQuestionnaire(JsonObject jsonQuestionnaire, JsonObjectBuilder jsonQuestionnaireBuilder) {
+ jsonQuestionnaire.forEach((key, jsonValue) -> {
+ if (! "components".equals(key)) {
+ jsonQuestionnaireBuilder.add(key, jsonValue);
+ } else {
+ editComponents(jsonQuestionnaireBuilder, (JsonArray) jsonValue);
+ }
+ });
+ }
+
+ private static void editComponents(JsonObjectBuilder jsonQuestionnaireBuilder, JsonArray jsonComponents) {
+ JsonArrayBuilder jsonComponentsBuilder = Json.createArrayBuilder();
+ for (JsonValue jsonValue1 : jsonComponents) {
+ JsonObject jsonComponent = (JsonObject) jsonValue1;
+ if (! "PairwiseLinks".equals(jsonComponent.getString("componentType"))) {
+ jsonComponentsBuilder.add(jsonValue1);
+ } else {
+ editPairwiseLinks(jsonComponentsBuilder, (JsonObject) jsonValue1);
+ }
+ }
+ jsonQuestionnaireBuilder.add("components", jsonComponentsBuilder.build());
+ }
+
+ private static void editPairwiseLinks(JsonArrayBuilder jsonComponentsBuilder, JsonObject jsonPairwiseLinks) {
+ JsonObjectBuilder jsonPairwiseBuilder = Json.createObjectBuilder();
+ jsonPairwiseLinks.forEach((key2, jsonValue2) -> {
+ if (! "symLinks".equals(key2)) {
+ jsonPairwiseBuilder.add(key2, jsonValue2);
+ } else {
+ editSymLinks(jsonPairwiseBuilder, (JsonObject) jsonValue2);
+ }
+ });
+ jsonComponentsBuilder.add(jsonPairwiseBuilder.build());
+ }
+
+ private static void editSymLinks(JsonObjectBuilder jsonPairwiseBuilder, JsonObject jsonSymLinks) {
+ JsonObjectBuilder jsonSymLinksBuilder = Json.createObjectBuilder();
+ JsonObjectBuilder jsonLINKSBuilder = Json.createObjectBuilder();
+ String symLinksName = jsonSymLinks.getJsonString("name").getString();
+ jsonSymLinks.getJsonArray("LINK").forEach(jsonValue3 -> {
+ JsonObject jsonSourceTarget = (JsonObject) jsonValue3;
+ JsonString sourceKey = (JsonString) jsonSourceTarget.get("source");
+ JsonString targetKey = (JsonString) jsonSourceTarget.get("target");
+ // target field is not mandatory and can be null
+ // json converted from xml can contain "null" string values
+ if (targetKey != null && !"null".equals(targetKey.getString())) {
+ jsonLINKSBuilder.add(sourceKey.getString(), targetKey);
+ } else {
+ jsonLINKSBuilder.addNull(sourceKey.getString());
+ }
+ });
+ jsonSymLinksBuilder.add(symLinksName, jsonLINKSBuilder.build());
+ jsonPairwiseBuilder.add("symLinks", jsonSymLinksBuilder.build());
+ }
+
+}
diff --git a/src/main/java/fr/insee/lunatic/exception/SerializationException.java b/src/main/java/fr/insee/lunatic/exception/SerializationException.java
new file mode 100644
index 00000000..febb80dd
--- /dev/null
+++ b/src/main/java/fr/insee/lunatic/exception/SerializationException.java
@@ -0,0 +1,10 @@
+package fr.insee.lunatic.exception;
+
+/** Thrown when an error occurs during serialization of a questionnaire object. */
+public class SerializationException extends Exception {
+
+ public SerializationException(String message, Exception e) {
+ super(message, e);
+ }
+
+}
diff --git a/src/main/resources/xsd/LunaticModel.xsd b/src/main/resources/xsd/LunaticModel.xsd
index 5b4da2b6..5c2d6fb0 100644
--- a/src/main/resources/xsd/LunaticModel.xsd
+++ b/src/main/resources/xsd/LunaticModel.xsd
@@ -32,7 +32,7 @@
-
+
@@ -115,6 +115,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -146,6 +174,7 @@
+
diff --git a/src/main/resources/xsd/LunaticModelFlat.xsd b/src/main/resources/xsd/LunaticModelFlat.xsd
index a490618a..f27fef6b 100644
--- a/src/main/resources/xsd/LunaticModelFlat.xsd
+++ b/src/main/resources/xsd/LunaticModelFlat.xsd
@@ -32,7 +32,7 @@
-
+
@@ -101,7 +101,7 @@
-
+
@@ -111,6 +111,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -141,6 +168,7 @@
+
diff --git a/src/main/resources/xslt/json-cleaner.xsl b/src/main/resources/xslt/json-cleaner.xsl
index acddd0ce..abfb987a 100644
--- a/src/main/resources/xslt/json-cleaner.xsl
+++ b/src/main/resources/xslt/json-cleaner.xsl
@@ -100,11 +100,35 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
diff --git a/src/test/java/fr/insee/lunatic/test/DataTranslatorsTest.java b/src/test/java/fr/insee/lunatic/test/DataTranslatorsTest.java
index 7a340b44..fb95a5b6 100644
--- a/src/test/java/fr/insee/lunatic/test/DataTranslatorsTest.java
+++ b/src/test/java/fr/insee/lunatic/test/DataTranslatorsTest.java
@@ -1,25 +1,25 @@
package fr.insee.lunatic.test;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
+import fr.insee.lunatic.Constants;
+import fr.insee.lunatic.conversion.data.JSONLunaticDataToXML;
+import fr.insee.lunatic.conversion.data.XMLLunaticDataToJSON;
+import fr.insee.lunatic.test.utils.XMLDiff;
import org.apache.commons.io.FileUtils;
import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlunit.diff.Diff;
-import fr.insee.lunatic.Constants;
-import fr.insee.lunatic.conversion.data.JSONLunaticDataToXML;
-import fr.insee.lunatic.conversion.data.XMLLunaticDataToJSON;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
public class DataTranslatorsTest {
@@ -27,7 +27,7 @@ public class DataTranslatorsTest {
private static final Logger logger = LoggerFactory.getLogger(DataTranslatorsTest.class);
- @BeforeClass
+ @BeforeAll
public static void setUpBeforeClass() throws Exception {
}
@@ -53,14 +53,14 @@ public void testDataXMLToJSON() {
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
@@ -79,18 +79,18 @@ public void testDataJSONToXML() {
File expectedFile = new File(String.format("%s/out/data.xml", basePath));
Diff diff = xmlDiff.getDiff(xmlOut,expectedFile);
- Assert.assertFalse(getDiffMessage(diff, basePath), diff.hasDifferences());
+ Assertions.assertFalse( diff.hasDifferences(), getDiffMessage(diff, basePath));
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
diff --git a/src/test/java/fr/insee/lunatic/test/JSONSerializerTest.java b/src/test/java/fr/insee/lunatic/test/JSONSerializerTest.java
new file mode 100644
index 00000000..d45cdd2b
--- /dev/null
+++ b/src/test/java/fr/insee/lunatic/test/JSONSerializerTest.java
@@ -0,0 +1,42 @@
+package fr.insee.lunatic.test;
+
+import fr.insee.lunatic.conversion.JSONSerializer;
+import fr.insee.lunatic.exception.SerializationException;
+import fr.insee.lunatic.model.flat.Questionnaire;
+import fr.insee.lunatic.test.utils.JsonFormatter;
+import org.junit.jupiter.api.Test;
+
+import javax.xml.bind.JAXBException;
+import java.io.UnsupportedEncodingException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class JSONSerializerTest {
+
+ @Test
+ void serialize_simplestCase() throws JAXBException, UnsupportedEncodingException {
+ //
+ Questionnaire questionnaire = new Questionnaire();
+ questionnaire.setId("foo-id");
+ //
+ JSONSerializer serializer = new JSONSerializer();
+ String result = serializer.serialize(questionnaire);
+ //
+ assertEquals("{\"Questionnaire\":{\"id\":\"foo-id\"}}",
+ JsonFormatter.compress(result));
+ }
+
+ @Test
+ void serialize2_simplestCase() throws SerializationException {
+ //
+ Questionnaire questionnaire = new Questionnaire();
+ questionnaire.setId("foo-id");
+ //
+ JSONSerializer serializer = new JSONSerializer();
+ String result = serializer.serialize2(questionnaire);
+ //
+ assertEquals("{\"id\":\"foo-id\"}",
+ JsonFormatter.compress(result));
+ }
+
+}
diff --git a/src/test/java/fr/insee/lunatic/test/JSONSymLinksCleanerTest.java b/src/test/java/fr/insee/lunatic/test/JSONSymLinksCleanerTest.java
new file mode 100644
index 00000000..b217a3c3
--- /dev/null
+++ b/src/test/java/fr/insee/lunatic/test/JSONSymLinksCleanerTest.java
@@ -0,0 +1,37 @@
+package fr.insee.lunatic.test;
+
+import fr.insee.lunatic.conversion.JSONSymLinksCleaner;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JSONSymLinksCleanerTest {
+
+ JSONSymLinksCleaner symLinksCleaner;
+
+ @BeforeEach
+ public void initCleaner() {
+ symLinksCleaner = new JSONSymLinksCleaner();
+ }
+
+ @Test
+ void nullString() throws IOException {
+ assertNull(symLinksCleaner.clean(null));
+ }
+
+ @Test
+ void sandbox_testJsonObjectGetString() {
+ JsonReader reader = Json.createReader(new ByteArrayInputStream("{\"foo\":1}".getBytes()));
+ JsonObject jsonObject = reader.readObject();
+ assertThrows(ClassCastException.class, () -> jsonObject.getString("foo"));
+ assertEquals("1", String.valueOf(jsonObject.get("foo")));
+ }
+
+}
diff --git a/src/test/java/fr/insee/lunatic/test/LunaticXmlToDataTest.java b/src/test/java/fr/insee/lunatic/test/LunaticXmlToDataTest.java
index c10eae20..a93b0638 100644
--- a/src/test/java/fr/insee/lunatic/test/LunaticXmlToDataTest.java
+++ b/src/test/java/fr/insee/lunatic/test/LunaticXmlToDataTest.java
@@ -1,14 +1,14 @@
package fr.insee.lunatic.test;
import fr.insee.lunatic.Constants;
-import fr.insee.lunatic.conversion.data.JSONLunaticDataToXML;
import fr.insee.lunatic.conversion.data.XMLLunaticDataToJSON;
import fr.insee.lunatic.conversion.data.XMLLunaticToXMLEmptyData;
+import fr.insee.lunatic.test.utils.XMLDiff;
import org.apache.commons.io.FileUtils;
import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,12 +27,12 @@ public class LunaticXmlToDataTest {
private static final Logger logger = LoggerFactory.getLogger(LunaticXmlToDataTest.class);
- @BeforeClass
+ @BeforeAll
public static void setUpBeforeClass() throws Exception {
}
- @Test
+ @org.junit.jupiter.api.Test
public void testLunaticXml2EmptyXmlData() {
logger.debug("Launch test : lunaticXML to empty xml data");
try {
@@ -46,18 +46,18 @@ public void testLunaticXml2EmptyXmlData() {
File expectedFile = new File(String.format("%s/out/questionnaire-data.xml", Constants.RESOURCES_FOLDER_DATA_PATH));
Diff diff = xmlDiff.getDiff(xmlOut,expectedFile);
- Assert.assertFalse(getDiffMessage(diff, basePath), diff.hasDifferences());
+ Assertions.assertFalse(diff.hasDifferences(), getDiffMessage(diff, basePath));
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
@@ -86,14 +86,14 @@ public void testLunaticXml2EmptyJsonData() {
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
diff --git a/src/test/java/fr/insee/lunatic/test/PairwiseTest.java b/src/test/java/fr/insee/lunatic/test/PairwiseTest.java
new file mode 100644
index 00000000..628964f8
--- /dev/null
+++ b/src/test/java/fr/insee/lunatic/test/PairwiseTest.java
@@ -0,0 +1,83 @@
+package fr.insee.lunatic.test;
+
+import fr.insee.lunatic.conversion.JSONCleaner;
+import fr.insee.lunatic.conversion.JSONDeserializer;
+import fr.insee.lunatic.conversion.XMLLunaticFlatToJSONLunaticFlatTranslator;
+import fr.insee.lunatic.conversion.XMLLunaticToXMLLunaticFlatTranslator;
+import fr.insee.lunatic.model.flat.PairwiseLinks;
+import fr.insee.lunatic.model.flat.Questionnaire;
+import org.junit.jupiter.api.Test;
+
+import javax.xml.bind.JAXBException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/** Test class to see if PairwiseLinks object doesn't break translators */
+class PairwiseTest {
+
+ @Test
+ void deserializeQuestionnaireContainingPairwise_doesContainPairwise() throws JAXBException {
+ //
+ JSONDeserializer jsonDeserializer = new JSONDeserializer();
+ //
+ Questionnaire questionnaire = jsonDeserializer.deserialize(
+ this.getClass().getClassLoader().getResourceAsStream("pairwise/pairwise-flat.json"));
+ //
+ assertNotNull(questionnaire);
+ assertTrue(questionnaire.getComponents().stream()
+ .anyMatch(componentType -> componentType instanceof PairwiseLinks));
+ }
+
+ @Test
+ void transformAndClean_questionnaireWithPairwise_doesNotThrow() throws Exception {
+ //
+ XMLLunaticToXMLLunaticFlatTranslator translator = new XMLLunaticToXMLLunaticFlatTranslator();
+ XMLLunaticFlatToJSONLunaticFlatTranslator translator2 = new XMLLunaticFlatToJSONLunaticFlatTranslator();
+ JSONCleaner jsonCleaner = new JSONCleaner();
+ //
+ String result = jsonCleaner.clean(
+ translator2.translate(
+ translator.generate(
+ this.getClass().getClassLoader().getResourceAsStream("pairwise/pairwise-hierarchical-test.xml")
+ )));
+ //
+ assertNotNull(result);
+ }
+
+ @Test
+ void transformAndClean_questionnaireWithPairwise_writeOutput() throws Exception {
+ //
+ XMLLunaticToXMLLunaticFlatTranslator translator = new XMLLunaticToXMLLunaticFlatTranslator();
+ XMLLunaticFlatToJSONLunaticFlatTranslator translator2 = new XMLLunaticFlatToJSONLunaticFlatTranslator();
+ JSONCleaner jsonCleaner = new JSONCleaner();
+ //
+ URL pairwiseFileUrl = this.getClass().getClassLoader().getResource("pairwise/pairwise-hierarchical-test.xml");
+ assert pairwiseFileUrl != null;
+ //
+ Path pairwisePath = Path.of(pairwiseFileUrl.toURI()).getParent();
+ Path outPath = Files.createTempDirectory(pairwisePath, "out");
+ System.out.printf("Writing test pairwise outputs in \n%s\n", outPath);
+
+ //
+ String xmlFlat = translator.generate(pairwiseFileUrl.openStream());
+ Files.writeString(
+ outPath.resolve("pairwise-flat.xml"),
+ xmlFlat);
+ String jsonFlat = translator2.translate(xmlFlat);
+ Files.writeString(
+ outPath.resolve("pairwise-flat.json"),
+ jsonFlat);
+ String result = jsonCleaner.clean(jsonFlat);
+ Files.writeString(
+ outPath.resolve("pairwise-cleaned.json"),
+ result);
+
+ //
+ assertNotNull(result);
+ }
+
+}
diff --git a/src/test/java/fr/insee/lunatic/test/TranslatorsTest.java b/src/test/java/fr/insee/lunatic/test/TranslatorsTest.java
index 2e06414e..eaef4db7 100644
--- a/src/test/java/fr/insee/lunatic/test/TranslatorsTest.java
+++ b/src/test/java/fr/insee/lunatic/test/TranslatorsTest.java
@@ -1,16 +1,15 @@
package fr.insee.lunatic.test;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
+import fr.insee.lunatic.Constants;
+import fr.insee.lunatic.conversion.JSONCleaner;
+import fr.insee.lunatic.conversion.XMLLunaticFlatToJSONLunaticFlatTranslator;
+import fr.insee.lunatic.conversion.XMLLunaticToJSONLunaticTranslator;
+import fr.insee.lunatic.conversion.XMLLunaticToXMLLunaticFlatTranslator;
+import fr.insee.lunatic.test.utils.XMLDiff;
import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.Customization;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
@@ -19,41 +18,51 @@
import org.slf4j.LoggerFactory;
import org.xmlunit.diff.Diff;
-import fr.insee.lunatic.Constants;
-import fr.insee.lunatic.conversion.JSONCleaner;
-import fr.insee.lunatic.conversion.XMLLunaticFlatToJSONLunaticFlatTranslator;
-import fr.insee.lunatic.conversion.XMLLunaticToJSONLunaticTranslator;
-import fr.insee.lunatic.conversion.XMLLunaticToXMLLunaticFlatTranslator;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.stream.JsonParser;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
public class TranslatorsTest {
private XMLDiff xmlDiff = new XMLDiff();
-
+
private static final Logger logger = LoggerFactory.getLogger(TranslatorsTest.class);
-
- @BeforeClass
+
+ @BeforeAll
public static void setUpBeforeClass() throws Exception {
}
-
-
- @Test
+
+ @org.junit.jupiter.api.Test
public void testQuestionnaireXMLFToJSONF() {
logger.debug("Launch test : XMLLunaticFlat -> JSONLunaticFlat");
try {
String basePath = Constants.RESOURCES_FOLDER_XMLF_2_JSONF_PATH;
-
+
Path outPath = Paths.get(Constants.TEMP_FOLDER_PATH + "/xmlf-2-jsonf-out.json");
Files.deleteIfExists(outPath);
Path outputFile = Files.createFile(outPath);
-
+
File in = new File(String.format("%s/form_flat.xml", Constants.RESOURCES_FOLDER_DUMMY_PATH));
-
+
XMLLunaticFlatToJSONLunaticFlatTranslator translator = new XMLLunaticFlatToJSONLunaticFlatTranslator();
JSONCleaner jsonCleaner = new JSONCleaner();
-
+
String jsonQuestionnaire = jsonCleaner.clean(translator.translate(in));
JSONObject jsonOut = new JSONObject(jsonQuestionnaire);
-
+
Files.write(outputFile, jsonQuestionnaire.getBytes("UTF-8"));
logger.debug("File generated at : "+outputFile.toString());
@@ -68,79 +77,79 @@ public void testQuestionnaireXMLFToJSONF() {
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
-
+
@Test
public void testQuestionnaireXMLHToXMLF() {
logger.debug("Launch test : XMLLunatic -> XMLLunaticFlat");
try {
String basePath = Constants.RESOURCES_FOLDER_XMLH_2_XMLF_PATH;
-
+
Path outPath = Paths.get(Constants.TEMP_FOLDER_PATH + "/xmlh-2-xmlf-out.xml");
Files.deleteIfExists(outPath);
Path outputFile = Files.createFile(outPath);
-
+
File in = new File(String.format("%s/form.xml", Constants.RESOURCES_FOLDER_DUMMY_PATH));
-
+
XMLLunaticToXMLLunaticFlatTranslator translator = new XMLLunaticToXMLLunaticFlatTranslator();
String xmlQuestionnaire = translator.generate(in);
Files.write(outputFile, xmlQuestionnaire.getBytes("UTF-8"));
logger.debug("File generated at : "+outputFile.toString());
-
+
File expectedFile = new File(String.format("%s/out.xml", basePath));
Diff diff = xmlDiff.getDiff(outputFile.toFile(),expectedFile);
- Assert.assertFalse(getDiffMessage(diff, basePath), diff.hasDifferences());
-
+ Assertions.assertFalse(diff.hasDifferences(), getDiffMessage(diff, basePath));
+
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
-
+
@Test
public void testQuestionnaireXMLHToJSONF() {
logger.debug("Launch test : XMLLunatic -> JSONLunaticFlat");
try {
-
+
long startTime = System.currentTimeMillis();
-
+
String basePath = Constants.RESOURCES_FOLDER_XMLH_2_JSONF_PATH;
-
+
Path outPath = Paths.get(Constants.TEMP_FOLDER_PATH + "/xmlh-2-jsonf-out.json");
Files.deleteIfExists(outPath);
Path outputFile = Files.createFile(outPath);
File in = new File(String.format("%s/form.xml", Constants.RESOURCES_FOLDER_DUMMY_PATH));
-
+
XMLLunaticToXMLLunaticFlatTranslator translator = new XMLLunaticToXMLLunaticFlatTranslator();
XMLLunaticFlatToJSONLunaticFlatTranslator translator2 = new XMLLunaticFlatToJSONLunaticFlatTranslator();
- JSONCleaner jsonCleaner = new JSONCleaner();
-
+ JSONCleaner jsonCleaner = new JSONCleaner();
+
String jsonQuestionnaire = jsonCleaner.clean(translator2.translate(translator.generate(in)));
JSONObject jsonOut = new JSONObject(jsonQuestionnaire);
Files.write(outputFile, jsonQuestionnaire.getBytes("UTF-8"));
-
+
long elapsedTime = System.currentTimeMillis() - startTime;
-
+
logger.debug("File generated at : "+outputFile.toString());
logger.debug("Transformation time for eno-XML to json lunatic fo JS: " + elapsedTime +" ms");
@@ -153,32 +162,32 @@ public void testQuestionnaireXMLHToJSONF() {
new Customization("enoCoreVersion",(o1, o2) -> true)));
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
-
+
@Test
public void testQuestionnaireXMLHToJSONH() {
logger.debug("Launch test : XMLLunatic -> JSONLunaticH");
try {
String basePath = Constants.RESOURCES_FOLDER_XMLH_2_JSONH_PATH;
-
+
Path outPath = Paths.get(Constants.TEMP_FOLDER_PATH + "/xmlh-2-jsonh-out.json");
Files.deleteIfExists(outPath);
Path outputFile = Files.createFile(outPath);
-
+
File in = new File(String.format("%s/form.xml", Constants.RESOURCES_FOLDER_DUMMY_PATH));
XMLLunaticToJSONLunaticTranslator translator = new XMLLunaticToJSONLunaticTranslator();
JSONCleaner jsonCleaner = new JSONCleaner();
-
+
String jsonQuestionnaire = jsonCleaner.clean(translator.translate(in));
JSONObject jsonOut = new JSONObject(jsonQuestionnaire);
Files.write(outputFile, jsonQuestionnaire.getBytes("UTF-8"));
@@ -195,14 +204,14 @@ public void testQuestionnaireXMLHToJSONH() {
} catch (IOException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (NullPointerException e) {
e.printStackTrace();
- Assert.fail();
+ Assertions.fail();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
- Assert.fail();
+ Assertions.fail();
}
}
@@ -210,6 +219,30 @@ private String getDiffMessage(Diff diff, String path) {
return String.format("Transformed output for %s should match expected XML document:\n %s", path,
diff.toString());
}
-
-
+
+ @Test
+ void xmlHierarchicalToJsonFlat_resizingIssue() throws Exception {
+ //
+ XMLLunaticToXMLLunaticFlatTranslator translator1 = new XMLLunaticToXMLLunaticFlatTranslator();
+ XMLLunaticFlatToJSONLunaticFlatTranslator translator2 = new XMLLunaticFlatToJSONLunaticFlatTranslator();
+ JSONCleaner cleaner = new JSONCleaner();
+ //
+ String xmlFlat = translator1.generate(this.getClass().getClassLoader().getResourceAsStream(
+ "pairwise/resizing-issue/lb3ei722-lunatic-hierarchical.xml"));
+ String jsonFlat = translator2.translate(xmlFlat);
+ String result = cleaner.clean(jsonFlat);
+ //
+ assertNotNull(result);
+ try (JsonReader jsonReader = Json.createReader(
+ new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)))) {
+ JsonObject resultJson = jsonReader.readObject();
+ JsonArray resizingVariables = resultJson.getJsonObject("resizing").getJsonObject("NB")
+ .getJsonArray("variables");
+ assertEquals(2, resizingVariables.size());
+ String variableName1 = resizingVariables.getString(0);
+ String variableName2 = resizingVariables.getString(1);
+ assertEquals(Set.of("PRENOM", "AGE"), Set.of(variableName1, variableName2));
+ }
+ }
+
}
diff --git a/src/test/java/fr/insee/lunatic/test/ValidatorTest.java b/src/test/java/fr/insee/lunatic/test/ValidatorTest.java
index fc35b272..7f5c881a 100644
--- a/src/test/java/fr/insee/lunatic/test/ValidatorTest.java
+++ b/src/test/java/fr/insee/lunatic/test/ValidatorTest.java
@@ -1,27 +1,14 @@
package fr.insee.lunatic.test;
-import fr.insee.lunatic.Constants;
-import fr.insee.lunatic.conversion.JSONCleaner;
-import fr.insee.lunatic.conversion.XMLLunaticFlatToJSONLunaticFlatTranslator;
-import fr.insee.lunatic.conversion.XMLLunaticToJSONLunaticTranslator;
-import fr.insee.lunatic.conversion.XMLLunaticToXMLLunaticFlatTranslator;
+import fr.insee.lunatic.test.utils.XMLDiff;
import fr.insee.lunatic.utils.Modele;
import fr.insee.lunatic.utils.SchemaValidator;
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.skyscreamer.jsonassert.JSONAssert;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.xmlunit.diff.Diff;
import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
public class ValidatorTest {
@@ -37,10 +24,10 @@ public void testValidateH() {
File in = new File(String.format("%s/form.xml", basePath));
try {
SchemaValidator schemaValidator = new SchemaValidator(Modele.HIERARCHICAL);
- Assert.assertTrue(schemaValidator.validateFile(in));
+ Assertions.assertTrue(schemaValidator.validateFile(in));
} catch (Exception e) {
- Assert.fail();
+ Assertions.fail();
// TODO Auto-generated catch block
e.printStackTrace();
}
@@ -52,10 +39,10 @@ public void testValidateF() {
File in = new File(String.format("%s/form_flat.xml", basePath));
try {
SchemaValidator schemaValidator = new SchemaValidator(Modele.FLAT);
- Assert.assertTrue(schemaValidator.validateFile(in));
+ Assertions.assertTrue(schemaValidator.validateFile(in));
} catch (Exception e) {
- Assert.fail();
+ Assertions.fail();
// TODO Auto-generated catch block
e.printStackTrace();
}
diff --git a/src/test/java/fr/insee/lunatic/test/utils/JsonFormatter.java b/src/test/java/fr/insee/lunatic/test/utils/JsonFormatter.java
new file mode 100644
index 00000000..0ec679aa
--- /dev/null
+++ b/src/test/java/fr/insee/lunatic/test/utils/JsonFormatter.java
@@ -0,0 +1,18 @@
+package fr.insee.lunatic.test.utils;
+
+/**
+ * Utils class to facilitate json comparison in tests.
+ */
+public class JsonFormatter {
+
+ /**
+ * Compress the json string by removing line breaks and spaces.
+ * Warning: this method also removes spaces inside string content.
+ * @param jsonString Json string.
+ * @return Compressed json string.
+ */
+ public static String compress(String jsonString) {
+ return jsonString.replaceAll("\\s+","").replaceAll("\\n+","");
+ }
+
+}
diff --git a/src/test/java/fr/insee/lunatic/test/XMLDiff.java b/src/test/java/fr/insee/lunatic/test/utils/XMLDiff.java
similarity index 97%
rename from src/test/java/fr/insee/lunatic/test/XMLDiff.java
rename to src/test/java/fr/insee/lunatic/test/utils/XMLDiff.java
index e2b20664..991d7646 100644
--- a/src/test/java/fr/insee/lunatic/test/XMLDiff.java
+++ b/src/test/java/fr/insee/lunatic/test/utils/XMLDiff.java
@@ -1,4 +1,4 @@
-package fr.insee.lunatic.test;
+package fr.insee.lunatic.test.utils;
import java.io.File;
import javax.xml.transform.stream.StreamSource;
diff --git a/src/test/resources/pairwise/pairwise-flat.json b/src/test/resources/pairwise/pairwise-flat.json
new file mode 100644
index 00000000..b14cc015
--- /dev/null
+++ b/src/test/resources/pairwise/pairwise-flat.json
@@ -0,0 +1,643 @@
+{
+ "id" : "lcswhwa1",
+ "modele" : "L2A2_LOOP",
+ "enoCoreVersion" : "2.4.1-pairwise-dev-pairwise",
+ "lunaticModelVersion" : "2.3.2-rc4",
+ "generatingDate" : "30-01-2023 21:23:48",
+ "missing" : false,
+ "pagination" : "question",
+ "maxPage" : "7",
+ "label" : {
+ "value" : "Recette liens deux à deux --- Boucle",
+ "type" : "VTL|MD"
+ },
+ "components" : [ {
+ "id" : "lcswhkve",
+ "componentType" : "Sequence",
+ "page" : "1",
+ "type" : "Sequence",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "lcswhkve",
+ "page" : "1",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ }
+ }
+ }
+ }, {
+ "id" : "lcswldsp",
+ "componentType" : "InputNumber",
+ "mandatory" : false,
+ "page" : "2",
+ "min" : 1.0,
+ "max" : 10.0,
+ "decimals" : 0,
+ "type" : "InputNumber",
+ "label" : {
+ "value" : "\"➡ \" || \"Combien de personnes dans votre ménage ?\"",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "controls" : [ {
+ "id" : "lcswldsp-format-borne-inf-sup",
+ "typeOfControl" : "FORMAT",
+ "criticality" : "ERROR",
+ "control" : {
+ "value" : "not(not(isnull(NB)) and (1>NB or 10NB)",
+ "type" : "VTL"
+ },
+ "errorMessage" : {
+ "value" : "\"Le nombre doit comporter au maximum 0 chiffre(s) après la virgule.\"",
+ "type" : "VTL|MD"
+ }
+ } ],
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "lcswhkve",
+ "page" : "1",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ }
+ }
+ },
+ "bindingDependencies" : [ "NB" ],
+ "response" : {
+ "name" : "NB"
+ }
+ }, {
+ "id" : "lcswrct3",
+ "componentType" : "Loop",
+ "page" : "3",
+ "depth" : 1,
+ "paginatedLoop" : false,
+ "type" : "Loop",
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "lcswhkve",
+ "page" : "1",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ }
+ }
+ },
+ "bindingDependencies" : [ "NB", "PRENOM" ],
+ "loopDependencies" : [ "NB" ],
+ "lines" : {
+ "min" : {
+ "value" : "nvl(NB, 1)",
+ "type" : "VTL"
+ },
+ "max" : {
+ "value" : "nvl(NB, 1)",
+ "type" : "VTL"
+ }
+ },
+ "components" : [ {
+ "id" : "lcswbr49",
+ "componentType" : "Subsequence",
+ "page" : "3",
+ "goToPage" : "3",
+ "type" : "Subsequence",
+ "label" : {
+ "value" : "Prénoms",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "lcswhkve",
+ "page" : "1",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ }
+ },
+ "subSequence" : {
+ "id" : "lcswbr49",
+ "page" : "3",
+ "label" : {
+ "value" : "Prénoms",
+ "type" : "VTL|MD"
+ }
+ }
+ },
+ "bindingDependencies" : [ "NB" ]
+ }, {
+ "id" : "lcswmnod",
+ "componentType" : "Input",
+ "mandatory" : false,
+ "page" : "3",
+ "maxLength" : 249,
+ "type" : "Input",
+ "label" : {
+ "value" : "\"➡ \" || \"Prénom ?\"",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "lcswhkve",
+ "page" : "1",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ }
+ },
+ "subSequence" : {
+ "id" : "lcswbr49",
+ "page" : "3",
+ "label" : {
+ "value" : "Prénoms",
+ "type" : "VTL|MD"
+ }
+ }
+ },
+ "bindingDependencies" : [ "PRENOM", "NB" ],
+ "response" : {
+ "name" : "PRENOM"
+ }
+ } ]
+ }, {
+ "id" : "lcswo5m5",
+ "componentType" : "Subsequence",
+ "goToPage" : "4",
+ "type" : "Subsequence",
+ "label" : {
+ "value" : "Liens deux à deux",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "lcswhkve",
+ "page" : "1",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ }
+ },
+ "subSequence" : {
+ "id" : "lcswo5m5",
+ "page" : "4",
+ "label" : {
+ "value" : "Liens deux à deux",
+ "type" : "VTL|MD"
+ }
+ }
+ }
+ }, {
+ "id" : "lcsxm1eu",
+ "componentType" : "PairwiseLinks",
+ "mandatory" : false,
+ "page" : "4",
+ "type" : "PairwiseLinks",
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "lcswhkve",
+ "page" : "1",
+ "label" : {
+ "value" : "\"I - \" || \"Composition du ménage\"",
+ "type" : "VTL|MD"
+ }
+ },
+ "subSequence" : {
+ "id" : "lcswo5m5",
+ "page" : "4",
+ "label" : {
+ "value" : "Liens deux à deux",
+ "type" : "VTL|MD"
+ }
+ }
+ },
+ "bindingDependencies" : [ "LIENS" ],
+ "xAxisIterations" : {
+ "value" : "count(PRENOM)",
+ "type" : "VTL"
+ },
+ "yAxisIterations" : {
+ "value" : "count(PRENOM)",
+ "type" : "VTL"
+ },
+ "components" : [ {
+ "id" : "lcsxm1eu-pairwise-dropdown",
+ "componentType" : "Dropdown",
+ "mandatory" : false,
+ "page" : "5",
+ "type" : "Dropdown",
+ "label" : {
+ "value" : "\"➡ \" || \"Quels sont vos liens ?\"",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "xAxis <> yAxis",
+ "type" : "VTL"
+ },
+ "bindingDependencies" : [ "LIENS" ],
+ "options" : [ {
+ "value" : "1",
+ "label" : {
+ "value" : "Son conjoint, sa conjointe",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "2",
+ "label" : {
+ "value" : "Sa mère, son père",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "3",
+ "label" : {
+ "value" : "Sa fille, son fils",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "4",
+ "label" : {
+ "value" : "Sa soeur, son frère (y compris demi et quasi)",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "5",
+ "label" : {
+ "value" : "Sa belle-mère, son beau-père (conjoint.e d’un des parents)",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "6",
+ "label" : {
+ "value" : "L’enfant du conjoint (belle-fille, beau-fils)",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "7",
+ "label" : {
+ "value" : "Sa belle-mère, son beau-père (parent du conjoint)",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "8",
+ "label" : {
+ "value" : "Sa belle-fille, son beau-fils (conjoint.e d’un enfant)",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "9",
+ "label" : {
+ "value" : "Sa grand-mère, son grand-père",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "10",
+ "label" : {
+ "value" : "Sa petite-fille, petit-fils",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "11",
+ "label" : {
+ "value" : "Sa tante, son oncle",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "12",
+ "label" : {
+ "value" : "Sa cousine, son cousin",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "13",
+ "label" : {
+ "value" : "Sa nièce, son neveu",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "14",
+ "label" : {
+ "value" : "Un enfant placé en famille d’accueil",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "15",
+ "label" : {
+ "value" : "Sa belle-soeur, son beau-frère",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "16",
+ "label" : {
+ "value" : "Un autre lien familial",
+ "type" : "VTL|MD"
+ }
+ }, {
+ "value" : "17",
+ "label" : {
+ "value" : "Autre lien (employé de maison, salarié logé, jeune au pair …)",
+ "type" : "VTL|MD"
+ }
+ } ],
+ "response" : {
+ "name" : "LIENS"
+ }
+ } ],
+ "symLinks" : {
+ "name" : "LIENS",
+ "LINK" : [ {
+ "source" : "1",
+ "target" : "1"
+ }, {
+ "source" : "2",
+ "target" : "3"
+ }, {
+ "source" : "3",
+ "target" : "2"
+ }, {
+ "source" : "4",
+ "target" : "4"
+ }, {
+ "source" : "5",
+ "target" : "6"
+ }, {
+ "source" : "6",
+ "target" : "5"
+ }, {
+ "source" : "7",
+ "target" : "8"
+ }, {
+ "source" : "8",
+ "target" : "7"
+ }, {
+ "source" : "9",
+ "target" : "10"
+ }, {
+ "source" : "10",
+ "target" : "9"
+ }, {
+ "source" : "11",
+ "target" : "13"
+ }, {
+ "source" : "12",
+ "target" : "12"
+ }, {
+ "source" : "13",
+ "target" : "11"
+ }, {
+ "source" : "14",
+ "target" : "null"
+ }, {
+ "source" : "15",
+ "target" : "null"
+ }, {
+ "source" : "16",
+ "target" : "16"
+ }, {
+ "source" : "17",
+ "target" : "17"
+ }, {
+ "source" : "18",
+ "target" : "18"
+ } ]
+ }
+ }, {
+ "id" : "COMMENT-SEQ",
+ "componentType" : "Sequence",
+ "page" : "6",
+ "type" : "Sequence",
+ "label" : {
+ "value" : "\"Commentaire\"",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "COMMENT-SEQ",
+ "page" : "6",
+ "label" : {
+ "value" : "\"Commentaire\"",
+ "type" : "VTL|MD"
+ }
+ }
+ }
+ }, {
+ "id" : "COMMENT-QUESTION",
+ "componentType" : "Textarea",
+ "mandatory" : false,
+ "page" : "7",
+ "maxLength" : 2000,
+ "type" : "Textarea",
+ "label" : {
+ "value" : "\"Avez-vous des remarques concernant l'enquête ou des commentaires ?\"",
+ "type" : "VTL|MD"
+ },
+ "conditionFilter" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "hierarchy" : {
+ "sequence" : {
+ "id" : "COMMENT-SEQ",
+ "page" : "6",
+ "label" : {
+ "value" : "\"Commentaire\"",
+ "type" : "VTL|MD"
+ }
+ }
+ },
+ "bindingDependencies" : [ "COMMENT_QE" ],
+ "response" : {
+ "name" : "COMMENT_QE"
+ }
+ } ],
+ "variables" : [ {
+ "variableType" : "COLLECTED",
+ "type" : "VariableType",
+ "name" : "COMMENT_QE",
+ "values" : {
+ "PREVIOUS" : null,
+ "COLLECTED" : null,
+ "FORCED" : null,
+ "EDITED" : null,
+ "INPUTED" : null
+ }
+ }, {
+ "variableType" : "COLLECTED",
+ "type" : "VariableType",
+ "name" : "NB",
+ "values" : {
+ "PREVIOUS" : null,
+ "COLLECTED" : null,
+ "FORCED" : null,
+ "EDITED" : null,
+ "INPUTED" : null
+ }
+ }, {
+ "variableType" : "COLLECTED",
+ "type" : "VariableTypeArray",
+ "name" : "PRENOM",
+ "values" : {
+ "PREVIOUS" : {
+ "PREVIOUS" : [ null ]
+ },
+ "COLLECTED" : {
+ "COLLECTED" : [ null ]
+ },
+ "FORCED" : {
+ "FORCED" : [ null ]
+ },
+ "EDITED" : {
+ "EDITED" : [ null ]
+ },
+ "INPUTED" : {
+ "INPUTED" : [ null ]
+ }
+ }
+ }, {
+ "variableType" : "COLLECTED",
+ "type" : "VariableTypeArray",
+ "name" : "LIENS",
+ "values" : {
+ "PREVIOUS" : {
+ "PREVIOUS" : [ {
+ "type" : "PREVIOUSArray",
+ "PREVIOUS" : [ null ]
+ } ]
+ },
+ "COLLECTED" : {
+ "COLLECTED" : [ {
+ "type" : "COLLECTEDArray",
+ "COLLECTED" : [ null ]
+ } ]
+ },
+ "FORCED" : {
+ "FORCED" : [ {
+ "type" : "FORCEDArray",
+ "FORCED" : [ null ]
+ } ]
+ },
+ "EDITED" : {
+ "EDITED" : [ {
+ "type" : "EDITEDArray",
+ "EDITED" : [ null ]
+ } ]
+ },
+ "INPUTED" : {
+ "INPUTED" : [ {
+ "type" : "INPUTEDArray",
+ "INPUTED" : [ null ]
+ } ]
+ }
+ }
+ }, {
+ "variableType" : "CALCULATED",
+ "type" : "VariableType",
+ "name" : "FILTER_RESULT_NB",
+ "expression" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "inFilter" : "false"
+ }, {
+ "variableType" : "CALCULATED",
+ "type" : "VariableType",
+ "name" : "FILTER_RESULT_PRENOM",
+ "expression" : {
+ "value" : "true",
+ "type" : "VTL"
+ },
+ "shapeFrom" : "PRENOM",
+ "inFilter" : "false"
+ }, {
+ "variableType" : "CALCULATED",
+ "type" : "VariableType",
+ "name" : "FILTER_RESULT_LIENS",
+ "expression" : {
+ "value" : "xAxis <> yAxis",
+ "type" : "VTL"
+ },
+ "inFilter" : "false"
+ }, {
+ "variableType" : "CALCULATED",
+ "type" : "VariableType",
+ "name" : "xAxis",
+ "expression" : {
+ "value" : "PRENOM",
+ "type" : "VTL"
+ },
+ "bindingDependencies" : [ "PRENOM" ],
+ "shapeFrom" : "PRENOM",
+ "inFilter" : "true"
+ }, {
+ "variableType" : "CALCULATED",
+ "type" : "VariableType",
+ "name" : "yAxis",
+ "expression" : {
+ "value" : "PRENOM",
+ "type" : "VTL"
+ },
+ "bindingDependencies" : [ "PRENOM" ],
+ "shapeFrom" : "PRENOM",
+ "inFilter" : "true"
+ } ],
+ "cleaning" : {
+ },
+ "resizing" : {
+ "NB" : [ {
+ "size" : "nvl(NB, 1)",
+ "variables" : "PRENOM",
+ "value" : "\n "
+ } ],
+ "PRENOM" : [ {
+ "sizeForLinksVariables" : "count(PRENOM)",
+ "sizeForLinksVariables" : "count(PRENOM)",
+ "linksVariables" : "LIENS",
+ "value" : "\n "
+ } ]
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/pairwise/pairwise-flat.xml b/src/test/resources/pairwise/pairwise-flat.xml
new file mode 100644
index 00000000..d0e5a40d
--- /dev/null
+++ b/src/test/resources/pairwise/pairwise-flat.xml
@@ -0,0 +1,622 @@
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+ not(not(isnull(NB)) and (1>NB or 10<NB))
+ VTL
+
+
+ " La valeur doit être comprise entre 1 et 10."
+ VTL|MD
+
+
+
+
+ not(not(isnull(NB)) and round(NB,0)<>NB)
+ VTL
+
+
+ "Le nombre doit comporter au maximum 0 chiffre(s) après la virgule."
+ VTL|MD
+
+
+
+
+
+
+
+ NB
+
+
+
+
+
+ nvl(NB, 1)
+ VTL
+
+
+ nvl(NB, 1)
+ VTL
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+ NB
+ PRENOM
+ NB
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ NB
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ PRENOM
+ NB
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ LIENS
+
+ count(PRENOM)
+ VTL
+
+
+ count(PRENOM)
+ VTL
+
+
+
+
+ 1
+
+
+
+ 3
+
+
+
+ 2
+
+
+
+ 4
+
+
+
+ 6
+
+
+
+ 5
+
+
+
+ 8
+
+
+
+ 7
+
+
+
+ 10
+
+
+
+ 9
+
+
+
+ 13
+
+
+
+ 12
+
+
+
+ 11
+
+
+
+ null
+
+
+
+ null
+
+
+
+ 16
+
+
+
+ 17
+
+
+
+ 18
+
+
+
+
+
+ xAxis <> yAxis
+ VTL
+
+ LIENS
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+ 7
+
+
+
+ 8
+
+
+
+ 9
+
+
+
+ 10
+
+
+
+ 11
+
+
+
+ 12
+
+
+
+ 13
+
+
+
+ 14
+
+
+
+ 15
+
+
+
+ 16
+
+
+
+ 17
+
+
+
+
+
+
+
+
+ COMMENT_QE
+
+
+
+
+
+
+
+
+
+
+ NB
+
+
+
+
+
+
+
+
+
+ PRENOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LIENS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FILTER_RESULT_NB
+
+ true
+ VTL
+
+ false
+
+
+ FILTER_RESULT_PRENOM
+
+ true
+ VTL
+
+ PRENOM
+ false
+
+
+ FILTER_RESULT_LIENS
+
+ xAxis <> yAxis
+ VTL
+
+ false
+
+
+ xAxis
+
+ PRENOM
+ VTL
+
+ PRENOM
+ PRENOM
+ true
+
+
+ yAxis
+
+ PRENOM
+ VTL
+
+ PRENOM
+ PRENOM
+ true
+
+
+
+
+ nvl(NB, 1)
+ PRENOM
+
+
+ count(PRENOM)
+ count(PRENOM)
+ LIENS
+
+
+
diff --git a/src/test/resources/pairwise/pairwise-hierarchical-test.xml b/src/test/resources/pairwise/pairwise-hierarchical-test.xml
new file mode 100644
index 00000000..603e8ac4
--- /dev/null
+++ b/src/test/resources/pairwise/pairwise-hierarchical-test.xml
@@ -0,0 +1,622 @@
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+ not(not(isnull(NB)) and (1>NB or 10<NB))
+ VTL
+
+
+ " La valeur doit être comprise entre 1 et 10."
+ VTL|MD
+
+
+
+
+ not(not(isnull(NB)) and round(NB,0)<>NB)
+ VTL
+
+
+ "Le nombre doit comporter au maximum 0 chiffre(s) après la virgule."
+ VTL|MD
+
+
+
+
+
+
+
+ NB
+
+
+
+
+
+ nvl(NB, 1)
+ VTL
+
+
+ nvl(NB, 1)
+ VTL
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+ NB
+ PRENOM
+ NB
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ NB
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ PRENOM
+ NB
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ LIENS
+
+ count(PRENOM)
+ VTL
+
+
+ count(PRENOM)
+ VTL
+
+
+
+
+ 1
+
+
+
+ 3
+
+
+
+ 2
+
+
+
+ 4
+
+
+
+ 6
+
+
+
+ 5
+
+
+
+ 8
+
+
+
+ 7
+
+
+
+ 10
+
+
+
+ 9
+
+
+
+ 13
+
+
+
+ 12
+
+
+
+ 11
+
+
+
+ null
+
+
+
+ null
+
+
+
+ 16
+
+
+
+ 17
+
+
+
+ 18
+
+
+
+
+
+ xAxis <> yAxis
+ VTL
+
+ LIENS
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+ 7
+
+
+
+ 8
+
+
+
+ 9
+
+
+
+ 10
+
+
+
+ 11
+
+
+
+ 12
+
+
+
+ 13
+
+
+
+ 14
+
+
+
+ 15
+
+
+
+ 16
+
+
+
+ 17
+
+
+
+
+
+
+
+
+
+ COMMENT_QE
+
+
+
+
+
+
+
+
+
+
+ NB
+
+
+
+
+
+
+
+
+
+ PRENOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LIENS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FILTER_RESULT_NB
+
+ true
+ VTL
+
+ false
+
+
+ FILTER_RESULT_PRENOM
+
+ true
+ VTL
+
+ PRENOM
+ false
+
+
+ FILTER_RESULT_LIENS
+
+ xAxis <> yAxis
+ VTL
+
+ false
+
+
+ xAxis
+
+ PRENOM
+ VTL
+
+ PRENOM
+ PRENOM
+ true
+
+
+ yAxis
+
+ PRENOM
+ VTL
+
+ PRENOM
+ PRENOM
+ true
+
+
+
+
+ nvl(NB, 1)
+ PRENOM
+
+
+ count(PRENOM)
+ count(PRENOM)
+ LIENS
+
+
+
diff --git a/src/test/resources/pairwise/resizing-issue/lb3ei722-lunatic-expected.json b/src/test/resources/pairwise/resizing-issue/lb3ei722-lunatic-expected.json
new file mode 100644
index 00000000..98295d71
--- /dev/null
+++ b/src/test/resources/pairwise/resizing-issue/lb3ei722-lunatic-expected.json
@@ -0,0 +1,649 @@
+
+ { "id" : "lb3ei722",
+ "modele" : "TESTSURSUM",
+ "enoCoreVersion" : "2.4.1",
+ "lunaticModelVersion" : "2.3.1",
+ "generatingDate" : "25-05-2023 14:42:02",
+ "missing" : false,
+ "pagination" : "question",
+ "maxPage" : "10",
+ "label" :
+ { "value" : "QNONREG - sum, min dans une boucle et sur controle prénom et test filtre occurrence",
+ "type" : "VTL|MD" },
+ "components" :
+ [
+ { "id" : "ksyjs7vy",
+ "componentType" : "Sequence",
+ "page" : "1",
+ "label" :
+ { "value" : "\"I - \" || \"S0\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyjs7vy",
+ "page" : "1",
+ "label" :
+ { "value" : "\"I - \" || \"S0\"",
+ "type" : "VTL|MD" } } } },
+
+ { "id" : "kze792d8",
+ "componentType" : "InputNumber",
+ "mandatory" : false,
+ "page" : "2",
+ "min" : 0,
+ "max" : 10,
+ "decimals" : 0,
+ "label" :
+ { "value" : "\"➡ \" || \"NB\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "controls" :
+ [
+ { "id" : "kze792d8-format-borne-inf-sup",
+ "typeOfControl" : "FORMAT",
+ "criticality" : "ERROR",
+ "control" :
+ { "value" : "not(not(isnull(NB)) and (0>NB or 10NB)",
+ "type" : "VTL" },
+ "errorMessage" :
+ { "value" : "\"Le nombre doit comporter au maximum 0 chiffre(s) après la virgule.\"",
+ "type" : "VTL|MD" } } ],
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyjs7vy",
+ "page" : "1",
+ "label" :
+ { "value" : "\"I - \" || \"S0\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "NB" ],
+ "response" :
+ { "name" : "NB" } },
+
+ { "id" : "ksykfdm9",
+ "componentType" : "Loop",
+ "page" : "3",
+ "depth" : 1,
+ "paginatedLoop" : false,
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyjs7vy",
+ "page" : "1",
+ "label" :
+ { "value" : "\"I - \" || \"S0\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "NB",
+ "PRENOM" ],
+ "loopDependencies" :
+ [ "NB" ],
+ "lines" :
+ { "min" :
+ { "value" : "cast(NB,integer)",
+ "type" : "VTL" },
+ "max" :
+ { "value" : "cast(NB,integer)",
+ "type" : "VTL" } },
+ "components" :
+ [
+ { "id" : "ksynhpl3",
+ "componentType" : "Subsequence",
+ "page" : "3",
+ "goToPage" : "3",
+ "label" :
+ { "value" : "\"Habitants\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyjs7vy",
+ "page" : "1",
+ "label" :
+ { "value" : "\"I - \" || \"S0\"",
+ "type" : "VTL|MD" } },
+ "subSequence" :
+ { "id" : "ksynhpl3",
+ "page" : "3",
+ "label" :
+ { "value" : "\"Habitants\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "NB" ] },
+
+ { "id" : "ksyjvi40",
+ "componentType" : "Input",
+ "mandatory" : false,
+ "page" : "3",
+ "maxLength" : 249,
+ "label" :
+ { "value" : "\"➡ \" || \"prénom\"",
+ "type" : "VTL|MD" },
+ "declarations" :
+ [
+ { "id" : "ksyjvi40-l7uj49ok",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"Tester Prénom vide et Prénom = A\"",
+ "type" : "VTL|MD" } } ],
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "controls" :
+ [
+ { "id" : "ksyjvi40-CI-0",
+ "typeOfControl" : "CONSISTENCY",
+ "criticality" : "WARN",
+ "control" :
+ { "value" : "not(nvl(PRENOM,\"\")=\"\")",
+ "type" : "VTL" },
+ "errorMessage" :
+ { "value" : "\"Prenom est vide - controle nvl\"",
+ "type" : "VTL|MD" },
+ "bindingDependencies" :
+ [ "PRENOM" ] },
+
+ { "id" : "ksyjvi40-CI-1",
+ "typeOfControl" : "CONSISTENCY",
+ "criticality" : "WARN",
+ "control" :
+ { "value" : "not(PRENOM = \"A\")",
+ "type" : "VTL" },
+ "errorMessage" :
+ { "value" : "\"PRénom vaut A\"",
+ "type" : "VTL|MD" },
+ "bindingDependencies" :
+ [ "PRENOM" ] } ],
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyjs7vy",
+ "page" : "1",
+ "label" :
+ { "value" : "\"I - \" || \"S0\"",
+ "type" : "VTL|MD" } },
+ "subSequence" :
+ { "id" : "ksynhpl3",
+ "page" : "3",
+ "label" :
+ { "value" : "\"Habitants\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "PRENOM",
+ "NB" ],
+ "response" :
+ { "name" : "PRENOM" } } ] },
+
+ { "id" : "ksyniqzx",
+ "componentType" : "Sequence",
+ "page" : "4",
+ "label" :
+ { "value" : "\"II - \" || \"S1\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyniqzx",
+ "page" : "4",
+ "label" :
+ { "value" : "\"II - \" || \"S1\"",
+ "type" : "VTL|MD" } } } },
+
+ { "id" : "ksynkaoo",
+ "componentType" : "Loop",
+ "page" : "5",
+ "maxPage" : "1",
+ "depth" : 1,
+ "paginatedLoop" : true,
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyniqzx",
+ "page" : "4",
+ "label" :
+ { "value" : "\"II - \" || \"S1\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "AGE",
+ "IND_MAJEUR",
+ "PRENOM" ],
+ "loopDependencies" :
+ [ "PRENOM" ],
+ "components" :
+ [
+ { "id" : "ksyjxw3a",
+ "componentType" : "Subsequence",
+ "goToPage" : "5.1",
+ "label" :
+ { "value" : "\"Les ages\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyniqzx",
+ "page" : "4",
+ "label" :
+ { "value" : "\"II - \" || \"S1\"",
+ "type" : "VTL|MD" } },
+ "subSequence" :
+ { "id" : "ksyjxw3a",
+ "page" : "5.1",
+ "label" :
+ { "value" : "\"Les ages\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "PRENOM" ] },
+
+ { "id" : "ksyke448",
+ "componentType" : "InputNumber",
+ "mandatory" : false,
+ "page" : "5.1",
+ "min" : 0,
+ "max" : 100,
+ "decimals" : 0,
+ "label" :
+ { "value" : "\"➡ \" || \"Age de l’individu : \" || PRENOM",
+ "type" : "VTL|MD" },
+ "declarations" :
+ [
+ { "id" : "ksyke448-ktwsl4qu",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"AGE vaut : \" || cast(AGE,string)",
+ "type" : "VTL|MD" } },
+
+ { "id" : "ksyke448-l7g2enbf",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"IND_MAJEUR :\" || cast(IND_MAJEUR,string)",
+ "type" : "VTL|MD" } } ],
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "controls" :
+ [
+ { "id" : "ksyke448-format-borne-inf-sup",
+ "typeOfControl" : "FORMAT",
+ "criticality" : "ERROR",
+ "control" :
+ { "value" : "not(not(isnull(AGE)) and (0>AGE or 100AGE)",
+ "type" : "VTL" },
+ "errorMessage" :
+ { "value" : "\"Le nombre doit comporter au maximum 0 chiffre(s) après la virgule.\"",
+ "type" : "VTL|MD" } },
+
+ { "id" : "ksyke448-CI-0",
+ "typeOfControl" : "CONSISTENCY",
+ "criticality" : "WARN",
+ "control" :
+ { "value" : "not(isnull(AGE))",
+ "type" : "VTL" },
+ "errorMessage" :
+ { "value" : "\"Age est vide\"",
+ "type" : "VTL|MD" },
+ "bindingDependencies" :
+ [ "AGE" ] } ],
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyniqzx",
+ "page" : "4",
+ "label" :
+ { "value" : "\"II - \" || \"S1\"",
+ "type" : "VTL|MD" } },
+ "subSequence" :
+ { "id" : "ksyjxw3a",
+ "page" : "5.1",
+ "label" :
+ { "value" : "\"Les ages\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "AGE",
+ "IND_MAJEUR",
+ "PRENOM" ],
+ "response" :
+ { "name" : "AGE" } } ],
+ "iterations" :
+ { "value" : "count(PRENOM)",
+ "type" : "VTL" } },
+
+ { "id" : "ku2pnlmr",
+ "componentType" : "Subsequence",
+ "page" : "6",
+ "goToPage" : "6",
+ "label" :
+ { "value" : "\"Affichage de qq var\"",
+ "type" : "VTL|MD" },
+ "declarations" :
+ [
+ { "id" : "ku2pnlmr-l7t4dzz2",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"Affichage du nb de majeurs : \" || cast(SUM_MAJEUR,string)",
+ "type" : "VTL|MD" } },
+
+ { "id" : "ku2pnlmr-l806u4c8",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"Affichage du somme age : \" || cast(SUM_AGE,string)",
+ "type" : "VTL|MD" } },
+
+ { "id" : "ku2pnlmr-lg6mo14c",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"Affichage du min des ages sans cast: \" || cast(MIN_AGE,string)",
+ "type" : "VTL|MD" } } ],
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyniqzx",
+ "page" : "4",
+ "label" :
+ { "value" : "\"II - \" || \"S1\"",
+ "type" : "VTL|MD" } },
+ "subSequence" :
+ { "id" : "ku2pnlmr",
+ "page" : "6",
+ "label" :
+ { "value" : "\"Affichage de qq var\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "SUM_MAJEUR",
+ "SUM_AGE",
+ "MIN_AGE" ] },
+
+ { "id" : "ku2pxugf",
+ "componentType" : "Input",
+ "mandatory" : false,
+ "page" : "7",
+ "maxLength" : 249,
+ "label" :
+ { "value" : "\"➡ \" || \"divers\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "(SUM_MAJEUR > 0)",
+ "type" : "VTL",
+ "bindingDependencies" :
+ [ "SUM_MAJEUR",
+ "IND_MAJEUR",
+ "AGE" ] },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "ksyniqzx",
+ "page" : "4",
+ "label" :
+ { "value" : "\"II - \" || \"S1\"",
+ "type" : "VTL|MD" } },
+ "subSequence" :
+ { "id" : "ku2pnlmr",
+ "page" : "6",
+ "label" :
+ { "value" : "\"Affichage de qq var\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "DIVERS" ],
+ "response" :
+ { "name" : "DIVERS" } },
+
+ { "id" : "l7yz0fe5",
+ "componentType" : "Sequence",
+ "page" : "8",
+ "label" :
+ { "value" : "\"III - \" || \"S3\"",
+ "type" : "VTL|MD" },
+ "declarations" :
+ [
+ { "id" : "l7yz0fe5-l7yyye9y",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"Affichage de la somme des ages : \" || cast(SUM_AGE,string)",
+ "type" : "VTL|MD" } },
+
+ { "id" : "l7yz0fe5-l7yz5mgk",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"Affichage du nb de majeurs : \" || cast(SUM_MAJEUR,string)",
+ "type" : "VTL|MD" } },
+
+ { "id" : "l7yz0fe5-l7yyrp0q",
+ "declarationType" : "HELP",
+ "position" : "AFTER_QUESTION_TEXT",
+ "label" :
+ { "value" : "\"Affichage du min des ages : \" || cast(MIN_AGE,string)",
+ "type" : "VTL|MD" } } ],
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "l7yz0fe5",
+ "page" : "8",
+ "label" :
+ { "value" : "\"III - \" || \"S3\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "SUM_AGE",
+ "SUM_MAJEUR",
+ "MIN_AGE" ] },
+
+ { "id" : "COMMENT-SEQ",
+ "componentType" : "Sequence",
+ "page" : "9",
+ "label" :
+ { "value" : "\"Commentaire\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "COMMENT-SEQ",
+ "page" : "9",
+ "label" :
+ { "value" : "\"Commentaire\"",
+ "type" : "VTL|MD" } } } },
+
+ { "id" : "COMMENT-QUESTION",
+ "componentType" : "Textarea",
+ "mandatory" : false,
+ "page" : "10",
+ "maxLength" : 2000,
+ "label" :
+ { "value" : "\"Avez-vous des remarques concernant l'enquête ou des commentaires ?\"",
+ "type" : "VTL|MD" },
+ "conditionFilter" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "hierarchy" :
+ { "sequence" :
+ { "id" : "COMMENT-SEQ",
+ "page" : "9",
+ "label" :
+ { "value" : "\"Commentaire\"",
+ "type" : "VTL|MD" } } },
+ "bindingDependencies" :
+ [ "COMMENT_QE" ],
+ "response" :
+ { "name" : "COMMENT_QE" } } ],
+ "variables" :
+ [
+ { "variableType" : "COLLECTED",
+ "name" : "COMMENT_QE",
+ "values" :
+ { "PREVIOUS" : null,
+ "COLLECTED" : null,
+ "FORCED" : null,
+ "EDITED" : null,
+ "INPUTED" : null } },
+
+ { "variableType" : "COLLECTED",
+ "name" : "NB",
+ "values" :
+ { "PREVIOUS" : null,
+ "COLLECTED" : null,
+ "FORCED" : null,
+ "EDITED" : null,
+ "INPUTED" : null } },
+
+ { "variableType" : "COLLECTED",
+ "name" : "PRENOM",
+ "values" :
+ { "PREVIOUS" :
+ [ null ],
+ "COLLECTED" :
+ [ null ],
+ "FORCED" :
+ [ null ],
+ "EDITED" :
+ [ null ],
+ "INPUTED" :
+ [ null ] } },
+
+ { "variableType" : "COLLECTED",
+ "name" : "AGE",
+ "values" :
+ { "PREVIOUS" :
+ [ null ],
+ "COLLECTED" :
+ [ null ],
+ "FORCED" :
+ [ null ],
+ "EDITED" :
+ [ null ],
+ "INPUTED" :
+ [ null ] } },
+
+ { "variableType" : "COLLECTED",
+ "name" : "DIVERS",
+ "values" :
+ { "PREVIOUS" : null,
+ "COLLECTED" : null,
+ "FORCED" : null,
+ "EDITED" : null,
+ "INPUTED" : null } },
+
+ { "variableType" : "CALCULATED",
+ "name" : "FILTER_RESULT_NB",
+ "expression" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "inFilter" : "false" },
+
+ { "variableType" : "CALCULATED",
+ "name" : "FILTER_RESULT_PRENOM",
+ "expression" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "shapeFrom" : "PRENOM",
+ "inFilter" : "false" },
+
+ { "variableType" : "CALCULATED",
+ "name" : "IND_MAJEUR",
+ "expression" :
+ { "value" : "if nvl(AGE,0) > 17 then 1 else 0",
+ "type" : "VTL" },
+ "bindingDependencies" :
+ [ "AGE" ],
+ "shapeFrom" : "PRENOM",
+ "inFilter" : "true" },
+
+ { "variableType" : "CALCULATED",
+ "name" : "FILTER_RESULT_AGE",
+ "expression" :
+ { "value" : "true",
+ "type" : "VTL" },
+ "shapeFrom" : "AGE",
+ "inFilter" : "false" },
+
+ { "variableType" : "CALCULATED",
+ "name" : "FILTER_RESULT_DIVERS",
+ "expression" :
+ { "value" : "(SUM_MAJEUR > 0)",
+ "type" : "VTL" },
+ "bindingDependencies" :
+ [ "SUM_MAJEUR" ],
+ "inFilter" : "false" },
+
+ { "variableType" : "CALCULATED",
+ "name" : "SUM_MAJEUR",
+ "expression" :
+ { "value" : "sum(IND_MAJEUR)",
+ "type" : "VTL" },
+ "bindingDependencies" :
+ [ "IND_MAJEUR",
+ "AGE" ],
+ "inFilter" : "true" },
+
+ { "variableType" : "CALCULATED",
+ "name" : "SUM_AGE",
+ "expression" :
+ { "value" : "sum(AGE)",
+ "type" : "VTL" },
+ "bindingDependencies" :
+ [ "AGE" ],
+ "inFilter" : "false" },
+
+ { "variableType" : "CALCULATED",
+ "name" : "MIN_AGE",
+ "expression" :
+ { "value" : "min(AGE)",
+ "type" : "VTL" },
+ "bindingDependencies" :
+ [ "AGE" ],
+ "inFilter" : "false" } ],
+ "cleaning" :
+ { "SUM_MAJEUR" :
+ { "DIVERS" : "(SUM_MAJEUR > 0)" },
+ "IND_MAJEUR" :
+ { "DIVERS" : "(SUM_MAJEUR > 0)" },
+ "AGE" :
+ { "DIVERS" : "(SUM_MAJEUR > 0)" } },
+ "resizing" :
+ { "NB" :
+ { "size" : "cast(NB,integer)",
+ "variables" :
+ [ "PRENOM",
+ "AGE" ] } } }
\ No newline at end of file
diff --git a/src/test/resources/pairwise/resizing-issue/lb3ei722-lunatic-hierarchical.xml b/src/test/resources/pairwise/resizing-issue/lb3ei722-lunatic-hierarchical.xml
new file mode 100644
index 00000000..22d3ce25
--- /dev/null
+++ b/src/test/resources/pairwise/resizing-issue/lb3ei722-lunatic-hierarchical.xml
@@ -0,0 +1,717 @@
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+ not(not(isnull(NB)) and (0>NB or 10<NB))
+ VTL
+
+
+ " La valeur doit être comprise entre 0 et 10."
+ VTL|MD
+
+
+
+
+ not(not(isnull(NB)) and round(NB,0)<>NB)
+ VTL
+
+
+ "Le nombre doit comporter au maximum 0 chiffre(s) après la virgule."
+ VTL|MD
+
+
+
+
+
+
+
+ NB
+
+
+
+
+
+ cast(NB,integer)
+ VTL
+
+
+ cast(NB,integer)
+ VTL
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+ NB
+ PRENOM
+ NB
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ NB
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+ not(nvl(PRENOM,"")="")
+ VTL
+
+
+ "Prenom est vide - controle nvl"
+ VTL|MD
+
+ PRENOM
+
+
+
+ not(PRENOM = "A")
+ VTL
+
+
+ "PRénom vaut A"
+ VTL|MD
+
+ PRENOM
+
+
+
+
+
+
+
+
+
+ PRENOM
+ NB
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+ count(PRENOM)
+ VTL
+
+
+ true
+ VTL
+
+
+
+
+
+
+ AGE
+ IND_MAJEUR
+ PRENOM
+ PRENOM
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ PRENOM
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+ not(not(isnull(AGE)) and (0>AGE or 100<AGE))
+ VTL
+
+
+ " La valeur doit être comprise entre 0 et 100."
+ VTL|MD
+
+
+
+
+ not(not(isnull(AGE)) and round(AGE,0)<>AGE)
+ VTL
+
+
+ "Le nombre doit comporter au maximum 0 chiffre(s) après la virgule."
+ VTL|MD
+
+
+
+
+ not(isnull(AGE))
+ VTL
+
+
+ "Age est vide"
+ VTL|MD
+
+ AGE
+
+
+
+
+
+
+
+
+
+ AGE
+ IND_MAJEUR
+ PRENOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+
+
+
+ SUM_MAJEUR
+ SUM_AGE
+ MIN_AGE
+
+
+
+ (SUM_MAJEUR > 0)
+ VTL
+ SUM_MAJEUR
+ IND_MAJEUR
+ AGE
+
+
+
+
+
+
+
+
+
+ DIVERS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ VTL
+
+
+
+
+
+
+ SUM_AGE
+ SUM_MAJEUR
+ MIN_AGE
+
+
+
+ COMMENT_QE
+
+
+
+
+
+
+
+
+
+
+ NB
+
+
+
+
+
+
+
+
+
+ PRENOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AGE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DIVERS
+
+
+
+
+
+
+
+
+
+ FILTER_RESULT_NB
+
+ true
+ VTL
+
+ false
+
+
+ FILTER_RESULT_PRENOM
+
+ true
+ VTL
+
+ PRENOM
+ false
+
+
+ IND_MAJEUR
+
+ if nvl(AGE,0) > 17 then 1 else 0
+ VTL
+
+ AGE
+ PRENOM
+ true
+
+
+ FILTER_RESULT_AGE
+
+ true
+ VTL
+
+ AGE
+ false
+
+
+ FILTER_RESULT_DIVERS
+
+ (SUM_MAJEUR > 0)
+ VTL
+
+ SUM_MAJEUR
+ false
+
+
+ SUM_MAJEUR
+
+ sum(IND_MAJEUR)
+ VTL
+
+ IND_MAJEUR
+ AGE
+ true
+
+
+ SUM_AGE
+
+ sum(AGE)
+ VTL
+
+ AGE
+ false
+
+
+ MIN_AGE
+
+ min(AGE)
+ VTL
+
+ AGE
+ false
+
+
+
+ (SUM_MAJEUR > 0)
+
+
+ (SUM_MAJEUR > 0)
+
+
+ (SUM_MAJEUR > 0)
+
+
+
+
+ cast(NB,integer)
+ PRENOM
+ AGE
+
+
+