Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ private static void inspectOrganizations(Scorm2004Organizations organizations,
indicators.add(SequencingIndicator.ORGANIZATION_SEQUENCING);
inspectSequencing(organization.getSequencing(), state, indicators, true, false);
}
if (organization.isObjectivesGlobalToSystem()) {
if (organization.isObjectivesGlobalToSystemSpecified()
&& organization.isObjectivesGlobalToSystem()) {
indicators.add(SequencingIndicator.ORGANIZATION_OBJECTIVES_GLOBAL);
state.organizationObjectivesGlobal = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package dev.jcputney.elearning.parser.input.scorm2004.ims.cp;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
Expand Down Expand Up @@ -75,7 +76,7 @@ public final class Scorm2004Organization implements Serializable {
*/
@JacksonXmlProperty(isAttribute = true, localName = "objectivesGlobalToSystem", namespace = ADLSeq.NAMESPACE_URI)
@JsonProperty("objectivesGlobalToSystem")
private boolean objectivesGlobalToSystem = false;
private Boolean objectivesGlobalToSystem;

/**
* The default for the adlcp:sharedDataGlobalToSystem attribute for items in this organization. If
Expand Down Expand Up @@ -186,7 +187,17 @@ public void setItems(List<Scorm2004Item> items) {
* @return true if the objectives are global to the system, false otherwise
*/
public boolean isObjectivesGlobalToSystem() {
return this.objectivesGlobalToSystem;
return this.objectivesGlobalToSystem == null || this.objectivesGlobalToSystem;
}

/**
* Returns whether the manifest explicitly declared objectivesGlobalToSystem.
*
* @return true when the attribute was present in the organization element
*/
@JsonIgnore
public boolean isObjectivesGlobalToSystemSpecified() {
return this.objectivesGlobalToSystem != null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import dev.jcputney.elearning.parser.exception.ManifestParseException;
import dev.jcputney.elearning.parser.exception.ModuleException;
import dev.jcputney.elearning.parser.exception.ModuleParsingException;
import dev.jcputney.elearning.parser.input.common.serialization.NormalizedIdDeserializer;
import dev.jcputney.elearning.parser.input.common.serialization.Scorm2004SchemaValidator;
import dev.jcputney.elearning.parser.input.scorm2004.ADLSeq;
import dev.jcputney.elearning.parser.input.scorm2004.IMSSS;
Expand Down Expand Up @@ -482,7 +483,8 @@ private Scorm2004Objective parseImsObjective(Element objectiveElement) {

private Scorm2004ObjectiveMapping parseImsMapInfo(Element mapInfoElement) {
Scorm2004ObjectiveMapping mapping = new Scorm2004ObjectiveMapping();
mapping.setTargetObjectiveID(optionalAttribute(mapInfoElement, "targetObjectiveID"));
mapping.setTargetObjectiveID(normalizeTargetObjectiveId(
optionalAttribute(mapInfoElement, "targetObjectiveID")));
setBooleanAttribute(mapInfoElement, "readSatisfiedStatus", mapping::setReadSatisfiedStatus);
setBooleanAttribute(mapInfoElement, "readNormalizedMeasure",
mapping::setReadNormalizedMeasure);
Expand Down Expand Up @@ -529,7 +531,8 @@ private ADLObjective parseAdlObjective(Element objectiveElement) {

private MapInfo parseAdlMapInfo(Element mapInfoElement) {
MapInfo mapInfo = new MapInfo();
mapInfo.setTargetObjectiveID(optionalAttribute(mapInfoElement, "targetObjectiveID"));
mapInfo.setTargetObjectiveID(normalizeTargetObjectiveId(
optionalAttribute(mapInfoElement, "targetObjectiveID")));
setBooleanAttribute(mapInfoElement, "readRawScore", mapInfo::setReadRawScore);
setBooleanAttribute(mapInfoElement, "readMinScore", mapInfo::setReadMinScore);
setBooleanAttribute(mapInfoElement, "readMaxScore", mapInfo::setReadMaxScore);
Expand All @@ -547,6 +550,14 @@ private MapInfo parseAdlMapInfo(Element mapInfoElement) {
return mapInfo;
}

private String normalizeTargetObjectiveId(String value) {
if (value == null) {
return null;
}
String decodedWhitespace = value.replaceAll("(?i)%(?:20|09|0A|0D)", " ");
return NormalizedIdDeserializer.normalize(decodedWhitespace);
}

private void setBooleanAttribute(Element element, String attributeName,
Consumer<Boolean> setter) {
String value = optionalAttribute(element, attributeName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,40 @@ void testUsesSequencingWithoutIndicators() {
assertFalse(manifest.usesSequencing(), "Empty manifest should not use sequencing");
}

@Test
void objectivesGlobalToSystemDefaultsToTrueWhenOmitted()
throws IOException, XMLStreamException, ModuleParsingException, ManifestParseException {
String modulePath =
"src/test/resources/modules/scorm2004/ContentPackagingMetadata_SCORM20043rdEdition";
Scorm2004Manifest manifest = new Scorm2004Parser(new LocalFileAccess(modulePath))
.parseManifest(Scorm2004Parser.MANIFEST_FILE);

Scorm2004Organization organization = manifest
.getOrganizations()
.getOrganizationList()
.get(0);

assertTrue(organization.isObjectivesGlobalToSystem());
assertFalse(organization.isObjectivesGlobalToSystemSpecified());
}

@Test
void objectivesGlobalToSystemPreservesExplicitFalse()
throws IOException, XMLStreamException, ModuleParsingException, ManifestParseException {
String modulePath =
"src/test/resources/modules/scorm2004/SequencingSimpleRemediation_SCORM20043rdEdition";
Scorm2004Manifest manifest = new Scorm2004Parser(new LocalFileAccess(modulePath))
.parseManifest(Scorm2004Parser.MANIFEST_FILE);

Scorm2004Organization organization = manifest
.getOrganizations()
.getOrganizationList()
.get(0);

assertFalse(organization.isObjectivesGlobalToSystem());
assertTrue(organization.isObjectivesGlobalToSystemSpecified());
}

/**
* Tests the getGlobalObjectiveIds method with a manifest that contains global objectives.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,15 @@ void testNormalScorm2004ManifestParsesSuccessfully() throws Exception {
assertThat(result.metadata()).isNotNull();
assertThat(result.metadata().getTitle()).isNotBlank();
}

@Test
void normalizesEncodedWhitespaceInGlobalObjectiveIds() throws Exception {
LocalFileAccess fileAccess = new LocalFileAccess(
"src/test/resources/modules/conformance/scorm2004/adl-cts/LMSTestPackage_OB-02b");
ModuleParserFactory factory = new DefaultModuleParserFactory(fileAccess);

Scorm2004Metadata metadata = (Scorm2004Metadata) factory.parseModule();

assertThat(metadata.getGlobalObjectiveIds()).containsExactly("gObj - OB 02 b");
}
}