public function testWithMapResponseValidationMissingAssociableIdentifier()
 {
     $bgObject = new Object('http://img.png', 'image/png');
     $bgObject->setWidth(100);
     $bgObject->setHeight(200);
     $testInteraction = GraphicGapInteractionBuilder::build('testInteraction', $bgObject, ['A' => 'img_A.png', 'B' => 'img_B.png', 'C' => 'img_C.png'], ['G1' => [0, 0, 10, 10], 'G2' => [0, 0, 10, 10]]);
     $responseProcessingTemplate = ResponseProcessingTemplate::mapResponse();
     $responseDeclaration = ResponseDeclarationBuilder::buildWithMapping('testIdentifier', ['A G1' => [1, false]], 'QtiDirectedPair');
     $mapper = new GraphicGapMatchInteractionMapper($testInteraction, $responseDeclaration, $responseProcessingTemplate);
     /** @var imageclozeassociation $q */
     $q = $mapper->getQuestionType();
     $this->assertEquals('imageclozeassociation', $q->get_type());
     $this->assertEquals(['<img src="img_A.png"/>', '<img src="img_B.png"/>', '<img src="img_C.png"/>'], $q->get_possible_responses());
     $this->assertFalse($q->get_duplicate_responses());
     $this->assertNull($q->get_validation());
     $containsWarning = false;
     foreach (LogService::read() as $message) {
         if (StringUtil::contains($message, 'Amount of gap identifiers 2 does not match the amount 1 for <responseDeclaration>')) {
             return true;
         }
     }
     $this->assertTrue($containsWarning);
 }
 private function buildItemBodyWithItemContent(array $interactions, $content)
 {
     // Map <itemBody>
     // TODO: Wrap these `content` stuff in a div
     // TODO: to avoid QtiComponentIterator bug ignoring 2nd element with empty content
     $contentCollection = QtiMarshallerUtil::unmarshallElement($content);
     $wrapperCollection = new FlowCollection();
     foreach ($contentCollection as $component) {
         $wrapperCollection->attach($component);
     }
     $divWrapper = new Div();
     $divWrapper->setContent($wrapperCollection);
     // Iterate through these elements and try to replace every single question `span` with its interaction equivalent
     $iterator = $divWrapper->getIterator();
     foreach ($iterator as $component) {
         if ($component instanceof Span && StringUtil::contains($component->getClass(), 'learnosity-response')) {
             $currentContainer = $iterator->getCurrentContainer();
             $questionReference = trim(str_replace('learnosity-response', '', $component->getClass()));
             $questionReference = trim(str_replace('question-', '', $questionReference));
             // Build the actual interaction
             $interaction = $interactions[$questionReference]['interaction'];
             $content = new FlowCollection();
             if (isset($interactions[$questionReference]['extraContent'])) {
                 $content->attach($interactions[$questionReference]['extraContent']);
             }
             $content->attach($interaction);
             $replacement = ContentCollectionBuilder::buildContent($currentContainer, $content)->current();
             $currentContainer->getComponents()->replace($component, $replacement);
         }
     }
     // Extract the actual content from the div wrapper and add that to our <itemBody>
     $componentsWithinDiv = $divWrapper->getComponents();
     $itemBody = new ItemBody();
     $itemBody->setContent(ContentCollectionBuilder::buildBlockCollectionContent($componentsWithinDiv));
     return $itemBody;
 }