From: Tim Hunt Date: Thu, 3 Feb 2011 11:07:11 +0000 (+0000) Subject: MDL-20636 Merge branch 'master' into qe2_wip X-Git-Tag: v2.1.0~482 X-Git-Url: http://git.moodle.org/gw?p=moodle.git;a=commitdiff_plain;h=74c479f212894edc81ee49e34248c1cdbe1c229a MDL-20636 Merge branch 'master' into qe2_wip Conflicts: lib/questionlib.php question/type/calculated/lang/en/qtype_calculated.php question/type/questiontype.php --- 74c479f212894edc81ee49e34248c1cdbe1c229a diff --cc question/format/gift/format.php index 168dc545b1c,e086691a21f..6d3e4c436fa mode 100644,100755..100644 --- a/question/format/gift/format.php +++ b/question/format/gift/format.php diff --cc question/format/gift/simpletest/testgiftformat.php index ade283c4005,113329a4dc5..8f44f32af27 --- a/question/format/gift/simpletest/testgiftformat.php +++ b/question/format/gift/simpletest/testgiftformat.php @@@ -659,6 -659,74 +659,74 @@@ FALSE#42 is the Ultimate Answer.#You ga $this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q); } + public function test_import_truefalse_true_answer1() { + $gift = "// name 0-11 + ::2-08 TSL::TSL is blablabla.{T}"; + $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); + + $importer = new qformat_gift(); + $q = $importer->readquestion($lines); + + $expectedq = (object) array( + 'name' => '2-08 TSL', + 'questiontext' => "TSL is blablabla.", + 'questiontextformat' => FORMAT_MOODLE, + 'generalfeedback' => '', + 'generalfeedbackformat' => FORMAT_MOODLE, + 'qtype' => 'truefalse', - 'defaultgrade' => 1, ++ 'defaultmark' => 1, + 'penalty' => 1, + 'length' => 1, + 'correctanswer' => 1, + 'feedbacktrue' => array( + 'text' => '', + 'format' => FORMAT_MOODLE, + 'files' => array(), + ), + 'feedbackfalse' => array( + 'text' => '', + 'format' => FORMAT_MOODLE, + 'files' => array(), + ), + ); + + $this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q); + } + + public function test_import_truefalse_true_answer2() { + $gift = "// name 0-11 + ::2-08 TSL::TSL is blablabla.{TRUE}"; + $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); + + $importer = new qformat_gift(); + $q = $importer->readquestion($lines); + + $expectedq = (object) array( + 'name' => '2-08 TSL', + 'questiontext' => "TSL is blablabla.", + 'questiontextformat' => FORMAT_MOODLE, + 'generalfeedback' => '', + 'generalfeedbackformat' => FORMAT_MOODLE, + 'qtype' => 'truefalse', - 'defaultgrade' => 1, ++ 'defaultmark' => 1, + 'penalty' => 1, + 'length' => 1, + 'correctanswer' => 1, + 'feedbacktrue' => array( + 'text' => '', + 'format' => FORMAT_MOODLE, + 'files' => array(), + ), + 'feedbackfalse' => array( + 'text' => '', + 'format' => FORMAT_MOODLE, + 'files' => array(), + ), + ); + + $this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q); + } + public function test_export_truefalse() { $qdata = (object) array( 'id' => 666 , diff --cc question/type/numerical/question.php index 7eba5a77365,00000000000..1e57595c3e3 mode 100644,000000..100644 --- a/question/type/numerical/question.php +++ b/question/type/numerical/question.php @@@ -1,151 -1,0 +1,151 @@@ +. + + +/** + * Numerical question definition class. + * + * @package qtype_numerical + * @copyright 2009 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once($CFG->dirroot . '/question/type/numerical/questiontype.php'); + + +/** + * Represents a numerical question. + * + * @copyright 2009 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class qtype_numerical_question extends question_graded_by_strategy + implements question_response_answer_comparer { + /** @var array of question_answer. */ + public $answers = array(); + /** @var qtype_numerical_answer_processor */ + public $ap; + + public function __construct() { + parent::__construct(new question_first_matching_answer_grading_strategy($this)); + } + + public function get_expected_data() { - return array('answer' => PARAM_TRIM); ++ return array('answer' => PARAM_RAW_TRIMMED); + } + + public function init_first_step(question_attempt_step $step) { + if ($step->has_qt_var('_separators')) { + list($point, $separator) = explode('$', $step->get_qt_var('_separators')); + $this->ap->set_characters($point, $separator); + } else { + $step->set_qt_var('_separators', + $this->ap->get_point() . '$' . $this->ap->get_separator()); + } + } + + public function summarise_response(array $response) { + if (isset($response['answer'])) { + return $response['answer']; + } else { + return null; + } + } + + public function is_complete_response(array $response) { + return array_key_exists('answer', $response) && + ($response['answer'] || $response['answer'] === '0' || $response['answer'] === 0); + } + + public function get_validation_error(array $response) { + if ($this->is_gradable_response($response)) { + return ''; + } + return get_string('pleaseenterananswer', 'qtype_numerical'); + } + + public function is_same_response(array $prevresponse, array $newresponse) { + return question_utils::arrays_same_at_key_missing_is_blank( + $prevresponse, $newresponse, 'answer'); + } + + public function get_answers() { + return $this->answers; + } + + public function compare_response_with_answer(array $response, question_answer $answer) { + list($value, $unit) = $this->ap->apply_units($response['answer']); + return $answer->within_tolerance($value); + } +} + + +/** + * Subclass of {@link question_answer} with the extra information required by + * the numerical question type. + * + * @copyright 2009 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class qtype_numerical_answer extends question_answer { + /** @var float allowable margin of error. */ + public $tolerance; + /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */ + public $tolerancetype = 2; + + public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) { + parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat); + $this->tolerance = abs($tolerance); + } + + public function get_tolerance_interval() { + if ($this->answer === '*') { + throw new Exception('Cannot work out tolerance interval for answer *.'); + } + + // We need to add a tiny fraction depending on the set precision to make + // the comparison work correctly, otherwise seemingly equal values can + // yield false. See MDL-3225. + $tolerance = (float) $this->tolerance + pow(10, -1 * ini_get('precision')); + + switch ($this->tolerancetype) { + case 1: case 'relative': + $range = abs($this->answer) * $tolerance; + return array($this->answer - $range, $this->answer + $range); + + case 2: case 'nominal': + $tolerance = $this->tolerance + pow(10, -1 * ini_get('precision')) * + max(1, abs($this->answer)); + return array($this->answer - $tolerance, $this->answer + $tolerance); + + case 3: case 'geometric': + $quotient = 1 + abs($tolerance); + return array($this->answer / $quotient, $this->answer * $quotient); + + default: + throw new Exception('Unknown tolerance type ' . $this->tolerancetype); + } + } + + public function within_tolerance($value) { + if ($this->answer === '*') { + return true; + } + list($min, $max) = $this->get_tolerance_interval(); + return $min <= $value && $value <= $max; + } +} diff --cc question/type/shortanswer/question.php index 8ea182dc3de,00000000000..ca361163d6f mode 100644,000000..100644 --- a/question/type/shortanswer/question.php +++ b/question/type/shortanswer/question.php @@@ -1,115 -1,0 +1,115 @@@ +. + + +/** + * Short answer question definition class. + * + * @package qtype_shortanswer + * @copyright 2009 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +/** + * Represents a short answer question. + * + * @copyright 2009 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class qtype_shortanswer_question extends question_graded_by_strategy + implements question_response_answer_comparer { + /** @var boolean whether answers should be graded case-sensitively. */ + public $usecase; + /** @var array of question_answer. */ + public $answers = array(); + + public function __construct() { + parent::__construct(new question_first_matching_answer_grading_strategy($this)); + } + + public function get_expected_data() { - return array('answer' => PARAM_TRIM); ++ return array('answer' => PARAM_RAW_TRIMMED); + } + + public function summarise_response(array $response) { + if (isset($response['answer'])) { + return $response['answer']; + } else { + return null; + } + } + + public function is_complete_response(array $response) { + return array_key_exists('answer', $response) && + ($response['answer'] || $response['answer'] === '0'); + } + + public function get_validation_error(array $response) { + if ($this->is_gradable_response($response)) { + return ''; + } + return get_string('pleaseenterananswer', 'qtype_shortanswer'); + } + + public function is_same_response(array $prevresponse, array $newresponse) { + return question_utils::arrays_same_at_key_missing_is_blank( + $prevresponse, $newresponse, 'answer'); + } + + public function get_answers() { + return $this->answers; + } + + public function compare_response_with_answer(array $response, question_answer $answer) { + return self::compare_string_with_wildcard($response['answer'], $answer->answer, !$this->usecase); + } + + public static function compare_string_with_wildcard($string, $pattern, $ignorecase) { + // Break the string on non-escaped asterisks. + $bits = preg_split('/(?get_last_qt_var('answer'); + $answer = $qa->get_question()->get_matching_answer(array('answer' => $currentanswer)); + $answerid = reset($args); // itemid is answer id. + return $options->feedback && $answerid == $answer->id; + + } else if ($component == 'question' && $filearea == 'hint') { + return $this->check_hint_file_access($qa, $options, $args); + + } else { + return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload); + } + } +}