]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-14905 Started on the DDL functional tests. Added an ugly but temporary hack into...
authornicolasconnault <nicolasconnault>
Wed, 21 May 2008 14:59:33 +0000 (14:59 +0000)
committernicolasconnault <nicolasconnault>
Wed, 21 May 2008 14:59:33 +0000 (14:59 +0000)
lib/ddl/simpletest/testddllib.php
lib/deprecatedlib.php
lib/dml/moodle_database.php
lib/dml/simpletest/testdmllib.php [new file with mode: 0755]
lib/dmllib.php
lib/weblib.php

index ee1732dde8910ec02c6f7ed2b969fbf2b75c71c6..7545d1608b3dd1e297a3b5d26cb9bcc7ab28f033 100755 (executable)
@@ -14,15 +14,14 @@ require_once($CFG->libdir . '/ddllib.php');
 
 class ddllib_test extends UnitTestCase {
     private $tables = array();
-    private $db;
     private $dbmanager;
 
     public 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();
+        $db = new mysqli_adodb_moodle_database();
+        $db->connect($CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->dbpersist, $CFG->prefix);
+        $this->dbmanager = $db->get_manager();
 
         $table = new xmldb_table("testtable");
         $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
index f8997abc33a3b2bf808ba0b837955a81e096f028..02f72e450c4372e6f42ed864c85db76fa886b11f 100644 (file)
@@ -7,7 +7,7 @@
 // Moodle - Modular Object-Oriented Dynamic Learning Environment         //
 //          http://moodle.org                                            //
 //                                                                       //
-// Copyright (C) 1999 onwards Martin Dougiamas, Moodle  http://moodle.com  //
+// Copyright (C) 1999 onwards Martin Dougiamas, Moodle  http://moodle.com//
 //                                                                       //
 // This program is free software; you can redistribute it and/or modify  //
 // it under the terms of the GNU General Public License as published by  //
@@ -506,8 +506,8 @@ function get_group_students($groupids, $sort='ul.timeaccess DESC') {
 }
 
 /**
- * Determines if the HTML editor is enabled. This function has 
- * been deprecated, but needs to remain available because it is 
+ * Determines if the HTML editor is enabled. This function has
+ * been deprecated, but needs to remain available because it is
  * used in language packs for Moodle 1.6 to 1.9.
  *
  * @deprecated Use {@link can_use_html_editor()} instead.
@@ -819,6 +819,15 @@ function error ($message, $link='') {
     debugging('error() is a deprecated function, please call print_error() instead of error()', DEBUG_DEVELOPER);
     $message = clean_text($message);   // In case nasties are in here
 
+    /**
+     * 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 (defined('FULLME') && FULLME == 'cron') {
         // Errors in cron should be mtrace'd.
         mtrace($message);
index 21c01043507d0b0012fdc7233ac4117cb7342214..503b501b79b0f8c6cf48a05262d87e150d55dcae 100644 (file)
@@ -181,8 +181,9 @@ abstract class moodle_database {
         // 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;
@@ -192,12 +193,12 @@ abstract class moodle_database {
             $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) {
@@ -216,12 +217,12 @@ abstract class moodle_database {
             } 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
@@ -229,7 +230,7 @@ abstract class moodle_database {
                 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
@@ -253,15 +254,15 @@ abstract class moodle_database {
             }
 
             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
@@ -283,7 +284,7 @@ abstract class moodle_database {
                     $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 :-(');
             }
         }
diff --git a/lib/dml/simpletest/testdmllib.php b/lib/dml/simpletest/testdmllib.php
new file mode 100755 (executable)
index 0000000..82cca6a
--- /dev/null
@@ -0,0 +1,199 @@
+<?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]));
+
+    }
+
+}
+
+?>
index 1b09e3691d35953fc82df6f95556d3702321215c..a62cd5ff97e480d207a1149ad88536e9ffe466f3 100644 (file)
@@ -52,7 +52,7 @@ define('SQL_PARAMS_QM', 2);
 /**
  * Bitmask, indicates only $1, $2.. type parameters are supported by db backend.
  */
-define('SQL_PARAMS_DOLAR', 4);
+define('SQL_PARAMS_DOLLAR', 4);
 
 
 /**
index a87df9058d9b913bb899355f6d8ff700ea6e75d3..e9d7819c906d4d853423e9c97cf5f2b8efb6ce7f 100644 (file)
@@ -622,7 +622,7 @@ function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
  *
  * $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
@@ -673,7 +673,7 @@ function element_to_popup_window ($type=null, $url=null, $name=null, $linkname=n
     } else {
         $name = 'popup';
     }
-    
+
     // get some default string, using the localized version of legacy defaults
     if (is_null($linkname) || $linkname === '') {
         $linkname = get_string('clickhere');
@@ -859,7 +859,7 @@ function choose_from_menu ($options, $name, $selected='', $nothing='choose', $sc
  * 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)
@@ -1110,16 +1110,16 @@ $targetwindow='self', $selectlabel='', $optionsextra=NULL) {
         $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";
     }
@@ -5638,6 +5638,16 @@ function print_error ($errorcode, $module='', $link='', $a=NULL) {
 
     $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);
@@ -5746,11 +5756,11 @@ function 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);
@@ -6442,8 +6452,8 @@ function print_side_block_start($heading='', $attributes = array()) {
         // 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>&nbsp;</div></div>';
@@ -6801,7 +6811,7 @@ function page_doc_link($text='', $iconpath='') {
  */
 function doc_link($path='', $text='', $iconpath='') {
     global $CFG;
-    
+
     if (empty($CFG->docroot)) {
         return '';
     }
@@ -6819,7 +6829,7 @@ function doc_link($path='', $text='', $iconpath='') {
 
     $str = "<a href=\"$url\"$target>";
 
-    if (empty($iconpath)) { 
+    if (empty($iconpath)) {
         $iconpath = $CFG->httpswwwroot . '/pix/docs.gif';
     }