From 2144bdf06c4ee342dee3a42bd63d656737b08cdc Mon Sep 17 00:00:00 2001 From: Laurent David Date: Mon, 29 May 2023 15:27:39 +0200 Subject: [PATCH] MDL-78056 mod_h5pactivity: Fix incorrect attempt report * Fix interpretation of the results on the attempt report whenever case sensitive option is enabled. --- .../classes/output/result/fillin.php | 7 +- .../tests/behat/result_fillin.feature | 12 +- .../tests/output/result/result_test.php | 129 ++++++++++++++++++ 3 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 mod/h5pactivity/tests/output/result/result_test.php diff --git a/mod/h5pactivity/classes/output/result/fillin.php b/mod/h5pactivity/classes/output/result/fillin.php index 35d33bbfea3..b3ef2e968fa 100644 --- a/mod/h5pactivity/classes/output/result/fillin.php +++ b/mod/h5pactivity/classes/output/result/fillin.php @@ -54,8 +54,9 @@ class fillin extends result { // There are two way in which H5P could force case sensitivity, with extensions // or using options in the correctpatterns. By default it is case sensible. $casesensitive = $extensions['https://h5p.org/x-api/case-sensitivity'] ?? true; - if (!empty($this->result->correctpattern) && strpos($this->result->correctpattern, '{case_matters=false}') !== null) { - $casesensitive = false; + if ((!empty($this->result->correctpattern) + && strpos($this->result->correctpattern, '{case_matters=false}') !== false)) { + $casesensitive = false; } $values = []; @@ -101,7 +102,7 @@ class fillin extends result { } else { $state = parent::INCORRECT; } - $option->useranswer = $this->get_answer($state, $gapresponse); + $option->useranswer = $this->get_answer($state, $this->response[$key]); $option->correctanswer = $this->get_answer(parent::TEXT, implode(' / ', $value)); diff --git a/mod/h5pactivity/tests/behat/result_fillin.feature b/mod/h5pactivity/tests/behat/result_fillin.feature index 057eea12d1e..44458204774 100644 --- a/mod/h5pactivity/tests/behat/result_fillin.feature +++ b/mod/h5pactivity/tests/behat/result_fillin.feature @@ -40,10 +40,10 @@ Feature: View fill the blanks attempt report When I navigate to "Attempts report" in current page administration And I follow "View report" Then I should see "Of which countries are Berlin, Washington, Beijing, Canberra and Brasilia the capitals?" - And I should see "brigadoon" in the "brasilia" "table_row" - And "Your answer is incorrect" "icon" should exist in the "brasilia" "table_row" - And I should see "emerald city" in the "washington" "table_row" - And I should see "narnia" in the "berlin" "table_row" - And "Your answer is incorrect" "icon" should exist in the "berlin" "table_row" - And "Your answer is correct" "icon" should exist in the "canberra" "table_row" + And I should see "Brigadoon" in the "Brasilia" "table_row" + And "Your answer is incorrect" "icon" should exist in the "Brasilia" "table_row" + And I should see "Emerald city" in the "Washington" "table_row" + And I should see "Narnia" in the "Berlin" "table_row" + And "Your answer is incorrect" "icon" should exist in the "Berlin" "table_row" + And "Your answer is correct" "icon" should exist in the "Canberra" "table_row" And I should not see "

" diff --git a/mod/h5pactivity/tests/output/result/result_test.php b/mod/h5pactivity/tests/output/result/result_test.php new file mode 100644 index 00000000000..fdb003af1c1 --- /dev/null +++ b/mod/h5pactivity/tests/output/result/result_test.php @@ -0,0 +1,129 @@ +. +namespace mod_h5pactivity\output\result; + +use core_xapi\local\statement\item_result; +use core_xapi\xapi_exception; +use mod_h5pactivity\local\manager; + +/** + * Result test class for H5P activity. + * + * @package mod_h5pactivity + * @covers \mod_h5pactivity\output\result + * @category test + * @copyright 2023 Laurent David + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class result_test extends \advanced_testcase { + /** + * Test result export_options + * + * @param array $providedresultdata + * @param array $expecteduseranswers + * @return void + * @dataProvider result_data_provider + * @covers \mod_h5pactivity\output\result::export_options + */ + public function test_result_options(array $providedresultdata, array $expecteduseranswers): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + $activity = $this->getDataGenerator()->create_module('h5pactivity', + ['course' => $course]); + + $manager = manager::create_from_instance($activity); + $cm = $manager->get_coursemodule(); + $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); + + $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity'); + + $params = ['cmid' => $cm->id, 'userid' => $student->id]; + $attempt = $generator->create_content($activity, $params); + $resultdata = [ + 'attemptid' => $attempt->id, + 'subcontent' => '', + 'timecreated' => time(), + 'completion' => true, + 'success' => true, + 'score' => (object) ['min' => 0, 'max' => 2, 'raw' => 2, 'scaled' => 1], + 'duration' => 'PT25S', + ]; + $resultdata = array_merge($resultdata, $providedresultdata); + $result = item_result::create_from_data((object) $resultdata); + $classname = "mod_h5pactivity\\output\\result\\{$providedresultdata['interactiontype']}"; + $classname = str_replace('-', '', $classname); + + $reflectionoutput = new \ReflectionClass($classname); + $constructor = $reflectionoutput->getConstructor(); + $constructor->setAccessible(true); + $resultoutput = $reflectionoutput->newInstanceWithoutConstructor(); + $constructor->invoke($resultoutput, $result->get_data()); + + $exportoptions = $reflectionoutput->getMethod('export_options'); + $exportoptions->setAccessible(true); + + $data = $exportoptions->invoke($resultoutput); + $useranswersdata = array_map(function($item) { + return $item->useranswer; + }, $data); + $this->assertEquals($expecteduseranswers, $useranswersdata); + } + + /** + * Data provider for result export_options test + * @return array[] + */ + public function result_data_provider(): array { + return [ + 'fill-in with case sensitive' => [ + 'result' => [ + 'interactiontype' => 'fill-in', + 'description' => '

Fill in the missing words

+

Meow .... this is a __________

+

Bark... this is a __________

', + 'correctpattern' => '["{case_matters=true}cat[,]dog"]', + 'response' => 'Cat[,]dog', + 'additionals' => '{"extensions":{"http:\\/\\/h5p.org\\/x-api\\/h5p-local-content-id":31,' + . '"https:\\/\\/h5p.org\\/x-api\\/case-sensitivity":true,' + . '"https:\\/\\/h5p.org\\/x-api\\/alternatives":[["cat"],["dog"]]},"contextExtensions":{}}', + ], + 'useranswers' => [ + (object) ['answer' => 'Cat', 'incorrect' => true], + (object) ['answer' => 'dog', 'correct' => true], + ], + ], + 'fill-in with case insensitive' => [ + 'result' => [ + 'interactiontype' => 'fill-in', + 'description' => '

Fill in the missing words

+

Meow .... this is a __________

+

Bark... this is a __________

', + 'correctpattern' => '["{case_matters=false}cat[,]dog"]', + 'response' => 'Cat[,]dog', + 'additionals' => '{"extensions":{"http:\\/\\/h5p.org\\/x-api\\/h5p-local-content-id":31,' + . '"https:\\/\\/h5p.org\\/x-api\\/case-sensitivity":false,' + . '"https:\\/\\/h5p.org\\/x-api\\/alternatives":[["cat"],["dog"]]},"contextExtensions":{}}', + ], + 'useranswers' => [ + (object) ['answer' => 'Cat', 'correct' => true], + (object) ['answer' => 'dog', 'correct' => true], + ], + ] + ]; + } +}