// convert table names
$sql = preg_replace('/\{([a-z][a-z0-9_]*)\}/', $this->prefix.'$1', $sql);
- $named_count = preg_match_all('/(?!:):[a-z][a-z0-9_]*/', $sql, $named_matches); // :: used in pgsql casts
- $dolar_count = preg_match_all('/\$[1-9][0-9]*/', $sql, $dolar_matches);
+ // NICOLAS C: Fixed regexp for negative backwards lookahead of double colons. Thanks for Sam Marshall's help
+ $named_count = preg_match_all('/(?<!:):[a-z][a-z0-9_]*/', $sql, $named_matches); // :: used in pgsql casts
+ $dollar_count = preg_match_all('/\$[1-9][0-9]*/', $sql, $dollar_matches);
$q_count = substr_count($sql, '?');
$count = 0;
$count = $named_count;
}
- if ($dolar_count) {
+ if ($dollar_count) {
if ($count) {
error('ERROR: Mixed types of sql query parameters!!');
}
- $type = SQL_PARAMS_DOLAR;
- $count = $dolar_count;
+ $type = SQL_PARAMS_DOLLAR;
+ $count = $dollar_count;
}
if ($q_count) {
} else if ($allowed_types & SQL_PARAMS_QM) {
return array($sql, array(), SQL_PARAMS_QM);
} else {
- return array($sql, array(), SQL_PARAMS_DOLAR);
+ return array($sql, array(), SQL_PARAMS_DOLLAR);
}
}
if ($count > count($params)) {
- error('ERROR: Incorrect number of query parameters!! '.s($sql));
+ error('ERROR: Incorrect number of query parameters!!');
}
if ($type & $allowed_types) { // bitwise AND
if ($type == SQL_PARAMS_QM) {
return array($sql, array_values($params), SQL_PARAMS_QM); // 0-based array required
} else {
- //better do the validation of names bellow
+ //better do the validation of names below
}
}
// needs some fixing or validation - there might be more params than needed
}
if ($target_type & SQL_PARAMS_QM) {
- $sql = preg_replace('/(?!:):[a-z][a-z0-9_]*/', '?', $sql);
+ $sql = preg_replace('/(?<!:):[a-z][a-z0-9_]*/', '?', $sql);
return array($sql, array_values($finalparams), SQL_PARAMS_QM); // 0-based required
} else if ($target_type & SQL_PARAMS_NAMED) {
return array($sql, $finalparams, SQL_PARAMS_NAMED);
- } else { // $type & SQL_PARAMS_DOLAR
+ } else { // $type & SQL_PARAMS_DOLLAR
error('Pg $1, $2 bound syntax not supported yet :-(');
}
- } else if ($type == SQL_PARAMS_DOLAR) {
+ } else if ($type == SQL_PARAMS_DOLLAR) {
error('Pg $1, $2 bound syntax not supported yet :-(');
} else { // $type == SQL_PARAMS_QM
$finalparams[$pname] = $param;
}
return array($sql, $finalparams, SQL_PARAMS_NAMED);
- } else { // $type & SQL_PARAMS_DOLAR
+ } else { // $type & SQL_PARAMS_DOLLAR
error('Pg $1, $2 bound syntax not supported yet :-(');
}
}
--- /dev/null
+<?php
+/**
+ * Unit tests for dmllib
+ * @package dmllib
+ */
+
+if (!defined('MOODLE_INTERNAL')) {
+ die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
+}
+
+require_once($CFG->libdir . '/simpletestlib/web_tester.php');
+require_once($CFG->libdir . '/dmllib.php');
+require_once($CFG->libdir . '/dml/mysql_adodb_moodle_database.php');
+
+class dmllib_test extends UnitTestCase {
+ private $tables = array();
+ private $dbmanager;
+ private $db;
+
+ function setUp() {
+ global $CFG;
+
+ $this->db = new mysqli_adodb_moodle_database();
+ $this->db->connect($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->prefix);
+ $this->dbmanager = $this->db->get_manager();
+
+ $table = new xmldb_table("testtable");
+ $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
+ $table->addFieldInfo('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('type', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM,
+ array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general');
+ $table->addFieldInfo('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, null);
+ $table->addFieldInfo('intro', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null, null, null);
+ $table->addFieldInfo('logo', XMLDB_TYPE_BINARY, 'big', null, XMLDB_NOTNULL, null, null, null);
+ $table->addFieldInfo('assessed', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('assesstimestart', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('assesstimefinish', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('scale', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('maxbytes', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('forcesubscribe', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('trackingtype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '1');
+ $table->addFieldInfo('rsstype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('rssarticles', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('grade', XMLDB_TYPE_NUMBER, '20,0', XMLDB_UNSIGNED, null, null, null, null, null);
+ $table->addFieldInfo('percent', XMLDB_TYPE_NUMBER, '5,2', null, null, null, null, null, null);
+ $table->addFieldInfo('warnafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('blockafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addFieldInfo('blockperiod', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0');
+ $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
+ $table->addIndexInfo('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
+
+ $table->setComment("This is a test'n drop table. You can drop it safely");
+
+ $this->dbmanager->create_table($table);
+ $this->tables[] = $table;
+
+ // insert records
+ $datafile = $CFG->libdir . '/dml/simpletest/fixtures/testdata.xml';
+ $xml = simplexml_load_file($datafile);
+
+ foreach ($xml->record as $record) {
+ $this->db->insert_record('testtable', $record);
+ }
+ }
+
+ function tearDown() {
+ foreach ($this->tables as $key => $table) {
+ if ($this->dbmanager->table_exists($table)) {
+ $this->dbmanager->drop_table($table, true, false);
+ }
+ }
+ unset($this->tables);
+
+ setup_DB();
+ }
+
+ function test_insert_record() {
+
+ }
+
+ function test_get_record_select() {
+ $record = $this->db->get_record_select('testtable', 'id = 1');
+ }
+
+ function test_fix_sql_params() {
+ // Malformed table placeholder
+ $sql = "SELECT * FROM [testtable]";
+ $sqlarray = $this->db->fix_sql_params($sql);
+ $this->assertEqual($sql, $sqlarray[0]);
+
+ // Correct table placeholder substitution
+ $sql = "SELECT * FROM {testtable}";
+ $sqlarray = $this->db->fix_sql_params($sql);
+ $this->assertEqual("SELECT * FROM {$this->db->get_prefix()}testtable", $sqlarray[0]);
+
+ // Malformed param placeholders
+ $sql = "SELECT * FROM {testtable} WHERE name = ?param1";
+ $params = array('param1' => 'first record');
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ $this->assertEqual("SELECT * FROM {$this->db->get_prefix()}testtable WHERE name = ?param1", $sqlarray[0]);
+
+ // Mixed param types (colon and dollar)
+ $sql = "SELECT * FROM {testtable} WHERE name = :param1, rsstype = \$1";
+ $params = array('param1' => 'first record', 'param2' => 1);
+ try {
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ } catch (Exception $e) {
+ $this->assertEqual('error() call: ERROR: Mixed types of sql query parameters!!', $e->getMessage());
+ }
+
+ // Mixed param types (question and dollar)
+ $sql = "SELECT * FROM {testtable} WHERE name = ?, rsstype = \$1";
+ $params = array('param1' => 'first record', 'param2' => 1);
+ $exception_caught = false;
+ try {
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ } catch (Exception $e) {
+ $exception_caught = true;
+ }
+ $this->assertTrue($exception_caught);
+
+ // Too many params in sql
+ $sql = "SELECT * FROM {testtable} WHERE name = ?, rsstype = ?, course = ?";
+ $params = array('first record', 1);
+ $exception_caught = false;
+ try {
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ } catch (Exception $e) {
+ $exception_caught = true;
+ }
+ $this->assertTrue($exception_caught);
+
+ // Too many params in array: no error
+ $params[] = 1;
+ $params[] = time();
+ $exception_caught = false;
+ $sqlarray = null;
+
+ try {
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ } catch (Exception $e) {
+ $exception_caught = true;
+ }
+ $this->assertFalse($exception_caught);
+ $this->assertTrue($sqlarray[0]);
+
+ // Named params missing from array
+ $sql = "SELECT * FROM {testtable} WHERE name = :name, rsstype = :rsstype";
+ $params = array('wrongname' => 'first record', 'rsstype' => 1);
+ $exception_caught = false;
+ try {
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ } catch (Exception $e) {
+ $exception_caught = true;
+ }
+ $this->assertTrue($exception_caught);
+
+ // Duplicate named param in query
+ $sql = "SELECT * FROM {testtable} WHERE name = :name, rsstype = :name";
+ $params = array('name' => 'first record', 'rsstype' => 1);
+ $exception_caught = false;
+ try {
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ } catch (Exception $e) {
+ $exception_caught = true;
+ }
+ $this->assertTrue($exception_caught);
+
+ // Unsupported Bound params
+ $sql = "SELECT * FROM {testtable} WHERE name = $1, rsstype = $2";
+ $params = array('first record', 1);
+ $exception_caught = false;
+ try {
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ } catch (Exception $e) {
+ $exception_caught = true;
+ }
+ $this->assertTrue($exception_caught);
+
+ // Correct named param placeholders
+ $sql = "SELECT * FROM {testtable} WHERE name = :name, rsstype = :rsstype";
+ $params = array('name' => 'first record', 'rsstype' => 1);
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ $this->assertEqual("SELECT * FROM {$this->db->get_prefix()}testtable WHERE name = ?, rsstype = ?", $sqlarray[0]);
+ $this->assertEqual(2, count($sqlarray[1]));
+
+ // Correct ? params
+ $sql = "SELECT * FROM {testtable} WHERE name = ?, rsstype = ?";
+ $params = array('first record', 1);
+ $sqlarray = $this->db->fix_sql_params($sql, $params);
+ $this->assertEqual("SELECT * FROM {$this->db->get_prefix()}testtable WHERE name = ?, rsstype = ?", $sqlarray[0]);
+ $this->assertEqual(2, count($sqlarray[1]));
+
+ }
+
+}
+
+?>
*
* $url must be relative to home page eg /mod/survey/stuff.php
* @param string $url Web link relative to home page
- * @param string $name Name to be assigned to the popup window (this is used by
+ * @param string $name Name to be assigned to the popup window (this is used by
* client-side scripts to "talk" to the popup window)
* @param string $linkname Text to be displayed as web link
* @param int $height Height to assign to popup window
} else {
$name = 'popup';
}
-
+
// get some default string, using the localized version of legacy defaults
if (is_null($linkname) || $linkname === '') {
$linkname = get_string('clickhere');
* Choose value 0 or 1 from a menu with options 'No' and 'Yes'.
* Other options like choose_from_menu.
* @param string $name
- * @param string $selected
+ * @param string $selected
* @param string $string (defaults to '')
* @param boolean $return whether this function should return a string or output it (defaults to false)
* @param boolean $disabled (defaults to false)
$selectlabel = '<label for="'.$formid.'_jump">'.$selectlabel.'</label>';
}
- //IE and Opera fire the onchange when ever you move into a dropdwown list with the keyboard.
+ //IE and Opera fire the onchange when ever you move into a dropdwown list with the keyboard.
//onfocus will call a function inside dropdown.js. It fixes this IE/Opera behavior.
if (check_browser_version('MSIE') || check_browser_version('Opera')) {
$output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" onfocus="initSelect(\''.$formid.'\','.$targetwindow.')" name="jump">'."\n";
}
//Other browser
else {
- $output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" name="jump" onchange="'.$targetwindow.'.location=document.getElementById(\''.$formid.'\').jump.options[document.getElementById(\''.$formid.'\').jump.selectedIndex].value;">'."\n";
+ $output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" name="jump" onchange="'.$targetwindow.'.location=document.getElementById(\''.$formid.'\').jump.options[document.getElementById(\''.$formid.'\').jump.selectedIndex].value;">'."\n";
}
-
+
if ($nothing != '') {
$output .= " <option value=\"javascript:void(0)\">$nothing</option>\n";
}
$message = get_string($errorcode, $module, $a);
+
+ /**
+ * TODO VERY DIRTY HACK USED FOR UNIT TESTING UNTIL PROPER EXCEPTION HANDLING IS IMPLEMENTED
+ */
+ if (defined('UNITTEST')) {
+ // Errors in unit test become exceptions, so you can unit test
+ // code that might call error().
+ throw new Exception('error() call: '. $message.($link!=='' ? ' ['.$link.']' : ''));
+ }
+
if (!isset($CFG->theme)) {
// error found before setup.php finished
print_early_error($message);
* Default errorcode is 1.
*
* Very useful for perl-like error-handling:
- *
+ *
* do_somethting() or mdie("Something went wrong");
*
* @param string $msg Error message
- * @param integer $errorcode Error code to emit
+ * @param integer $errorcode Error code to emit
*/
function mdie($msg='', $errorcode=1) {
trigger_error($msg);
// page block including the h2 for accessibility
if(strpos($heading,'</div>')===false) {
$heading='<div class="title"><h2>'.$heading.'</h2></div>';
- }
-
+ }
+
echo '<div class="header">';
if (!empty($THEME->customcorners)) {
echo '<div class="bt"><div> </div></div>';
*/
function doc_link($path='', $text='', $iconpath='') {
global $CFG;
-
+
if (empty($CFG->docroot)) {
return '';
}
$str = "<a href=\"$url\"$target>";
- if (empty($iconpath)) {
+ if (empty($iconpath)) {
$iconpath = $CFG->httpswwwroot . '/pix/docs.gif';
}