MDL-69823 qtype: Support core question types

This commit is contained in:
Juan Leyva 2020-09-30 11:27:29 +02:00
parent caddb8f175
commit 440aaccb57
18 changed files with 291 additions and 1 deletions

View File

@ -178,4 +178,23 @@ class qtype_calculated_question_test extends advanced_testcase {
$this->assertEquals('category' . $question->category,
$question->get_variants_selection_seed());
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$this->resetAfterTest();
$question = test_question_maker::make_question('calculated');
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertNotEmpty($options);
$this->assertEquals(0, $options['unitgradingtype']);
$this->assertEquals(0, $options['unitpenalty']);
$this->assertEquals(qtype_numerical::UNITNONE, $options['unitdisplay']);
$this->assertEmpty($options['unitsleft']);
}
}

View File

@ -185,4 +185,31 @@ class qtype_essay_question extends question_with_responses {
$filearea, $args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// This is a partial implementation, returning only the most relevant question settings for now,
// ideally, we should return as much as settings as possible (depending on the state and display options).
$settings = [
'responseformat' => $this->responseformat,
'responserequired' => $this->responserequired,
'responsefieldlines' => $this->responsefieldlines,
'attachments' => $this->attachments,
'attachmentsrequired' => $this->attachmentsrequired,
'maxbytes' => $this->maxbytes,
'filetypeslist' => $this->filetypeslist,
'responsetemplate' => $this->responsetemplate,
'responsetemplateformat' => $this->responsetemplateformat,
];
return $settings;
}
}

View File

@ -239,4 +239,27 @@ class qtype_essay_question_test extends advanced_testcase {
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$this->resetAfterTest();
$essay = test_question_maker::make_an_essay_question();
$essay->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($essay);
$displayoptions = new question_display_options();
$options = $essay->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertNotEmpty($options);
$this->assertEquals('editor', $options['responseformat']);
$this->assertEquals(1, $options['responserequired']);
$this->assertEquals(15, $options['responsefieldlines']);
$this->assertEquals(0, $options['attachments']);
$this->assertEquals(0, $options['attachmentsrequired']);
$this->assertNull($options['maxbytes']);
$this->assertNull($options['filetypeslist']);
$this->assertEquals('', $options['responsetemplate']);
$this->assertEquals(FORMAT_MOODLE, $options['responsetemplateformat']);
}
}

View File

@ -331,4 +331,21 @@ abstract class qtype_gapselect_question_base extends question_graded_automatical
$args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// This is a partial implementation, returning only the most relevant question settings for now,
// ideally, we should return as much as settings as possible (depending on the state and display options).
return [
'shufflechoices' => $this->shufflechoices,
];
}
}

View File

@ -246,4 +246,17 @@ class qtype_gapselect_question_test extends basic_testcase {
3 => new question_classified_response(2, 'assiduous', 0),
), $gapselect->classify_response(array('p1' => '0', 'p2' => '1', 'p3' => '2')));
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$question = test_question_maker::make_question('gapselect', 'maths');
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertEquals(1, $options['shufflechoices']);
}
}

View File

@ -354,4 +354,21 @@ class qtype_match_question extends question_graded_automatically_with_countback
$args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// This is a partial implementation, returning only the most relevant question settings for now,
// ideally, we should return as much as settings as possible (depending on the state and display options).
return [
'shufflestems' => $this->shufflestems,
];
}
}

View File

@ -233,4 +233,16 @@ class qtype_match_question_test extends advanced_testcase {
$this->assertEquals(array(4, 4), $m->get_num_parts_right($postdata));
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$question = test_question_maker::make_question('match');
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertEquals(1, $options['shufflestems']);
}
}

View File

@ -355,4 +355,19 @@ class qtype_multianswer_question extends question_graded_automatically_with_coun
$args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// Empty implementation for now in order to avoid debugging in core questions (generated in the parent class),
// ideally, we should return as much as settings as possible (depending on the state and display options).
return null;
}
}

View File

@ -238,4 +238,19 @@ class qtype_multianswer_question_test extends advanced_testcase {
$finalgrade = $question->compute_final_grade($responses, 1);
$this->assertEquals(1 / 3 * (1 - 3 * 0.2) + 2 / 3 * (1 - 2 * 0.2), $finalgrade);
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$this->resetAfterTest();
$question = test_question_maker::make_question('multianswer');
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertNull($options);
}
}

View File

@ -147,6 +147,26 @@ abstract class qtype_multichoice_base extends question_graded_automatically {
$args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// This is a partial implementation, returning only the most relevant question settings for now,
// ideally, we should return as much as settings as possible (depending on the state and display options).
return [
'shuffleanswers' => $this->shuffleanswers,
'answernumbering' => $this->answernumbering,
'showstandardinstruction' => $this->showstandardinstruction,
'layout' => $this->layout,
];
}
}

View File

@ -175,4 +175,19 @@ class qtype_multichoice_multi_question_test extends advanced_testcase {
}
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$question = test_question_maker::make_a_multichoice_multi_question();
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertEquals(1, $options['shuffleanswers']);
$this->assertEquals('abc', $options['answernumbering']);
$this->assertEquals(0, $options['showstandardinstruction']);
$this->assertEquals(1, $options['shuffleanswers']);
}
}

View File

@ -44,7 +44,8 @@ class qtype_numerical_question extends question_graded_automatically {
public $unitgradingtype;
/** @var number the penalty for a missing or unrecognised unit. */
public $unitpenalty;
/** @var boolean whether the units come before or after the number */
public $unitsleft;
/** @var qtype_numerical_answer_processor */
public $ap;
@ -318,6 +319,26 @@ class qtype_numerical_question extends question_graded_automatically {
$args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// This is a partial implementation, returning only the most relevant question settings for now,
// ideally, we should return as much as settings as possible (depending on the state and display options).
return [
'unitgradingtype' => $this->unitgradingtype,
'unitpenalty' => $this->unitpenalty,
'unitdisplay' => $this->unitdisplay,
'unitsleft' => $this->unitsleft,
];
}
}

View File

@ -359,6 +359,7 @@ class qtype_numerical extends question_type {
$question->unitdisplay = $questiondata->options->showunits;
$question->unitgradingtype = $questiondata->options->unitgradingtype;
$question->unitpenalty = $questiondata->options->unitpenalty;
$question->unitsleft = $questiondata->options->unitsleft;
$question->ap = $this->make_answer_processor($questiondata->options->units,
$questiondata->options->unitsleft);
}

View File

@ -306,4 +306,23 @@ class qtype_numerical_question_test extends advanced_testcase {
new question_classified_response(null, '$abc', 0.0)),
$num->classify_response(array('answer' => '$abc')));
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$this->resetAfterTest();
$question = test_question_maker::make_question('numerical', 'unit');
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertNotEmpty($options);
$this->assertEquals(1, $options['unitgradingtype']);
$this->assertEquals(0.5, $options['unitpenalty']);
$this->assertEquals(qtype_numerical::UNITSELECT, $options['unitdisplay']);
$this->assertEmpty($options['unitsleft']);
}
}

View File

@ -184,4 +184,17 @@ class qtype_shortanswer_question extends question_graded_by_strategy
$args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// No need to return anything, external clients do not need additional information for rendering this question type.
return null;
}
}

View File

@ -226,4 +226,19 @@ class qtype_shortanswer_question_test extends advanced_testcase {
question_classified_response::no_response()),
$sa->classify_response(array('answer' => '')));
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$this->resetAfterTest();
$question = test_question_maker::make_question('shortanswer');
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertNull($options);
}
}

View File

@ -123,4 +123,17 @@ class qtype_truefalse_question extends question_graded_automatically {
$args, $forcedownload);
}
}
/**
* Return the question settings that define this question as structured data.
*
* @param question_attempt $qa the current attempt for which we are exporting the settings.
* @param question_display_options $options the question display options which say which aspects of the question
* should be visible.
* @return mixed structure representing the question settings. In web services, this will be JSON-encoded.
*/
public function get_question_definition_for_external_rendering(question_attempt $qa, question_display_options $options) {
// No need to return anything, external clients do not need additional information for rendering this question type.
return null;
}
}

View File

@ -107,4 +107,19 @@ class qtype_truefalse_question_test extends advanced_testcase {
$tf->id => question_classified_response::no_response()),
$tf->classify_response(array()));
}
/**
* test_get_question_definition_for_external_rendering
*/
public function test_get_question_definition_for_external_rendering() {
$this->resetAfterTest();
$question = test_question_maker::make_question('truefalse', 'true');
$question->start_attempt(new question_attempt_step(), 1);
$qa = test_question_maker::get_a_qa($question);
$displayoptions = new question_display_options();
$options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
$this->assertNull($options);
}
}