Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: end question labels #774

Merged
merged 7 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.6-SNAPSHOT'
version = '3.11.7-SNAPSHOT'
sourceCompatibility = '17'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,21 @@ public void applyProcessing(EnoQuestionnaire enoQuestionnaire) {
EnoIndex enoIndex = enoQuestionnaire.getIndex();
assert enoIndex != null;
EnoCatalog enoCatalog = new EnoCatalog(enoQuestionnaire);

//
ProcessingPipeline<EnoQuestionnaire> processingPipeline = new ProcessingPipeline<>();
processingPipeline.start(enoQuestionnaire)
.thenIf(parameters.isIdentificationQuestion(), new EnoAddIdentificationSection())
.thenIf(parameters.isResponseTimeQuestion(), new EnoAddResponseTimeSection())
.thenIf(parameters.isCommentSection(), new EnoAddCommentSection())
.then(new EnoModeSelection(parameters.getSelectedModes(), enoCatalog))
.thenIf(parameters.isSequenceNumbering(), new EnoAddNumberingInSequences(
parameters.getModeParameter()))
.then(new EnoAddPrefixInQuestionLabels(
parameters.isArrowCharInQuestions(), parameters.getQuestionNumberingMode(),
parameters.getModeParameter()))
parameters.getModeParameter()));
// This step will be re-used after for question numbering reasons
EnoAddPrefixInQuestionLabels prefixingStep = new EnoAddPrefixInQuestionLabels(
parameters.isArrowCharInQuestions(), parameters.getQuestionNumberingMode(),
parameters.getModeParameter());
processingPipeline.then(prefixingStep)
.thenIf(parameters.isResponseTimeQuestion(), new EnoAddResponseTimeSection(prefixingStep))
.thenIf(parameters.isCommentSection(), new EnoAddCommentSection(prefixingStep))
.then(new EnoInsertComponentFilters())
.then(new EnoResolveBindingReferences());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public class EnoAddCommentSection implements ProcessingStep<EnoQuestionnaire> {
public static final boolean COMMENT_QUESTION_MANDATORY = false;
public static final int COMMENT_QUESTION_LENGTH = 2000;

private final EnoAddPrefixInQuestionLabels prefixingStep;

public EnoAddCommentSection(EnoAddPrefixInQuestionLabels prefixingStep) {
this.prefixingStep = prefixingStep;
}

public void apply(EnoQuestionnaire enoQuestionnaire) {
//
EnoIndex enoIndex = enoQuestionnaire.getIndex();
Expand All @@ -49,6 +55,7 @@ public void apply(EnoQuestionnaire enoQuestionnaire) {
commentQuestion.setName(COMMENT_VARIABLE_NAME);
commentQuestion.setLabel(new DynamicLabel());
commentQuestion.getLabel().setValue(COMMENT_QUESTION_LABEL);
prefixingStep.addPrefixInQuestionLabel(commentQuestion);
commentQuestion.setMandatory(COMMENT_QUESTION_MANDATORY);
commentQuestion.setLengthType(TextQuestion.qualifyLength(COMMENT_QUESTION_LENGTH));
commentQuestion.setMaxLength(BigInteger.valueOf(COMMENT_QUESTION_LENGTH));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class EnoAddPrefixInQuestionLabels implements ProcessingStep<EnoQuestionn
private final QuestionNumberingMode questionNumberingMode;
private final EnoParameters.ModeParameter modeParameter;

private int questionNumber;

public EnoAddPrefixInQuestionLabels(boolean arrowCharInQuestions, QuestionNumberingMode questionNumberingMode,
EnoParameters.ModeParameter modeParameter) {
this.arrowCharInQuestions = arrowCharInQuestions;
Expand All @@ -35,24 +37,21 @@ public void apply(EnoQuestionnaire enoQuestionnaire) {
//
assert enoQuestionnaire.getIndex() != null;
//
if (QuestionNumberingMode.NONE.equals(questionNumberingMode) && !arrowCharInQuestions) {
if (prefixingDisabled())
return;
}
//
int questionNumber = 1;
questionNumber = 1;
for (Sequence sequence : enoQuestionnaire.getSequences()) {
for (String componentId : getSequenceComponentIds(sequence)) {
EnoComponent component = (EnoComponent) enoQuestionnaire.get(componentId);
if (component instanceof Subsequence subsequence) {
for (String questionId : getSequenceComponentIds(subsequence)) {
Question question = (Question) enoQuestionnaire.get(questionId);
addPrefixInQuestionLabel(question, questionNumber);
questionNumber ++;
addPrefixInQuestionLabel(question);
}
} else {
Question question = (Question) component;
addPrefixInQuestionLabel(question, questionNumber);
questionNumber ++;
addPrefixInQuestionLabel(question);
}
}
if (questionNumberingMode == QuestionNumberingMode.SEQUENCE) {
Expand All @@ -61,6 +60,10 @@ public void apply(EnoQuestionnaire enoQuestionnaire) {
}
}

private boolean prefixingDisabled() {
return QuestionNumberingMode.NONE.equals(questionNumberingMode) && !arrowCharInQuestions;
}

/**
* Returns the ordered list of component ids within the sequence or subsequence.
* @param sequence Sequence or subsequence object.
Expand All @@ -70,9 +73,12 @@ private List<String> getSequenceComponentIds(AbstractSequence sequence) {
return sequence.getSequenceStructure().stream().map(StructureItemReference::getId).toList();
}

private void addPrefixInQuestionLabel(Question question, int questionNumber) {
public void addPrefixInQuestionLabel(Question question) {
if (prefixingDisabled())
return;
DynamicLabel questionLabel = question.getLabel();
questionLabel.setValue(addPrefixInLabel(questionLabel.getValue(), questionNumber));
questionNumber ++;
}

private String addPrefixInLabel(String questionLabelValue, int questionNumber) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public class EnoAddResponseTimeSection implements ProcessingStep<EnoQuestionnair
public static final double RESPONSE_TIME_MINUTES_QUESTION_MAX_VALUE = 59;
public static final BigInteger RESPONSE_TIME_MINUTES_QUESTION_DECIMALS = BigInteger.ZERO;

private final EnoAddPrefixInQuestionLabels prefixingStep;

public EnoAddResponseTimeSection(EnoAddPrefixInQuestionLabels prefixingStep) {
this.prefixingStep = prefixingStep;
}

public void apply(EnoQuestionnaire enoQuestionnaire) {
//
EnoIndex enoIndex = enoQuestionnaire.getIndex();
Expand Down Expand Up @@ -68,6 +74,7 @@ public void apply(EnoQuestionnaire enoQuestionnaire) {
hoursQuestion.setName(HOURS_VARIABLE_NAME);
hoursQuestion.setLabel(new DynamicLabel());
hoursQuestion.getLabel().setValue(RESPONSE_TIME_QUESTION_LABEL);
prefixingStep.addPrefixInQuestionLabel(hoursQuestion);
hoursQuestion.setMandatory(RESPONSE_TIME_QUESTION_MANDATORY);
hoursQuestion.setMinValue(HOURS_QUESTION_MIN_VALUE);
hoursQuestion.setMaxValue(HOURS_QUESTION_MAX_VALUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public void applyProcessing(Questionnaire lunaticQuestionnaire, EnoQuestionnaire
.then(new LunaticAddResizing(enoQuestionnaire))
.then(new LunaticAddHierarchy())
.then(new LunaticAddPageNumbers(parameters.getLunaticPaginationMode()))
.then(new LunaticResponseTimeQuestionPagination())
.then(new LunaticAddCleaningVariables())
.thenIf(parameters.isControls(), new LunaticAddControlFormat())
.then(new LunaticReverseConsistencyControlLabel())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package fr.insee.eno.core.processing.out.steps.lunatic;

import fr.insee.eno.core.processing.ProcessingStep;
import fr.insee.eno.core.processing.common.steps.EnoAddResponseTimeSection;
import fr.insee.lunatic.model.flat.ComponentType;
import fr.insee.lunatic.model.flat.Questionnaire;

import java.util.Optional;

public class LunaticResponseTimeQuestionPagination implements ProcessingStep<Questionnaire> {

@Override
public void apply(Questionnaire lunaticQuestionnaire) {
Optional<ComponentType> hoursQuestionComponent = lunaticQuestionnaire.getComponents().stream()
.filter(component -> EnoAddResponseTimeSection.HOURS_QUESTION_ID.equals(component.getId()))
.findAny();
if (hoursQuestionComponent.isPresent()) {
String pageNumber = hoursQuestionComponent.get().getPage();
int hoursQuestionComponentIndex = lunaticQuestionnaire.getComponents().indexOf(hoursQuestionComponent.get());
// minutes question is just after the hours question
lunaticQuestionnaire.getComponents().get(hoursQuestionComponentIndex + 1).setPage(pageNumber);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,57 @@
import fr.insee.eno.core.DDIToLunatic;
import fr.insee.eno.core.exceptions.business.DDIParsingException;
import fr.insee.eno.core.model.EnoQuestionnaire;
import fr.insee.eno.core.model.label.DynamicLabel;
import fr.insee.eno.core.model.question.TextQuestion;
import fr.insee.eno.core.model.sequence.Sequence;
import fr.insee.eno.core.model.sequence.StructureItemReference;
import fr.insee.eno.core.parameter.EnoParameters;
import fr.insee.eno.core.parameter.Format;
import fr.insee.eno.core.reference.EnoIndex;
import fr.insee.lunatic.model.flat.Questionnaire;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class EnoAddCommentSectionTest {

@Test
void commentQuestionLabel_arrowAndNumberPrefix() {
// Given a questionnaire with one question
EnoQuestionnaire enoQuestionnaire = new EnoQuestionnaire();
enoQuestionnaire.setIndex(new EnoIndex());
Sequence sequence = new Sequence();
sequence.getSequenceStructure().add(
new StructureItemReference("question-id", StructureItemReference.StructureItemType.QUESTION));
TextQuestion question = new TextQuestion();
question.setId("question-id");
question.setLabel(new DynamicLabel());
question.getLabel().setValue("\"Foo label\"");
enoQuestionnaire.getIndex().put("question-id", question);
enoQuestionnaire.getSequences().add(sequence);
enoQuestionnaire.getSingleResponseQuestions().add(question);
//
EnoAddPrefixInQuestionLabels prefixingStep = new EnoAddPrefixInQuestionLabels(
true, EnoParameters.QuestionNumberingMode.ALL, EnoParameters.ModeParameter.PROCESS);
prefixingStep.apply(enoQuestionnaire);

// When
new EnoAddCommentSection(prefixingStep).apply(enoQuestionnaire);

// Then
Optional<TextQuestion> commentQuestion = enoQuestionnaire.getSingleResponseQuestions().stream()
.filter(TextQuestion.class::isInstance)
.map(TextQuestion.class::cast)
.filter(singleResponseQuestion -> EnoAddCommentSection.COMMENT_QUESTION_ID.equals(singleResponseQuestion.getId()))
.findAny();
assertTrue(commentQuestion.isPresent());
String expected = "\"➡ 2. \" || " + EnoAddCommentSection.COMMENT_QUESTION_LABEL;
assertEquals(expected, commentQuestion.get().getLabel().getValue());
}

@Test
void integrationTest() throws DDIParsingException {
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,93 @@
import fr.insee.eno.core.DDIToLunatic;
import fr.insee.eno.core.exceptions.business.DDIParsingException;
import fr.insee.eno.core.model.EnoQuestionnaire;
import fr.insee.eno.core.model.question.NumericQuestion;
import fr.insee.eno.core.model.sequence.Sequence;
import fr.insee.eno.core.parameter.EnoParameters;
import fr.insee.eno.core.parameter.Format;
import fr.insee.eno.core.reference.EnoIndex;
import fr.insee.lunatic.model.flat.Questionnaire;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class EnoAddResponseTimeSectionTest {

@Test
void hoursQuestionLabel_noPrefix() {
// Given
EnoQuestionnaire enoQuestionnaire = new EnoQuestionnaire();
enoQuestionnaire.setIndex(new EnoIndex());
EnoAddPrefixInQuestionLabels prefixingStep = new EnoAddPrefixInQuestionLabels(
false, EnoParameters.QuestionNumberingMode.NONE, EnoParameters.ModeParameter.PROCESS);
prefixingStep.apply(enoQuestionnaire);
EnoAddResponseTimeSection processing = new EnoAddResponseTimeSection(prefixingStep);
// When
processing.apply(enoQuestionnaire);
// Then
Optional<NumericQuestion> hoursQuestion = enoQuestionnaire.getSingleResponseQuestions().stream()
.filter(NumericQuestion.class::isInstance)
.map(NumericQuestion.class::cast)
.filter(singleResponseQuestion -> EnoAddResponseTimeSection.HOURS_QUESTION_ID.equals(singleResponseQuestion.getId()))
.findAny();
Optional<NumericQuestion> minutesQuestion = enoQuestionnaire.getSingleResponseQuestions().stream()
.filter(NumericQuestion.class::isInstance)
.map(NumericQuestion.class::cast)
.filter(singleResponseQuestion -> EnoAddResponseTimeSection.MINUTES_QUESTION_ID.equals(singleResponseQuestion.getId()))
.findAny();
assertTrue(hoursQuestion.isPresent());
assertTrue(minutesQuestion.isPresent());
assertEquals(EnoAddResponseTimeSection.RESPONSE_TIME_QUESTION_LABEL, hoursQuestion.get().getLabel().getValue());
assertEquals("", minutesQuestion.get().getLabel().getValue());
}

@Test
void hoursQuestionLabel_arrowPrefix() {
// Given
EnoQuestionnaire enoQuestionnaire = new EnoQuestionnaire();
enoQuestionnaire.setIndex(new EnoIndex());
EnoAddPrefixInQuestionLabels prefixingStep = new EnoAddPrefixInQuestionLabels(
true, EnoParameters.QuestionNumberingMode.NONE, EnoParameters.ModeParameter.PROCESS);
prefixingStep.apply(enoQuestionnaire);
EnoAddResponseTimeSection processing = new EnoAddResponseTimeSection(prefixingStep);
// When
processing.apply(enoQuestionnaire);
// Then
Optional<NumericQuestion> hoursQuestion = enoQuestionnaire.getSingleResponseQuestions().stream()
.filter(NumericQuestion.class::isInstance)
.map(NumericQuestion.class::cast)
.filter(singleResponseQuestion -> EnoAddResponseTimeSection.HOURS_QUESTION_ID.equals(singleResponseQuestion.getId()))
.findAny();
assertTrue(hoursQuestion.isPresent());
String expected = "\"➡ \" || " + EnoAddResponseTimeSection.RESPONSE_TIME_QUESTION_LABEL;
assertEquals(expected, hoursQuestion.get().getLabel().getValue());
}

@Test
void hoursQuestionLabel_arrowAndNumberPrefix() {
// Given
EnoQuestionnaire enoQuestionnaire = new EnoQuestionnaire();
enoQuestionnaire.setIndex(new EnoIndex());
EnoAddPrefixInQuestionLabels prefixingStep = new EnoAddPrefixInQuestionLabels(
true, EnoParameters.QuestionNumberingMode.SEQUENCE, EnoParameters.ModeParameter.PROCESS);
prefixingStep.apply(enoQuestionnaire);
EnoAddResponseTimeSection processing = new EnoAddResponseTimeSection(prefixingStep);
// When
processing.apply(enoQuestionnaire);
// Then
Optional<NumericQuestion> hoursQuestion = enoQuestionnaire.getSingleResponseQuestions().stream()
.filter(NumericQuestion.class::isInstance)
.map(NumericQuestion.class::cast)
.filter(singleResponseQuestion -> EnoAddResponseTimeSection.HOURS_QUESTION_ID.equals(singleResponseQuestion.getId()))
.findAny();
assertTrue(hoursQuestion.isPresent());
String expected = "\"➡ 1. \" || " + EnoAddResponseTimeSection.RESPONSE_TIME_QUESTION_LABEL;
assertEquals(expected, hoursQuestion.get().getLabel().getValue());
}

@Test
void integrationTest() throws DDIParsingException {
//
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package fr.insee.eno.core.processing.out.steps.lunatic;

import fr.insee.eno.core.mappers.LunaticMapper;
import fr.insee.eno.core.model.EnoQuestionnaire;
import fr.insee.eno.core.parameter.EnoParameters;
import fr.insee.eno.core.processing.common.steps.EnoAddPrefixInQuestionLabels;
import fr.insee.eno.core.processing.common.steps.EnoAddResponseTimeSection;
import fr.insee.eno.core.processing.out.steps.lunatic.pagination.LunaticAddPageNumbers;
import fr.insee.eno.core.reference.EnoIndex;
import fr.insee.lunatic.model.flat.ComponentType;
import fr.insee.lunatic.model.flat.Questionnaire;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;

class LunaticResponseTimeQuestionPaginationTest {

@Test
void questionPaginationMode_hoursAndMinutesQuestionShouldHaveTheSameNumber() {
// Given
EnoQuestionnaire enoQuestionnaire = new EnoQuestionnaire();
enoQuestionnaire.setIndex(new EnoIndex());
new EnoAddResponseTimeSection(new EnoAddPrefixInQuestionLabels(
true, EnoParameters.QuestionNumberingMode.NONE, EnoParameters.ModeParameter.CAWI))
.apply(enoQuestionnaire);
//
Questionnaire lunaticQuestionnaire = new Questionnaire();
LunaticMapper lunaticMapper = new LunaticMapper();
lunaticMapper.mapQuestionnaire(enoQuestionnaire, lunaticQuestionnaire);
//
new LunaticAddPageNumbers(EnoParameters.LunaticPaginationMode.QUESTION).apply(lunaticQuestionnaire);

// When
new LunaticResponseTimeQuestionPagination().apply(lunaticQuestionnaire);

// Then
Optional<ComponentType> hoursQuestionComponent = lunaticQuestionnaire.getComponents().stream()
.filter(component -> EnoAddResponseTimeSection.HOURS_QUESTION_ID.equals(component.getId()))
.findAny();
Optional<ComponentType> minutesQuestionComponent = lunaticQuestionnaire.getComponents().stream()
.filter(component -> EnoAddResponseTimeSection.MINUTES_QUESTION_ID.equals(component.getId()))
.findAny();
assertTrue(hoursQuestionComponent.isPresent());
assertTrue(minutesQuestionComponent.isPresent());
assertThat(hoursQuestionComponent.get().getPage()).isEqualTo(minutesQuestionComponent.get().getPage());
}

}