Commit 8d6fb0c6 authored by Tim Hunt's avatar Tim Hunt
Browse files

MDL-47494 gapselect: Fix codechecker issues.

Also remove old translations that are now in AMOS, and add some unit
tests.
parent 61ba43b0
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/** /**
* @package moodlecore * @package qtype_gapselect
* @subpackage backup-moodle2
* @copyright 2011 The Open University * @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/ */
...@@ -26,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); ...@@ -26,7 +25,7 @@ defined('MOODLE_INTERNAL') || die();
/** /**
* Provides the information to backup gapselect questions * Provides the information to backup gapselect questions.
* *
* @copyright 2011 The Open University * @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
...@@ -34,37 +33,37 @@ defined('MOODLE_INTERNAL') || die(); ...@@ -34,37 +33,37 @@ defined('MOODLE_INTERNAL') || die();
class backup_qtype_gapselect_plugin extends backup_qtype_plugin { class backup_qtype_gapselect_plugin extends backup_qtype_plugin {
/** /**
* Returns the qtype information to attach to question element * Returns the qtype information to attach to question element.
*/ */
protected function define_question_plugin_structure() { protected function define_question_plugin_structure() {
// Define the virtual plugin element with the condition to fulfill // Define the virtual plugin element with the condition to fulfill.
$plugin = $this->get_plugin_element(null, '../../qtype', 'gapselect'); $plugin = $this->get_plugin_element(null, '../../qtype', 'gapselect');
// Create one standard named plugin element (the visible container) // Create one standard named plugin element (the visible container).
$pluginwrapper = new backup_nested_element($this->get_recommended_name()); $pluginwrapper = new backup_nested_element($this->get_recommended_name());
// connect the visible container ASAP // Connect the visible container ASAP.
$plugin->add_child($pluginwrapper); $plugin->add_child($pluginwrapper);
// This qtype uses standard question_answers, add them here // This qtype uses standard question_answers, add them here
// to the tree before any other information that will use them // to the tree before any other information that will use them.
$this->add_question_question_answers($pluginwrapper); $this->add_question_question_answers($pluginwrapper);
// Now create the qtype own structures // Now create the qtype own structures.
$gapselect = new backup_nested_element('gapselect', array('id'), array( $gapselect = new backup_nested_element('gapselect', array('id'), array(
'shuffleanswers', 'correctfeedback', 'correctfeedbackformat', 'shuffleanswers', 'correctfeedback', 'correctfeedbackformat',
'partiallycorrectfeedback', 'partiallycorrectfeedbackformat', 'partiallycorrectfeedback', 'partiallycorrectfeedbackformat',
'incorrectfeedback', 'incorrectfeedbackformat', 'shownumcorrect')); 'incorrectfeedback', 'incorrectfeedbackformat', 'shownumcorrect'));
// Now the own qtype tree // Now the own qtype tree.
$pluginwrapper->add_child($gapselect); $pluginwrapper->add_child($gapselect);
// set source to populate the data // Set source to populate the data.
$gapselect->set_source_table('question_gapselect', $gapselect->set_source_table('question_gapselect',
array('questionid' => backup::VAR_PARENTID)); array('questionid' => backup::VAR_PARENTID));
// don't need to annotate ids nor files // Don't need to annotate ids or files.
return $plugin; return $plugin;
} }
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/** /**
* @package moodlecore * @package qtype_gapselect
* @subpackage backup-moodle2
* @copyright 2011 The Open University * @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/ */
...@@ -26,8 +25,8 @@ defined('MOODLE_INTERNAL') || die(); ...@@ -26,8 +25,8 @@ defined('MOODLE_INTERNAL') || die();
/** /**
* restore plugin class that provides the necessary information * Restore plugin class that provides the necessary information
* needed to restore one gapselect qtype plugin * needed to restore one gapselect qtype plugin.
* *
* @copyright 2011 The Open University * @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
...@@ -35,22 +34,22 @@ defined('MOODLE_INTERNAL') || die(); ...@@ -35,22 +34,22 @@ defined('MOODLE_INTERNAL') || die();
class restore_qtype_gapselect_plugin extends restore_qtype_plugin { class restore_qtype_gapselect_plugin extends restore_qtype_plugin {
/** /**
* Returns the paths to be handled by the plugin at question level * Returns the paths to be handled by the plugin at question level.
*/ */
protected function define_question_plugin_structure() { protected function define_question_plugin_structure() {
$paths = array(); $paths = array();
// This qtype uses question_answers, add them // This qtype uses question_answers, add them.
$this->add_question_question_answers($paths); $this->add_question_question_answers($paths);
// Add own qtype stuff // Add own qtype stuff.
$elename = 'gapselect'; $elename = 'gapselect';
// we used get_recommended_name() so this works // We used get_recommended_name() so this works.
$elepath = $this->get_pathfor('/gapselect'); $elepath = $this->get_pathfor('/gapselect');
$paths[] = new restore_path_element($elename, $elepath); $paths[] = new restore_path_element($elename, $elepath);
return $paths; // And we return the interesting paths return $paths; // And we return the interesting paths.
} }
/** /**
...@@ -62,18 +61,18 @@ class restore_qtype_gapselect_plugin extends restore_qtype_plugin { ...@@ -62,18 +61,18 @@ class restore_qtype_gapselect_plugin extends restore_qtype_plugin {
$data = (object)$data; $data = (object)$data;
$oldid = $data->id; $oldid = $data->id;
// Detect if the question is created or mapped // Detect if the question is created or mapped.
$oldquestionid = $this->get_old_parentid('question'); $oldquestionid = $this->get_old_parentid('question');
$newquestionid = $this->get_new_parentid('question'); $newquestionid = $this->get_new_parentid('question');
$questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false; $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
// If the question has been created by restore, we need to create its question_gapselect too // If the question has been created by restore, we need to create its question_gapselect too.
if ($questioncreated) { if ($questioncreated) {
// Adjust some columns // Adjust some columns.
$data->questionid = $newquestionid; $data->questionid = $newquestionid;
// Insert record // Insert record.
$newitemid = $DB->insert_record('question_gapselect', $data); $newitemid = $DB->insert_record('question_gapselect', $data);
// Create mapping (needed for decoding links) // Create mapping (needed for decoding links).
$this->set_mapping('question_gapselect', $oldid, $newitemid); $this->set_mapping('question_gapselect', $oldid, $newitemid);
} }
} }
......
...@@ -47,49 +47,59 @@ class qtype_gapselect_edit_form_base extends question_edit_form { ...@@ -47,49 +47,59 @@ class qtype_gapselect_edit_form_base extends question_edit_form {
); );
/** @var string regex to match HTML open tags. */ /** @var string regex to match HTML open tags. */
private $htmltstarttagsandattributes = '/<\s*\w.*?>/'; private $htmltstarttagsandattributes = '~<\s*\w+\b[^>]*>~';
/** @var string regex to match HTML close tags or br. */ /** @var string regex to match HTML close tags or br. */
private $htmltclosetags = '~<\s*/\s*\w\s*.*?>|<\s*br\s*>~'; private $htmltclosetags = '~<\s*/\s*\w+\b[^>]*>~';
/** @var string regex to select text like [[cat]] (including the square brackets). */ /** @var string regex to select text like [[cat]] (including the square brackets). */
private $squarebracketsregex = '/\[\[[^]]*?\]\]/'; private $squarebracketsregex = '/\[\[[^]]*?\]\]/';
private function get_html_tags($text) { /**
$textarray = array(); * Vaidate some input to make sure it does not contain any tags other than
* $this->allowedhtmltags.
* @param unknown_type $text the input to validate.
* @return string any validation errors.
*/
protected function get_illegal_tag_error($text) {
// Remove legal tags.
$strippedtext = $text;
foreach ($this->allowedhtmltags as $htmltag) { foreach ($this->allowedhtmltags as $htmltag) {
$tagpair = "/<\s*\/?\s*$htmltag\s*.*?>/"; $tagpair = "~<\s*/?\s*$htmltag\b\s*[^>]*>~";
preg_match_all($tagpair, $text, $textarray); $strippedtext = preg_replace($tagpair, '', $strippedtext);
if ($textarray[0]) {
return $textarray[0];
}
} }
preg_match_all($this->htmltstarttagsandattributes, $text, $textarray); $textarray = array();
preg_match_all($this->htmltstarttagsandattributes, $strippedtext, $textarray);
if ($textarray[0]) { if ($textarray[0]) {
$tag = htmlspecialchars($textarray[0][0]); return $this->allowed_tags_message($textarray[0][0]);
$allowedtaglist = $this->get_list_of_printable_allowed_tags($this->allowedhtmltags);
return $tag . ' is not allowed (only ' . $allowedtaglist .
' and corresponsing closing tags are allowed)';
} }
preg_match_all($this->htmltclosetags, $text, $textarray); preg_match_all($this->htmltclosetags, $strippedtext, $textarray);
if ($textarray[0]) { if ($textarray[0]) {
$tag = htmlspecialchars($textarray[0][0]); return $this->allowed_tags_message($textarray[0][0]);
$allowedtaglist=$this->get_list_of_printable_allowed_tags($this->allowedhtmltags);
return $tag . ' is not allowed (only ' . $allowedtaglist .
' and corresponsing closing tags are allowed)';
} }
return false; return '';
}
private function allowed_tags_message($badtag) {
$a = new stdClass();
$a->tag = htmlspecialchars($badtag);
$a->allowed = $this->get_list_of_printable_allowed_tags($this->allowedhtmltags);
if ($a->allowed) {
return get_string('tagsnotallowed', 'qtype_gapselect', $a);
} else {
return get_string('tagsnotallowedatall', 'qtype_gapselect', $a);
}
} }
private function get_list_of_printable_allowed_tags($allowedhtmltags) { private function get_list_of_printable_allowed_tags($allowedhtmltags) {
$allowedtaglist = null; $allowedtaglist = array();
foreach ($allowedhtmltags as $htmltag) { foreach ($allowedhtmltags as $htmltag) {
$allowedtaglist .= htmlspecialchars('<'.$htmltag.'>') . ', '; $allowedtaglist[] = htmlspecialchars('<' . $htmltag . '>');
} }
return $allowedtaglist; return implode(', ', $allowedtaglist);
} }
/** /**
...@@ -99,7 +109,7 @@ class qtype_gapselect_edit_form_base extends question_edit_form { ...@@ -99,7 +109,7 @@ class qtype_gapselect_edit_form_base extends question_edit_form {
protected function definition_inner($mform) { protected function definition_inner($mform) {
global $CFG; global $CFG;
//add the answer (choice) fields to the form // Add the answer (choice) fields to the form.
$this->definition_answer_choice($mform); $this->definition_answer_choice($mform);
$this->add_combined_feedback_fields(true); $this->add_combined_feedback_fields(true);
...@@ -192,7 +202,7 @@ class qtype_gapselect_edit_form_base extends question_edit_form { ...@@ -192,7 +202,7 @@ class qtype_gapselect_edit_form_base extends question_edit_form {
$questiontext = $data['questiontext']; $questiontext = $data['questiontext'];
$choices = $data['choices']; $choices = $data['choices'];
//check the whether the slots are valid // Check the whether the slots are valid.
$errorsinquestiontext = $this->validate_slots($questiontext['text'], $choices); $errorsinquestiontext = $this->validate_slots($questiontext['text'], $choices);
if ($errorsinquestiontext) { if ($errorsinquestiontext) {
$errors['questiontext'] = $errorsinquestiontext; $errors['questiontext'] = $errorsinquestiontext;
...@@ -200,13 +210,10 @@ class qtype_gapselect_edit_form_base extends question_edit_form { ...@@ -200,13 +210,10 @@ class qtype_gapselect_edit_form_base extends question_edit_form {
foreach ($choices as $key => $choice) { foreach ($choices as $key => $choice) {
$answer = $choice['answer']; $answer = $choice['answer'];
//check whether the html-tags are allowed tags // Check whether the html-tags are allowed tags.
$validtags = $this->get_html_tags($answer); $tagerror = $this->get_illegal_tag_error($answer);
if (is_array($validtags)) { if ($tagerror) {
continue; $errors['choices['.$key.']'] = $tagerror;
}
if ($validtags) {
$errors['choices['.$key.']'] = $validtags;
} }
} }
return $errors; return $errors;
...@@ -257,4 +264,4 @@ class qtype_gapselect_edit_form_base extends question_edit_form { ...@@ -257,4 +264,4 @@ class qtype_gapselect_edit_form_base extends question_edit_form {
public function qtype() { public function qtype() {
return ''; return '';
} }
} }
\ No newline at end of file
...@@ -40,3 +40,5 @@ $string['pluginnameadding'] = 'Adding a select missing words question'; ...@@ -40,3 +40,5 @@ $string['pluginnameadding'] = 'Adding a select missing words question';
$string['pluginnameediting'] = 'Editing a select missing words question'; $string['pluginnameediting'] = 'Editing a select missing words question';
$string['pluginnamesummary'] = 'Missing words in some text are filled in using dropdown menus.'; $string['pluginnamesummary'] = 'Missing words in some text are filled in using dropdown menus.';
$string['shuffle'] = 'Shuffle'; $string['shuffle'] = 'Shuffle';
$string['tagsnotallowed'] = '{$a->tag} is not allowed. (Only {$a->allowed} are permitted.)';
$string['tagsnotallowedatall'] = '{$a->tag} is not allowed. (No HTML is allowed here.)';
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Language strings for the gap-select question type.
*
* @package qtype_gapselect
* @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['addmorechoiceblanks'] = 'Vides pour {no} choix supplémentaires';
$string['answer'] = 'Réponse';
$string['choices'] = 'Choix';
$string['choicex'] = 'Choix {no}';
$string['correctansweris'] = 'La réponse correcte est : {$a}';
$string['errorblankchoice'] = 'Veuillez sélectionner un choix : Le choix {$a} est vide.';
$string['errormissingchoice'] = 'Veuillez sélectionner le texte de la question: {$a} n\'a pas été trouvé parmi les choix possibles! Seuls les numéros de choix existants peuvent être utilisés dans les espaces réservés.';
$string['errornoslots'] = 'Le texte de la question doit contenir des espaces reservés du type [[1]] pour définir l\'emplacement des mots qui seront choisis.';
$string['errorquestiontextblank'] = 'Vous devez entrer le texte de la question.';
$string['group'] = 'Groupe';
$string['pleaseputananswerineachbox'] = 'Veuillez entrer une réponse dans chaque boîte.';
$string['pluginname'] = 'Sélectionnez les mots manquants';
$string['pluginname_help'] = 'Entrez une question du type "Le [[1]] saute par-dessus le [[2]]", puis entrez les différents mots possibles pour les intervalles 1 et 2.';
$string['pluginname_link'] = 'question/type/gapselect';
$string['pluginnameadding'] = 'Ajouter une question permettant de sélectionner le mot manquant';
$string['pluginnameediting'] = 'Editer une question permettant de sélectionner le mot manquant';
$string['pluginnamesummary'] = 'Les mots manquants des textes sont comblés en utilisant des listes déroulantes.';
$string['shuffle'] = 'Mélanger';
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Local language pack from http://www.moodle.vsu.ru
*
* @package qtype
* @subpackage gapselect
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['addmorechoiceblanks'] = 'Шаблоны для ещё {no} вариантов';
$string['answer'] = 'Ответ';
$string['choices'] = 'Варианты выбора';
$string['choicex'] = 'Вариант {no}';
$string['correctansweris'] = 'Верный ответ: {$a}';
$string['errorblankchoice'] = 'Пожалуйста, проверьте варианты выбора: вариант выбора {$a} пуст.';
$string['errormissingchoice'] = 'Пожалуйста, проверьте текст вопроса: {$a} не найден среди вариантов выбора! Только номера ответов, которые существуют в вариантах выбора могут быть использованы как метки-заполнители.';
$string['errornoslots'] = 'Текст вопроса должен содержать метки-заполнители, например [[1]], для обозначения местонахождения пропущенных слов.';
$string['errorquestiontextblank'] = 'Вы должны ввести какой-либо текст.';
$string['group'] = 'Группа';
$string['pleaseputananswerineachbox'] = 'Пожалуйста, добавьте ответ в каждую ячейку';
$string['pluginname'] = 'Выбрать пропущенные слова';
$string['pluginnameadding'] = 'Добавить вопрос на выборку пропущенных слов';
$string['pluginnameediting'] = 'Редактировать вопрос на выборку пропущенных слов';
$string['pluginnamesummary'] = 'Пропущенные слова в тексте заполняются с помощью выпадающего меню.';
$string['pluginname_help'] = 'Напишите текст, например "[[1]] перепрыгивает через [[2]]", затем введите возможные слова для меток 1 и 2 внизу';
$string['shuffle'] = 'Перемешать';
...@@ -18,8 +18,7 @@ ...@@ -18,8 +18,7 @@
* Definition class for embedded element in question text question. Parent of * Definition class for embedded element in question text question. Parent of
* gap-select, drag and drop and possibly others. * gap-select, drag and drop and possibly others.
* *
* @package qtype * @package qtype_gapselect
* @subpackage gapselect
* @copyright 2011 The Open University * @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/ */
...@@ -30,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); ...@@ -30,7 +29,7 @@ defined('MOODLE_INTERNAL') || die();
/** /**
* Represents embedded element in question text question. Parent of drag and drop and select from * Represents embedded element in question text question. Parent of drag and drop and select from
* drop down list and ?others? * drop down list and others.
* *
* @copyright 2011 The Open University * @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
......
...@@ -56,7 +56,7 @@ abstract class qtype_gapselect_base extends question_type { ...@@ -56,7 +56,7 @@ abstract class qtype_gapselect_base extends question_type {
$oldanswers = $DB->get_records('question_answers', $oldanswers = $DB->get_records('question_answers',
array('question' => $question->id), 'id ASC'); array('question' => $question->id), 'id ASC');
// Insert all the new answers // Insert all the new answers.
foreach ($question->choices as $key => $choice) { foreach ($question->choices as $key => $choice) {
if (trim($choice['answer']) == '') { if (trim($choice['answer']) == '') {
...@@ -82,7 +82,7 @@ abstract class qtype_gapselect_base extends question_type { ...@@ -82,7 +82,7 @@ abstract class qtype_gapselect_base extends question_type {
} }
} }
// Delete old answer records // Delete old answer records.
foreach ($oldanswers as $oa) { foreach ($oldanswers as $oa) {
$DB->delete_records('question_answers', array('id' => $oa->id)); $DB->delete_records('question_answers', array('id' => $oa->id));
} }
...@@ -259,7 +259,7 @@ abstract class qtype_gapselect_base extends question_type { ...@@ -259,7 +259,7 @@ abstract class qtype_gapselect_base extends question_type {
return false; return false;
} }
//get the slots // Get the slots.
$slots = $this->getEmbeddedTextArray($question); $slots = $this->getEmbeddedTextArray($question);
if (!$slots) { if (!$slots) {
...@@ -269,7 +269,7 @@ abstract class qtype_gapselect_base extends question_type { ...@@ -269,7 +269,7 @@ abstract class qtype_gapselect_base extends question_type {
$output = array(); $output = array();
foreach ($slots as $slot) { foreach ($slots as $slot) {
$output[] = substr($slot, 2, strlen($slot) - 4); //2 is for '[[' and 4 is for '[[]]'. $output[] = substr($slot, 2, strlen($slot) - 4); // 2 is for '[[' and 4 is for '[[]]'.
} }
return $output; return $output;
} }
...@@ -282,7 +282,7 @@ abstract class qtype_gapselect_base extends question_type { ...@@ -282,7 +282,7 @@ abstract class qtype_gapselect_base extends question_type {
} }
} }
// Shuffle answers within this group // Shuffle answers within this group.
if ($question->options->shuffleanswers == 1) { if ($question->options->shuffleanswers == 1) {
shuffle($goupofanswers); shuffle($goupofanswers);
} }
......
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for the select missing words question definition class.
*
* @package qtype_gapselect
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
require_once($CFG->dirroot . '/question/type/edit_question_form.php');
require_once($CFG->dirroot . '/question/type/gapselect/edit_form_base.php');
/**
* Subclass of qtype_gapselect_edit_form_base that is easier to used in unit tests.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_gapselect_edit_form_base_testable extends qtype_gapselect_edit_form_base {
public function __construct() {
$syscontext = context_system::instance();
$category = question_make_default_categories(array($syscontext));
$fakequestion = new stdClass();
$fakequestion->qtype = 'stack';
$fakequestion->category = $category->id;
$fakequestion->questiontext = 'Test [[1]] question [[2]]';
$fakequestion->options = new stdClass();
$fakequestion->options->answers = array();
$fakequestion->formoptions = new stdClass();
$fakequestion->formoptions->movecontext = null;
$fakequestion->formoptions->repeatelements = true;