private static AssessmentItem createAssessmentItem() {
    AssessmentItem assessmentItem =
        AssessmentItemFactory.createAssessmentItem(QTI21QuestionType.sc, "Single choice");

    // define correct answer
    Identifier responseDeclarationId = Identifier.assumedLegal("RESPONSE_1");
    Identifier correctResponseId = IdentifierGenerator.newAsIdentifier("sc");
    ResponseDeclaration responseDeclaration =
        createSingleChoiceCorrectResponseDeclaration(
            assessmentItem, responseDeclarationId, correctResponseId);
    assessmentItem
        .getNodeGroups()
        .getResponseDeclarationGroup()
        .getResponseDeclarations()
        .add(responseDeclaration);

    // outcomes
    appendDefaultOutcomeDeclarations(assessmentItem, 1.0d);

    // the single choice interaction
    ItemBody itemBody = appendDefaultItemBody(assessmentItem);
    ChoiceInteraction choiceInteraction =
        appendChoiceInteraction(itemBody, responseDeclarationId, 1, true);

    appendSimpleChoice(choiceInteraction, "New answer", correctResponseId);

    // response processing
    ResponseProcessing responseProcessing =
        createResponseProcessing(assessmentItem, responseDeclarationId);
    assessmentItem
        .getNodeGroups()
        .getResponseProcessingGroup()
        .setResponseProcessing(responseProcessing);
    return assessmentItem;
  }
 @Test
 public void testValidateCorrectObjectLinkToApipProducesNoErrors() {
   final ContentLinkInfo cli = new ContentLinkInfo(accessElement);
   cli.setObjectLink(new ObjectLink(null));
   cli.setApipLinkIdentifierRef(Identifier.parseString("hello"));
   cli.validate(context);
   assertNoNotificationsRecorded();
 }
 /**
  * Gets (first) templateDeclaration with given identifier, or null if no such variable is defined.
  *
  * @param identifier given identifier
  * @return templateDeclaration with given identifier or null
  */
 public TemplateDeclaration getTemplateDeclaration(final Identifier identifier) {
   Assert.notNull(identifier);
   for (final TemplateDeclaration declaration : getTemplateDeclarations()) {
     if (identifier.equals(declaration.getIdentifier())) {
       return declaration;
     }
   }
   return null;
 }
 /**
  * Gets (first) explicitly-defined outcomeDeclaration with given identifier, or null if no such
  * declaration exists.
  *
  * <p>NB: Doesn't include the implicitly-defined {@link
  * QtiConstants#VARIABLE_COMPLETION_STATUS_NAME} variable
  *
  * @param identifier given identifier
  * @return outcomeDeclaration with given identifier or null
  * @see #getCompletionStatusOutcomeDeclaration()
  */
 @Override
 public OutcomeDeclaration getOutcomeDeclaration(final Identifier identifier) {
   Assert.notNull(identifier);
   for (final OutcomeDeclaration declaration : getOutcomeDeclarations()) {
     if (identifier.equals(declaration.getIdentifier())) {
       return declaration;
     }
   }
   return null;
 }
 @Test
 public void testValidateCorrectObjectLinkToQtiProducesNoErrors() {
   final String targetId = "hello";
   paragraph.setId(Identifier.parseString(targetId));
   final ContentLinkInfo cli = new ContentLinkInfo(accessElement);
   cli.setObjectLink(new ObjectLink(null));
   cli.setQtiLinkIdentifierRef(targetId);
   cli.validate(context);
   assertNoNotificationsRecorded();
 }
 @Test
 public void testValidateHavingBothIdRefsProducesError() {
   final String targetId = "hello";
   paragraph.setId(Identifier.parseString(targetId));
   final ContentLinkInfo cli = new ContentLinkInfo(accessElement);
   cli.setObjectLink(new ObjectLink(cli));
   cli.setQtiLinkIdentifierRef(targetId);
   cli.setApipLinkIdentifierRef(Identifier.parseString("helloAgain"));
   cli.validate(context);
   Assert.assertEquals(1, recorder.getNotifications().size());
   Assert.assertEquals(
       NotificationLevel.ERROR, recorder.getNotifications().get(0).getNotificationLevel());
   Assert.assertEquals(
       NotificationType.MODEL_VALIDATION,
       recorder.getNotifications().get(0).getNotificationType());
   Assert.assertEquals(
       "contentLinkInfo must only have either qtiLinkIdentifierRef or apipLinkIdentifierRef specified, but not both.",
       recorder.getNotifications().get(0).getMessage());
 }
 @Test
 public void testValidateMissingObjectLinkAndTextLinkProducesError() {
   final ContentLinkInfo cli = new ContentLinkInfo(accessElement);
   cli.setApipLinkIdentifierRef(Identifier.parseString("hello"));
   cli.validate(context);
   Assert.assertEquals(1, recorder.getNotifications().size());
   Assert.assertEquals(
       NotificationLevel.ERROR, recorder.getNotifications().get(0).getNotificationLevel());
   Assert.assertEquals(
       NotificationType.MODEL_VALIDATION,
       recorder.getNotifications().get(0).getNotificationType());
   Assert.assertEquals(
       "Not enough children: objectLinkOrTextLink. Expected at least: 1, but found: 0",
       recorder.getNotifications().get(0).getMessage());
 }
 @Test
 public void testValidateQtiReferencesNoMatchingIdElementProducesError() {
   paragraph.setId(Identifier.parseString("wrongId"));
   final ContentLinkInfo cli = new ContentLinkInfo(accessElement);
   cli.setObjectLink(new ObjectLink(cli));
   cli.setQtiLinkIdentifierRef("targetId");
   cli.validate(context);
   Assert.assertEquals(1, recorder.getNotifications().size());
   Assert.assertEquals(
       NotificationLevel.ERROR, recorder.getNotifications().get(0).getNotificationLevel());
   Assert.assertEquals(
       NotificationType.MODEL_VALIDATION,
       recorder.getNotifications().get(0).getNotificationType());
   Assert.assertEquals(
       "contentLinkInfo with qtiLinkIdentifierRef of 'targetId' does not point to an extant Qti content element.",
       recorder.getNotifications().get(0).getMessage());
 }
 @Override
 public boolean isCorrect(Choice choice) {
   return correctAnswer != null && correctAnswer.equals(choice.getIdentifier());
 }