Skip to content

Commit

Permalink
fix: invalid cast in lunatic resizing pairwise processing (#765)
Browse files Browse the repository at this point in the history
* test: failing questionnaire

* fix(variables): cast after control of calculated variable

* style: unnecessary import

* refactor(loop scope): throw exceptions in invalid cases

* test: bug should be resolved now

This DDI has been generated with previous Eno legacy version. To be re-generated with the new DDI loop specification.

* test: DDI with up-to-date modeling

* test: add pogues source for ljr4jm9a

* test: update functional test exception case

* chore: bump version
  • Loading branch information
nsenave authored Oct 23, 2023
1 parent 099d11d commit 246de9b
Show file tree
Hide file tree
Showing 8 changed files with 56,063 additions and 24 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {

allprojects {
group = 'fr.insee.eno'
version = '3.11.1-SNAPSHOT'
version = '3.11.2-SNAPSHOT'
sourceCompatibility = '17'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import fr.insee.eno.core.exceptions.technical.MappingException;
import fr.insee.eno.core.model.EnoObject;
import fr.insee.eno.core.parameter.Format;
import fr.insee.eno.core.processing.in.steps.ddi.DDIResolveSequencesStructure;
import fr.insee.eno.core.reference.DDIIndex;
import lombok.*;
import reusable33.ReferenceType;
Expand All @@ -16,7 +15,7 @@
* The <Code>ItemReference</Code> objects are only use to hold information derived from DDI,
* these are resolved into <Code>StructureItemReference</Code> objects in a DDI processing.
* @see StructureItemReference
* @see DDIResolveSequencesStructure */
* @see fr.insee.eno.core.processing.in.steps.ddi.DDIResolveSequencesStructure */
@Getter
@Setter
@NoArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.insee.eno.core.processing.in.steps.ddi;

import fr.insee.eno.core.exceptions.technical.MappingException;
import fr.insee.eno.core.model.EnoQuestionnaire;
import fr.insee.eno.core.model.navigation.Filter;
import fr.insee.eno.core.model.navigation.Loop;
Expand Down Expand Up @@ -46,26 +47,17 @@ private void resolveScopeFrom(Filter filter, Loop loop) {
}
}

/**
* Iterates on the sub-loop item references to resolve the loop object scope.
* @param subLoop A loop object (unchanged), its "loop items" are read.
* @param loop The loop whose scope is being resolved.
* */
private void resolveScopeFrom(Loop subLoop, Loop loop) {
for (ItemReference loopItem : subLoop.getLoopItems()) {
resolveStructure(loop, loopItem);
}
}

private void resolveStructure(Loop loop, ItemReference itemReference) {
switch (itemReference.getType()) {
case SEQUENCE, SUBSEQUENCE, QUESTION ->
case SEQUENCE, SUBSEQUENCE ->
loop.getLoopScope().add(StructureItemReference.from(itemReference));
case LOOP -> { // (nested loops)
log.warn("Nested loops is not completely supported for now."); // (supported here but not everywhere)
Loop subLoop = (Loop) enoQuestionnaire.get(itemReference.getId());
resolveScopeFrom(subLoop, loop);
}
case QUESTION ->
throw new MappingException(String.format(
"%s has the question of id '%s' in its scope. " +
"The scope of a loop should be either sequence(s) or subsequence(s).",
loop, itemReference.getId()));
case LOOP ->
throw new UnsupportedOperationException("Nested loops are not supported.");
case FILTER -> { // (filter inside loop)
Filter filter = (Filter) enoQuestionnaire.get(itemReference.getId());
resolveScopeFrom(filter, loop);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ private List<String> findResizingVariablesForPairwise(PairwiseLinks pairwiseLink
throw new LunaticPairwiseException(String.format(
"Source variable '%s' of pairwise component '%s' cannot be found in questionnaire variables.",
pairwiseSourceVariableName, pairwiseLinks));
VariableType pairwiseSourceVariable = (VariableType) correspondingVariable.get();
// If it not a calculated, simply return the variable name
if (! VariableTypeEnum.CALCULATED.equals(correspondingVariable.get().getVariableType()))
return List.of(pairwiseSourceVariableName);
// Otherwise return its binding dependencies (without the calculated variable)
VariableType pairwiseSourceVariable = (VariableType) correspondingVariable.get();
return pairwiseSourceVariable.getBindingDependencies().stream()
.filter(variableName -> !pairwiseSourceVariableName.equals(variableName))
.toList();
Expand Down
1 change: 1 addition & 0 deletions eno-core/src/test/java/fr/insee/eno/core/DDIToEnoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class DDIToEnoTest {
"lhpz68wp", // designed to test question grouping
"li49zxju", // 'vpp' survey
"lmyjrqbb", // several linked loops
"ljr4jm9a", // 'quality of life' survey
})
@DisplayName("Large questionnaires, DDI to Eno, transformation should succeed")
void transformQuestionnaire_nonNullOutput(String questionnaireId) throws DDIParsingException {
Expand Down
21 changes: 18 additions & 3 deletions eno-core/src/test/java/fr/insee/eno/core/DDIToLunaticTest.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
package fr.insee.eno.core;

import fr.insee.eno.core.exceptions.business.DDIParsingException;
import fr.insee.eno.core.exceptions.business.LunaticLogicException;
import fr.insee.eno.core.parameter.EnoParameters;
import fr.insee.eno.core.parameter.EnoParameters.Context;
import fr.insee.eno.core.parameter.EnoParameters.ModeParameter;
import fr.insee.eno.core.parameter.Format;
import fr.insee.lunatic.model.flat.ComponentTypeEnum;
import fr.insee.lunatic.model.flat.Loop;
import fr.insee.lunatic.model.flat.Questionnaire;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.io.InputStream;
import java.util.List;

import static fr.insee.lunatic.model.flat.ComponentTypeEnum.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.*;

/**
* Functional tests for the DDI to Lunatic transformation.
Expand Down Expand Up @@ -45,6 +49,17 @@ void transformQuestionnaire_nonNullOutput(String questionnaireId) throws DDIPars
assertNotNull(lunaticQuestionnaire);
}

// TODO: confirm the business rule here between generating incomplete resizing or throw an exception
@Test
void ddiLinkedLoopAndPairwiseWithSameSizeVariable_shouldThrowException() {
// Given
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(
"functional/ddi/ddi-ljr4jm9a.xml");
EnoParameters enoParameters = EnoParameters.of(Context.DEFAULT, ModeParameter.CAWI, Format.LUNATIC);
// When + Then
assertThrows(LunaticLogicException.class, () -> DDIToLunatic.transform(inputStream, enoParameters));
}

@Nested
@DisplayName("DDI to Lunatic, functional test with 'l20g2ba7'")
class FunctionalTest1 {
Expand Down
Loading

0 comments on commit 246de9b

Please sign in to comment.