Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
integration
prechecker
Commits
bc65073a
Commit
bc65073a
authored
Jun 30, 2015
by
Dan Poltawski
Browse files
Merge branch 'MDL-47787-m28' of
https://github.com/tbannister/moodle
into MOODLE_28_STABLE
parents
41b330ab
d45b318a
Changes
5
Hide whitespace changes
Inline
Side-by-side
admin/cli/fix_orphaned_question_categories.php
0 → 100644
View file @
bc65073a
<?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/>.
/**
* This script fixes orphaned question categories.
*
* Orphaned question categories have had their associated context deleted
* but the category itself remains in the database with an invalid context.
*
* @package core
* @subpackage cli
* @copyright 2013 Tyler Bannister (tyler.bannister@remote-learner.net)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define
(
'CLI_SCRIPT'
,
true
);
require
(
__DIR__
.
'/../../config.php'
);
require_once
(
$CFG
->
libdir
.
'/clilib.php'
);
require_once
(
$CFG
->
libdir
.
'/questionlib.php'
);
$long
=
array
(
'fix'
=>
false
,
'help'
=>
false
);
$short
=
array
(
'f'
=>
'fix'
,
'h'
=>
'help'
);
// Now get cli options.
list
(
$options
,
$unrecognized
)
=
cli_get_params
(
$long
,
$short
);
if
(
$unrecognized
)
{
$unrecognized
=
implode
(
"
\n
"
,
$unrecognized
);
cli_error
(
get_string
(
'cliunknowoption'
,
'admin'
,
$unrecognized
));
}
if
(
$options
[
'help'
])
{
$help
=
"Fix orphaned question categories.
This scripts detects question categories that have had their
context deleted, thus severing them from their original purpose.
This script will find the orphaned categories and delete the unused
questions in each category found. Used questions will not be
deleted, instead they will be moved to a rescue question category.
Options:
-h, --help Print out this help
-f, --fix Fix the orphaned question categories in the DB.
If not specified only check and report problems to STDERR.
Example:
\$
sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_question_categories.php
\$
sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_question_categories.php -f
"
;
echo
$help
;
die
;
}
cli_heading
(
'Checking for orphaned categories'
);
$sql
=
'SELECT qc.id, qc.contextid, qc.name
FROM {question_categories} qc
LEFT JOIN {context} c ON qc.contextid = c.id
WHERE c.id IS NULL'
;
$categories
=
$DB
->
get_recordset_sql
(
$sql
);
$i
=
0
;
foreach
(
$categories
as
$category
)
{
$i
+=
1
;
echo
"Found orphaned category:
{
$category
->
name
}
\n
"
;
if
(
!
empty
(
$options
[
'fix'
]))
{
echo
"Cleaning..."
;
// One transaction per category.
$transaction
=
$DB
->
start_delegated_transaction
();
question_category_delete_safe
(
$category
);
$transaction
->
allow_commit
();
echo
" Done!
\n
"
;
}
}
if
((
$i
>
0
)
&&
!
empty
(
$options
[
'fix'
]))
{
echo
"Found and removed
{
$i
}
orphaned question categories
\n
"
;
}
else
if
(
$i
>
0
)
{
echo
"Found
{
$i
}
orphaned question categories. To fix, run:
\n
"
;
echo
"
\$
sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_question_categories.php --fix
\n
"
;
}
else
{
echo
"No orphaned question categories found.
\n
"
;
}
$categories
->
close
();
course/lib.php
View file @
bc65073a
...
...
@@ -1636,7 +1636,7 @@ function set_coursemodule_visible($id, $visible) {
}
/**
* This function will handle
s
the whole deletion process of a module. This includes calling
* This function will handle the whole deletion process of a module. This includes calling
* the modules delete_instance function, deleting files, events, grades, conditional data,
* the data in the course_module and course_sections table and adding a module deletion
* event to the DB.
...
...
@@ -1648,9 +1648,10 @@ function course_delete_module($cmid) {
global
$CFG
,
$DB
;
require_once
(
$CFG
->
libdir
.
'/gradelib.php'
);
require_once
(
$CFG
->
libdir
.
'/questionlib.php'
);
require_once
(
$CFG
->
dirroot
.
'/blog/lib.php'
);
require_once
(
$CFG
->
dirroot
.
'/calendar/lib.php'
);
require_once
(
$CFG
->
dirroot
.
'/tag/lib.php'
);
require_once
(
$CFG
->
dirroot
.
'/tag/lib.php'
);
// Get the course module.
if
(
!
$cm
=
$DB
->
get_record
(
'course_modules'
,
array
(
'id'
=>
$cmid
)))
{
...
...
@@ -1682,6 +1683,9 @@ function course_delete_module($cmid) {
"Cannot delete this module as the function
{
$modulename
}
_delete_instance is missing in mod/
$modulename
/lib.php."
);
}
// Delete activity context questions and question categories.
question_delete_activity
(
$cm
);
// Call the delete_instance function, if it returns false throw an exception.
if
(
!
$deleteinstancefunction
(
$cm
->
instance
))
{
throw
new
moodle_exception
(
'cannotdeletemoduleinstance'
,
''
,
''
,
null
,
...
...
course/tests/courselib_test.php
View file @
bc65073a
...
...
@@ -539,7 +539,23 @@ class core_course_courselib_testcase extends advanced_testcase {
return
$moduleinfo
;
}
/**
* Data provider for course_delete module
*
* @return array An array of arrays contain test data
*/
public
function
provider_course_delete_module
()
{
$data
=
array
();
$data
[
'assign'
]
=
array
(
'assign'
,
array
(
'duedate'
=>
time
()));
$data
[
'quiz'
]
=
array
(
'quiz'
,
array
(
'duedate'
=>
time
()));
return
$data
;
}
/**
* Test the create_course function
*/
public
function
test_create_course
()
{
global
$DB
;
$this
->
resetAfterTest
(
true
);
...
...
@@ -1352,51 +1368,92 @@ class core_course_courselib_testcase extends advanced_testcase {
$this
->
assertEquals
(
$pagecm
->
visible
,
0
);
}
public
function
test_course_delete_module
()
{
/**
* Tests the function that deletes a course module
*
* @param string $type The type of module for the test
* @param array $options The options for the module creation
* @dataProvider provider_course_delete_module
*/
public
function
test_course_delete_module
(
$type
,
$options
)
{
global
$DB
;
$this
->
resetAfterTest
(
true
);
$this
->
setAdminUser
();
// Create course and modules.
$course
=
$this
->
getDataGenerator
()
->
create_course
(
array
(
'numsections'
=>
5
));
$options
[
'course'
]
=
$course
->
id
;
// Generate an assignment with due date (will generate a course event).
$
assign
=
$this
->
getDataGenerator
()
->
create_module
(
'assign'
,
array
(
'duedate'
=>
time
(),
'course'
=>
$course
->
id
)
);
$
module
=
$this
->
getDataGenerator
()
->
create_module
(
$type
,
$options
);
// Get the module context.
$modcontext
=
context_module
::
instance
(
$
assign
->
cmid
);
$modcontext
=
context_module
::
instance
(
$
module
->
cmid
);
// Verify context exists.
$this
->
assertInstanceOf
(
'context_module'
,
$modcontext
);
// Add some tags to this assignment.
tag_set
(
'assign'
,
$assign
->
id
,
array
(
'Tag 1'
,
'Tag 2'
,
'Tag 3'
),
'mod_assign'
,
$modcontext
->
id
);
// Confirm the tag instances were added.
$this
->
assertEquals
(
3
,
$DB
->
count_records
(
'tag_instance'
,
array
(
'component'
=>
'mod_assign'
,
'contextid'
=>
$modcontext
->
id
)));
// Verify event assignment event has been generated.
$eventcount
=
$DB
->
count_records
(
'event'
,
array
(
'instance'
=>
$assign
->
id
,
'modulename'
=>
'assign'
));
$this
->
assertEquals
(
1
,
$eventcount
);
// Make module specific messes.
switch
(
$type
)
{
case
'assign'
:
// Add some tags to this assignment.
tag_set
(
'assign'
,
$module
->
id
,
array
(
'Tag 1'
,
'Tag 2'
,
'Tag 3'
),
'mod_assign'
,
$modcontext
->
id
);
// Confirm the tag instances were added.
$criteria
=
array
(
'component'
=>
'mod_assign'
,
'contextid'
=>
$modcontext
->
id
);
$this
->
assertEquals
(
3
,
$DB
->
count_records
(
'tag_instance'
,
$criteria
));
// Verify event assignment event has been generated.
$eventcount
=
$DB
->
count_records
(
'event'
,
array
(
'instance'
=>
$module
->
id
,
'modulename'
=>
$type
));
$this
->
assertEquals
(
1
,
$eventcount
);
break
;
case
'quiz'
:
$qgen
=
$this
->
getDataGenerator
()
->
get_plugin_generator
(
'core_question'
);
$qcat
=
$qgen
->
create_question_category
(
array
(
'contextid'
=>
$modcontext
->
id
));
$questions
=
array
(
$qgen
->
create_question
(
'shortanswer'
,
null
,
array
(
'category'
=>
$qcat
->
id
)),
$qgen
->
create_question
(
'shortanswer'
,
null
,
array
(
'category'
=>
$qcat
->
id
)),
);
$this
->
expectOutputRegex
(
'/'
.
get_string
(
'unusedcategorydeleted'
,
'question'
)
.
'/'
);
break
;
default
:
break
;
}
// Run delete..
course_delete_module
(
$
assign
->
cmid
);
course_delete_module
(
$
module
->
cmid
);
// Verify the context has been removed.
$this
->
assertFalse
(
context_module
::
instance
(
$
assign
->
cmid
,
IGNORE_MISSING
));
$this
->
assertFalse
(
context_module
::
instance
(
$
module
->
cmid
,
IGNORE_MISSING
));
// Verify the course_module record has been deleted.
$cmcount
=
$DB
->
count_records
(
'course_modules'
,
array
(
'id'
=>
$
assign
->
cmid
));
$cmcount
=
$DB
->
count_records
(
'course_modules'
,
array
(
'id'
=>
$
module
->
cmid
));
$this
->
assertEmpty
(
$cmcount
);
// Verify event assignment events have been removed.
$eventcount
=
$DB
->
count_records
(
'event'
,
array
(
'instance'
=>
$assign
->
id
,
'modulename'
=>
'assign'
));
$this
->
assertEmpty
(
$eventcount
);
// Verify the tag instances were deleted.
$this
->
assertEquals
(
0
,
$DB
->
count_records
(
'tag_instance'
,
array
(
'component'
=>
'mod_assign'
,
'contextid'
=>
$modcontext
->
id
)));
// Test clean up of module specific messes.
switch
(
$type
)
{
case
'assign'
:
// Verify event assignment events have been removed.
$eventcount
=
$DB
->
count_records
(
'event'
,
array
(
'instance'
=>
$module
->
id
,
'modulename'
=>
$type
));
$this
->
assertEmpty
(
$eventcount
);
// Verify the tag instances were deleted.
$criteria
=
array
(
'component'
=>
'mod_assign'
,
'contextid'
=>
$modcontext
->
id
);
$this
->
assertEquals
(
0
,
$DB
->
count_records
(
'tag_instance'
,
$criteria
));
break
;
case
'quiz'
:
// Verify category deleted.
$criteria
=
array
(
'contextid'
=>
$modcontext
->
id
);
$this
->
assertEquals
(
0
,
$DB
->
count_records
(
'question_categories'
,
$criteria
));
// Verify questions deleted.
$criteria
=
array
(
'category'
=>
$qcat
->
id
);
$this
->
assertEquals
(
0
,
$DB
->
count_records
(
'question'
,
$criteria
));
break
;
default
:
break
;
}
}
/**
...
...
lib/questionlib.php
View file @
bc65073a
...
...
@@ -261,6 +261,52 @@ function question_category_isused($categoryid, $recursive = false) {
'Please use question_category_in_use instead.'
);
}
/**
* Category is about to be deleted,
* 1/ All questions are deleted for this question category.
* 2/ Any questions that can't be deleted are moved to a new category
* NOTE: this function is called from lib/db/upgrade.php
*
* @param object|coursecat $category course category object
*/
function
question_category_delete_safe
(
$category
)
{
global
$DB
;
$criteria
=
array
(
'category'
=>
$category
->
id
);
$context
=
context
::
instance_by_id
(
$category
->
contextid
,
IGNORE_MISSING
);
$rescue
=
null
;
// See the code around the call to question_save_from_deletion.
// Deal with any questions in the category.
if
(
$questions
=
$DB
->
get_records
(
'question'
,
$criteria
,
''
,
'id,qtype'
))
{
// Try to delete each question.
foreach
(
$questions
as
$question
)
{
question_delete_question
(
$question
->
id
);
}
// Check to see if there were any questions that were kept because
// they are still in use somehow, even though quizzes in courses
// in this category will already have been deleted. This could
// happen, for example, if questions are added to a course,
// and then that course is moved to another category (MDL-14802).
$questionids
=
$DB
->
get_records_menu
(
'question'
,
$criteria
,
''
,
'id, 1'
);
if
(
!
empty
(
$questionids
))
{
$parentcontextid
=
SYSCONTEXTID
;
$name
=
get_string
(
'unknown'
,
'question'
);
if
(
$context
!==
false
)
{
$name
=
$context
->
get_context_name
();
$parentcontext
=
$context
->
get_parent_context
();
if
(
$parentcontext
)
{
$parentcontextid
=
$parentcontext
->
id
;
}
}
question_save_from_deletion
(
array_keys
(
$questionids
),
$parentcontextid
,
$name
,
$rescue
);
}
}
// Now delete the category.
$DB
->
delete_records
(
'question_categories'
,
array
(
'id'
=>
$category
->
id
));
}
/**
* Tests whether any question in a category is used by any part of Moodle.
*
...
...
@@ -347,54 +393,52 @@ function question_delete_question($questionid) {
}
/**
* All question categories and their questions are deleted for this co
urse
.
* All question categories and their questions are deleted for this co
ntext id
.
*
* @param stdClass $course an object representing the activity
* @param boolean $feedback to specify if the process must output a summary of its work
* @return boolean
* @param object $contextid The contextid to delete question categories from
* @return array Feedback from deletes (if any)
*/
function
question_delete_co
urse
(
$course
,
$feedback
=
true
)
{
global
$DB
,
$OUTPUT
;
function
question_delete_co
ntext
(
$contextid
)
{
global
$DB
;
//To store feedback to be showed at the end of the process
$feedbackdata
=
array
();
//Cache some strings
$strcatdeleted
=
get_string
(
'unusedcategorydeleted'
,
'question'
);
$coursecontext
=
context_course
::
instance
(
$course
->
id
);
$categoriescourse
=
$DB
->
get_records
(
'question_categories'
,
array
(
'contextid'
=>
$coursecontext
->
id
),
'parent'
,
'id, parent, name, contextid'
);
if
(
$categoriescourse
)
{
$fields
=
'id, parent, name, contextid'
;
if
(
$categories
=
$DB
->
get_records
(
'question_categories'
,
array
(
'contextid'
=>
$contextid
),
'parent'
,
$fields
))
{
//Sort categories following their tree (parent-child) relationships
//this will make the feedback more readable
$categoriescourse
=
sort_categories_by_tree
(
$categoriescourse
);
foreach
(
$categoriescourse
as
$category
)
{
$categories
=
sort_categories_by_tree
(
$categories
);
//Delete it completely (questions and category itself)
//deleting questions
if
(
$questions
=
$DB
->
get_records
(
'question'
,
array
(
'category'
=>
$category
->
id
),
''
,
'id,qtype'
))
{
foreach
(
$questions
as
$question
)
{
question_delete_question
(
$question
->
id
);
}
$DB
->
delete_records
(
"question"
,
array
(
"category"
=>
$category
->
id
));
}
//delete the category
$DB
->
delete_records
(
'question_categories'
,
array
(
'id'
=>
$category
->
id
));
foreach
(
$categories
as
$category
)
{
question_category_delete_safe
(
$category
);
//Fill feedback
$feedbackdata
[]
=
array
(
$category
->
name
,
$strcatdeleted
);
}
//Inform about changes performed if feedback is enabled
if
(
$feedback
)
{
$table
=
new
html_table
();
$table
->
head
=
array
(
get_string
(
'category'
,
'question'
),
get_string
(
'action'
));
$table
->
data
=
$feedbackdata
;
echo
html_writer
::
table
(
$table
);
}
}
return
$feedbackdata
;
}
/**
* All question categories and their questions are deleted for this course.
*
* @param stdClass $course an object representing the activity
* @param boolean $feedback to specify if the process must output a summary of its work
* @return boolean
*/
function
question_delete_course
(
$course
,
$feedback
=
true
)
{
$coursecontext
=
context_course
::
instance
(
$course
->
id
);
$feedbackdata
=
question_delete_context
(
$coursecontext
->
id
,
$feedback
);
// Inform about changes performed if feedback is enabled.
if
(
$feedback
&&
$feedbackdata
)
{
$table
=
new
html_table
();
$table
->
head
=
array
(
get_string
(
'category'
,
'question'
),
get_string
(
'action'
));
$table
->
data
=
$feedbackdata
;
echo
html_writer
::
table
(
$table
);
}
return
true
;
}
...
...
@@ -415,58 +459,10 @@ function question_delete_course_category($category, $newcategory, $feedback=true
$context
=
context_coursecat
::
instance
(
$category
->
id
);
if
(
empty
(
$newcategory
))
{
$feedbackdata
=
array
();
// To store feedback to be showed at the end of the process
$rescueqcategory
=
null
;
// See the code around the call to question_save_from_deletion.
$strcatdeleted
=
get_string
(
'unusedcategorydeleted'
,
'question'
);
// Loop over question categories.
if
(
$categories
=
$DB
->
get_records
(
'question_categories'
,
array
(
'contextid'
=>
$context
->
id
),
'parent'
,
'id, parent, name'
))
{
foreach
(
$categories
as
$category
)
{
// Deal with any questions in the category.
if
(
$questions
=
$DB
->
get_records
(
'question'
,
array
(
'category'
=>
$category
->
id
),
''
,
'id,qtype'
))
{
// Try to delete each question.
foreach
(
$questions
as
$question
)
{
question_delete_question
(
$question
->
id
);
}
// Check to see if there were any questions that were kept because
// they are still in use somehow, even though quizzes in courses
// in this category will already have been deleted. This could
// happen, for example, if questions are added to a course,
// and then that course is moved to another category (MDL-14802).
$questionids
=
$DB
->
get_records_menu
(
'question'
,
array
(
'category'
=>
$category
->
id
),
''
,
'id, 1'
);
if
(
!
empty
(
$questionids
))
{
$parentcontextid
=
false
;
$parentcontext
=
$context
->
get_parent_context
();
if
(
$parentcontext
)
{
$parentcontextid
=
$parentcontext
->
id
;
}
if
(
!
$rescueqcategory
=
question_save_from_deletion
(
array_keys
(
$questionids
),
$parentcontextid
,
$context
->
get_context_name
(),
$rescueqcategory
))
{
return
false
;
}
$feedbackdata
[]
=
array
(
$category
->
name
,
get_string
(
'questionsmovedto'
,
'question'
,
$rescueqcategory
->
name
));
}
}
// Now delete the category.
if
(
!
$DB
->
delete_records
(
'question_categories'
,
array
(
'id'
=>
$category
->
id
)))
{
return
false
;
}
$feedbackdata
[]
=
array
(
$category
->
name
,
$strcatdeleted
);
}
// End loop over categories.
}
$feedbackdata
=
question_delete_context
(
$context
->
id
,
$feedback
);
// Output feedback if requested.
if
(
$feedback
and
$feedbackdata
)
{
if
(
$feedback
&&
$feedbackdata
)
{
$table
=
new
html_table
();
$table
->
head
=
array
(
get_string
(
'questioncategory'
,
'question'
),
get_string
(
'action'
));
$table
->
data
=
$feedbackdata
;
...
...
@@ -501,7 +497,7 @@ function question_delete_course_category($category, $newcategory, $feedback=true
* Enter description here...
*
* @param array $questionids of question ids
* @param object $newcontext the context to create the saved category in.
* @param object $newcontext
id
the context to create the saved category in.
* @param string $oldplace a textual description of the think being deleted,
* e.g. from get_context_name
* @param object $newcategory
...
...
@@ -538,44 +534,16 @@ function question_save_from_deletion($questionids, $newcontextid, $oldplace,
* @return boolean
*/
function
question_delete_activity
(
$cm
,
$feedback
=
true
)
{
global
$DB
,
$OUTPUT
;
//To store feedback to be showed at the end of the process
$feedbackdata
=
array
();
global
$DB
;
//Cache some strings
$strcatdeleted
=
get_string
(
'unusedcategorydeleted'
,
'question'
);
$modcontext
=
context_module
::
instance
(
$cm
->
id
);
if
(
$categoriesmods
=
$DB
->
get_records
(
'question_categories'
,
array
(
'contextid'
=>
$modcontext
->
id
),
'parent'
,
'id, parent, name, contextid'
))
{
//Sort categories following their tree (parent-child) relationships
//this will make the feedback more readable
$categoriesmods
=
sort_categories_by_tree
(
$categoriesmods
);
foreach
(
$categoriesmods
as
$category
)
{
//Delete it completely (questions and category itself)
//deleting questions
if
(
$questions
=
$DB
->
get_records
(
'question'
,
array
(
'category'
=>
$category
->
id
),
''
,
'id,qtype'
))
{
foreach
(
$questions
as
$question
)
{
question_delete_question
(
$question
->
id
);
}
$DB
->
delete_records
(
"question"
,
array
(
"category"
=>
$category
->
id
));
}
//delete the category
$DB
->
delete_records
(
'question_categories'
,
array
(
'id'
=>
$category
->
id
));
//Fill feedback
$feedbackdata
[]
=
array
(
$category
->
name
,
$strcatdeleted
);
}
//Inform about changes performed if feedback is enabled
if
(
$feedback
)
{
$table
=
new
html_table
();
$table
->
head
=
array
(
get_string
(
'category'
,
'question'
),
get_string
(
'action'
));
$table
->
data
=
$feedbackdata
;
echo
html_writer
::
table
(
$table
);
}
$feedbackdata
=
question_delete_context
(
$modcontext
->
id
,
$feedback
);
// Inform about changes performed if feedback is enabled.
if
(
$feedback
&&
$feedbackdata
)
{
$table
=
new
html_table
();
$table
->
head
=
array
(
get_string
(
'category'
,
'question'
),
get_string
(
'action'
));
$table
->
data
=
$feedbackdata
;
echo
html_writer
::
table
(
$table
);
}
return
true
;
}
...
...
@@ -1397,7 +1365,7 @@ function question_has_capability_on($question, $cap, $cachecat = -1) {
if
(
!
isset
(
$categories
[
$question
->
category
]))
{
if
(
!
$categories
[
$question
->
category
]
=
$DB
->
get_record
(
'question_categories'
,
array
(
'id'
=>
$question
->
category
)))
{
print_error
(
'invalidcategory'
,
'qu
iz
'
);
print_error
(
'invalidcategory'
,
'qu
estion
'
);
}
}
$category
=
$categories
[
$question
->
category
];
...
...
lib/tests/questionlib_test.php
View file @
bc65073a
...
...
@@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
global
$CFG
;
require_once
(
$CFG
->
libdir
.
'/questionlib.php'
);
require_once
(
$CFG
->
dirroot
.
'/mod/quiz/locallib.php'
);
require_once
(
$CFG
->
dirroot
.
'/tag/lib.php'
);
// Get the necessary files to perform backup and restore.
...
...
@@ -58,6 +59,61 @@ class core_questionlib_testcase extends advanced_testcase {
gc_collect_cycles
();
}
/**
* Return true and false to test functions with feedback on and off.
*
* @return array Test data
*/
public
function
provider_feedback
()
{
return
array
(
'Feedback test'
=>
array
(
true
),
'No feedback test'
=>
array
(
false
)
);
}
/**
* Setup a course, a quiz, a question category and a question for testing.
*
* @param string $type The type of question category to create.
* @return array The created data objects
*/
public
function
setup_quiz_and_questions
(
$type
=
'module'
)
{
// Create course category.
$category
=
$this
->
getDataGenerator
()
->
create_category
();
// Create course.
$course
=
$this
->
getDataGenerator
()
->
create_course
(
array
(
'numsections'
=>
5
));
$options
=
array
(
'course'
=>
$course
->
id
,
'duedate'
=>
time
(),
);
// Generate an assignment with due date (will generate a course event).
$quiz
=
$this
->
getDataGenerator
()
->
create_module
(
'quiz'
,
$options
);
$qgen
=
$this
->
getDataGenerator
()
->
get_plugin_generator
(
'core_question'
);
if
(
'course'
==
$type
)
{
$context
=
context_course
::
instance
(
$course
->
id
);
}
else
if
(
'category'
==
$type
)
{
$context
=
context_coursecat
::
instance
(
$category
->
id
);
}
else
{
$context
=
context_module
::
instance
(
$quiz
->
cmid
);
}
$qcat
=
$qgen
->
create_question_category
(
array
(
'contextid'
=>
$context
->
id
));
$questions
=
array
(
$qgen
->
create_question
(
'shortanswer'
,
null
,
array
(
'category'
=>
$qcat
->
id
)),
$qgen
->
create_question
(
'shortanswer'
,
null
,
array
(
'category'
=>
$qcat
->
id
)),
);
quiz_add_quiz_question
(
$questions
[
0
]
->
id
,
$quiz
);
return
array
(
$category
,
$course
,
$quiz
,
$qcat
,
$questions
);
}
public
function
test_question_reorder_qtypes
()
{
$this
->
assertEquals
(
array
(
0
=>
't2'
,
1
=>
't1'
,
2
=>
't3'
),
...
...
@@ -205,4 +261,140 @@ class core_questionlib_testcase extends advanced_testcase {