View source
<?php
class QuestionsImportTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => t('Question importing unit test'),
'description' => t('Test importing of questions in various formats.'),
'group' => t('Quiz'),
);
}
function setUp() {
parent::setUp('taxonomy', 'quiz', 'views', 'autoload', 'multichoice', 'quiz_directions', 'quiz_question', 'querypath', 'questions_import', 'short_answer', 'truefalse', 'long_answer', 'matching', 'questions_export');
$user = $this
->drupalCreateUser(array(
'administer site configuration',
'access administration pages',
'administer quiz',
'access quiz',
'administer blocks',
'import questions',
'create quiz',
'administer quiz configuration',
'use PHP for block visibility',
'administer blocks',
'create multichoice',
'edit any multichoice',
'administer taxonomy',
'allow multiple correct answers',
'allow any number of answers',
'export questions',
));
$this
->drupalLogin($user);
$quiz_settings = array();
$quiz_settings['title'] = $this
->randomName(128);
$quiz_settings['comment'] = $this
->randomName(256);
$quiz_settings['type'] = 'quiz';
$this
->drupalCreateNode($quiz_settings);
}
function getQuizQuestionList($quiz_nid) {
$db_questions = array();
$sql = "SELECT nr.nid, nr.vid, nr.body, n.type FROM {node_revisions} nr\nJOIN {quiz_node_relationship} qnr ON qnr.child_nid = nr.nid\nJOIN {node} n ON n.nid = nr.nid\nWHERE parent_nid = %d\nORDER BY n.nid";
$result = db_query($sql, $quiz_nid);
while ($question_node = db_fetch_array($result)) {
$db_questions[] = $question_node;
}
return $db_questions;
}
function quizHelper($import_questions = array(), $quiz_nid = 1) {
$db_questions = $this
->getQuizQuestionList($quiz_nid);
$this
->assertEqual(count($import_questions), count($db_questions), "Checking right number of questions in database 2 (expected " . count($import_questions) . " got " . count($db_questions) . ")");
if (count($db_questions) != count($import_questions)) {
return;
}
foreach ($import_questions as $index => $import_q) {
$db_q = $db_questions[$index];
$this
->assertEqual($import_q->question, $db_q['body'], "Question prompts in database match generated import (expected '{$import_q->question}' but got '{$db_q['body']}')");
$this
->assertEqual($import_q->type, $db_q['type'], "Question node types in database match generated import (expected '{$import_q->type}' but got '{$db_q['type']}')");
$this
->answersHelper($import_q, $db_q);
}
}
function answersHelper($import_q, $db_q) {
$node_obj = (object) $db_q;
switch ($import_q->type) {
case 'multichoice':
$mc = multichoice_load($node_obj);
$this
->assertEqual(count($import_q->answers), count($mc->answers), "[multichoice] Matching number of options (expected " . count($import_q->answers) . ", got " . count($mc->answers) . ") " . print_r($mc, true) . print_r($db_q, true));
foreach ($import_q->answers as $index => $import_answer) {
$db_answer = $mc->answers[$index]['answer'];
$this
->assertEqual($import_answer, $db_answer, "[multichoice] Matching option text (expected {$import_answer}, got {$db_answer})");
if ($import_q->answer == $index) {
$this
->assertEqual($mc->answers[$index]['is_correct'], 1, "[multichoice] Matching correct answer(s) (expected question answer to be correct)");
}
else {
$this
->assertEqual($mc->answers[$index]['is_correct'], 0, "[multichoice] Matching incorrect answer(s) (expected question answer to be incorrect)");
}
}
break;
case 'true_false':
$tf = quiz_question_load($node_obj);
$correct = $tf->correct_answer == 0 ? 'false' : 'true';
$this
->assertEqual($import_q->answer, $correct, "[true_false] Matching right answer (expected " . $import_q->answer . ", got " . $correct . ")");
break;
case 'short_answer':
$sa = quiz_question_load($node_obj);
$correct = $sa->correct_answer;
$this
->assertEqual($import_q->answer, $correct, "[short_answer] Checking right answer (expected " . $import_q->answer . ", got " . $correct . ")" . print_r($sa, true));
$this
->assertEqual($import_q->value, $sa->maximum_score, "[short_answer] Checking right score (expected " . $import_q->value . ", got " . $sa->maximum_score . ")");
$this
->assertEqual($import_q->sat, $sa->correct_answer_evaluation, "[short_answer] Checking short answer evaluation type (expected " . $import_q->sat . " (i.e." . $import_q->shortanswertype . "), got " . $sa->correct_answer_evaluation . ")");
break;
case 'matching':
$ma = quiz_question_load($node_obj);
$ma = $ma['answer'];
foreach ($import_q->matches as $index => $i_match) {
$this
->assertEqual($i_match, $ma[$index]['question'], "[matching] Checking corresponding matches {$i_match}, {$ma[$index]['question']}");
$this
->assertEqual($import_q->answers[$index], $ma[$index]['answer'], "[matching] Checking corresponding answers {$import_q->answers[$index]}, {$ma[$index]['answer']}");
}
break;
}
}
function writeImport($input_type, $question) {
$char = array(
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
);
switch ($input_type) {
case "aiken":
switch ($question->type) {
case "multichoice":
$write = $question->type . "\r\n" . $question->question . "\r\n";
for ($i = 0; $i < count($question->answers); $i++) {
$write .= "{$char[$i]}: {$question->answers[$i]}\r\n nil \r\n";
}
$write .= "ANSWER: {$char[$question->answer]} \r\n \r\n";
break;
case "true_false":
$write = $question->type . "\r\n" . $question->question . "\r\n" . $question->answer . "\r\n" . $question->feedback . "\r\n \r\n";
break;
case "short_answer":
$write = $question->type . "\r\n" . $question->question . "\r\n" . $question->answer . "\r\n" . $question->value . "\r\n" . $question->shortanswertype . "\r\n \r\n";
break;
case "long_answer":
$write = $question->type . "\r\n" . $question->question . "\r\n" . $question->value . "\r\n \r\n";
break;
}
break;
case "csv":
switch ($question->type) {
case "multichoice":
$write = $question->type . ', ' . $question->question . ', ';
for ($i = 0; $i < count($question->answers); $i++) {
$write .= $question->answers[$i] . ', nil, ';
}
$write .= $question->answers[$question->answer] . "\r\n";
break;
case "true_false":
$write = $question->type . ', ' . $question->question . ', ' . $question->answer . ', ' . $question->feedback . "\r\n";
break;
case "short_answer":
$write = $question->type . ', ' . $question->question . ', ' . $question->answer . ', ' . $question->value . ', ' . $question->shortanswertype . "\r\n";
break;
case "matching":
$write = $question->type . ', ' . $question->question . ', ';
for ($i = 0; $i < count($question->matches); $i++) {
$write .= $question->matches[$i] . ', ';
$write .= $question->answers[$i] . ', nil, ';
}
$write .= "\r\n";
break;
case "long_answer":
$write = $question->type . ', ' . $question->question . ', ' . $question->value . "\r\n";
break;
}
break;
}
return $write;
}
function medlyHelper($import_type) {
switch ($import_type) {
case 'aiken':
$import_settings['import_type'] = 'native_aiken';
$filetype = '.txt';
break;
case 'csv':
$import_settings['import_type'] = 'native_csv';
$filetype = '.csv';
break;
}
$import_questions = array();
$filepath = file_create_filename($import_type . '_medly' . $filetype, file_directory_temp());
$handle = fopen($filepath, "w+");
for ($i = 0; $i < 30; $i++) {
$question_type = mt_rand(0, 2);
$question = new stdClass();
switch ($question_type) {
case 0:
$question->num_options = mt_rand(1, 10);
$question->answer = mt_rand(0, $question->num_options - 1);
$question->question = "Question #{$i}:";
$question->type = "multichoice";
$question->answers = array();
$write = $question->type . "\r\n" . $question->question . "\r\n";
for ($j = 0; $j < $question->num_options; $j++) {
$question->answers[$j] = "Option #{$j}";
}
break;
case 1:
$question->answer = mt_rand(0, 1) == 0 ? "true" : "false";
$question->question = "Question #{$i}:";
$question->type = "true_false";
$question->feedback = "Feedback on question #{$i}";
break;
case 2:
$question->answer = "The answer is {$i}.";
$question->question = "Question #{$i}:";
$question->type = "short_answer";
$question->value = mt_rand(1, 5);
$question->sat = mt_rand(0, 3);
switch ($question->sat) {
case 0:
$question->shortanswertype = "case sensitive match";
break;
case 1:
$question->shortanswertype = "case insensitive match";
break;
case 2:
$question->shortanswertype = "regular expression match";
break;
case 3:
$question->shortanswertype = "manually score match";
break;
}
break;
}
$write = $this
->writeImport($import_type, $question);
fwrite($handle, $write);
$import_questions[] = $question;
}
$import_settings['quiz_node'] = '1';
$import_settings['field_separator'] = ',';
$import_settings['files[upload]'] = $filepath;
$msg = $this
->drupalPost('admin/quiz/questions_import', $import_settings, 'Import');
$this
->assertPattern('/30 questions were imported successfully/', t('Checking import success message'));
$this
->quizHelper($import_questions);
}
function multichoiceHelper($import_type) {
$import_questions = array();
switch ($import_type) {
case 'aiken':
$import_settings['import_type'] = 'native_aiken';
$filetype = '.txt';
break;
case 'csv':
$import_settings['import_type'] = 'native_csv';
$filetype = '.csv';
break;
}
$filepath = file_create_filename($import_type . '_multichoice' . $filetype, file_directory_temp());
$handle = fopen($filepath, "w+");
for ($i = 0; $i < 30; $i++) {
$question = new stdClass();
$question->num_options = mt_rand(2, 6);
$question->answer = mt_rand(0, $question->num_options - 1);
$question->question = "Question #{$i}:";
$question->type = "multichoice";
$question->answers = array();
for ($j = 0; $j < $question->num_options; $j++) {
$question->answers[$j] = "Option #{$j}";
}
$write = $this
->writeImport($import_type, $question);
fwrite($handle, $write);
$import_questions[] = $question;
}
fclose($handle);
$import_settings['quiz_node'] = '1';
$import_settings['field_separator'] = ',';
$import_settings['files[upload]'] = $filepath;
$msg = $this
->drupalPost('admin/quiz/questions_import', $import_settings, 'Import');
$this
->assertPattern('/30 questions were imported successfully/', t('Checking import success message'));
$this
->quizHelper($import_questions);
}
function matchingHelper($import_type) {
$import_questions = array();
switch ($import_type) {
case 'aiken':
$this
->assertEqual(0, 1, "Aiken does not support matching import questions");
return;
break;
case 'csv':
$import_settings['import_type'] = 'native_csv';
$filetype = '.csv';
break;
}
$filepath = file_create_filename($import_type . '_matching' . $filetype, "sites/default/files");
$handle = fopen($filepath, "w+");
for ($i = 0; $i < 30; $i++) {
$question = new stdClass();
$question->num_options = mt_rand(1, 10);
$question->question = "Question #{$i}:";
$question->type = "matching";
$question->matches = array();
$question->answers = array();
for ($j = 0; $j < $question->num_options; $j++) {
$question->matches[] = "Match #{$j}";
$question->answers[] = "Answer #{$j}";
}
$write = $this
->writeImport($import_type, $question);
fwrite($handle, $write);
$import_questions[] = $question;
}
fclose($handle);
$import_settings['quiz_node'] = '1';
$import_settings['field_separator'] = ',';
$import_settings['files[upload]'] = $filepath;
$msg = $this
->drupalPost('admin/quiz/questions_import', $import_settings, 'Import');
$this
->assertPattern('/30 questions were imported successfully/', t('Checking import success message'));
$this
->quizHelper($import_questions);
}
function truefalseHelper($import_type) {
$import_questions = array();
switch ($import_type) {
case 'aiken':
$import_settings['import_type'] = 'native_aiken';
$filetype = '.txt';
break;
case 'csv':
$import_settings['import_type'] = 'native_csv';
$filetype = '.csv';
break;
}
$filepath = file_create_filename($import_type . '_truefalse' . $filetype, file_directory_temp());
$handle = fopen($filepath, "w+");
for ($i = 0; $i < 50; $i++) {
$question = new stdClass();
$question->answer = mt_rand(0, 1) == 0 ? "true" : "false";
$question->question = "Question #{$i}:";
$question->type = "true_false";
$question->feedback = "Feedback on question #{$i}";
$write = $this
->writeImport($import_type, $question);
fwrite($handle, $write);
$import_questions[] = $question;
}
fclose($handle);
$import_settings['quiz_node'] = '1';
$import_settings['field_separator'] = ',';
$import_settings['files[upload]'] = $filepath;
$msg = $this
->drupalPost('admin/quiz/questions_import', $import_settings, 'Import');
$this
->assertEqual(0, 1, $msg);
$this
->assertPattern('/50 questions were imported successfully/', t('Checking import success message'));
$this
->quizHelper($import_questions);
}
function shortanswerHelper($import_type) {
$import_questions = array();
switch ($import_type) {
case 'aiken':
$import_settings['import_type'] = 'native_aiken';
$filetype = '.txt';
break;
case 'csv':
$import_settings['import_type'] = 'native_csv';
$filetype = '.csv';
break;
}
$filepath = file_create_filename($import_type . '_shortanswer' . $filetype, file_directory_temp());
$handle = fopen($filepath, "w+");
for ($i = 0; $i < 20; $i++) {
$question = new stdClass();
$question->answer = "The answer is {$i}.";
$question->question = "Question #{$i}:";
$question->type = "short_answer";
$question->value = mt_rand(1, 5);
$question->sat = mt_rand(0, 3);
switch ($question->sat) {
case 0:
$question->shortanswertype = "case sensitive match";
break;
case 1:
$question->shortanswertype = "case insensitive match";
break;
case 2:
$question->shortanswertype = "regular expression match";
break;
case 3:
$question->shortanswertype = "manually score match";
break;
}
$write = $this
->writeImport($import_type, $question);
fwrite($handle, $write);
$import_questions[] = $question;
}
fclose($handle);
$import_settings['quiz_node'] = '1';
$import_settings['field_separator'] = ',';
$import_settings['files[upload]'] = $filepath;
$msg = $this
->drupalPost('admin/quiz/questions_import', $import_settings, 'Import');
$this
->assertPattern('/20 questions were imported successfully/', t('Checking import success message'));
$this
->quizHelper($import_questions);
}
function multiloadHelper($import_type) {
$import_settings['quiz_node'] = '1';
switch ($import_type) {
case 'aiken':
$import_settings['import_type'] = 'native_aiken';
$filetype = '.txt';
break;
case 'csv':
$import_settings['import_type'] = 'native_csv';
$filetype = '.csv';
break;
}
$import_settings['field_separator'] = ',';
$import_questions = array();
for ($i = 0; $i < 6; $i++) {
$filepath = file_create_filename($import_type . '_multi_' . $i . $filetype, file_directory_temp());
$handle = fopen($filepath, "w+");
for ($j = $i * 5; $j < ($i + 1) * 5; $j++) {
$question = new stdClass();
$question->num_options = mt_rand(2, 5);
$question->answer = mt_rand(0, $question->num_options - 1);
$question->question = "Question #{$j}:";
$question->type = "multichoice";
$question->answers = array(
"true",
"false",
);
for ($k = 0; $k < $question->num_options; $k++) {
$question->answers[$k] = "Option #{$k}";
}
$write = $this
->writeImport($import_type, $question);
fwrite($handle, $write);
$import_questions[] = $question;
}
fclose($handle);
$import_settings['files[upload]'] = $filepath;
$this
->drupalPost('admin/quiz/questions_import', $import_settings, 'Import');
$this
->assertPattern('/5 questions were imported successfully/', t('Checking import success message'));
}
$this
->quizHelper($import_questions);
}
function disabled_testAikenRoundTrip() {
$import_settings['quiz_node'] = '1';
$import_settings['import_type'] = 'native_aiken';
$import_settings['field_separator'] = ',';
$import_settings['files[upload]'] = realpath(drupal_get_path('module', 'quiz') . '/Examples/questions_import/aiken_example.txt');
$msg = $this
->drupalPost('admin/quiz/questions_import', $import_settings, 'Import');
$export_settings['quiz_node'] = '1';
$export_settings['export_format'] = 'native_aiken';
$this
->drupalPost('admin/quiz/questions_export', $export_settings, 'Export');
$h1 = file(file_directory_path() . '/Quiz.txt');
$h2 = file(realpath(drupal_get_path('module', 'quiz') . '/Examples/questions_import/aiken_export.txt'));
$this
->assertEqual(count($h1), count($h2), "[Aiken roundtrip] Same number of lines");
for ($i = 0; $i < count($h2) && $i < count($h1); $i++) {
$this
->assertIdentical($h1[$i], $h2[$i], "[Aiken roundtrip] Checking lines are the same");
}
}
function testAikenMedly() {
$this
->medlyHelper('aiken');
}
function testAikenMultichoice() {
$this
->multichoiceHelper('aiken');
}
function testAikenTrueFalse() {
$this
->truefalseHelper('aiken');
}
function testAikenShortAnswer() {
$this
->shortanswerHelper('aiken');
}
function testAikenMultiload() {
$this
->multiloadHelper('aiken');
}
function testCsvMedly() {
$this
->medlyHelper('csv');
}
function testCsvMultichoice() {
$this
->multichoiceHelper('csv');
}
function testCsvMatching() {
$this
->matchingHelper('csv');
}
function testCsvTrueFalse() {
$this
->truefalseHelper('csv');
}
function testCsvShortAnswer() {
$this
->shortanswerHelper('csv');
}
function testCsvMultiload() {
$this
->multiloadHelper('csv');
}
}