/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.ims.qti21.model.xml; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.UUID; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.FileUtils; import org.olat.core.util.WebappHelper; import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; import org.olat.ims.qti21.model.xml.interactions.EssayAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.EntryType; import org.olat.ims.qti21.model.xml.interactions.HotspotAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.KPrimAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.MultipleChoiceAssessmentItemBuilder; import org.olat.ims.qti21.model.xml.interactions.SingleChoiceAssessmentItemBuilder; import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.item.interaction.ChoiceInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.ExtendedTextInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.HotspotInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.MatchInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.TextEntryInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleMatchSet; import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration; import uk.ac.ed.ph.jqtiplus.provision.BadResourceException; import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader; import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader; import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; import uk.ac.ed.ph.jqtiplus.validation.ItemValidationResult; import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; /** * * Initial date: 20.05.2016<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ @RunWith(Parameterized.class) public class AssessmentItemBuilderTest { private static final OLog log = Tracing.createLoggerFor(AssessmentItemBuilderTest.class); @Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { { Boolean.TRUE }, { Boolean.FALSE } }); } private Boolean build; public AssessmentItemBuilderTest(Boolean build) { this.build = build; } @Test public void findFeedbacks() throws URISyntaxException { URL itemUrl = AssessmentItemBuilderTest.class.getResource("assessment-item-single-choice-feedbacks.xml"); AssessmentItem assessmentItem = loadAssessmentItem(itemUrl); QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); SingleChoiceAssessmentItemBuilder itemBuilder = new SingleChoiceAssessmentItemBuilder(assessmentItem, qtiSerializer); if(build.booleanValue()) { itemBuilder.build(); } ModalFeedbackBuilder correctFeedback = itemBuilder.getCorrectFeedback(); Assert.assertNotNull(correctFeedback); Assert.assertTrue(correctFeedback.isCorrectRule()); ModalFeedbackBuilder incorrectFeedback = itemBuilder.getIncorrectFeedback(); Assert.assertNotNull(incorrectFeedback); Assert.assertTrue(incorrectFeedback.isIncorrectRule()); } /** * Check if a bare bone single choice created with our builder make a valid assessmentItem. * * @throws IOException * @throws URISyntaxException */ @Test public void buildAssessmentItem_singleChoice() throws IOException, URISyntaxException { QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); SingleChoiceAssessmentItemBuilder itemBuilder = new SingleChoiceAssessmentItemBuilder("Single choice", "New answer", qtiSerializer); if(build.booleanValue()) { itemBuilder.build(); } AssessmentItem assessmentItem = itemBuilder.getAssessmentItem(); ItemValidationResult itemResult = serializeAndReload(assessmentItem); AssessmentItem reloadedItem = itemResult.getResolvedAssessmentItem().getItemLookup().extractIfSuccessful(); List<Interaction> interactions = reloadedItem.getItemBody().findInteractions(); Assert.assertNotNull(interactions); Assert.assertEquals(1, interactions.size()); Assert.assertTrue(interactions.get(0) instanceof ChoiceInteraction); } /** * Check if a bare bone multiple choice created with our builder make a valid assessmentItem. * * @throws IOException * @throws URISyntaxException */ @Test public void buildAssessmentItem_multipleChoice() throws IOException, URISyntaxException { QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); MultipleChoiceAssessmentItemBuilder itemBuilder = new MultipleChoiceAssessmentItemBuilder("Multiple choice", "New answer", qtiSerializer); if(build.booleanValue()) { itemBuilder.build(); } AssessmentItem assessmentItem = itemBuilder.getAssessmentItem(); ItemValidationResult itemResult = serializeAndReload(assessmentItem); AssessmentItem reloadedItem = itemResult.getResolvedAssessmentItem().getItemLookup().extractIfSuccessful(); List<Interaction> interactions = reloadedItem.getItemBody().findInteractions(); Assert.assertNotNull(interactions); Assert.assertEquals(1, interactions.size()); Assert.assertTrue(interactions.get(0) instanceof ChoiceInteraction); } @Test public void buildAssessmentItem_essay() throws IOException, URISyntaxException { QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); EssayAssessmentItemBuilder itemBuilder = new EssayAssessmentItemBuilder("Essay", qtiSerializer); if(build.booleanValue()) { itemBuilder.build(); } AssessmentItem assessmentItem = itemBuilder.getAssessmentItem(); ItemValidationResult itemResult = serializeAndReload(assessmentItem); AssessmentItem reloadedItem = itemResult.getResolvedAssessmentItem().getItemLookup().extractIfSuccessful(); List<Interaction> interactions = reloadedItem.getItemBody().findInteractions(); Assert.assertNotNull(interactions); Assert.assertEquals(1, interactions.size()); Assert.assertTrue(interactions.get(0) instanceof ExtendedTextInteraction); } @Test public void buildAssessmentItem_gap() throws IOException, URISyntaxException { QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); FIBAssessmentItemBuilder itemBuilder = new FIBAssessmentItemBuilder("Gap text", EntryType.text, qtiSerializer); if(build.booleanValue()) { itemBuilder.build(); } AssessmentItem assessmentItem = itemBuilder.getAssessmentItem(); ItemValidationResult itemResult = serializeAndReload(assessmentItem); AssessmentItem reloadedItem = itemResult.getResolvedAssessmentItem().getItemLookup().extractIfSuccessful(); List<Interaction> interactions = reloadedItem.getItemBody().findInteractions(); Assert.assertNotNull(interactions); Assert.assertEquals(1, interactions.size()); Assert.assertTrue(interactions.get(0) instanceof TextEntryInteraction); TextEntryInteraction interaction = (TextEntryInteraction)interactions.get(0); Assert.assertNotNull(interaction.getResponseIdentifier()); ResponseDeclaration responseDeclaration = reloadedItem.getResponseDeclaration(interaction.getResponseIdentifier()); Assert.assertNotNull(responseDeclaration); } @Test public void buildAssessmentItem_hotspot() throws IOException, URISyntaxException { QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); HotspotAssessmentItemBuilder itemBuilder = new HotspotAssessmentItemBuilder("Hotspot", qtiSerializer); if(build.booleanValue()) { itemBuilder.build(); } AssessmentItem assessmentItem = itemBuilder.getAssessmentItem(); ItemValidationResult itemResult = serializeAndReload(assessmentItem); AssessmentItem reloadedItem = itemResult.getResolvedAssessmentItem().getItemLookup().extractIfSuccessful(); List<Interaction> interactions = reloadedItem.getItemBody().findInteractions(); Assert.assertNotNull(interactions); Assert.assertEquals(1, interactions.size()); Assert.assertTrue(interactions.get(0) instanceof HotspotInteraction); HotspotInteraction interaction = (HotspotInteraction)interactions.get(0); Assert.assertNotNull(interaction.getResponseIdentifier()); ResponseDeclaration responseDeclaration = reloadedItem.getResponseDeclaration(interaction.getResponseIdentifier()); Assert.assertNotNull(responseDeclaration); } @Test public void buildAssessmentItem_kprim() throws IOException, URISyntaxException { QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); KPrimAssessmentItemBuilder itemBuilder = new KPrimAssessmentItemBuilder("Kprim", "New answer", qtiSerializer); if(build.booleanValue()) { itemBuilder.build(); } AssessmentItem singleChoiceItem = itemBuilder.getAssessmentItem(); ItemValidationResult itemResult = serializeAndReload(singleChoiceItem); AssessmentItem reloadedItem = itemResult.getResolvedAssessmentItem().getItemLookup().extractIfSuccessful(); List<Interaction> interactions = reloadedItem.getItemBody().findInteractions(); Assert.assertNotNull(interactions); Assert.assertEquals(1, interactions.size()); Assert.assertTrue(interactions.get(0) instanceof MatchInteraction); MatchInteraction interaction = (MatchInteraction)interactions.get(0); Assert.assertNotNull(interaction.getResponseIdentifier()); ResponseDeclaration responseDeclaration = reloadedItem.getResponseDeclaration(interaction.getResponseIdentifier()); Assert.assertNotNull(responseDeclaration); Assert.assertEquals(2, interaction.getSimpleMatchSets().size()); SimpleMatchSet matchSet = interaction.getSimpleMatchSets().get(0); Assert.assertEquals(4, matchSet.getSimpleAssociableChoices().size()); SimpleMatchSet correctWrongSet = interaction.getSimpleMatchSets().get(1); Assert.assertEquals(2, correctWrongSet.getSimpleAssociableChoices().size()); } /** * The method serialize as xml the assessmentItem, load it, validate it and return the itemResult. * * @param assessmentItem * @return * @throws IOException */ private ItemValidationResult serializeAndReload(AssessmentItem assessmentItem) throws IOException { QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager()); File tmpDir = new File(WebappHelper.getTmpDir(), "itembuilder" + UUID.randomUUID()); tmpDir.mkdirs(); File outputFile = new File(tmpDir, "sc_item.xml"); try(FileOutputStream out = new FileOutputStream(outputFile)) { qtiSerializer.serializeJqtiObject(assessmentItem, out); } catch(Exception e) { log.error("", e); } QtiXmlReader qtiXmlReader = new QtiXmlReader(new JqtiExtensionManager()); ResourceLocator fileResourceLocator = new PathResourceLocator(outputFile.toPath()); AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, fileResourceLocator); ItemValidationResult itemResult = assessmentObjectXmlLoader.loadResolveAndValidateItem(outputFile.toURI()); BadResourceException e = itemResult.getResolvedAssessmentItem().getItemLookup().getBadResourceException(); if(e != null) { StringBuilder err = new StringBuilder(); BadRessourceHelper.extractMessage(e, err); log.error(err.toString()); } FileUtils.deleteDirsAndFiles(tmpDir.toPath()); Assert.assertFalse("Has errors", (itemResult.getModelValidationErrors().size() > 0)); return itemResult; } private AssessmentItem loadAssessmentItem(URL itemUrl) throws URISyntaxException { QtiXmlReader qtiXmlReader = new QtiXmlReader(new JqtiExtensionManager()); ResourceLocator fileResourceLocator = new PathResourceLocator(Paths.get(itemUrl.toURI())); AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, fileResourceLocator); ResolvedAssessmentItem item = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(itemUrl.toURI()); return item.getItemLookup().getRootNodeHolder().getRootNode(); } }